Skip to content

Commit 2f906ee

Browse files
committed
Add autoreleasepool functionality.
This replicates the behaviour of @autoreleasepool blocks in Objective-C and allows higher performance creation of autorelease pools.
1 parent 1171ef8 commit 2f906ee

File tree

3 files changed

+55
-0
lines changed

3 files changed

+55
-0
lines changed

src/rc/autorelease.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use std::os::raw::c_void;
2+
use runtime::{objc_autoreleasePoolPush, objc_autoreleasePoolPop};
3+
4+
// we use a struct to ensure that objc_autoreleasePoolPop during unwinding.
5+
struct AutoReleaseHelper {
6+
context: *mut c_void,
7+
}
8+
9+
impl AutoReleaseHelper {
10+
unsafe fn new() -> Self {
11+
AutoReleaseHelper { context: objc_autoreleasePoolPush() }
12+
}
13+
}
14+
15+
impl Drop for AutoReleaseHelper {
16+
fn drop(&mut self) {
17+
unsafe { objc_autoreleasePoolPop(self.context) }
18+
}
19+
}
20+
21+
/**
22+
Execute `f` in the context of a new autorelease pool. The pool is drained
23+
after the execution of `f` completes. This corresponds to @autoreleasepool blocks
24+
in Objective-c and Swift.
25+
*/
26+
pub fn autoreleasepool<F: FnOnce()>(f: F) {
27+
let _context = unsafe { AutoReleaseHelper::new() };
28+
f();
29+
}

src/rc/mod.rs

+23
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,18 @@ For more information on Objective-C's reference counting, see Apple's documentat
1111

1212
mod strong;
1313
mod weak;
14+
mod autorelease;
1415

1516
pub use self::strong::StrongPtr;
1617
pub use self::weak::WeakPtr;
18+
pub use self::autorelease::autoreleasepool;
1719

1820
// These tests use NSObject, which isn't present for GNUstep
1921
#[cfg(all(test, any(target_os = "macos", target_os = "ios")))]
2022
mod tests {
2123
use runtime::Object;
2224
use super::StrongPtr;
25+
use super::autoreleasepool;
2326

2427
#[test]
2528
fn test_strong_clone() {
@@ -66,4 +69,24 @@ mod tests {
6669
let strong = weak2.load();
6770
assert!(*strong == *obj);
6871
}
72+
73+
#[test]
74+
fn test_autorelease() {
75+
let obj = unsafe {
76+
StrongPtr::new(msg_send![class!(NSObject), new])
77+
};
78+
79+
fn retain_count(obj: *mut Object) -> usize {
80+
unsafe { msg_send![obj, retainCount] }
81+
}
82+
let cloned = obj.clone();
83+
84+
autoreleasepool(|| {
85+
obj.autorelease();
86+
assert!(retain_count(*cloned) == 2);
87+
});
88+
89+
// make sure that the autoreleased value has been released
90+
assert!(retain_count(*cloned) == 1);
91+
}
6992
}

src/runtime.rs

+3
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ extern {
109109
pub fn objc_allocateProtocol(name: *const c_char) -> *mut Protocol;
110110
pub fn objc_registerProtocol(proto: *mut Protocol);
111111

112+
pub fn objc_autoreleasePoolPush() -> *mut c_void;
113+
pub fn objc_autoreleasePoolPop(context: *mut c_void);
114+
112115
pub fn protocol_addMethodDescription(proto: *mut Protocol, name: Sel, types: *const c_char, isRequiredMethod: BOOL,
113116
isInstanceMethod: BOOL);
114117
pub fn protocol_addProtocol(proto: *mut Protocol, addition: *const Protocol);

0 commit comments

Comments
 (0)