extern crate objc;
extern crate objc_foundation;
extern crate objc_id;
pub use ::NSCallback;
use std::sync::{Once, ONCE_INIT};
use objc::Message;
use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel};
use self::objc_foundation::{INSObject, NSObject};
use std::collections::BTreeMap;
use self::objc_id::Id;
use self::objc_id::WeakId;
use self::objc_id::Shared;
use std::sync::mpsc::Sender;
pub struct RustWrapperClass {
pub objc: Id<ObjcSubclass, Shared>,
pub cb_fn: Option<Box<dyn Fn(&mut RustWrapperClass, u64)>>,
pub map: BTreeMap<u64, NSCallback>,
pub tx: Sender<String>,
}
pub type NSObj = Box<RustWrapperClass>;
pub type NSObjc = Id<ObjcSubclass, Shared>;
pub trait NSObjCallbackTrait {
fn set_value(&mut self, u64, NSCallback);
fn get_value(&self, u64) -> &NSCallback;
}
impl NSObjCallbackTrait for RustWrapperClass {
fn set_value(&mut self, key: u64, val: NSCallback) {
self.map.insert(key, val);
}
fn get_value(&self, key: u64) -> &NSCallback {
self.map.get(&key).unwrap()
}
}
pub trait NSObjTrait {
fn alloc(tx: Sender<String>) -> NSObj;
fn selector(&self) -> Sel;
fn take_objc(&mut self) -> NSObjc;
fn add_callback(&mut self, *const Object, NSCallback);
}
impl NSObjTrait for NSObj {
fn add_callback(&mut self, item: *const Object, cb: NSCallback) {
let sender: u64 = item as u64;
self.set_value(sender, cb);
}
fn alloc(tx: Sender<String>) -> NSObj {
let objc = ObjcSubclass::new().share();
let rust = Box::new(RustWrapperClass {
objc: objc,
map: BTreeMap::<u64,NSCallback>::new(),
cb_fn: None,
tx: tx,
});
unsafe {
let ptr: u64 = &*rust as *const RustWrapperClass as u64;
let _:() = msg_send![rust.objc, setRustData: ptr];
}
return rust
}
fn selector(&self) -> Sel {
sel!(cb:)
}
fn take_objc(&mut self) -> NSObjc {
let weak = WeakId::new(&self.objc);
weak.load().unwrap()
}
}
impl NSObjCallbackTrait for NSObj {
fn set_value(&mut self, key: u64, val: NSCallback) {
self.map.insert(key, val);
}
fn get_value(&self, key: u64) -> &NSCallback {
self.map.get(&key).unwrap()
}
}
pub enum ObjcSubclass {}
impl ObjcSubclass {}
unsafe impl Message for ObjcSubclass { }
static OBJC_SUBCLASS_REGISTER_CLASS: Once = ONCE_INIT;
impl INSObject for ObjcSubclass {
fn class() -> &'static Class {
OBJC_SUBCLASS_REGISTER_CLASS.call_once(|| {
let superclass = NSObject::class();
let mut decl = ClassDecl::new("ConnectrObjcSubclass", superclass).expect("Failed to create custom ObjC class.");
decl.add_ivar::<u64>("_rustdata");
extern fn objc_cb(this: &mut Object, _cmd: Sel, sender: u64) {
unsafe {
let ptr: u64 = *this.get_ivar("_rustdata");
let rustdata: &mut RustWrapperClass = &mut *(ptr as *mut RustWrapperClass);
if let Some(ref cb) = rustdata.cb_fn {
let rustdata: &mut RustWrapperClass = &mut *(ptr as *mut RustWrapperClass);
cb(rustdata, sender);
}
}
}
extern fn objc_set_rust_data(this: &mut Object, _cmd: Sel, ptr: u64) {
unsafe {this.set_ivar("_rustdata", ptr);}
}
extern fn objc_get_rust_data(this: &Object, _cmd: Sel) -> u64 {
unsafe {*this.get_ivar("_rustdata")}
}
extern fn objc_url(_this: &Object, _cmd: Sel, _event: u64, _reply: u64) {
info!("connectr URL support not implemented yet.");
}
unsafe {
let f: extern fn(&mut Object, Sel, u64) = objc_cb;
decl.add_method(sel!(cb:), f);
let f: extern fn(&mut Object, Sel, u64) = objc_set_rust_data;
decl.add_method(sel!(setRustData:), f);
let f: extern fn(&Object, Sel) -> u64 = objc_get_rust_data;
decl.add_method(sel!(rustData), f);
let f: extern fn(&Object, Sel, u64, u64) = objc_url;
decl.add_method(sel!(handleURLEvent:withReplyEvent:), f);
}
decl.register();
});
Class::get("ConnectrObjcSubclass").unwrap()
}
}