#![deny(unsafe_op_in_unsafe_fn)]
use std::marker::PhantomData;
use std::sync::Once;
use objc2::declare::{ClassBuilder, Ivar, IvarType};
use objc2::foundation::NSObject;
use objc2::rc::{Id, Owned};
use objc2::runtime::{Class, Object, Sel};
use objc2::{msg_send, msg_send_id, sel};
use objc2::{ClassType, Encoding, Message, RefEncode};
struct NumberIvar<'a> {
p: PhantomData<&'a mut u8>,
}
unsafe impl<'a> IvarType for NumberIvar<'a> {
type Type = &'a mut u8;
const NAME: &'static str = "_number_ptr";
}
#[repr(C)]
pub struct MyObject<'a> {
superclass: NSObject,
number: Ivar<NumberIvar<'a>>,
}
unsafe impl RefEncode for MyObject<'_> {
const ENCODING_REF: Encoding = Object::ENCODING_REF;
}
unsafe impl Message for MyObject<'_> {}
impl<'a> MyObject<'a> {
unsafe extern "C" fn init_with_ptr(
&mut self,
_cmd: Sel,
ptr: Option<&'a mut u8>,
) -> Option<&'a mut Self> {
let this: Option<&mut Self> = unsafe { msg_send![super(self), init] };
this.map(|this| {
Ivar::write(&mut this.number, ptr.expect("got NULL number ptr"));
this
})
}
pub fn new(number: &'a mut u8) -> Id<Self, Owned> {
unsafe {
let obj = msg_send_id![Self::class(), alloc];
msg_send_id![obj, initWithPtr: number]
}
}
pub fn get(&self) -> &u8 {
&self.number
}
pub fn set(&mut self, number: u8) {
**self.number = number;
}
}
unsafe impl<'a> ClassType for MyObject<'a> {
type Super = NSObject;
const NAME: &'static str = "MyObject";
fn class() -> &'static Class {
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_static_ivar::<NumberIvar<'a>>();
unsafe {
builder.add_method(
sel!(initWithPtr:),
Self::init_with_ptr as unsafe extern "C" fn(_, _, _) -> _,
);
}
let _cls = builder.register();
});
Class::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);
println!("Number: {}", obj.get());
obj.set(7);
println!("Number: {}", obj.get());
let obj = Id::into_shared(obj);
let obj2 = obj.clone();
println!("Number: {}", obj.get());
println!("Number: {}", obj2.get());
drop(obj);
drop(obj2);
println!("Number: {}", number);
}