objc_foundation/
object.rs

1use std::any::Any;
2
3use objc::Message;
4use objc::runtime::{BOOL, Class, NO};
5use objc_id::{Id, ShareId};
6
7use NSString;
8
9/*
10 The Sized bound is unfortunate; ideally, objc objects would not be
11 treated as Sized. However, rust won't allow casting a dynamically-sized type
12 pointer to an Object pointer, because dynamically-sized types can have fat
13 pointers (two words) instead of real pointers.
14 */
15pub trait INSObject : Any + Sized + Message {
16    fn class() -> &'static Class;
17
18    fn hash_code(&self) -> usize {
19        unsafe {
20            msg_send![self, hash]
21        }
22    }
23
24    fn is_equal<T>(&self, other: &T) -> bool where T: INSObject {
25        let result: BOOL = unsafe {
26            msg_send![self, isEqual:other]
27        };
28        result != NO
29    }
30
31    fn description(&self) -> ShareId<NSString> {
32        unsafe {
33            let result: *mut NSString = msg_send![self, description];
34            Id::from_ptr(result)
35        }
36    }
37
38    fn is_kind_of(&self, cls: &Class) -> bool {
39        let result: BOOL = unsafe {
40            msg_send![self, isKindOfClass:cls]
41        };
42        result != NO
43    }
44
45    fn new() -> Id<Self> {
46        let cls = Self::class();
47        unsafe {
48            let obj: *mut Self = msg_send![cls, alloc];
49            let obj: *mut Self = msg_send![obj, init];
50            Id::from_retained_ptr(obj)
51        }
52    }
53}
54
55object_struct!(NSObject);
56
57#[cfg(test)]
58mod tests {
59    use {INSString, NSString};
60    use super::{INSObject, NSObject};
61
62    #[test]
63    fn test_is_equal() {
64        let obj1 = NSObject::new();
65        assert!(obj1.is_equal(&*obj1));
66
67        let obj2 = NSObject::new();
68        assert!(!obj1.is_equal(&*obj2));
69    }
70
71    #[test]
72    fn test_hash_code() {
73        let obj = NSObject::new();
74        assert!(obj.hash_code() == obj.hash_code());
75    }
76
77    #[test]
78    fn test_description() {
79        let obj = NSObject::new();
80        let description = obj.description();
81        let expected = format!("<NSObject: {:p}>", &*obj);
82        assert!(description.as_str() == &*expected);
83    }
84
85    #[test]
86    fn test_is_kind_of() {
87        let obj = NSObject::new();
88        assert!(obj.is_kind_of(NSObject::class()));
89        assert!(!obj.is_kind_of(NSString::class()));
90    }
91}