objc2/
encode.rs

1//! # Support for type-encodings.
2//!
3//! The Objective-C runtime includes encodings for each method that describe
4//! the argument and return types. This module contains traits for annotating
5//! types that has an Objective-C type-encoding: Specifically [`Encode`] for
6//! structs/numeric types and [`RefEncode`] for references.
7//!
8//! Additionally, this exports the [`Encoding`] and [`EncodingBox`] types from
9//! [`objc2-encode`][objc2_encode], see that crate for a few more details on
10//! what Objective-C type-encodings are.
11//!
12//!
13//! ## Examples
14//!
15//! Implementing [`Encode`] and [`RefEncode`] for a custom type:
16//!
17//! ```
18//! use objc2::encode::{Encode, Encoding, RefEncode};
19//!
20//! #[repr(C)]
21//! struct MyStruct {
22//!     a: f32, // float
23//!     b: i16, // int16_t
24//! }
25//!
26//! unsafe impl Encode for MyStruct {
27//!     const ENCODING: Encoding = Encoding::Struct(
28//!         "MyStruct", // Must use the same name as defined in C header files
29//!         &[
30//!             f32::ENCODING, // Same as Encoding::Float
31//!             i16::ENCODING, // Same as Encoding::Short
32//!         ],
33//!     );
34//! }
35//!
36//! // @encode(MyStruct) -> "{MyStruct=fs}"
37//! assert!(MyStruct::ENCODING.equivalent_to_str("{MyStruct=fs}"));
38//!
39//! unsafe impl RefEncode for MyStruct {
40//!     const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
41//! }
42//!
43//! // @encode(MyStruct*) -> "^{MyStruct=fs}"
44//! assert!(MyStruct::ENCODING_REF.equivalent_to_str("^{MyStruct=fs}"));
45//! ```
46//!
47//! Implementing [`Encode`] for a few core-graphics types.
48//!
49//! Note that these are available in `objc2-foundation`, so the implementation
50//! here is mostly for demonstration.
51//!
52//! ```
53#![doc = include_str!("../examples/encode_core_graphics.rs")]
54//! ```
55//!
56//! Implementing [`Encode`] and [`RefEncode`] for a transparent newtype.
57//!
58//! ```
59#![doc = include_str!("../examples/encode_nsuinteger.rs")]
60//! ```
61//!
62//! Implementing [`RefEncode`] for an object, in this case `NSString`.
63//!
64//! ```
65#![doc = include_str!("../examples/encode_nsstring.rs")]
66//! ```
67//!
68//! Implementing [`RefEncode`] for a type where you don't necessarily know
69//! about the exact internals / the internals are not representable in Rust.
70//!
71//! ```
72#![doc = include_str!("../examples/encode_opaque_type.rs")]
73//! ```
74
75use core::cell::{Cell, UnsafeCell};
76use core::ffi::c_void;
77use core::mem::{self, ManuallyDrop, MaybeUninit};
78use core::num::{
79    NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU16, NonZeroU32,
80    NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
81};
82use core::ptr::NonNull;
83use core::sync::atomic;
84
85#[doc(inline)]
86pub use objc2_encode::{Encoding, EncodingBox, ParseError};
87
88use crate::runtime::{AnyObject, Imp, Sel};
89
90/// Types that have an Objective-C type-encoding.
91///
92/// Usually you will want to implement [`RefEncode`] as well.
93///
94/// If your type is an opaque type you should not need to implement this;
95/// there you will only need [`RefEncode`].
96///
97///
98/// # Safety
99///
100/// The type must be FFI-safe, meaning a C-compatible `repr` (`repr(C)`,
101/// `repr(u8)`, `repr(transparent)` where the inner types are C-compatible,
102/// and so on). See the [nomicon on other `repr`s][reprs].
103///
104/// Objective-C will make assumptions about the type (like its size, alignment
105/// and ABI) from its encoding, so the implementer must verify that the
106/// encoding is accurate.
107///
108/// Concretely, [`Self::ENCODING`] must match the result of running `@encode`
109/// in Objective-C with the type in question.
110///
111/// You should also beware of having [`Drop`] types implement this, since when
112/// passed to Objective-C via `objc2::msg_send!` their destructor will not be
113/// called!
114///
115///
116/// # Examples
117///
118/// Implementing for a struct:
119///
120/// ```
121/// # use objc2::encode::{Encode, Encoding, RefEncode};
122/// # use core::ffi::c_void;
123/// #
124/// #[repr(C)]
125/// struct MyType {
126///     a: i32,
127///     b: f64,
128///     c: *const c_void,
129/// }
130///
131/// unsafe impl Encode for MyType {
132///     const ENCODING: Encoding = Encoding::Struct(
133///         // The name of the type that Objective-C sees.
134///         "MyType",
135///         &[
136///             // Delegate to field's implementations.
137///             // The order is the same as in the definition.
138///             i32::ENCODING,
139///             f64::ENCODING,
140///             <*const c_void>::ENCODING,
141///         ],
142///     );
143/// }
144///
145/// // Note: You would also implement `RefEncode` for this type.
146/// ```
147///
148/// [reprs]: https://doc.rust-lang.org/nomicon/other-reprs.html
149pub unsafe trait Encode {
150    /// The Objective-C type-encoding for this type.
151    const ENCODING: Encoding;
152}
153
154/// Types whose references has an Objective-C type-encoding.
155///
156/// Implementing this for `T` provides [`Encode`] implementations for:
157/// - `*const T`
158/// - `*mut T`
159/// - `&T`
160/// - `&mut T`
161/// - `NonNull<T>`
162/// - `Option<&T>`
163/// - `Option<&mut T>`
164/// - `Option<NonNull<T>>`
165///
166///
167/// # Reasoning behind this trait's existence
168///
169/// External crates cannot implement [`Encode`] for pointers or [`Option`]s
170/// containing references, so instead, they can implement this trait.
171/// Additionally it would be very cumbersome if every type had to implement
172/// [`Encode`] for all possible pointer types.
173///
174/// Finally, having this trait allows for much cleaner generic code that need
175/// to represent types that can be encoded as pointers.
176///
177///
178/// # Safety
179///
180/// References to the object must be FFI-safe.
181///
182/// See the nomicon entry on [representing opaque structs][opaque] for
183/// information on how to represent objects that you don't know the layout of
184/// (or use `extern type` ([RFC-1861]) if you're using nightly).
185///
186/// Objective-C will make assumptions about the type (like its size, alignment
187/// and ABI) from its encoding, so the implementer must verify that the
188/// encoding is accurate.
189///
190/// Concretely, [`Self::ENCODING_REF`] must match the result of running
191/// `@encode` in Objective-C with a pointer to the type in question.
192///
193/// [opaque]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
194/// [RFC-1861]: https://rust-lang.github.io/rfcs/1861-extern-types.html
195pub unsafe trait RefEncode {
196    /// The Objective-C type-encoding for a reference of this type.
197    ///
198    /// Should be one of [`Encoding::Object`], [`Encoding::Block`],
199    /// [`Encoding::Class`], [`Encoding::Pointer`], [`Encoding::Sel`] or
200    /// [`Encoding::Unknown`].
201    ///
202    ///
203    /// # Examples
204    ///
205    /// This is usually implemented either as an object pointer:
206    /// ```
207    /// # use objc2::encode::{Encoding, RefEncode};
208    /// # #[repr(C)]
209    /// # struct MyObject {
210    /// #     _priv: [u8; 0],
211    /// # }
212    /// # unsafe impl RefEncode for MyObject {
213    /// const ENCODING_REF: Encoding = Encoding::Object;
214    /// # }
215    /// ```
216    ///
217    /// Or as a pointer to the type, delegating the rest to the [`Encode`]
218    /// implementation:
219    /// ```
220    /// # use objc2::encode::{Encode, Encoding, RefEncode};
221    /// # #[repr(transparent)]
222    /// # struct MyType(i32);
223    /// # unsafe impl Encode for MyType {
224    /// #     const ENCODING: Encoding = i32::ENCODING;
225    /// # }
226    /// # unsafe impl RefEncode for MyType {
227    /// const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
228    /// # }
229    /// ```
230    const ENCODING_REF: Encoding;
231}
232
233/// A helper trait for types that follow the "null pointer optimization", and
234/// are encodable inside an [`Option`].
235///
236/// See [the `Option` documentation][option-repr] for details on which types
237/// this holds for, and [the nomicon][nomicon-npo] for more details on the
238/// null pointer optimization.
239///
240/// This trait used to work around the orphan rule, which would normally
241/// prevent you from implementing [`Encode`]/[`RefEncode`] for
242/// `Option<CustomType>`.
243///
244/// [option-repr]: https://doc.rust-lang.org/1.75.0/std/option/index.html#representation
245/// [nomicon-npo]: https://doc.rust-lang.org/nightly/nomicon/ffi.html#the-nullable-pointer-optimization
246///
247///
248/// # Safety
249///
250/// You must ensure that the implemented type `T` has the same layout and
251/// function call ABI as `Option<T>`.
252///
253///
254/// # Examples
255///
256/// ```
257/// use objc2::encode::{Encode, Encoding, OptionEncode};
258/// use core::ptr::NonNull;
259/// use core::ffi::c_void;
260///
261/// #[repr(transparent)]
262/// struct MyBlockType(NonNull<c_void>);
263///
264/// // SAFETY: `MyBlockType` is meant to represent a pointer to a block
265/// unsafe impl Encode for MyBlockType {
266///     const ENCODING: Encoding = Encoding::Block;
267/// }
268///
269/// // SAFETY: `MyBlockType` is `repr(transparent)` over `NonNull`, which
270/// // means that `Option<MyBlockType>` has the same layout.
271/// unsafe impl OptionEncode for MyBlockType {}
272///
273/// assert_eq!(<Option<MyBlockType>>::ENCODING, MyBlockType::ENCODING);
274/// ```
275pub unsafe trait OptionEncode {}
276
277// SAFETY: Implementor of `OptionEncode` guarantees this impl is sound
278unsafe impl<T: Encode + OptionEncode> Encode for Option<T> {
279    const ENCODING: Encoding = {
280        if mem::size_of::<T>() != mem::size_of::<Option<T>>() {
281            panic!("invalid OptionEncode + Encode implementation");
282        }
283        T::ENCODING
284    };
285}
286
287// SAFETY: Implementor of `OptionEncode` guarantees this impl is sound
288unsafe impl<T: RefEncode + OptionEncode> RefEncode for Option<T> {
289    const ENCODING_REF: Encoding = {
290        if mem::size_of::<T>() != mem::size_of::<Option<T>>() {
291            panic!("invalid OptionEncode + RefEncode implementation");
292        }
293        T::ENCODING_REF
294    };
295}
296
297mod return_private {
298    pub trait Sealed {}
299}
300
301/// Types that are safe as the return value from Objective-C.
302///
303/// This is a sealed trait, and should not need to be implemented manually.
304///
305///
306/// # Safety
307///
308/// Similar to [`Encode`], except the value is only guaranteed to be valid as
309/// a return value, both from functions/methods you're calling, and from
310/// declared functions/methods.
311///
312/// It does not have to be valid as e.g. an instance variable, or as an
313/// argument to a function.
314pub unsafe trait EncodeReturn: return_private::Sealed {
315    /// The Objective-C type-encoding for this type.
316    const ENCODING_RETURN: Encoding;
317}
318
319impl return_private::Sealed for () {}
320// SAFETY: `()` is the same as C's `void` type, which is a valid return type
321unsafe impl EncodeReturn for () {
322    const ENCODING_RETURN: Encoding = Encoding::Void;
323}
324
325impl<T: Encode> return_private::Sealed for T {}
326// SAFETY: All `Encode` types are also valid as return types
327unsafe impl<T: Encode> EncodeReturn for T {
328    const ENCODING_RETURN: Encoding = T::ENCODING;
329}
330
331mod argument_private {
332    pub trait Sealed {}
333}
334
335/// Types that are safe as arguments to Objective-C methods.
336///
337/// This is a sealed trait, and should not need to be implemented manually.
338///
339///
340/// # Safety
341///
342/// Similar to [`Encode`], except the value is only guaranteed to be valid as
343/// an argument or a parameter, both from functions/methods you're calling and
344/// from declared functions/methods.
345///
346/// It does not have to be valid as e.g. an instance variable, or as an
347/// argument to a function.
348//
349// Note: This is mostly implemented for consistency; there are (not that I've
350// found at least) no places where this is not just `Encode`.
351//
352// You might be tempted to think that `bool` could work in this, but that
353// would be a mistake (even ignoring that its size is different on certain
354// targets) because it cannot be safely used in custom defined methods.
355pub unsafe trait EncodeArgument: argument_private::Sealed {
356    /// The Objective-C type-encoding for this type.
357    const ENCODING_ARGUMENT: Encoding;
358}
359
360impl<T: Encode> argument_private::Sealed for T {}
361// SAFETY: All `Encode` types are also valid as argument types
362unsafe impl<T: Encode> EncodeArgument for T {
363    const ENCODING_ARGUMENT: Encoding = T::ENCODING;
364}
365
366mod args_private {
367    pub trait Sealed {}
368}
369
370/// Types that represent an ordered group of function arguments, where each
371/// argument has an Objective-C type-encoding, or can be converted from one.
372///
373/// This is implemented for tuples of up to 16 arguments, where each argument
374/// implements [`EncodeArgument`]. It is a sealed trait, and should not need
375/// to be implemented manually - it is primarily used to make generic code a
376/// bit easier to read and understand.
377///
378/// Note that tuples themselves don't implement [`Encode`] directly, because
379/// they're not FFI-safe!
380pub trait EncodeArguments: args_private::Sealed {
381    /// The encodings for the arguments.
382    const ENCODINGS: &'static [Encoding];
383
384    /// Invoke a message sending function with the given object, selector,
385    /// and arguments.
386    ///
387    /// Implementation-wise, this is a bit ugly, but simply just easiest to
388    /// have the method on this trait, since inside `MessageReceiver` we only
389    /// want to publicly require `EncodeArguments`, and not another private
390    /// trait.
391    #[doc(hidden)]
392    unsafe fn __invoke<R: EncodeReturn>(
393        msg_send_fn: Imp,
394        receiver: *mut AnyObject,
395        sel: Sel,
396        args: Self,
397    ) -> R;
398}
399
400macro_rules! encode_args_impl {
401    ($($a:ident: $T: ident),*) => {
402        impl<$($T: EncodeArgument),*> args_private::Sealed for ($($T,)*) {}
403
404        impl<$($T: EncodeArgument),*> EncodeArguments for ($($T,)*) {
405            const ENCODINGS: &'static [Encoding] = &[
406                $($T::ENCODING_ARGUMENT),*
407            ];
408
409            #[inline]
410            unsafe fn __invoke<R: EncodeReturn>(msg_send_fn: Imp, receiver: *mut AnyObject, sel: Sel, ($($a,)*): Self) -> R {
411                // Message sending works by passing the receiver as the first
412                // argument, the selector as the second argument, and the rest
413                // of the arguments after that.
414                //
415                // The imp must be cast to the appropriate function pointer
416                // type before being called; contrary to how the headers and
417                // documentation describe them, the msgSend functions are not
418                // parametric on all platforms, instead they "trampoline" to
419                // the actual method implementations.
420                //
421                // SAFETY: We're transmuting an `unsafe` function pointer to
422                // another `unsafe` function pointer.
423                let msg_send_fn: unsafe extern "C-unwind" fn(*mut AnyObject, Sel $(, $T)*) -> R = unsafe {
424                    mem::transmute(msg_send_fn)
425                };
426
427                // SAFETY: Caller upholds that the imp is safe to call with
428                // the given receiver, selector and arguments.
429                //
430                // TODO: On x86_64 it would be more efficient to use a GOT
431                // entry here (e.g. adding `nonlazybind` in LLVM).
432                // Same can be said of e.g. `objc_retain` and `objc_release`.
433                unsafe { msg_send_fn(receiver, sel $(, $a)*) }
434            }
435        }
436    };
437}
438
439encode_args_impl!();
440encode_args_impl!(a: A);
441encode_args_impl!(a: A, b: B);
442encode_args_impl!(a: A, b: B, c: C);
443encode_args_impl!(a: A, b: B, c: C, d: D);
444encode_args_impl!(a: A, b: B, c: C, d: D, e: E);
445encode_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
446encode_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
447encode_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
448encode_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
449encode_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
450encode_args_impl!(
451    a: A,
452    b: B,
453    c: C,
454    d: D,
455    e: E,
456    f: F,
457    g: G,
458    h: H,
459    i: I,
460    j: J,
461    k: K
462);
463encode_args_impl!(
464    a: A,
465    b: B,
466    c: C,
467    d: D,
468    e: E,
469    f: F,
470    g: G,
471    h: H,
472    i: I,
473    j: J,
474    k: K,
475    l: L
476);
477encode_args_impl!(
478    a: A,
479    b: B,
480    c: C,
481    d: D,
482    e: E,
483    f: F,
484    g: G,
485    h: H,
486    i: I,
487    j: J,
488    k: K,
489    l: L,
490    m: M
491);
492encode_args_impl!(
493    a: A,
494    b: B,
495    c: C,
496    d: D,
497    e: E,
498    f: F,
499    g: G,
500    h: H,
501    i: I,
502    j: J,
503    k: K,
504    l: L,
505    m: M,
506    n: N
507);
508encode_args_impl!(
509    a: A,
510    b: B,
511    c: C,
512    d: D,
513    e: E,
514    f: F,
515    g: G,
516    h: H,
517    i: I,
518    j: J,
519    k: K,
520    l: L,
521    m: M,
522    n: N,
523    o: O
524);
525encode_args_impl!(
526    a: A,
527    b: B,
528    c: C,
529    d: D,
530    e: E,
531    f: F,
532    g: G,
533    h: H,
534    i: I,
535    j: J,
536    k: K,
537    l: L,
538    m: M,
539    n: N,
540    o: O,
541    p: P
542);
543
544// TODO: Implement for `PhantomData` and `PhantomPinned`?
545
546/// Helper for implementing [`Encode`].
547macro_rules! encode_impls {
548    ($($t:ty => $e:ident,)*) => ($(
549        unsafe impl Encode for $t {
550            const ENCODING: Encoding = Encoding::$e;
551        }
552    )*);
553}
554
555encode_impls!(
556    i8 => Char,
557    i16 => Short,
558    i32 => Int,
559    i64 => LongLong,
560    u8 => UChar,
561    u16 => UShort,
562    u32 => UInt,
563    u64 => ULongLong,
564    f32 => Float,
565    f64 => Double,
566
567    // TODO: i128 & u128
568    // https://github.com/rust-lang/rust/issues/54341
569);
570
571// TODO: Structs in core::arch?
572
573macro_rules! encode_impls_size {
574    ($($t:ty => ($t16:ty, $t32:ty, $t64:ty),)*) => ($(
575        // SAFETY: `usize` and `isize` is ABI compatible with `uN`/`iN` of the
576        // same size.
577        // <https://doc.rust-lang.org/nightly/std/primitive.fn.html#abi-compatibility>
578        #[doc = concat!("The encoding of [`", stringify!($t), "`] varies based on the target pointer width.")]
579        unsafe impl Encode for $t {
580            #[cfg(target_pointer_width = "16")]
581            const ENCODING: Encoding = <$t16>::ENCODING;
582            #[cfg(target_pointer_width = "32")]
583            const ENCODING: Encoding = <$t32>::ENCODING;
584            #[cfg(target_pointer_width = "64")]
585            const ENCODING: Encoding = <$t64>::ENCODING;
586        }
587    )*);
588}
589
590encode_impls_size!(
591    isize => (i16, i32, i64),
592    usize => (u16, u32, u64),
593);
594
595/// Helper for implementing [`RefEncode`].
596macro_rules! pointer_refencode_impl {
597    ($($t:ty),*) => ($(
598        unsafe impl RefEncode for $t {
599            const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
600        }
601    )*);
602}
603
604pointer_refencode_impl!(i16, i32, i64, isize, u16, u32, u64, usize, f32, f64);
605
606/// Pointers to [`i8`] use the special [`Encoding::String`] encoding.
607unsafe impl RefEncode for i8 {
608    const ENCODING_REF: Encoding = Encoding::String;
609}
610
611/// Pointers to [`u8`] use the special [`Encoding::String`] encoding.
612unsafe impl RefEncode for u8 {
613    const ENCODING_REF: Encoding = Encoding::String;
614}
615
616/// Helper for implementing [`Encode`] for nonzero integer types.
617macro_rules! encode_impls_nonzero {
618    ($($nonzero:ident => $type:ty,)*) => ($(
619        unsafe impl Encode for $nonzero {
620            const ENCODING: Encoding = <$type>::ENCODING;
621        }
622
623        unsafe impl RefEncode for $nonzero {
624            const ENCODING_REF: Encoding = <$type>::ENCODING_REF;
625        }
626
627        // SAFETY: nonzero types have a NUL niche that is exploited by Option
628        unsafe impl OptionEncode for $nonzero {}
629    )*);
630}
631
632encode_impls_nonzero!(
633    NonZeroI8 => i8,
634    NonZeroI16 => i16,
635    NonZeroI32 => i32,
636    NonZeroI64 => i64,
637    NonZeroIsize => isize,
638    NonZeroU8 => u8,
639    NonZeroU16 => u16,
640    NonZeroU32 => u32,
641    NonZeroU64 => u64,
642    NonZeroUsize => usize,
643);
644
645/// Helper for implementing for atomic types.
646macro_rules! encode_atomic_impls {
647    ($(
648        $(#[$m:meta])*
649        $atomic:ident => $type:ty,
650    )*) => ($(
651        // SAFETY: C11 `_Atomic` types use compatible synchronization
652        // primitives, and the atomic type is guaranteed to have the same
653        // in-memory representation as the underlying type.
654        $(#[$m])*
655        unsafe impl Encode for atomic::$atomic {
656            const ENCODING: Encoding = Encoding::Atomic(&<$type>::ENCODING);
657        }
658
659        $(#[$m])*
660        unsafe impl RefEncode for atomic::$atomic {
661            const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
662        }
663    )*);
664}
665
666encode_atomic_impls!(
667    #[cfg(target_has_atomic = "8")]
668    AtomicI8 => i8,
669    #[cfg(target_has_atomic = "8")]
670    AtomicU8 => u8,
671
672    #[cfg(target_has_atomic = "16")]
673    AtomicI16 => i16,
674    #[cfg(target_has_atomic = "16")]
675    AtomicU16 => u16,
676
677    #[cfg(target_has_atomic = "32")]
678    AtomicI32 => i32,
679    #[cfg(target_has_atomic = "32")]
680    AtomicU32 => u32,
681
682    #[cfg(target_has_atomic = "64")]
683    AtomicI64 => i64,
684    #[cfg(target_has_atomic = "64")]
685    AtomicU64 => u64,
686
687    // TODO
688    // #[cfg(target_has_atomic = "128")]
689    // AtomicI128 => i128,
690    // #[cfg(target_has_atomic = "128")]
691    // AtomicU128 => u128,
692
693    #[cfg(target_has_atomic = "ptr")]
694    AtomicIsize => isize,
695    #[cfg(target_has_atomic = "ptr")]
696    AtomicUsize => usize,
697);
698
699// SAFETY: Guaranteed to have the same in-memory representation as `*mut T`.
700#[cfg(target_has_atomic = "ptr")]
701unsafe impl<T: RefEncode> Encode for atomic::AtomicPtr<T> {
702    const ENCODING: Encoding = Encoding::Atomic(&T::ENCODING_REF);
703}
704
705#[cfg(target_has_atomic = "ptr")]
706unsafe impl<T: RefEncode> RefEncode for atomic::AtomicPtr<T> {
707    const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
708}
709
710unsafe impl RefEncode for c_void {
711    const ENCODING_REF: Encoding = Encoding::Pointer(&Encoding::Void);
712}
713
714unsafe impl<T: Encode, const LENGTH: usize> Encode for [T; LENGTH] {
715    const ENCODING: Encoding = Encoding::Array(LENGTH as u64, &T::ENCODING);
716}
717
718unsafe impl<T: Encode, const LENGTH: usize> RefEncode for [T; LENGTH] {
719    const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
720}
721
722macro_rules! encode_impls_transparent {
723    ($($t:ident<T $(: ?$b:ident)?>,)*) => ($(
724        unsafe impl<T: Encode $(+ ?$b)?> Encode for $t<T> {
725            const ENCODING: Encoding = T::ENCODING;
726        }
727
728        unsafe impl<T: RefEncode $(+ ?$b)?> RefEncode for $t<T> {
729            const ENCODING_REF: Encoding = T::ENCODING_REF;
730        }
731    )*);
732}
733
734encode_impls_transparent! {
735    // SAFETY: Guaranteed to have the same layout as `T`, and is subject to
736    // the same layout optimizations as `T`.
737    // TODO: With specialization: `impl Encode for ManuallyDrop<Box<T>>`
738    ManuallyDrop<T: ?Sized>,
739
740    // SAFETY: Guaranteed to have the same in-memory representation `T`.
741    //
742    // The fact that this has `repr(no_niche)` has no effect on us, since we
743    // don't unconditionally implement `Encode` generically over `Option`.
744    // (e.g. an `Option<UnsafeCell<&u8>>` impl is not available).
745    UnsafeCell<T: ?Sized>,
746
747    // SAFETY: Guaranteed to have the same layout as `UnsafeCell<T>`.
748    Cell<T: ?Sized>,
749
750    // The inner field is not public, so may not be safe.
751    // TODO: Pin<T>,
752
753    // SAFETY: Guaranteed to have the same size, alignment, and ABI as `T`.
754    MaybeUninit<T>,
755
756    // SAFETY: Guaranteed to have the same layout and ABI as `T`.
757    Wrapping<T>,
758
759    // TODO: Types that need to be made repr(transparent) first:
760    // - core::cell::Ref?
761    // - core::cell::RefCell?
762    // - core::cell::RefMut?
763    // - core::panic::AssertUnwindSafe<T>
764    // TODO: core::num::Saturating when that is stabilized
765    // TODO: core::cmp::Reverse?
766}
767
768/// Helper for implementing `Encode`/`RefEncode` for pointers to types that
769/// implement `RefEncode`.
770///
771/// Using `?Sized` is safe here because we delegate to other implementations
772/// (which will verify that the implementation is safe for the unsized type).
773macro_rules! encode_pointer_impls {
774    (unsafe impl<T: RefEncode> $x:ident for Pointer<T> {
775        const $c:ident = $e:expr;
776    }) => (
777        unsafe impl<T: RefEncode + ?Sized> $x for *const T {
778            const $c: Encoding = $e;
779        }
780
781        unsafe impl<T: RefEncode + ?Sized> $x for *mut T {
782            const $c: Encoding = $e;
783        }
784
785        unsafe impl<'a, T: RefEncode + ?Sized> $x for &'a T {
786            const $c: Encoding = $e;
787        }
788
789        unsafe impl<'a, T: RefEncode + ?Sized> $x for &'a mut T {
790            const $c: Encoding = $e;
791        }
792
793        unsafe impl<T: RefEncode + ?Sized> $x for NonNull<T> {
794            const $c: Encoding = $e;
795        }
796    );
797}
798
799// Implement `Encode` for types that are `RefEncode`.
800//
801// This allows users to implement `Encode` for custom types that have a
802// specific encoding as a pointer, instead of having to implement it for each
803// pointer-like type in turn.
804encode_pointer_impls!(
805    unsafe impl<T: RefEncode> Encode for Pointer<T> {
806        const ENCODING = T::ENCODING_REF;
807    }
808);
809
810// Implement `RefEncode` for pointers to types that are `RefEncode`.
811//
812// This implements `Encode` for pointers to pointers (to pointers, and so on),
813// which would otherwise be very cumbersome to do manually.
814encode_pointer_impls!(
815    unsafe impl<T: RefEncode> RefEncode for Pointer<T> {
816        const ENCODING_REF = Encoding::Pointer(&T::ENCODING_REF);
817    }
818);
819
820// SAFETY: References and `NonNull` have a NULL niche
821unsafe impl<T: RefEncode + ?Sized> OptionEncode for &T {}
822unsafe impl<T: RefEncode + ?Sized> OptionEncode for &mut T {}
823unsafe impl<T: RefEncode + ?Sized> OptionEncode for NonNull<T> {}
824
825/// Helper for implementing [`Encode`]/[`RefEncode`] for function pointers
826/// whose arguments implement [`Encode`].
827///
828/// Ideally we'd implement it for all function pointers, but due to coherence
829/// issues, see <https://github.com/rust-lang/rust/issues/56105>, function
830/// pointers that are higher-ranked over lifetimes don't get implemented.
831///
832/// We could fix it by adding those impls and allowing `coherence_leak_check`,
833/// but it would have to be done for _all_ references, `Option<&T>` and such
834/// as well. So trying to do it quickly requires generating a polynomial
835/// amount of implementations, which IMO is overkill for such a small issue.
836///
837/// Using `?Sized` is probably not safe here because C functions can only take
838/// and return items with a known size.
839macro_rules! encode_fn_pointer_impl {
840    (@ $FnTy: ty, $($Arg: ident),*) => {
841        unsafe impl<Ret: EncodeReturn, $($Arg: EncodeArgument),*> Encode for $FnTy {
842            const ENCODING: Encoding = Encoding::Pointer(&Encoding::Unknown);
843        }
844        unsafe impl<Ret: EncodeReturn, $($Arg: EncodeArgument),*> RefEncode for $FnTy {
845            const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
846        }
847        // SAFETY: Function pointers have a NULL niche
848        unsafe impl<Ret: EncodeReturn, $($Arg: EncodeArgument),*> OptionEncode for $FnTy {}
849    };
850    (# $abi:literal; $($Arg: ident),+) => {
851        // Normal functions
852        encode_fn_pointer_impl!(@ extern $abi fn($($Arg),+) -> Ret, $($Arg),+ );
853        encode_fn_pointer_impl!(@ unsafe extern $abi fn($($Arg),+) -> Ret, $($Arg),+ );
854        // Variadic functions
855        encode_fn_pointer_impl!(@ extern $abi fn($($Arg),+ , ...) -> Ret, $($Arg),+ );
856        encode_fn_pointer_impl!(@ unsafe extern $abi fn($($Arg),+ , ...) -> Ret, $($Arg),+ );
857    };
858    (# $abi:literal; ) => {
859        // No variadic functions with 0 parameters
860        encode_fn_pointer_impl!(@ extern $abi fn() -> Ret, );
861        encode_fn_pointer_impl!(@ unsafe extern $abi fn() -> Ret, );
862    };
863    ($($Arg: ident),*) => {
864        encode_fn_pointer_impl!(# "C"; $($Arg),*);
865        encode_fn_pointer_impl!(# "C-unwind"; $($Arg),*);
866    };
867}
868
869// Up to 16 arguments
870encode_fn_pointer_impl!();
871encode_fn_pointer_impl!(A);
872encode_fn_pointer_impl!(A, B);
873encode_fn_pointer_impl!(A, B, C);
874encode_fn_pointer_impl!(A, B, C, D);
875encode_fn_pointer_impl!(A, B, C, D, E);
876encode_fn_pointer_impl!(A, B, C, D, E, F);
877encode_fn_pointer_impl!(A, B, C, D, E, F, G);
878encode_fn_pointer_impl!(A, B, C, D, E, F, G, H);
879encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I);
880encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J);
881encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K);
882encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K, L);
883encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M);
884encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
885encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
886encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
887
888#[cfg(test)]
889mod tests {
890    use super::*;
891
892    use core::sync::atomic::*;
893
894    #[test]
895    fn test_c_string() {
896        assert_eq!(i8::ENCODING, Encoding::Char);
897        assert_eq!(u8::ENCODING, Encoding::UChar);
898
899        assert_eq!(<*const i8>::ENCODING, Encoding::String);
900        assert_eq!(<&u8>::ENCODING, Encoding::String);
901        assert_eq!(i8::ENCODING_REF, Encoding::String);
902        assert_eq!(i8::ENCODING_REF, Encoding::String);
903
904        assert_eq!(
905            <*const *const i8>::ENCODING,
906            Encoding::Pointer(&Encoding::String)
907        );
908        assert_eq!(<&&u8>::ENCODING, Encoding::Pointer(&Encoding::String));
909    }
910
911    #[test]
912    fn test_i32() {
913        assert_eq!(i32::ENCODING, Encoding::Int);
914        assert_eq!(<&i32>::ENCODING, Encoding::Pointer(&Encoding::Int));
915        assert_eq!(
916            <&&i32>::ENCODING,
917            Encoding::Pointer(&Encoding::Pointer(&Encoding::Int))
918        );
919    }
920
921    #[test]
922    fn test_atomic() {
923        assert_eq!(AtomicI32::ENCODING, Encoding::Atomic(&Encoding::Int));
924        assert_eq!(
925            AtomicI32::ENCODING_REF,
926            Encoding::Pointer(&Encoding::Atomic(&Encoding::Int))
927        );
928        assert_eq!(
929            AtomicPtr::<i32>::ENCODING,
930            Encoding::Atomic(&Encoding::Pointer(&Encoding::Int))
931        );
932
933        assert_eq!(AtomicI8::ENCODING, Encoding::Atomic(&Encoding::Char));
934        assert_eq!(
935            AtomicI8::ENCODING_REF,
936            Encoding::Pointer(&Encoding::Atomic(&Encoding::Char))
937        );
938        assert_eq!(
939            AtomicPtr::<i8>::ENCODING,
940            Encoding::Atomic(&Encoding::String)
941        );
942    }
943
944    #[test]
945    fn test_void() {
946        assert_eq!(
947            <*const c_void>::ENCODING,
948            Encoding::Pointer(&Encoding::Void)
949        );
950        assert_eq!(<&c_void>::ENCODING, Encoding::Pointer(&Encoding::Void));
951        assert_eq!(
952            <&*const c_void>::ENCODING,
953            Encoding::Pointer(&Encoding::Pointer(&Encoding::Void))
954        );
955        assert_eq!(
956            <AtomicPtr<c_void>>::ENCODING,
957            Encoding::Atomic(&Encoding::Pointer(&Encoding::Void))
958        );
959    }
960
961    #[test]
962    fn test_transparent() {
963        assert_eq!(<ManuallyDrop<u8>>::ENCODING, u8::ENCODING);
964        assert_eq!(<ManuallyDrop<&u8>>::ENCODING, u8::ENCODING_REF);
965        assert_eq!(<ManuallyDrop<Option<&u8>>>::ENCODING, u8::ENCODING_REF);
966        assert_eq!(<&ManuallyDrop<Option<&u8>>>::ENCODING, <&&u8>::ENCODING);
967
968        assert_eq!(<UnsafeCell<u8>>::ENCODING, u8::ENCODING);
969        assert_eq!(<UnsafeCell<&u8>>::ENCODING, <&u8>::ENCODING);
970        assert_eq!(<Cell<u8>>::ENCODING, u8::ENCODING);
971        assert_eq!(<Cell<&u8>>::ENCODING, <&u8>::ENCODING);
972        // assert_eq!(<Pin<u8>>::ENCODING, u8::ENCODING);
973        assert_eq!(<MaybeUninit<u8>>::ENCODING, u8::ENCODING);
974        assert_eq!(<Wrapping<u8>>::ENCODING, u8::ENCODING);
975    }
976
977    #[test]
978    fn test_extern_fn_pointer() {
979        assert_eq!(
980            <extern "C" fn()>::ENCODING,
981            Encoding::Pointer(&Encoding::Unknown)
982        );
983        assert_eq!(
984            <extern "C" fn(x: i32) -> u32>::ENCODING,
985            Encoding::Pointer(&Encoding::Unknown)
986        );
987        assert_eq!(
988            <Option<unsafe extern "C" fn()>>::ENCODING,
989            Encoding::Pointer(&Encoding::Unknown)
990        );
991        assert_eq!(
992            <extern "C-unwind" fn()>::ENCODING,
993            Encoding::Pointer(&Encoding::Unknown)
994        );
995    }
996
997    #[test]
998    fn test_extern_fn_pointer_elided_lifetime() {
999        fn impls_encode<T: Encode>(_x: T) {}
1000
1001        extern "C" fn my_fn1(_x: &i32) {}
1002        extern "C" fn my_fn2(_x: &i32, _y: &u8) {}
1003        extern "C" fn my_fn3(x: &u8) -> &u8 {
1004            x
1005        }
1006        extern "C" fn my_fn4<'a>(x: &'a u8, _y: &i32) -> &'a u8 {
1007            x
1008        }
1009
1010        impls_encode(my_fn1 as extern "C" fn(_));
1011        impls_encode(my_fn2 as extern "C" fn(_, _));
1012        impls_encode(my_fn3 as extern "C" fn(_) -> _);
1013        impls_encode(my_fn4 as extern "C" fn(_, _) -> _);
1014    }
1015
1016    #[test]
1017    fn test_return() {
1018        assert_eq!(<i32>::ENCODING_RETURN, <i32>::ENCODING);
1019        assert_eq!(<()>::ENCODING_RETURN, Encoding::Void);
1020    }
1021
1022    #[test]
1023    fn test_argument() {
1024        assert_eq!(<i32>::ENCODING_ARGUMENT, <i32>::ENCODING);
1025    }
1026
1027    #[test]
1028    fn test_arguments() {
1029        assert_eq!(<()>::ENCODINGS, &[] as &[Encoding]);
1030        assert_eq!(<(i8,)>::ENCODINGS, &[i8::ENCODING]);
1031        assert_eq!(<(i8, u32)>::ENCODINGS, &[i8::ENCODING, u32::ENCODING]);
1032    }
1033}