1- use core:: { ffi:: c_void, mem:: ManuallyDrop , pin:: Pin , ptr:: NonNull } ;
1+ use core:: ffi:: c_void;
2+ use core:: mem:: ManuallyDrop ;
3+ use core:: num:: {
4+ NonZeroI16 , NonZeroI32 , NonZeroI64 , NonZeroI8 , NonZeroIsize , NonZeroU16 , NonZeroU32 ,
5+ NonZeroU64 , NonZeroU8 , NonZeroUsize , Wrapping ,
6+ } ;
7+ use core:: pin:: Pin ;
8+ use core:: ptr:: NonNull ;
29
310use crate :: Encoding ;
411
@@ -160,17 +167,22 @@ encode_impls!(
160167 u64 => ULongLong ,
161168 f32 => Float ,
162169 f64 => Double ,
163- ( ) => Void ,
164- * mut i8 => String ,
165- * const i8 => String ,
166- * mut u8 => String ,
167- * const u8 => String ,
168170) ;
169171
172+ /// To allow usage as the return type of generic functions.
173+ ///
174+ /// You should not rely on this encoding to exist for any other purpose (since
175+ /// `()` is not FFI-safe)!
176+ ///
177+ /// TODO: Figure out a way to remove this.
178+ unsafe impl Encode for ( ) {
179+ const ENCODING : Encoding < ' static > = Encoding :: Void ;
180+ }
181+
170182/// Using this directly is heavily discouraged, since the type of BOOL differs
171183/// across platforms.
172184///
173- /// Use `objc2_sys::BOOL::ENCODING` or ` objc2::runtime::Bool` instead.
185+ /// Use `objc2::runtime::Bool::ENCODING ` instead.
174186unsafe impl Encode for bool {
175187 const ENCODING : Encoding < ' static > = Encoding :: Bool ;
176188}
@@ -194,16 +206,45 @@ encode_impls_size!(
194206 usize => ( u16 , u32 , u64 ) ,
195207) ;
196208
197- /// Simple helper for implementing [`Encode`] for integer types.
209+ /// Simple helper for implementing [`RefEncode`].
210+ macro_rules! pointer_refencode_impl {
211+ ( $( $t: ty) ,* ) => ( $(
212+ unsafe impl RefEncode for $t {
213+ const ENCODING_REF : Encoding <' static > = Encoding :: Pointer ( & Self :: ENCODING ) ;
214+ }
215+ ) * ) ;
216+ }
217+
218+ pointer_refencode_impl ! ( bool , i16 , i32 , i64 , isize , u16 , u32 , u64 , usize , f32 , f64 ) ;
219+
220+ /// Pointers to [`i8`] use the special [`Encoding::String`] encoding.
221+ unsafe impl RefEncode for i8 {
222+ const ENCODING_REF : Encoding < ' static > = Encoding :: String ;
223+ }
224+
225+ /// Pointers to [`u8`] use the special [`Encoding::String`] encoding.
226+ unsafe impl RefEncode for u8 {
227+ const ENCODING_REF : Encoding < ' static > = Encoding :: String ;
228+ }
229+
230+ /// Simple helper for implementing [`Encode`] for nonzero integer types.
198231macro_rules! encode_impls_nonzero {
199232 ( $( $nonzero: ident => $type: ty, ) * ) => ( $(
200- unsafe impl Encode for core :: num :: $nonzero {
233+ unsafe impl Encode for $nonzero {
201234 const ENCODING : Encoding <' static > = <$type>:: ENCODING ;
202235 }
203236
204- unsafe impl Encode for Option <core :: num :: $nonzero> {
237+ unsafe impl Encode for Option <$nonzero> {
205238 const ENCODING : Encoding <' static > = <$type>:: ENCODING ;
206239 }
240+
241+ unsafe impl RefEncode for $nonzero {
242+ const ENCODING_REF : Encoding <' static > = <$type>:: ENCODING_REF ;
243+ }
244+
245+ unsafe impl RefEncode for Option <$nonzero> {
246+ const ENCODING_REF : Encoding <' static > = <$type>:: ENCODING_REF ;
247+ }
207248 ) * ) ;
208249}
209250
@@ -229,12 +270,20 @@ unsafe impl Encode for *const c_void {
229270 const ENCODING : Encoding < ' static > = Encoding :: Pointer ( & Encoding :: Void ) ;
230271}
231272
273+ unsafe impl RefEncode for * const c_void {
274+ const ENCODING_REF : Encoding < ' static > = Encoding :: Pointer ( & Self :: ENCODING ) ;
275+ }
276+
232277/// [`Encode`] is implemented manually for `*mut c_void`, instead of
233278/// implementing [`RefEncode`], to discourage creating `&mut c_void`.
234279unsafe impl Encode for * mut c_void {
235280 const ENCODING : Encoding < ' static > = Encoding :: Pointer ( & Encoding :: Void ) ;
236281}
237282
283+ unsafe impl RefEncode for * mut c_void {
284+ const ENCODING_REF : Encoding < ' static > = Encoding :: Pointer ( & Self :: ENCODING ) ;
285+ }
286+
238287unsafe impl < T : Encode , const LENGTH : usize > Encode for [ T ; LENGTH ] {
239288 const ENCODING : Encoding < ' static > = Encoding :: Array ( LENGTH , & T :: ENCODING ) ;
240289}
@@ -265,6 +314,16 @@ unsafe impl<T: RefEncode> RefEncode for Pin<T> {
265314 const ENCODING_REF : Encoding < ' static > = T :: ENCODING_REF ;
266315}
267316
317+ // SAFETY: `Wrapping` is `repr(transparent)`.
318+ unsafe impl < T : Encode > Encode for Wrapping < T > {
319+ const ENCODING : Encoding < ' static > = T :: ENCODING ;
320+ }
321+
322+ // SAFETY: `Wrapping` is `repr(transparent)`.
323+ unsafe impl < T : RefEncode > RefEncode for Wrapping < T > {
324+ const ENCODING_REF : Encoding < ' static > = T :: ENCODING_REF ;
325+ }
326+
268327/// Helper for implementing `Encode`/`RefEncode` for pointers to types that
269328/// implement `RefEncode`.
270329///
@@ -423,3 +482,66 @@ encode_args_impl!(A, B, C, D, E, F, G, H, I);
423482encode_args_impl ! ( A , B , C , D , E , F , G , H , I , J ) ;
424483encode_args_impl ! ( A , B , C , D , E , F , G , H , I , J , K ) ;
425484encode_args_impl ! ( A , B , C , D , E , F , G , H , I , J , K , L ) ;
485+
486+ #[ cfg( test) ]
487+ mod tests {
488+ use super :: * ;
489+
490+ #[ test]
491+ fn test_c_string ( ) {
492+ assert_eq ! ( i8 :: ENCODING , Encoding :: Char ) ;
493+ assert_eq ! ( u8 :: ENCODING , Encoding :: UChar ) ;
494+
495+ assert_eq ! ( <* const i8 >:: ENCODING , Encoding :: String ) ;
496+ assert_eq ! ( <& u8 >:: ENCODING , Encoding :: String ) ;
497+ assert_eq ! ( i8 :: ENCODING_REF , Encoding :: String ) ;
498+ assert_eq ! ( i8 :: ENCODING_REF , Encoding :: String ) ;
499+
500+ assert_eq ! (
501+ <* const * const i8 >:: ENCODING ,
502+ Encoding :: Pointer ( & Encoding :: String )
503+ ) ;
504+ assert_eq ! ( <&&u8 >:: ENCODING , Encoding :: Pointer ( & Encoding :: String ) ) ;
505+ }
506+
507+ #[ test]
508+ fn test_i32 ( ) {
509+ assert_eq ! ( i32 :: ENCODING , Encoding :: Int ) ;
510+ assert_eq ! ( <& i32 >:: ENCODING , Encoding :: Pointer ( & Encoding :: Int ) ) ;
511+ assert_eq ! (
512+ <&&i32 >:: ENCODING ,
513+ Encoding :: Pointer ( & Encoding :: Pointer ( & Encoding :: Int ) )
514+ ) ;
515+ }
516+
517+ #[ test]
518+ fn test_void ( ) {
519+ // TODO: Remove this
520+ assert_eq ! ( <( ) >:: ENCODING , Encoding :: Void ) ;
521+ assert_eq ! (
522+ <* const c_void>:: ENCODING ,
523+ Encoding :: Pointer ( & Encoding :: Void )
524+ ) ;
525+ assert_eq ! (
526+ <& * const c_void>:: ENCODING ,
527+ Encoding :: Pointer ( & Encoding :: Pointer ( & Encoding :: Void ) )
528+ ) ;
529+
530+ // Shouldn't compile
531+ // assert_eq!(<c_void>::ENCODING, Encoding::Void);
532+ // assert_eq!(<*const ()>::ENCODING, Encoding::Pointer(&Encoding::Void));
533+ // assert_eq!(<&c_void>::ENCODING, Encoding::Pointer(&Encoding::Void));
534+ }
535+
536+ #[ test]
537+ fn test_extern_fn_pointer ( ) {
538+ assert_eq ! (
539+ <extern "C" fn ( ) >:: ENCODING ,
540+ Encoding :: Pointer ( & Encoding :: Unknown )
541+ ) ;
542+ assert_eq ! (
543+ <extern "C" fn ( x: ( ) ) -> ( ) >:: ENCODING ,
544+ Encoding :: Pointer ( & Encoding :: Unknown )
545+ ) ;
546+ }
547+ }
0 commit comments