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 ;
2
9
3
10
use crate :: Encoding ;
4
11
@@ -160,17 +167,22 @@ encode_impls!(
160
167
u64 => ULongLong ,
161
168
f32 => Float ,
162
169
f64 => Double ,
163
- ( ) => Void ,
164
- * mut i8 => String ,
165
- * const i8 => String ,
166
- * mut u8 => String ,
167
- * const u8 => String ,
168
170
) ;
169
171
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
+
170
182
/// Using this directly is heavily discouraged, since the type of BOOL differs
171
183
/// across platforms.
172
184
///
173
- /// Use `objc2_sys::BOOL::ENCODING` or ` objc2::runtime::Bool` instead.
185
+ /// Use `objc2::runtime::Bool::ENCODING ` instead.
174
186
unsafe impl Encode for bool {
175
187
const ENCODING : Encoding < ' static > = Encoding :: Bool ;
176
188
}
@@ -194,16 +206,45 @@ encode_impls_size!(
194
206
usize => ( u16 , u32 , u64 ) ,
195
207
) ;
196
208
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.
198
231
macro_rules! encode_impls_nonzero {
199
232
( $( $nonzero: ident => $type: ty, ) * ) => ( $(
200
- unsafe impl Encode for core :: num :: $nonzero {
233
+ unsafe impl Encode for $nonzero {
201
234
const ENCODING : Encoding <' static > = <$type>:: ENCODING ;
202
235
}
203
236
204
- unsafe impl Encode for Option <core :: num :: $nonzero> {
237
+ unsafe impl Encode for Option <$nonzero> {
205
238
const ENCODING : Encoding <' static > = <$type>:: ENCODING ;
206
239
}
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
+ }
207
248
) * ) ;
208
249
}
209
250
@@ -229,12 +270,20 @@ unsafe impl Encode for *const c_void {
229
270
const ENCODING : Encoding < ' static > = Encoding :: Pointer ( & Encoding :: Void ) ;
230
271
}
231
272
273
+ unsafe impl RefEncode for * const c_void {
274
+ const ENCODING_REF : Encoding < ' static > = Encoding :: Pointer ( & Self :: ENCODING ) ;
275
+ }
276
+
232
277
/// [`Encode`] is implemented manually for `*mut c_void`, instead of
233
278
/// implementing [`RefEncode`], to discourage creating `&mut c_void`.
234
279
unsafe impl Encode for * mut c_void {
235
280
const ENCODING : Encoding < ' static > = Encoding :: Pointer ( & Encoding :: Void ) ;
236
281
}
237
282
283
+ unsafe impl RefEncode for * mut c_void {
284
+ const ENCODING_REF : Encoding < ' static > = Encoding :: Pointer ( & Self :: ENCODING ) ;
285
+ }
286
+
238
287
unsafe impl < T : Encode , const LENGTH : usize > Encode for [ T ; LENGTH ] {
239
288
const ENCODING : Encoding < ' static > = Encoding :: Array ( LENGTH , & T :: ENCODING ) ;
240
289
}
@@ -265,6 +314,16 @@ unsafe impl<T: RefEncode> RefEncode for Pin<T> {
265
314
const ENCODING_REF : Encoding < ' static > = T :: ENCODING_REF ;
266
315
}
267
316
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
+
268
327
/// Helper for implementing `Encode`/`RefEncode` for pointers to types that
269
328
/// implement `RefEncode`.
270
329
///
@@ -423,3 +482,66 @@ encode_args_impl!(A, B, C, D, E, F, G, H, I);
423
482
encode_args_impl ! ( A , B , C , D , E , F , G , H , I , J ) ;
424
483
encode_args_impl ! ( A , B , C , D , E , F , G , H , I , J , K ) ;
425
484
encode_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