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}