#![deny(unsafe_op_in_unsafe_fn)]
use std::marker::PhantomData;
use std::sync::Once;
use objc2::declare::ClassBuilder;
use objc2::rc::{Id, Owned, Shared};
use objc2::runtime::{Class, Object, Sel};
use objc2::{msg_send, msg_send_id, sel};
use objc2::{Encoding, Message, RefEncode};
use objc2_foundation::NSObject;
#[repr(C)]
pub struct MyObject<'a> {
inner: Object,
p: PhantomData<Option<&'a mut u8>>,
}
unsafe impl RefEncode for MyObject<'_> {
const ENCODING_REF: Encoding<'static> = Object::ENCODING_REF;
}
unsafe impl Message for MyObject<'_> {}
static MYOBJECT_REGISTER_CLASS: Once = Once::new();
impl<'a> MyObject<'a> {
fn new(number_ptr: &'a mut u8) -> Id<Self, Owned> {
unsafe {
let obj = msg_send_id![Self::class(), alloc];
msg_send_id![obj, initWithPtr: number_ptr].unwrap()
}
}
fn get(&self) -> Option<&'a u8> {
unsafe { *self.inner.ivar::<Option<&'a u8>>("_number_ptr") }
}
fn write(&mut self, number: u8) {
let ptr = unsafe { self.inner.ivar_mut::<Option<&'a mut u8>>("_number_ptr") };
if let Some(ptr) = ptr {
**ptr = number;
}
}
fn class() -> &'static Class {
MYOBJECT_REGISTER_CLASS.call_once(|| {
let superclass = NSObject::class();
let mut builder = ClassBuilder::new("MyObject", superclass).unwrap();
builder.add_ivar::<Option<&mut u8>>("_number_ptr");
unsafe extern "C" fn init_with_ptr(
this: *mut Object,
_cmd: Sel,
ptr: *mut u8,
) -> *mut Object {
let this: *mut Object = unsafe { msg_send![super(this, NSObject::class()), init] };
if let Some(this) = unsafe { this.as_mut() } {
unsafe { this.set_ivar::<*mut u8>("_number_ptr", ptr) };
}
this
}
unsafe {
let init_with_ptr: unsafe extern "C" fn(_, _, _) -> _ = init_with_ptr;
builder.add_method(sel!(initWithPtr:), init_with_ptr);
}
builder.register();
});
Class::get("MyObject").unwrap()
}
}
fn main() {
let mut number = 54;
let mut obj = MyObject::new(&mut number);
println!("Number: {}", obj.get().unwrap());
obj.write(7);
println!("Number: {}", obj.get().unwrap());
let obj: Id<_, Shared> = obj.into();
let obj2 = obj.clone();
println!("Number: {}", obj.get().unwrap());
println!("Number: {}", obj2.get().unwrap());
drop(obj);
drop(obj2);
println!("Number: {}", number);
}