Skip to content

Commit c4dfb53

Browse files
authored
Merge pull request #497 from madsmtm/refactor-encodings
Add `EncodeReturn`, `EncodeArgument` and `EncodeArguments`
2 parents 567a970 + e03b060 commit c4dfb53

30 files changed

+476
-411
lines changed

crates/block2/src/block.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
use core::marker::PhantomData;
22
use core::mem;
33

4-
use objc2::encode::__unstable::EncodeReturn;
5-
use objc2::encode::{Encode, Encoding, RefEncode};
4+
use objc2::encode::{EncodeArgument, EncodeReturn, Encoding, RefEncode};
65

76
use crate::ffi;
87

98
/// Types that may be used as the arguments of an Objective-C block.
109
///
1110
/// This is implemented for tuples of up to 12 arguments, where each argument
12-
/// implements [`Encode`].
11+
/// implements [`EncodeArgument`].
1312
///
1413
///
1514
/// # Safety
@@ -28,7 +27,7 @@ pub unsafe trait BlockArguments: Sized {
2827

2928
macro_rules! block_args_impl {
3029
($($a:ident: $t:ident),*) => (
31-
unsafe impl<$($t: Encode),*> BlockArguments for ($($t,)*) {
30+
unsafe impl<$($t: EncodeArgument),*> BlockArguments for ($($t,)*) {
3231
#[inline]
3332
unsafe fn __call_block<R: EncodeReturn>(
3433
invoke: unsafe extern "C" fn(),

crates/block2/src/concrete_block.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ use core::ops::Deref;
55
use core::ptr;
66
use std::os::raw::c_ulong;
77

8-
use objc2::encode::__unstable::EncodeReturn;
9-
use objc2::encode::{Encode, Encoding, RefEncode};
8+
use objc2::encode::{EncodeArgument, EncodeReturn, Encoding, RefEncode};
109

1110
use crate::{ffi, Block, BlockArguments, RcBlock};
1211

@@ -17,7 +16,8 @@ mod private {
1716
/// Types that may be converted into a [`ConcreteBlock`].
1817
///
1918
/// This is implemented for [`Fn`] closures of up to 12 arguments, where each
20-
/// argument and the return type implements [`Encode`].
19+
/// argument implements [`EncodeArgument`] and the return type implements
20+
/// [`EncodeReturn`].
2121
///
2222
///
2323
/// # Safety
@@ -37,12 +37,12 @@ macro_rules! concrete_block_impl {
3737
concrete_block_impl!($f,);
3838
);
3939
($f:ident, $($a:ident : $t:ident),*) => (
40-
impl<$($t: Encode,)* R: EncodeReturn, X> private::Sealed<($($t,)*)> for X
40+
impl<$($t: EncodeArgument,)* R: EncodeReturn, X> private::Sealed<($($t,)*)> for X
4141
where
4242
X: Fn($($t,)*) -> R,
4343
{}
4444

45-
unsafe impl<$($t: Encode,)* R: EncodeReturn, X> IntoConcreteBlock<($($t,)*)> for X
45+
unsafe impl<$($t: EncodeArgument,)* R: EncodeReturn, X> IntoConcreteBlock<($($t,)*)> for X
4646
where
4747
X: Fn($($t,)*) -> R,
4848
{

crates/block2/src/global.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use core::ops::Deref;
55
use core::ptr;
66
use std::os::raw::c_ulong;
77

8-
use objc2::encode::__unstable::EncodeReturn;
8+
use objc2::encode::EncodeReturn;
99

1010
use super::{ffi, Block};
1111
use crate::BlockArguments;

crates/objc2/CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
88

99
### Added
1010
* Added `mutability::IsMainThreadOnly`.
11+
* Added new `encode` traits `EncodeReturn`, `EncodeArgument` and
12+
`EncodeArguments`.
13+
14+
### Changed
15+
* **BREAKING**: `AnyClass::verify_sel` now take more well-defined types
16+
`EncodeArguments` and `EncodeReturn`.
1117

1218

1319
## 0.4.1 - 2023-07-31
+168
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
use crate::encode::{EncodeArgument, EncodeReturn};
2+
use crate::rc::Id;
3+
use crate::runtime::Bool;
4+
use crate::Message;
5+
6+
mod argument_private {
7+
pub trait Sealed {}
8+
}
9+
10+
/// Represents types that can be converted to/from an [`EncodeArgument`] type.
11+
///
12+
/// This is implemented specially for [`bool`] to allow using that as
13+
/// Objective-C `BOOL`, where it would otherwise not be allowed (since they
14+
/// are not ABI compatible).
15+
///
16+
/// This is also done specially for `&mut Id<_>`-like arguments, to allow
17+
/// using those as "out" parameters.
18+
pub trait ConvertArgument: argument_private::Sealed {
19+
/// The inner type that this can be converted to and from.
20+
#[doc(hidden)]
21+
type __Inner: EncodeArgument;
22+
23+
/// A helper type for out parameters.
24+
#[doc(hidden)]
25+
type __StoredBeforeMessage: Sized;
26+
27+
#[doc(hidden)]
28+
fn __from_declared_param(inner: Self::__Inner) -> Self;
29+
30+
#[doc(hidden)]
31+
fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage);
32+
33+
#[doc(hidden)]
34+
unsafe fn __process_after_message_send(_stored: Self::__StoredBeforeMessage) {}
35+
}
36+
37+
// Implemented in writeback.rs
38+
impl<T: Message> argument_private::Sealed for &mut Id<T> {}
39+
impl<T: Message> argument_private::Sealed for Option<&mut Id<T>> {}
40+
impl<T: Message> argument_private::Sealed for &mut Option<Id<T>> {}
41+
impl<T: Message> argument_private::Sealed for Option<&mut Option<Id<T>>> {}
42+
43+
impl<T: EncodeArgument> argument_private::Sealed for T {}
44+
impl<T: EncodeArgument> ConvertArgument for T {
45+
type __Inner = Self;
46+
47+
type __StoredBeforeMessage = ();
48+
49+
#[inline]
50+
fn __from_declared_param(inner: Self::__Inner) -> Self {
51+
inner
52+
}
53+
54+
#[inline]
55+
fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage) {
56+
(self, ())
57+
}
58+
}
59+
60+
impl argument_private::Sealed for bool {}
61+
impl ConvertArgument for bool {
62+
type __Inner = Bool;
63+
64+
type __StoredBeforeMessage = ();
65+
66+
#[inline]
67+
fn __from_declared_param(inner: Self::__Inner) -> Self {
68+
inner.as_bool()
69+
}
70+
71+
#[inline]
72+
fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage) {
73+
(Bool::new(self), ())
74+
}
75+
}
76+
77+
mod return_private {
78+
pub trait Sealed {}
79+
}
80+
81+
/// Same as [`ConvertArgument`], but for return types.
82+
pub trait ConvertReturn: return_private::Sealed {
83+
/// The inner type that this can be converted to and from.
84+
#[doc(hidden)]
85+
type __Inner: EncodeReturn;
86+
87+
#[doc(hidden)]
88+
fn __into_declared_return(self) -> Self::__Inner;
89+
90+
#[doc(hidden)]
91+
fn __from_return(inner: Self::__Inner) -> Self;
92+
}
93+
94+
impl<T: EncodeReturn> return_private::Sealed for T {}
95+
impl<T: EncodeReturn> ConvertReturn for T {
96+
type __Inner = Self;
97+
98+
#[inline]
99+
fn __into_declared_return(self) -> Self::__Inner {
100+
self
101+
}
102+
103+
#[inline]
104+
fn __from_return(inner: Self::__Inner) -> Self {
105+
inner
106+
}
107+
}
108+
109+
impl return_private::Sealed for bool {}
110+
impl ConvertReturn for bool {
111+
type __Inner = Bool;
112+
113+
#[inline]
114+
fn __into_declared_return(self) -> Self::__Inner {
115+
Bool::new(self)
116+
}
117+
118+
#[inline]
119+
fn __from_return(inner: Self::__Inner) -> Self {
120+
inner.as_bool()
121+
}
122+
}
123+
124+
#[cfg(test)]
125+
mod tests {
126+
use super::*;
127+
128+
use core::any::TypeId;
129+
130+
#[test]
131+
fn convert_normally_noop() {
132+
assert_eq!(
133+
TypeId::of::<<i32 as ConvertArgument>::__Inner>(),
134+
TypeId::of::<i32>()
135+
);
136+
assert_eq!(<i32 as ConvertArgument>::__from_declared_param(42), 42);
137+
assert_eq!(ConvertArgument::__into_argument(42i32).0, 42);
138+
}
139+
140+
#[test]
141+
fn convert_i8() {
142+
assert_eq!(
143+
TypeId::of::<<i8 as ConvertArgument>::__Inner>(),
144+
TypeId::of::<i8>()
145+
);
146+
assert_eq!(<i8 as ConvertArgument>::__from_declared_param(-3), -3);
147+
assert_eq!(ConvertArgument::__into_argument(-3i32).0, -3);
148+
}
149+
150+
#[test]
151+
fn convert_bool() {
152+
assert!(!<bool as ConvertArgument>::__from_declared_param(Bool::NO));
153+
assert!(<bool as ConvertArgument>::__from_declared_param(Bool::YES));
154+
assert!(!<bool as ConvertReturn>::__from_return(Bool::NO));
155+
assert!(<bool as ConvertReturn>::__from_return(Bool::YES));
156+
157+
assert!(!ConvertArgument::__into_argument(false).0.as_bool());
158+
assert!(ConvertArgument::__into_argument(true).0.as_bool());
159+
assert!(!ConvertReturn::__into_declared_return(false).as_bool());
160+
assert!(ConvertReturn::__into_declared_return(true).as_bool());
161+
162+
#[cfg(all(feature = "apple", target_os = "macos", target_arch = "x86_64"))]
163+
assert_eq!(
164+
<bool as ConvertArgument>::__Inner::ENCODING_ARGUMENT,
165+
crate::encode::Encoding::Char,
166+
);
167+
}
168+
}

crates/objc2/src/__macro_helpers/mod.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,17 @@ pub use std::sync::Once;
2929

3030
mod cache;
3131
mod common_selectors;
32+
mod convert;
3233
mod declare_class;
34+
mod writeback;
3335

3436
pub use self::cache::{CachedClass, CachedSel};
3537
pub use self::common_selectors::{alloc_sel, dealloc_sel, init_sel, new_sel};
3638
pub use self::declare_class::{
3739
assert_mutability_matches_superclass_mutability, MaybeOptionId, MessageRecieveId,
3840
ValidSubclassMutability,
3941
};
42+
pub use convert::{ConvertArgument, ConvertReturn};
4043

4144
/// Helper for specifying the retain semantics for a given selector family.
4245
///
@@ -125,8 +128,8 @@ pub trait MsgSendId<T, U> {
125128
} else {
126129
// In this case, the error has very likely been created, but has
127130
// been autoreleased (as is common for "out parameters", see
128-
// `src/rc/writeback.rs`). Hence we need to retain it if we want
129-
// it to live across autorelease pools.
131+
// `src/__macro_helpers/writeback.rs`). Hence we need to retain it
132+
// if we want it to live across autorelease pools.
130133
//
131134
// SAFETY: The message send is guaranteed to populate the error
132135
// object, or leave it as NULL. The error is shared, and all

crates/objc2/src/rc/writeback.rs renamed to crates/objc2/src/__macro_helpers/writeback.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
use core::mem::ManuallyDrop;
1111
use core::ptr::NonNull;
1212

13-
use crate::encode::__unstable::EncodeConvertArgument;
13+
use super::ConvertArgument;
1414
use crate::rc::Id;
1515
use crate::Message;
1616

1717
// Note the `'static` bound here - this may not be necessary, but I'm unsure
1818
// of the exact requirements, so we better keep it for now.
19-
impl<T: Message + 'static> EncodeConvertArgument for &mut Id<T> {
19+
impl<T: Message + 'static> ConvertArgument for &mut Id<T> {
2020
// We use `*mut T` as the inner value instead of `NonNull<T>`, since we
2121
// want to do debug checking that the value hasn't unexpectedly been
2222
// overwritten to contain NULL (which is clear UB, but the user might have
@@ -109,7 +109,7 @@ impl<T: Message + 'static> EncodeConvertArgument for &mut Id<T> {
109109
}
110110
}
111111

112-
impl<T: Message + 'static> EncodeConvertArgument for &mut Option<Id<T>> {
112+
impl<T: Message + 'static> ConvertArgument for &mut Option<Id<T>> {
113113
type __Inner = NonNull<*mut T>;
114114

115115
type __StoredBeforeMessage = (Self::__Inner, *mut T);
@@ -156,7 +156,7 @@ impl<T: Message + 'static> EncodeConvertArgument for &mut Option<Id<T>> {
156156
// known at compile-time, and for the `None` case it would be detrimental to
157157
// have extra `retain/release` calls here.
158158

159-
impl<T: Message + 'static> EncodeConvertArgument for Option<&mut Id<T>> {
159+
impl<T: Message + 'static> ConvertArgument for Option<&mut Id<T>> {
160160
type __Inner = Option<NonNull<*mut T>>;
161161

162162
type __StoredBeforeMessage = Option<(NonNull<*mut T>, NonNull<T>)>;
@@ -185,7 +185,7 @@ impl<T: Message + 'static> EncodeConvertArgument for Option<&mut Id<T>> {
185185
}
186186
}
187187

188-
impl<T: Message + 'static> EncodeConvertArgument for Option<&mut Option<Id<T>>> {
188+
impl<T: Message + 'static> ConvertArgument for Option<&mut Option<Id<T>>> {
189189
type __Inner = Option<NonNull<*mut T>>;
190190

191191
type __StoredBeforeMessage = Option<(NonNull<*mut T>, *mut T)>;

crates/objc2/src/declare/mod.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,7 @@ use core::ptr;
131131
use core::ptr::NonNull;
132132
use std::ffi::CString;
133133

134-
use crate::encode::__unstable::{EncodeArguments, EncodeReturn};
135-
use crate::encode::{Encode, Encoding, RefEncode};
134+
use crate::encode::{Encode, EncodeArgument, EncodeArguments, EncodeReturn, Encoding, RefEncode};
136135
use crate::ffi;
137136
use crate::mutability::IsMutable;
138137
use crate::rc::Allocated;
@@ -171,14 +170,14 @@ macro_rules! method_decl_impl {
171170
where
172171
T: ?Sized + $t_bound,
173172
$r: EncodeReturn,
174-
$($t: Encode,)*
173+
$($t: EncodeArgument,)*
175174
{}
176175

177176
impl<$($l,)* T, $r, $($t),*> MethodImplementation for $f
178177
where
179178
T: ?Sized + $t_bound,
180179
$r: EncodeReturn,
181-
$($t: Encode,)*
180+
$($t: EncodeArgument,)*
182181
{
183182
type Callee = T;
184183
type Ret = $r;
@@ -193,13 +192,13 @@ macro_rules! method_decl_impl {
193192
impl<$($l,)* $r, $($t),*> private::Sealed for $f
194193
where
195194
$r: EncodeReturn,
196-
$($t: Encode,)*
195+
$($t: EncodeArgument,)*
197196
{}
198197

199198
impl<$($l,)* $r, $($t),*> MethodImplementation for $f
200199
where
201200
$r: EncodeReturn,
202-
$($t: Encode,)*
201+
$($t: EncodeArgument,)*
203202
{
204203
type Callee = $callee;
205204
type Ret = $r;
@@ -215,14 +214,14 @@ macro_rules! method_decl_impl {
215214
impl<T, $($t),*> private::Sealed for $f
216215
where
217216
T: ?Sized + Message,
218-
$($t: Encode,)*
217+
$($t: EncodeArgument,)*
219218
{}
220219

221220
#[doc(hidden)]
222221
impl<T, $($t),*> MethodImplementation for $f
223222
where
224223
T: ?Sized + Message,
225-
$($t: Encode,)*
224+
$($t: EncodeArgument,)*
226225
{
227226
type Callee = T;
228227
type Ret = __IdReturnValue;

0 commit comments

Comments
 (0)