#![deny(unsafe_op_in_unsafe_fn)]
use std::cell::Cell;
use std::marker::PhantomData;
use std::sync::Once;
use objc2::rc::Retained;
use objc2::runtime::{AnyClass, AnyObject, ClassBuilder, NSObject};
use objc2::{msg_send, ClassType, Encoding, Message, RefEncode};
type Ivar<'a> = &'a Cell<u8>;
#[repr(C)]
struct MyObject<'a> {
inner: AnyObject,
p: PhantomData<Ivar<'a>>,
}
unsafe impl RefEncode for MyObject<'_> {
const ENCODING_REF: Encoding = NSObject::ENCODING_REF;
}
unsafe impl Message for MyObject<'_> {}
impl<'a> MyObject<'a> {
fn class() -> &'static AnyClass {
static REGISTER_CLASS: Once = Once::new();
REGISTER_CLASS.call_once(|| {
let superclass = NSObject::class();
let mut builder = ClassBuilder::new(c"MyObject", superclass).unwrap();
builder.add_ivar::<Ivar<'_>>(c"number");
let _cls = builder.register();
});
AnyClass::get(c"MyObject").unwrap()
}
fn new(number: &'a mut u8) -> Retained<Self> {
let this: Retained<Self> = unsafe { msg_send![Self::class(), new] };
let number = Cell::from_mut(number);
let ivar = Self::class().instance_variable(c"number").unwrap();
unsafe { ivar.load_ptr::<Ivar<'_>>(&this.inner).write(number) };
this
}
fn get(&self) -> u8 {
let ivar = Self::class().instance_variable(c"number").unwrap();
unsafe { ivar.load::<Ivar<'_>>(&self.inner).get() }
}
fn set(&self, number: u8) {
let ivar = Self::class().instance_variable(c"number").unwrap();
unsafe { ivar.load::<Ivar<'_>>(&self.inner).set(number) };
}
}
fn main() {
let mut number = 54;
let obj = MyObject::new(&mut number);
assert_eq!(obj.get(), 54);
obj.set(7);
assert_eq!(obj.get(), 7);
let clone = obj.clone();
clone.set(42);
assert_eq!(obj.get(), 42);
drop(clone);
drop(obj);
assert_eq!(number, 42);
}