Module objc2::encode

source ·
Expand description

§Support for type-encodings.

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, 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.

use objc2::encode::{Encode, Encoding};

#[cfg(target_pointer_width = "32")]
type CGFloat = f32;
#[cfg(target_pointer_width = "64")]
type CGFloat = f64;

#[repr(C)]
struct CGPoint {
    x: CGFloat,
    y: CGFloat,
}

// SAFETY: The struct is `repr(C)`, and the encoding is correct.
unsafe impl Encode for CGPoint {
    const ENCODING: Encoding = Encoding::Struct("CGPoint", &[CGFloat::ENCODING, CGFloat::ENCODING]);
}

#[repr(C)]
struct CGSize {
    width: CGFloat,
    height: CGFloat,
}

// SAFETY: The struct is `repr(C)`, and the encoding is correct.
unsafe impl Encode for CGSize {
    const ENCODING: Encoding = Encoding::Struct("CGSize", &[CGFloat::ENCODING, CGFloat::ENCODING]);
}

#[repr(C)]
struct CGRect {
    origin: CGPoint,
    size: CGSize,
}

// SAFETY: The struct is `repr(C)`, and the encoding is correct.
unsafe impl Encode for CGRect {
    const ENCODING: Encoding = Encoding::Struct("CGRect", &[CGPoint::ENCODING, CGSize::ENCODING]);
}

fn main() {
    let expected = if cfg!(target_pointer_width = "64") {
        "{CGRect={CGPoint=dd}{CGSize=dd}}"
    } else {
        "{CGRect={CGPoint=ff}{CGSize=ff}}"
    };

    assert!(CGRect::ENCODING.equivalent_to_str(expected));
}

Implementing Encode and RefEncode for a transparent newtype.

use objc2::encode::{Encode, Encoding, RefEncode};

// Note: In this case `NSUInteger` could be a type alias for `usize`, and
// actually that's already available as `objc2::ffi::NSUInteger`.
#[repr(transparent)]
struct NSUInteger {
    _inner: usize,
}

// SAFETY: `NSUInteger` has the same `repr` as `usize`.
unsafe impl Encode for NSUInteger {
    // Running `@encode(NSUInteger)` gives `Q` on 64-bit systems and `I` on
    // 32-bit systems. This corresponds exactly to `usize`, which is also how
    // we've defined our struct.
    const ENCODING: Encoding = usize::ENCODING;
}

// SAFETY: `&NSUInteger` has the same representation as `&usize`.
unsafe impl RefEncode for NSUInteger {
    // Running `@encode(NSUInteger*)` gives `^Q` on 64-bit systems and `^I` on
    // 32-bit systems. So implementing `RefEncode` as a plain pointer is
    // correct.
    const ENCODING_REF: Encoding = Encoding::Pointer(&NSUInteger::ENCODING);
}

fn main() {
    assert!(NSUInteger::ENCODING.equivalent_to_str("Q"));
    assert!(<&NSUInteger>::ENCODING.equivalent_to_str("^Q"));
    assert!(<&NSUInteger>::ENCODING.equivalent_to_str("r^Q"));
}

Implementing RefEncode for an object, in this case NSString.

use objc2::encode::{Encode, Encoding, RefEncode};
use objc2::runtime::AnyObject;

#[repr(transparent)]
struct NSString {
    // `NSString` has the same layout / works the same as `AnyObject`.
    _priv: AnyObject,
}

// We don't know the size of NSString, so we can only hold pointers to it.
//
// SAFETY: The string is `repr(transparent)` over `AnyObject`.
unsafe impl RefEncode for NSString {
    const ENCODING_REF: Encoding = Encoding::Object;
}

fn main() {
    // The `RefEncode` implementation provide an `Encode` implementation for
    // pointers to the object.
    assert_eq!(<*const NSString>::ENCODING, Encoding::Object);
    assert_eq!(<*mut NSString>::ENCODING, Encoding::Object);
    assert_eq!(<&NSString>::ENCODING, Encoding::Object);
    assert_eq!(<&mut NSString>::ENCODING, Encoding::Object);
    assert_eq!(<Option<&NSString>>::ENCODING, Encoding::Object);
    assert_eq!(<Option<&mut NSString>>::ENCODING, Encoding::Object);
}

Implementing RefEncode for a type where you don’t necessarily know about the exact internals / the internals are not representable in Rust.

use objc2::encode::{Encoding, RefEncode};

// We choose in this case to represent `NSDecimal` as an opaque struct because
// we don't know much about the internals.
//
// Therefore we do not implement `Encode`.
#[repr(C)]
struct NSDecimal {
    // Note: This should be an [extern type][rfc-1861] instead, when that
    // becomes possible, for now we use this as a workaround.
    //
    // [rfc-1861]: https://rust-lang.github.io/rfcs/1861-extern-types.html
    _priv: [u8; 0],
}

// SAFETY: `&NSDecimal` is a valid pointer, and the encoding is correct.
unsafe impl RefEncode for NSDecimal {
    const ENCODING_REF: Encoding = Encoding::Pointer(&Encoding::Struct("?", &[]));
}

fn main() {
    // Running `@encode` on `NSDecimal*` on my 64-bit system gives
    // `^{?=cCCC[38C]}`, but empty structs are treated as equivalent to all
    // other structs by `objc2`.
    assert!(NSDecimal::ENCODING_REF.equivalent_to_str("^{?=cCCC[38C]}"));
    // Does not compile:
    // println!("{:?}", NSDecimal::ENCODING);
}

Structs§

  • The error that was encountered while parsing an encoding string.

Enums§

Traits§

  • Types that have an Objective-C type-encoding.
  • Types that are safe as arguments to Objective-C methods.
  • Types that represent an ordered group of function arguments, where each argument has an Objective-C type-encoding, or can be converted from one.
  • Types that are safe as the return value from Objective-C.
  • A helper trait for types that follow the “null pointer optimization”, and are encodable inside an Option.
  • Types whoose references has an Objective-C type-encoding.