Skip to content

Commit

Permalink
Add autoreleasepool functionality.
Browse files Browse the repository at this point in the history
This replicates the behaviour of @autoreleasepool blocks in
Objective-C and allows higher performance creation of autorelease pools.
  • Loading branch information
jrmuizel committed Jul 22, 2018
1 parent 1171ef8 commit 2f906ee
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 0 deletions.
29 changes: 29 additions & 0 deletions src/rc/autorelease.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::os::raw::c_void;
use runtime::{objc_autoreleasePoolPush, objc_autoreleasePoolPop};

// we use a struct to ensure that objc_autoreleasePoolPop during unwinding.
struct AutoReleaseHelper {
context: *mut c_void,
}

impl AutoReleaseHelper {
unsafe fn new() -> Self {
AutoReleaseHelper { context: objc_autoreleasePoolPush() }
}
}

impl Drop for AutoReleaseHelper {
fn drop(&mut self) {
unsafe { objc_autoreleasePoolPop(self.context) }
}
}

/**
Execute `f` in the context of a new autorelease pool. The pool is drained
after the execution of `f` completes. This corresponds to @autoreleasepool blocks
in Objective-c and Swift.
*/
pub fn autoreleasepool<F: FnOnce()>(f: F) {
let _context = unsafe { AutoReleaseHelper::new() };
f();
}
23 changes: 23 additions & 0 deletions src/rc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@ For more information on Objective-C's reference counting, see Apple's documentat

mod strong;
mod weak;
mod autorelease;

pub use self::strong::StrongPtr;
pub use self::weak::WeakPtr;
pub use self::autorelease::autoreleasepool;

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

#[test]
fn test_strong_clone() {
Expand Down Expand Up @@ -66,4 +69,24 @@ mod tests {
let strong = weak2.load();
assert!(*strong == *obj);
}

#[test]
fn test_autorelease() {
let obj = unsafe {
StrongPtr::new(msg_send![class!(NSObject), new])
};

fn retain_count(obj: *mut Object) -> usize {
unsafe { msg_send![obj, retainCount] }
}
let cloned = obj.clone();

autoreleasepool(|| {
obj.autorelease();
assert!(retain_count(*cloned) == 2);
});

// make sure that the autoreleased value has been released
assert!(retain_count(*cloned) == 1);
}
}
3 changes: 3 additions & 0 deletions src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ extern {
pub fn objc_allocateProtocol(name: *const c_char) -> *mut Protocol;
pub fn objc_registerProtocol(proto: *mut Protocol);

pub fn objc_autoreleasePoolPush() -> *mut c_void;
pub fn objc_autoreleasePoolPop(context: *mut c_void);

pub fn protocol_addMethodDescription(proto: *mut Protocol, name: Sel, types: *const c_char, isRequiredMethod: BOOL,
isInstanceMethod: BOOL);
pub fn protocol_addProtocol(proto: *mut Protocol, addition: *const Protocol);
Expand Down

0 comments on commit 2f906ee

Please sign in to comment.