//! # Support for type-encodings. //! //! The Objective-C runtime includes encodings for each method that describe //! the argument and return types. This module contains traits for annotating //! types that has an Objective-C type-encoding: Specifically [`Encode`] for //! structs/numeric types and [`RefEncode`] for references. //! //! Additionally, this exports the [`Encoding`] and [`EncodingBox`] types from //! [`objc2-encode`][objc2_encode], see that crate for a few more details on //! what Objective-C type-encodings are. //! //! //! ## Examples //! //! Implementing [`Encode`] and [`RefEncode`] for a custom type: //! //! ``` //! use objc2::encode::{Encode, Encoding, RefEncode}; //! //! #[repr(C)] //! struct MyStruct { //! a: f32, // float //! b: i16, // int16_t //! } //! //! unsafe impl Encode for MyStruct { //! const ENCODING: Encoding = Encoding::Struct( //! "MyStruct", // Must use the same name as defined in C header files //! &[ //! f32::ENCODING, // Same as Encoding::Float //! i16::ENCODING, // Same as Encoding::Short //! ], //! ); //! } //! //! // @encode(MyStruct) -> "{MyStruct=fs}" //! assert!(MyStruct::ENCODING.equivalent_to_str("{MyStruct=fs}")); //! //! unsafe impl RefEncode for MyStruct { //! const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING); //! } //! //! // @encode(MyStruct*) -> "^{MyStruct=fs}" //! assert!(MyStruct::ENCODING_REF.equivalent_to_str("^{MyStruct=fs}")); //! ``` //! //! Implementing [`Encode`] for a few core-graphics types. //! //! Note that these are available in `objc2-foundation`, so the implementation //! here is mostly for demonstration. //! //! ``` #![doc = include_str!("../examples/encode_core_graphics.rs")] //! ``` //! //! Implementing [`Encode`] and [`RefEncode`] for a transparent newtype. //! //! ``` #![doc = include_str!("../examples/encode_nsuinteger.rs")] //! ``` //! //! Implementing [`RefEncode`] for an object, in this case `NSString`. //! //! ``` #![doc = include_str!("../examples/encode_nsstring.rs")] //! ``` //! //! Implementing [`RefEncode`] for a type where you don't necessarily know //! about the exact internals / the internals are not representable in Rust. //! //! ``` #![doc = include_str!("../examples/encode_opaque_type.rs")] //! ```
use core::cell::{Cell, UnsafeCell}; use core::ffi::c_void; use core::mem::{self, ManuallyDrop, MaybeUninit}; use core::num::{
NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU16, NonZeroU32,
NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
}; use core::ptr::NonNull; use core::sync::atomic;
/// Types that have an Objective-C type-encoding. /// /// Usually you will want to implement [`RefEncode`] as well. /// /// If your type is an opaque type you should not need to implement this; /// there you will only need [`RefEncode`]. /// /// /// # Safety /// /// The type must be FFI-safe, meaning a C-compatible `repr` (`repr(C)`, /// `repr(u8)`, `repr(transparent)` where the inner types are C-compatible, /// and so on). See the [nomicon on other `repr`s][reprs]. /// /// Objective-C will make assumptions about the type (like its size, alignment /// and ABI) from its encoding, so the implementer must verify that the /// encoding is accurate. /// /// Concretely, [`Self::ENCODING`] must match the result of running `@encode` /// in Objective-C with the type in question. /// /// You should also beware of having [`Drop`] types implement this, since when /// passed to Objective-C via `objc2::msg_send!` their destructor will not be /// called! /// /// /// # Examples /// /// Implementing for a struct: /// /// ``` /// # use objc2::encode::{Encode, Encoding, RefEncode}; /// # use core::ffi::c_void; /// # /// #[repr(C)] /// struct MyType { /// a: i32, /// b: f64, /// c: *const c_void, /// } /// /// unsafe impl Encode for MyType { /// const ENCODING: Encoding = Encoding::Struct( /// // The name of the type that Objective-C sees. /// "MyType", /// &[ /// // Delegate to field's implementations. /// // The order is the same as in the definition. /// i32::ENCODING, /// f64::ENCODING, /// <*const c_void>::ENCODING, /// ], /// ); /// } /// /// // Note: You would also implement `RefEncode` for this type. /// ``` /// /// [reprs]: https://doc.rust-lang.org/nomicon/other-reprs.html pubunsafetrait Encode { /// The Objective-C type-encoding for this type. const ENCODING: Encoding;
}
/// Types whose references has an Objective-C type-encoding. /// /// Implementing this for `T` provides [`Encode`] implementations for: /// - `*const T` /// - `*mut T` /// - `&T` /// - `&mut T` /// - `NonNull<T>` /// - `Option<&T>` /// - `Option<&mut T>` /// - `Option<NonNull<T>>` /// /// /// # Reasoning behind this trait's existence /// /// External crates cannot implement [`Encode`] for pointers or [`Option`]s /// containing references, so instead, they can implement this trait. /// Additionally it would be very cumbersome if every type had to implement /// [`Encode`] for all possible pointer types. /// /// Finally, having this trait allows for much cleaner generic code that need /// to represent types that can be encoded as pointers. /// /// /// # Safety /// /// References to the object must be FFI-safe. /// /// See the nomicon entry on [representing opaque structs][opaque] for /// information on how to represent objects that you don't know the layout of /// (or use `extern type` ([RFC-1861]) if you're using nightly). /// /// Objective-C will make assumptions about the type (like its size, alignment /// and ABI) from its encoding, so the implementer must verify that the /// encoding is accurate. /// /// Concretely, [`Self::ENCODING_REF`] must match the result of running /// `@encode` in Objective-C with a pointer to the type in question. /// /// [opaque]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs /// [RFC-1861]: https://rust-lang.github.io/rfcs/1861-extern-types.html pubunsafetrait RefEncode { /// The Objective-C type-encoding for a reference of this type. /// /// Should be one of [`Encoding::Object`], [`Encoding::Block`], /// [`Encoding::Class`], [`Encoding::Pointer`], [`Encoding::Sel`] or /// [`Encoding::Unknown`]. /// /// /// # Examples /// /// This is usually implemented either as an object pointer: /// ``` /// # use objc2::encode::{Encoding, RefEncode}; /// # #[repr(C)] /// # struct MyObject { /// # _priv: [u8; 0], /// # } /// # unsafe impl RefEncode for MyObject { /// const ENCODING_REF: Encoding = Encoding::Object; /// # } /// ``` /// /// Or as a pointer to the type, delegating the rest to the [`Encode`] /// implementation: /// ``` /// # use objc2::encode::{Encode, Encoding, RefEncode}; /// # #[repr(transparent)] /// # struct MyType(i32); /// # unsafe impl Encode for MyType { /// # const ENCODING: Encoding = i32::ENCODING; /// # } /// # unsafe impl RefEncode for MyType { /// const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING); /// # } /// ``` const ENCODING_REF: Encoding;
}
/// A helper trait for types that follow the "null pointer optimization", and /// are encodable inside an [`Option`]. /// /// See [the `Option` documentation][option-repr] for details on which types /// this holds for, and [the nomicon][nomicon-npo] for more details on the /// null pointer optimization. /// /// This trait used to work around the orphan rule, which would normally /// prevent you from implementing [`Encode`]/[`RefEncode`] for /// `Option<CustomType>`. /// /// [option-repr]: https://doc.rust-lang.org/1.75.0/std/option/index.html#representation /// [nomicon-npo]: https://doc.rust-lang.org/nightly/nomicon/ffi.html#the-nullable-pointer-optimization /// /// /// # Safety /// /// You must ensure that the implemented type `T` has the same layout and /// function call ABI as `Option<T>`. /// /// /// # Examples /// /// ``` /// use objc2::encode::{Encode, Encoding, OptionEncode}; /// use core::ptr::NonNull; /// use core::ffi::c_void; /// /// #[repr(transparent)] /// struct MyBlockType(NonNull<c_void>); /// /// // SAFETY: `MyBlockType` is meant to represent a pointer to a block /// unsafe impl Encode for MyBlockType { /// const ENCODING: Encoding = Encoding::Block; /// } /// /// // SAFETY: `MyBlockType` is `repr(transparent)` over `NonNull`, which /// // means that `Option<MyBlockType>` has the same layout. /// unsafe impl OptionEncode for MyBlockType {} /// /// assert_eq!(<Option<MyBlockType>>::ENCODING, MyBlockType::ENCODING); /// ``` pubunsafetrait OptionEncode {}
// SAFETY: Implementor of `OptionEncode` guarantees this impl is sound unsafeimpl<T: Encode + OptionEncode> Encode for Option<T> { const ENCODING: Encoding = { if mem::size_of::<T>() != mem::size_of::<Option<T>>() {
panic!("invalid OptionEncode + Encode implementation");
}
T::ENCODING
};
}
// SAFETY: Implementor of `OptionEncode` guarantees this impl is sound unsafeimpl<T: RefEncode + OptionEncode> RefEncode for Option<T> { const ENCODING_REF: Encoding = { if mem::size_of::<T>() != mem::size_of::<Option<T>>() {
panic!("invalid OptionEncode + RefEncode implementation");
}
T::ENCODING_REF
};
}
mod return_private { pubtrait Sealed {}
}
/// Types that are safe as the return value from Objective-C. /// /// This is a sealed trait, and should not need to be implemented manually. /// /// /// # Safety /// /// Similar to [`Encode`], except the value is only guaranteed to be valid as /// a return value, both from functions/methods you're calling, and from /// declared functions/methods. /// /// It does not have to be valid as e.g. an instance variable, or as an /// argument to a function. pubunsafetrait EncodeReturn: return_private::Sealed { /// The Objective-C type-encoding for this type. const ENCODING_RETURN: Encoding;
}
impl return_private::Sealed for () {} // SAFETY: `()` is the same as C's `void` type, which is a valid return type unsafeimpl EncodeReturn for () { const ENCODING_RETURN: Encoding = Encoding::Void;
}
impl<T: Encode> return_private::Sealed for T {} // SAFETY: All `Encode` types are also valid as return types unsafeimpl<T: Encode> EncodeReturn for T { const ENCODING_RETURN: Encoding = T::ENCODING;
}
mod argument_private { pubtrait Sealed {}
}
/// Types that are safe as arguments to Objective-C methods. /// /// This is a sealed trait, and should not need to be implemented manually. /// /// /// # Safety /// /// Similar to [`Encode`], except the value is only guaranteed to be valid as /// an argument or a parameter, both from functions/methods you're calling and /// from declared functions/methods. /// /// It does not have to be valid as e.g. an instance variable, or as an /// argument to a function. // // Note: This is mostly implemented for consistency; there are (not that I've // found at least) no places where this is not just `Encode`. // // You might be tempted to think that `bool` could work in this, but that // would be a mistake (even ignoring that its size is different on certain // targets) because it cannot be safely used in custom defined methods. pubunsafetrait EncodeArgument: argument_private::Sealed { /// The Objective-C type-encoding for this type. const ENCODING_ARGUMENT: Encoding;
}
impl<T: Encode> argument_private::Sealed for T {} // SAFETY: All `Encode` types are also valid as argument types unsafeimpl<T: Encode> EncodeArgument for T { const ENCODING_ARGUMENT: Encoding = T::ENCODING;
}
mod args_private { pubtrait Sealed {}
}
/// Types that represent an ordered group of function arguments, where each /// argument has an Objective-C type-encoding, or can be converted from one. /// /// This is implemented for tuples of up to 16 arguments, where each argument /// implements [`EncodeArgument`]. It is a sealed trait, and should not need /// to be implemented manually - it is primarily used to make generic code a /// bit easier to read and understand. /// /// Note that tuples themselves don't implement [`Encode`] directly, because /// they're not FFI-safe! pubtrait EncodeArguments: args_private::Sealed { /// The encodings for the arguments. const ENCODINGS: &'static [Encoding];
/// Invoke a message sending function with the given object, selector, /// and arguments. /// /// Implementation-wise, this is a bit ugly, but simply just easiest to /// have the method on this trait, since inside `MessageReceiver` we only /// want to publicly require `EncodeArguments`, and not another private /// trait. #[doc(hidden)] unsafefn __invoke<R: EncodeReturn>(
msg_send_fn: Imp,
receiver: *mut AnyObject,
sel: Sel,
args: Self,
) -> R;
}
#[inline] unsafefn __invoke<R: EncodeReturn>(msg_send_fn: Imp, receiver: *mut AnyObject, sel: Sel, ($($a,)*): Self) -> R { // Message sending works by passing the receiver as the first // argument, the selector as the second argument, and the rest // of the arguments after that. // // The imp must be cast to the appropriate function pointer // type before being called; contrary to how the headers and // documentation describe them, the msgSend functions are not // parametric on all platforms, instead they "trampoline" to // the actual method implementations. // // SAFETY: We're transmuting an `unsafe` function pointer to // another `unsafe` function pointer. let msg_send_fn: unsafeextern"C-unwind"fn(*mut AnyObject, Sel $(, $T)*) -> R = unsafe {
mem::transmute(msg_send_fn)
};
// SAFETY: Caller upholds that the imp is safe to call with // the given receiver, selector and arguments. // // TODO: On x86_64 it would be more efficient to use a GOT // entry here (e.g. adding `nonlazybind` in LLVM). // Same can be said of e.g. `objc_retain` and `objc_release`. unsafe { msg_send_fn(receiver, sel $(, $a)*) }
}
}
};
}
encode_args_impl!();
encode_args_impl!(a: A);
encode_args_impl!(a: A, b: B);
encode_args_impl!(a: A, b: B, c: C);
encode_args_impl!(a: A, b: B, c: C, d: D);
encode_args_impl!(a: A, b: B, c: C, d: D, e: E);
encode_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
encode_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
encode_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
encode_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
encode_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
encode_args_impl!(
a: A,
b: B,
c: C,
d: D,
e: E,
f: F,
g: G,
h: H,
i: I,
j: J,
k: K
);
encode_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
);
encode_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
);
encode_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
);
encode_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
);
encode_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
);
// TODO: Implement for `PhantomData` and `PhantomPinned`?
/// Helper for implementing for atomic types.
macro_rules! encode_atomic_impls {
($(
$(#[$m:meta])*
$atomic:ident => $type:ty,
)*) => ($( // SAFETY: C11 `_Atomic` types use compatible synchronization // primitives, and the atomic type is guaranteed to have the same // in-memory representation as the underlying type.
$(#[$m])* unsafeimpl Encode for atomic::$atomic { const ENCODING: Encoding = Encoding::Atomic(&<$type>::ENCODING);
}
// SAFETY: Guaranteed to have the same in-memory representation as `*mut T`. #[cfg(target_has_atomic = "ptr")] unsafeimpl<T: RefEncode> Encode for atomic::AtomicPtr<T> { const ENCODING: Encoding = Encoding::Atomic(&T::ENCODING_REF);
}
encode_impls_transparent! { // SAFETY: Guaranteed to have the same layout as `T`, and is subject to // the same layout optimizations as `T`. // TODO: With specialization: `impl Encode for ManuallyDrop<Box<T>>`
ManuallyDrop<T: ?Sized>,
// SAFETY: Guaranteed to have the same in-memory representation `T`. // // The fact that this has `repr(no_niche)` has no effect on us, since we // don't unconditionally implement `Encode` generically over `Option`. // (e.g. an `Option<UnsafeCell<&u8>>` impl is not available).
UnsafeCell<T: ?Sized>,
// SAFETY: Guaranteed to have the same layout as `UnsafeCell<T>`.
Cell<T: ?Sized>,
// The inner field is not public, so may not be safe. // TODO: Pin<T>,
// SAFETY: Guaranteed to have the same size, alignment, and ABI as `T`.
MaybeUninit<T>,
// SAFETY: Guaranteed to have the same layout and ABI as `T`.
Wrapping<T>,
// TODO: Types that need to be made repr(transparent) first: // - core::cell::Ref? // - core::cell::RefCell? // - core::cell::RefMut? // - core::panic::AssertUnwindSafe<T> // TODO: core::num::Saturating when that is stabilized // TODO: core::cmp::Reverse?
}
/// Helper for implementing `Encode`/`RefEncode` for pointers to types that /// implement `RefEncode`. /// /// Using `?Sized` is safe here because we delegate to other implementations /// (which will verify that the implementation is safe for the unsized type).
macro_rules! encode_pointer_impls {
(unsafeimpl<T: RefEncode> $x:ident for Pointer<T> { const $c:ident = $e:expr;
}) => ( unsafeimpl<T: RefEncode + ?Sized> $x for *const T { const $c: Encoding = $e;
}
unsafeimpl<T: RefEncode + ?Sized> $x for *mut T { const $c: Encoding = $e;
}
unsafeimpl<'a, T: RefEncode + ?Sized> $x for &'a T { const $c: Encoding = $e;
}
unsafeimpl<'a, T: RefEncode + ?Sized> $x for &'a mut T { const $c: Encoding = $e;
}
// Implement `Encode` for types that are `RefEncode`. // // This allows users to implement `Encode` for custom types that have a // specific encoding as a pointer, instead of having to implement it for each // pointer-like type in turn.
encode_pointer_impls!( unsafeimpl<T: RefEncode> Encode for Pointer<T> { const ENCODING = T::ENCODING_REF;
}
);
// Implement `RefEncode` for pointers to types that are `RefEncode`. // // This implements `Encode` for pointers to pointers (to pointers, and so on), // which would otherwise be very cumbersome to do manually.
encode_pointer_impls!( unsafeimpl<T: RefEncode> RefEncode for Pointer<T> { const ENCODING_REF = Encoding::Pointer(&T::ENCODING_REF);
}
);
// SAFETY: References and `NonNull` have a NULL niche unsafeimpl<T: RefEncode + ?Sized> OptionEncode for &T {} unsafeimpl<T: RefEncode + ?Sized> OptionEncode for &mut T {} unsafeimpl<T: RefEncode + ?Sized> OptionEncode for NonNull<T> {}
/// Helper for implementing [`Encode`]/[`RefEncode`] for function pointers /// whose arguments implement [`Encode`]. /// /// Ideally we'd implement it for all function pointers, but due to coherence /// issues, see <https://github.com/rust-lang/rust/issues/56105>, function /// pointers that are higher-ranked over lifetimes don't get implemented. /// /// We could fix it by adding those impls and allowing `coherence_leak_check`, /// but it would have to be done for _all_ references, `Option<&T>` and such /// as well. So trying to do it quickly requires generating a polynomial /// amount of implementations, which IMO is overkill for such a small issue. /// /// Using `?Sized` is probably not safe here because C functions can only take /// and return items with a known size.
macro_rules! encode_fn_pointer_impl {
(@ $FnTy: ty, $($Arg: ident),*) => { unsafeimpl<Ret: EncodeReturn, $($Arg: EncodeArgument),*> Encode for $FnTy { const ENCODING: Encoding = Encoding::Pointer(&Encoding::Unknown);
} unsafeimpl<Ret: EncodeReturn, $($Arg: EncodeArgument),*> RefEncode for $FnTy { const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
} // SAFETY: Function pointers have a NULL niche unsafeimpl<Ret: EncodeReturn, $($Arg: EncodeArgument),*> OptionEncode for $FnTy {}
};
(# $abi:literal; $($Arg: ident),+) => { // Normal functions
encode_fn_pointer_impl!(@ extern $abi fn($($Arg),+) -> Ret, $($Arg),+ );
encode_fn_pointer_impl!(@ unsafeextern $abi fn($($Arg),+) -> Ret, $($Arg),+ ); // Variadic functions
encode_fn_pointer_impl!(@ extern $abi fn($($Arg),+ , ...) -> Ret, $($Arg),+ );
encode_fn_pointer_impl!(@ unsafeextern $abi fn($($Arg),+ , ...) -> Ret, $($Arg),+ );
};
(# $abi:literal; ) => { // No variadic functions with 0 parameters
encode_fn_pointer_impl!(@ extern $abi fn() -> Ret, );
encode_fn_pointer_impl!(@ unsafeextern $abi fn() -> Ret, );
};
($($Arg: ident),*) => {
encode_fn_pointer_impl!(# "C"; $($Arg),*);
encode_fn_pointer_impl!(# "C-unwind"; $($Arg),*);
};
}
// Up to 16 arguments
encode_fn_pointer_impl!();
encode_fn_pointer_impl!(A);
encode_fn_pointer_impl!(A, B);
encode_fn_pointer_impl!(A, B, C);
encode_fn_pointer_impl!(A, B, C, D);
encode_fn_pointer_impl!(A, B, C, D, E);
encode_fn_pointer_impl!(A, B, C, D, E, F);
encode_fn_pointer_impl!(A, B, C, D, E, F, G);
encode_fn_pointer_impl!(A, B, C, D, E, F, G, H);
encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I);
encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J);
encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K);
encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K, L);
encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M);
encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.