Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

View File

@@ -0,0 +1,129 @@
//! Note: We can't use the `declare_class!` macro for this, it doesn't support
//! such use-cases (yet). Instead, we'll declare the class manually.
#![deny(unsafe_op_in_unsafe_fn)]
use std::marker::PhantomData;
use std::sync::Once;
use objc2::mutability::Mutable;
use objc2::rc::Retained;
use objc2::runtime::{AnyClass, ClassBuilder, NSObject, Sel};
use objc2::{msg_send, msg_send_id, sel};
use objc2::{ClassType, Encoding, Message, RefEncode};
/// Struct that represents our custom object.
#[repr(C)]
struct MyObject<'a> {
// Required to give MyObject the proper layout
superclass: NSObject,
p: PhantomData<&'a mut u8>,
}
unsafe impl RefEncode for MyObject<'_> {
const ENCODING_REF: Encoding = NSObject::ENCODING_REF;
}
unsafe impl Message for MyObject<'_> {}
impl<'a> MyObject<'a> {
unsafe extern "C" fn init_with_ptr<'s>(
&'s mut self,
_cmd: Sel,
ptr: Option<&'a mut u8>,
) -> Option<&'s mut Self> {
let this: Option<&mut Self> = unsafe { msg_send![super(self), init] };
this.map(|this| {
let ivar = Self::class().instance_variable("number").unwrap();
// SAFETY: The ivar is added with the same type below
unsafe {
ivar.load_ptr::<&mut u8>(&this.superclass)
.write(ptr.expect("got NULL number ptr"))
};
this
})
}
fn new(number: &'a mut u8) -> Retained<Self> {
// SAFETY: The lifetime of the reference is properly bound to the
// returned type
unsafe { msg_send_id![Self::alloc(), initWithPtr: number] }
}
fn get(&self) -> u8 {
let ivar = Self::class().instance_variable("number").unwrap();
// SAFETY: The ivar is added with the same type below, and is initialized in `init_with_ptr`
unsafe { **ivar.load::<&mut u8>(&self.superclass) }
}
fn set(&mut self, number: u8) {
let ivar = Self::class().instance_variable("number").unwrap();
// SAFETY: The ivar is added with the same type below, and is initialized in `init_with_ptr`
unsafe { **ivar.load_mut::<&mut u8>(&mut self.superclass) = number };
}
}
unsafe impl<'a> ClassType for MyObject<'a> {
type Super = NSObject;
type Mutability = Mutable;
const NAME: &'static str = "MyObject";
fn class() -> &'static AnyClass {
// TODO: Use std::lazy::LazyCell
static REGISTER_CLASS: Once = Once::new();
REGISTER_CLASS.call_once(|| {
let superclass = NSObject::class();
let mut builder = ClassBuilder::new(Self::NAME, superclass).unwrap();
builder.add_ivar::<&mut u8>("number");
unsafe {
builder.add_method(
sel!(initWithPtr:),
Self::init_with_ptr as unsafe extern "C" fn(_, _, _) -> _,
);
}
let _cls = builder.register();
});
AnyClass::get("MyObject").unwrap()
}
fn as_super(&self) -> &Self::Super {
&self.superclass
}
fn as_super_mut(&mut self) -> &mut Self::Super {
&mut self.superclass
}
}
fn main() {
let mut number = 54;
let mut obj = MyObject::new(&mut number);
assert_eq!(obj.get(), 54);
// It is not possible to convert to `Retained<NSObject>`, since that would
// loose the lifetime information that `MyObject` stores.
//
// let obj = Retained::into_super(obj);
//
// Neither is it possible to clone or retain the object, since it is
// marked as `Mutable` in `ClassType::Mutability`.
//
// let obj2 = obj.clone();
//
// Finally, it is not possible to access `number` any more, since `obj`
// holds a mutable reference to it.
//
// assert_eq!(number, 7);
// But we can now mutate the referenced `number`
obj.set(7);
assert_eq!(obj.get(), 7);
drop(obj);
// And now that we've dropped `obj`, we can access `number` again
assert_eq!(number, 7);
}

View File

@@ -0,0 +1,49 @@
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));
}

View File

@@ -0,0 +1,26 @@
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);
}

View File

@@ -0,0 +1,30 @@
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"));
}

View File

@@ -0,0 +1,28 @@
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);
}

52
vendor/objc2/examples/introspection.rs vendored Normal file
View File

@@ -0,0 +1,52 @@
use objc2::runtime::{AnyClass, NSObject};
use objc2::{sel, ClassType, Encode};
fn main() {
// Get the class representing `NSObject`
let cls = NSObject::class();
// Inspect various properties of the class
println!("NSObject superclass: {:?}", cls.superclass());
println!("NSObject size: {}", cls.instance_size());
println!(
"-[NSObject alloc] would work: {}",
cls.responds_to(sel!(alloc))
);
println!(
"+[NSObject alloc] would work: {}",
cls.metaclass().responds_to(sel!(alloc))
);
// Inspect an instance variable on the class
//
// Note: You should not rely on the `isa` ivar being available,
// this is only for demonstration.
let ivar = cls
.instance_variable("isa")
.expect("No ivar with name 'isa' found on NSObject");
println!(
"Instance variable {} has type encoding {:?}",
ivar.name(),
ivar.type_encoding()
);
assert!(<*const AnyClass>::ENCODING.equivalent_to_str(ivar.type_encoding()));
// Inspect a method of the class
let method = cls.instance_method(sel!(hash)).unwrap();
println!(
"-[NSObject hash] takes {} parameters",
method.arguments_count()
);
let hash_return = method.return_type();
println!("-[NSObject hash] return type: {hash_return:?}");
assert!(usize::ENCODING.equivalent_to_str(&hash_return));
// Create an instance
let obj = NSObject::new();
println!("NSObject address: {obj:p}");
// Read an ivar on the object
let isa: *const AnyClass = unsafe { *ivar.load(&obj) };
println!("NSObject isa: {isa:?}");
}