makepad_objc_sys/rc/
mod.rs

1/*!
2Utilities for reference counting Objective-C objects.
3
4The utilities of the `rc` module provide ARC-like semantics for working with
5Objective-C's reference counted objects in Rust.
6A `StrongPtr` retains an object and releases the object when dropped.
7A `WeakPtr` will not retain the object, but can be upgraded to a `StrongPtr`
8and safely fails if the object has been deallocated.
9
10These utilities are not intended to provide a fully safe interface, but can be
11useful when writing higher-level Rust wrappers for Objective-C code.
12
13For more information on Objective-C's reference counting, see Apple's documentation:
14<https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html>
15
16# Example
17
18``` no_run
19# #[macro_use] extern crate makepad_objc_sys;
20# use makepad_objc_sys::rc::{autoreleasepool, StrongPtr};
21# fn main() {
22// StrongPtr will release the object when dropped
23let obj = unsafe {
24    StrongPtr::new(msg_send![class!(NSObject), new])
25};
26
27// Cloning retains the object an additional time
28let cloned = obj.clone();
29autoreleasepool(|| {
30    // Autorelease consumes the StrongPtr, but won't
31    // actually release until the end of an autoreleasepool
32    cloned.autorelease();
33});
34
35// Weak references won't retain the object
36let weak = obj.weak();
37drop(obj);
38assert!(weak.load().is_null());
39# }
40```
41*/
42
43mod strong;
44mod weak;
45mod autorelease;
46
47pub use self::strong::StrongPtr;
48pub use self::weak::WeakPtr;
49pub use self::autorelease::autoreleasepool;
50
51// These tests use NSObject, which isn't present for GNUstep
52#[cfg(all(test, any(target_os = "macos", target_os = "ios")))]
53mod tests {
54    use runtime::Object;
55    use super::StrongPtr;
56    use super::autoreleasepool;
57
58    #[test]
59    fn test_strong_clone() {
60        fn retain_count(obj: *mut Object) -> usize {
61            unsafe { msg_send![obj, retainCount] }
62        }
63
64        let obj = unsafe {
65            StrongPtr::new(msg_send![class!(NSObject), new])
66        };
67        assert!(retain_count(*obj) == 1);
68
69        let cloned = obj.clone();
70        assert!(retain_count(*cloned) == 2);
71        assert!(retain_count(*obj) == 2);
72
73        drop(obj);
74        assert!(retain_count(*cloned) == 1);
75    }
76
77    #[test]
78    fn test_weak() {
79        let obj = unsafe {
80            StrongPtr::new(msg_send![class!(NSObject), new])
81        };
82        let weak = obj.weak();
83
84        let strong = weak.load();
85        assert!(*strong == *obj);
86        drop(strong);
87
88        drop(obj);
89        assert!(weak.load().is_null());
90    }
91
92    #[test]
93    fn test_weak_copy() {
94        let obj = unsafe {
95            StrongPtr::new(msg_send![class!(NSObject), new])
96        };
97        let weak = obj.weak();
98
99        let weak2 = weak.clone();
100        let strong = weak2.load();
101        assert!(*strong == *obj);
102    }
103
104    #[test]
105    fn test_autorelease() {
106        let obj = unsafe {
107            StrongPtr::new(msg_send![class!(NSObject), new])
108        };
109
110        fn retain_count(obj: *mut Object) -> usize {
111            unsafe { msg_send![obj, retainCount] }
112        }
113        let cloned = obj.clone();
114
115        autoreleasepool(|| {
116                        obj.autorelease();
117                        assert!(retain_count(*cloned) == 2);
118        });
119
120        // make sure that the autoreleased value has been released
121        assert!(retain_count(*cloned) == 1);
122    }
123}