use crate::encode::{EncodeArgument, EncodeArguments, EncodeReturn}; use crate::rc::Retained; use crate::runtime::Bool; use crate::Message; mod argument_private { pub trait Sealed {} } /// Represents types that can be converted to/from an [`EncodeArgument`] type. /// /// This is implemented specially for [`bool`] to allow using that as /// Objective-C `BOOL`, where it would otherwise not be allowed (since they /// are not ABI compatible). /// /// This is also done specially for `&mut Retained<_>`-like arguments, to allow /// using those as "out" parameters. pub trait ConvertArgument: argument_private::Sealed { /// The inner type that this can be converted to and from. #[doc(hidden)] type __Inner: EncodeArgument; /// A helper type for out parameters. #[doc(hidden)] type __StoredBeforeMessage: Sized; #[doc(hidden)] fn __from_declared_param(inner: Self::__Inner) -> Self; #[doc(hidden)] fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage); #[doc(hidden)] #[inline] unsafe fn __process_after_message_send(_stored: Self::__StoredBeforeMessage) {} } // Implemented in writeback.rs impl argument_private::Sealed for &mut Retained {} impl argument_private::Sealed for Option<&mut Retained> {} impl argument_private::Sealed for &mut Option> {} impl argument_private::Sealed for Option<&mut Option>> {} impl argument_private::Sealed for T {} impl ConvertArgument for T { type __Inner = Self; type __StoredBeforeMessage = (); #[inline] fn __from_declared_param(inner: Self::__Inner) -> Self { inner } #[inline] fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage) { (self, ()) } } impl argument_private::Sealed for bool {} impl ConvertArgument for bool { type __Inner = Bool; type __StoredBeforeMessage = (); #[inline] fn __from_declared_param(inner: Self::__Inner) -> Self { inner.as_bool() } #[inline] fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage) { (Bool::new(self), ()) } } mod return_private { pub trait Sealed {} } /// Same as [`ConvertArgument`], but for return types. pub trait ConvertReturn: return_private::Sealed { /// The inner type that this can be converted to and from. #[doc(hidden)] type __Inner: EncodeReturn; #[doc(hidden)] fn __into_declared_return(self) -> Self::__Inner; #[doc(hidden)] fn __from_return(inner: Self::__Inner) -> Self; } impl return_private::Sealed for T {} impl ConvertReturn for T { type __Inner = Self; #[inline] fn __into_declared_return(self) -> Self::__Inner { self } #[inline] fn __from_return(inner: Self::__Inner) -> Self { inner } } impl return_private::Sealed for bool {} impl ConvertReturn for bool { type __Inner = Bool; #[inline] fn __into_declared_return(self) -> Self::__Inner { Bool::new(self) } #[inline] fn __from_return(inner: Self::__Inner) -> Self { inner.as_bool() } } pub trait ConvertArguments { #[doc(hidden)] type __Inner: EncodeArguments; #[doc(hidden)] type __StoredBeforeMessage: Sized; #[doc(hidden)] fn __into_arguments(self) -> (Self::__Inner, Self::__StoredBeforeMessage); #[doc(hidden)] unsafe fn __process_after_message_send(_stored: Self::__StoredBeforeMessage); } pub trait TupleExtender { #[doc(hidden)] type PlusOneArgument; #[doc(hidden)] fn add_argument(self, arg: T) -> Self::PlusOneArgument; } macro_rules! args_impl { ($($a:ident: $t:ident),*) => ( impl<$($t: ConvertArgument),*> ConvertArguments for ($($t,)*) { type __Inner = ($($t::__Inner,)*); type __StoredBeforeMessage = ($($t::__StoredBeforeMessage,)*); #[inline] fn __into_arguments(self) -> (Self::__Inner, Self::__StoredBeforeMessage) { let ($($a,)*) = self; $(let $a = ConvertArgument::__into_argument($a);)* (($($a.0,)*), ($($a.1,)*)) } #[inline] unsafe fn __process_after_message_send(($($a,)*): Self::__StoredBeforeMessage) { $( unsafe { <$t as ConvertArgument>::__process_after_message_send($a) }; )* } } impl<$($t,)* T> TupleExtender for ($($t,)*) { type PlusOneArgument = ($($t,)* T,); #[inline] fn add_argument(self, arg: T) -> Self::PlusOneArgument { let ($($a,)*) = self; ($($a,)* arg,) } } ); } args_impl!(); args_impl!(a: A); args_impl!(a: A, b: B); args_impl!(a: A, b: B, c: C); args_impl!(a: A, b: B, c: C, d: D); args_impl!(a: A, b: B, c: C, d: D, e: E); args_impl!(a: A, b: B, c: C, d: D, e: E, f: F); args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G); args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H); args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I); args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J); args_impl!( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K ); args_impl!( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L ); args_impl!( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M ); args_impl!( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N ); args_impl!( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O ); args_impl!( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P ); #[cfg(test)] mod tests { use super::*; use core::any::TypeId; #[test] fn convert_normally_noop() { assert_eq!( TypeId::of::<::__Inner>(), TypeId::of::() ); assert_eq!(::__from_declared_param(42), 42); assert_eq!(ConvertArgument::__into_argument(42i32).0, 42); } #[test] fn convert_i8() { assert_eq!( TypeId::of::<::__Inner>(), TypeId::of::() ); assert_eq!(::__from_declared_param(-3), -3); assert_eq!(ConvertArgument::__into_argument(-3i32).0, -3); } #[test] fn convert_bool() { assert!(!::__from_declared_param(Bool::NO)); assert!(::__from_declared_param(Bool::YES)); assert!(!::__from_return(Bool::NO)); assert!(::__from_return(Bool::YES)); assert!(!ConvertArgument::__into_argument(false).0.as_bool()); assert!(ConvertArgument::__into_argument(true).0.as_bool()); assert!(!ConvertReturn::__into_declared_return(false).as_bool()); assert!(ConvertReturn::__into_declared_return(true).as_bool()); #[cfg(all(target_vendor = "apple", target_os = "macos", target_arch = "x86_64"))] assert_eq!( ::__Inner::ENCODING_ARGUMENT, crate::encode::Encoding::Char, ); } }