objc2/__macro_helpers/
convert.rs

1use crate::encode::{EncodeArgument, EncodeArguments, EncodeReturn};
2use crate::rc::{Allocated, Retained};
3use crate::runtime::{AnyObject, Bool, Sel};
4use crate::Message;
5
6mod 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 Retained<_>`-like arguments, to
17/// allow using those as "out" / pass-by-writeback parameters.
18pub 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    ///
25    /// When dropped, this will process any necessary change to the
26    /// parameters.
27    #[doc(hidden)]
28    type __WritebackOnDrop: Sized;
29
30    #[doc(hidden)]
31    fn __from_defined_param(inner: Self::__Inner) -> Self;
32
33    /// # Safety
34    ///
35    /// The `__WritebackOnDrop` return type must not be leaked, and the
36    /// `__Inner` pointer must not be used after the `__WritebackOnDrop` has
37    /// dropped.
38    ///
39    /// NOTE: The standard way to ensure such a thing is with closures, but
40    /// using those would interact poorly with backtraces of the message send,
41    /// so we're forced to ensure this out of band.
42    #[doc(hidden)]
43    unsafe fn __into_argument(self) -> (Self::__Inner, Self::__WritebackOnDrop);
44}
45
46// Implemented in writeback.rs
47impl<T: Message> argument_private::Sealed for &mut Retained<T> {}
48impl<T: Message> argument_private::Sealed for Option<&mut Retained<T>> {}
49impl<T: Message> argument_private::Sealed for &mut Option<Retained<T>> {}
50impl<T: Message> argument_private::Sealed for Option<&mut Option<Retained<T>>> {}
51
52impl<T: EncodeArgument> argument_private::Sealed for T {}
53impl<T: EncodeArgument> ConvertArgument for T {
54    type __Inner = Self;
55
56    type __WritebackOnDrop = ();
57
58    #[inline]
59    fn __from_defined_param(inner: Self::__Inner) -> Self {
60        inner
61    }
62
63    #[inline]
64    unsafe fn __into_argument(self) -> (Self::__Inner, Self::__WritebackOnDrop) {
65        (self, ())
66    }
67}
68
69impl argument_private::Sealed for bool {}
70impl ConvertArgument for bool {
71    type __Inner = Bool;
72
73    type __WritebackOnDrop = ();
74
75    #[inline]
76    fn __from_defined_param(inner: Self::__Inner) -> Self {
77        inner.as_bool()
78    }
79
80    #[inline]
81    unsafe fn __into_argument(self) -> (Self::__Inner, Self::__WritebackOnDrop) {
82        (Bool::new(self), ())
83    }
84}
85
86mod return_private {
87    pub trait Sealed {}
88}
89
90/// Same as [`ConvertArgument`], but for return types.
91///
92/// See `RetainSemantics` for more details.
93pub trait ConvertReturn<MethodFamily>: return_private::Sealed {
94    type Inner: EncodeReturn;
95
96    #[track_caller]
97    unsafe fn convert_message_return(
98        inner: Self::Inner,
99        receiver_ptr: *mut AnyObject,
100        sel: Sel,
101    ) -> Self;
102
103    fn convert_defined_return(self) -> Self::Inner;
104}
105
106impl<T: EncodeReturn> return_private::Sealed for T {}
107impl<T: EncodeReturn, MethodFamily> ConvertReturn<MethodFamily> for T {
108    type Inner = Self;
109
110    #[inline]
111    unsafe fn convert_message_return(
112        inner: Self::Inner,
113        _receiver_ptr: *mut AnyObject,
114        _sel: Sel,
115    ) -> Self {
116        inner
117    }
118
119    #[inline]
120    fn convert_defined_return(self) -> Self::Inner {
121        self
122    }
123}
124
125impl return_private::Sealed for bool {}
126impl<MethodFamily> ConvertReturn<MethodFamily> for bool {
127    type Inner = Bool;
128
129    #[inline]
130    unsafe fn convert_message_return(
131        inner: Self::Inner,
132        _receiver_ptr: *mut AnyObject,
133        _sel: Sel,
134    ) -> Self {
135        inner.as_bool()
136    }
137
138    #[inline]
139    fn convert_defined_return(self) -> Self::Inner {
140        Bool::new(self)
141    }
142}
143
144// Implemented in retain_semantics.rs
145impl<T: ?Sized + Message> return_private::Sealed for Retained<T> {}
146impl<T: ?Sized + Message> return_private::Sealed for Option<Retained<T>> {}
147impl<T: ?Sized + Message> return_private::Sealed for Allocated<T> {}
148
149pub trait ConvertArguments {
150    #[doc(hidden)]
151    type __Inner: EncodeArguments;
152
153    #[doc(hidden)]
154    type __WritebackOnDrop: Sized;
155
156    #[doc(hidden)]
157    unsafe fn __into_arguments(self) -> (Self::__Inner, Self::__WritebackOnDrop);
158}
159
160pub trait TupleExtender<T> {
161    #[doc(hidden)]
162    type PlusOneArgument;
163    #[doc(hidden)]
164    fn add_argument(self, arg: T) -> Self::PlusOneArgument;
165}
166
167macro_rules! args_impl {
168    ($($a:ident: $t:ident),*) => (
169        impl<$($t: ConvertArgument),*> ConvertArguments for ($($t,)*) {
170            type __Inner = ($($t::__Inner,)*);
171
172            type __WritebackOnDrop = ($($t::__WritebackOnDrop,)*);
173
174            #[inline]
175            unsafe fn __into_arguments(self) -> (Self::__Inner, Self::__WritebackOnDrop) {
176                let ($($a,)*) = self;
177                // SAFETY: Upheld by caller
178                $(let $a = unsafe { ConvertArgument::__into_argument($a) };)*
179
180                (($($a.0,)*), ($($a.1,)*))
181            }
182        }
183
184        impl<$($t,)* T> TupleExtender<T> for ($($t,)*) {
185            type PlusOneArgument = ($($t,)* T,);
186
187            #[inline]
188            fn add_argument(self, arg: T) -> Self::PlusOneArgument {
189                let ($($a,)*) = self;
190                ($($a,)* arg,)
191            }
192        }
193    );
194}
195
196args_impl!();
197args_impl!(a: A);
198args_impl!(a: A, b: B);
199args_impl!(a: A, b: B, c: C);
200args_impl!(a: A, b: B, c: C, d: D);
201args_impl!(a: A, b: B, c: C, d: D, e: E);
202args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
203args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
204args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
205args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
206args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
207args_impl!(
208    a: A,
209    b: B,
210    c: C,
211    d: D,
212    e: E,
213    f: F,
214    g: G,
215    h: H,
216    i: I,
217    j: J,
218    k: K
219);
220args_impl!(
221    a: A,
222    b: B,
223    c: C,
224    d: D,
225    e: E,
226    f: F,
227    g: G,
228    h: H,
229    i: I,
230    j: J,
231    k: K,
232    l: L
233);
234args_impl!(
235    a: A,
236    b: B,
237    c: C,
238    d: D,
239    e: E,
240    f: F,
241    g: G,
242    h: H,
243    i: I,
244    j: J,
245    k: K,
246    l: L,
247    m: M
248);
249args_impl!(
250    a: A,
251    b: B,
252    c: C,
253    d: D,
254    e: E,
255    f: F,
256    g: G,
257    h: H,
258    i: I,
259    j: J,
260    k: K,
261    l: L,
262    m: M,
263    n: N
264);
265args_impl!(
266    a: A,
267    b: B,
268    c: C,
269    d: D,
270    e: E,
271    f: F,
272    g: G,
273    h: H,
274    i: I,
275    j: J,
276    k: K,
277    l: L,
278    m: M,
279    n: N,
280    o: O
281);
282args_impl!(
283    a: A,
284    b: B,
285    c: C,
286    d: D,
287    e: E,
288    f: F,
289    g: G,
290    h: H,
291    i: I,
292    j: J,
293    k: K,
294    l: L,
295    m: M,
296    n: N,
297    o: O,
298    p: P
299);
300
301#[cfg(test)]
302mod tests {
303    use super::*;
304
305    use core::any::TypeId;
306    use core::ptr;
307
308    use crate::sel;
309
310    #[test]
311    fn convert_normally_noop() {
312        assert_eq!(
313            TypeId::of::<<i32 as ConvertArgument>::__Inner>(),
314            TypeId::of::<i32>()
315        );
316        assert_eq!(<i32 as ConvertArgument>::__from_defined_param(42), 42);
317        assert_eq!(unsafe { ConvertArgument::__into_argument(42i32).0 }, 42);
318    }
319
320    #[test]
321    fn convert_i8() {
322        assert_eq!(
323            TypeId::of::<<i8 as ConvertArgument>::__Inner>(),
324            TypeId::of::<i8>()
325        );
326        assert_eq!(<i8 as ConvertArgument>::__from_defined_param(-3), -3);
327        assert_eq!(unsafe { ConvertArgument::__into_argument(-3i32).0 }, -3);
328    }
329
330    #[test]
331    fn convert_bool() {
332        let receiver_ptr = ptr::null_mut::<AnyObject>();
333        let sel = sel!(foo);
334
335        assert!(!<bool as ConvertArgument>::__from_defined_param(Bool::NO));
336        assert!(<bool as ConvertArgument>::__from_defined_param(Bool::YES));
337        assert!(!unsafe {
338            <bool as ConvertReturn<()>>::convert_message_return(Bool::NO, receiver_ptr, sel)
339        });
340        assert!(unsafe {
341            <bool as ConvertReturn<()>>::convert_message_return(Bool::YES, receiver_ptr, sel)
342        });
343
344        assert!(!unsafe { ConvertArgument::__into_argument(false).0 }.as_bool());
345        assert!(unsafe { ConvertArgument::__into_argument(true).0 }.as_bool());
346        assert!(!ConvertReturn::<()>::convert_defined_return(false).as_bool());
347        assert!(ConvertReturn::<()>::convert_defined_return(true).as_bool());
348
349        #[cfg(all(target_vendor = "apple", target_os = "macos", target_arch = "x86_64"))]
350        assert_eq!(
351            <bool as ConvertArgument>::__Inner::ENCODING_ARGUMENT,
352            crate::encode::Encoding::Char,
353        );
354    }
355}