summaryrefslogtreecommitdiffstats
path: root/third_party/rust/objc/src/test_utils.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/objc/src/test_utils.rs')
-rw-r--r--third_party/rust/objc/src/test_utils.rs187
1 files changed, 187 insertions, 0 deletions
diff --git a/third_party/rust/objc/src/test_utils.rs b/third_party/rust/objc/src/test_utils.rs
new file mode 100644
index 0000000000..873f82f6b1
--- /dev/null
+++ b/third_party/rust/objc/src/test_utils.rs
@@ -0,0 +1,187 @@
+use std::ops::{Deref, DerefMut};
+use std::os::raw::c_char;
+use std::sync::{Once, ONCE_INIT};
+
+use declare::{ClassDecl, ProtocolDecl};
+use runtime::{Class, Object, Protocol, Sel, self};
+use {Encode, Encoding};
+
+pub struct CustomObject {
+ obj: *mut Object,
+}
+
+impl CustomObject {
+ fn new(class: &Class) -> Self {
+ let obj = unsafe {
+ runtime::class_createInstance(class, 0)
+ };
+ CustomObject { obj: obj }
+ }
+}
+
+impl Deref for CustomObject {
+ type Target = Object;
+
+ fn deref(&self) -> &Object {
+ unsafe { &*self.obj }
+ }
+}
+
+impl DerefMut for CustomObject {
+ fn deref_mut(&mut self) -> &mut Object {
+ unsafe { &mut *self.obj }
+ }
+}
+
+impl Drop for CustomObject {
+ fn drop(&mut self) {
+ unsafe {
+ runtime::object_dispose(self.obj);
+ }
+ }
+}
+
+#[derive(Eq, PartialEq)]
+pub struct CustomStruct {
+ pub a: u64,
+ pub b: u64,
+ pub c: u64,
+ pub d: u64,
+}
+
+unsafe impl Encode for CustomStruct {
+ fn encode() -> Encoding {
+ let mut code = "{CustomStruct=".to_owned();
+ for _ in 0..4 {
+ code.push_str(u64::encode().as_str());
+ }
+ code.push_str("}");
+ unsafe {
+ Encoding::from_str(&code)
+ }
+ }
+}
+
+pub fn custom_class() -> &'static Class {
+ static REGISTER_CUSTOM_CLASS: Once = ONCE_INIT;
+
+ REGISTER_CUSTOM_CLASS.call_once(|| {
+ // The runtime will call this method, so it has to be implemented
+ extern fn custom_obj_class_initialize(_this: &Class, _cmd: Sel) { }
+
+ let mut decl = ClassDecl::root("CustomObject", custom_obj_class_initialize).unwrap();
+ let proto = custom_protocol();
+
+ decl.add_protocol(proto);
+ decl.add_ivar::<u32>("_foo");
+
+ extern fn custom_obj_set_foo(this: &mut Object, _cmd: Sel, foo: u32) {
+ unsafe { this.set_ivar::<u32>("_foo", foo); }
+ }
+
+ extern fn custom_obj_get_foo(this: &Object, _cmd: Sel) -> u32 {
+ unsafe { *this.get_ivar::<u32>("_foo") }
+ }
+
+ extern fn custom_obj_get_struct(_this: &Object, _cmd: Sel) -> CustomStruct {
+ CustomStruct { a: 1, b: 2, c: 3, d: 4 }
+ }
+
+ extern fn custom_obj_class_method(_this: &Class, _cmd: Sel) -> u32 {
+ 7
+ }
+
+ extern fn custom_obj_set_bar(this: &mut Object, _cmd: Sel, bar: u32) {
+ unsafe { this.set_ivar::<u32>("_foo", bar) ;}
+ }
+
+ extern fn custom_obj_add_number_to_number(_this: &Class, _cmd: Sel, fst: i32, snd: i32) -> i32 {
+ fst + snd
+ }
+
+ unsafe {
+ let set_foo: extern fn(&mut Object, Sel, u32) = custom_obj_set_foo;
+ decl.add_method(sel!(setFoo:), set_foo);
+ let get_foo: extern fn(&Object, Sel) -> u32 = custom_obj_get_foo;
+ decl.add_method(sel!(foo), get_foo);
+ let get_struct: extern fn(&Object, Sel) -> CustomStruct = custom_obj_get_struct;
+ decl.add_method(sel!(customStruct), get_struct);
+ let class_method: extern fn(&Class, Sel) -> u32 = custom_obj_class_method;
+ decl.add_class_method(sel!(classFoo), class_method);
+
+ let protocol_instance_method: extern fn(&mut Object, Sel, u32) = custom_obj_set_bar;
+ decl.add_method(sel!(setBar:), protocol_instance_method);
+ let protocol_class_method: extern fn(&Class, Sel, i32, i32) -> i32 = custom_obj_add_number_to_number;
+ decl.add_class_method(sel!(addNumber:toNumber:), protocol_class_method);
+ }
+
+ decl.register();
+ });
+
+ class!(CustomObject)
+}
+
+pub fn custom_protocol() -> &'static Protocol {
+ static REGISTER_CUSTOM_PROTOCOL: Once = ONCE_INIT;
+
+ REGISTER_CUSTOM_PROTOCOL.call_once(|| {
+ let mut decl = ProtocolDecl::new("CustomProtocol").unwrap();
+
+ decl.add_method_description::<(i32,), ()>(sel!(setBar:), true);
+ decl.add_method_description::<(), *const c_char>(sel!(getName), false);
+ decl.add_class_method_description::<(i32, i32), i32>(sel!(addNumber:toNumber:), true);
+
+ decl.register();
+ });
+
+ Protocol::get("CustomProtocol").unwrap()
+}
+
+pub fn custom_subprotocol() -> &'static Protocol {
+ static REGISTER_CUSTOM_SUBPROTOCOL: Once = ONCE_INIT;
+
+ REGISTER_CUSTOM_SUBPROTOCOL.call_once(|| {
+ let super_proto = custom_protocol();
+ let mut decl = ProtocolDecl::new("CustomSubProtocol").unwrap();
+
+ decl.add_protocol(super_proto);
+ decl.add_method_description::<(u32,), u32>(sel!(calculateFoo:), true);
+
+ decl.register();
+ });
+
+ Protocol::get("CustomSubProtocol").unwrap()
+}
+
+pub fn custom_object() -> CustomObject {
+ CustomObject::new(custom_class())
+}
+
+pub fn custom_subclass() -> &'static Class {
+ static REGISTER_CUSTOM_SUBCLASS: Once = ONCE_INIT;
+
+ REGISTER_CUSTOM_SUBCLASS.call_once(|| {
+ let superclass = custom_class();
+ let mut decl = ClassDecl::new("CustomSubclassObject", superclass).unwrap();
+
+ extern fn custom_subclass_get_foo(this: &Object, _cmd: Sel) -> u32 {
+ let foo: u32 = unsafe {
+ msg_send![super(this, custom_class()), foo]
+ };
+ foo + 2
+ }
+
+ unsafe {
+ let get_foo: extern fn(&Object, Sel) -> u32 = custom_subclass_get_foo;
+ decl.add_method(sel!(foo), get_foo);
+ }
+
+ decl.register();
+ });
+
+ class!(CustomSubclassObject)
+}
+
+pub fn custom_subclass_object() -> CustomObject {
+ CustomObject::new(custom_subclass())
+}