Files
another-boids-in-rust/vendor/objc2/tests/id_retain_autoreleased.rs

50 lines
1.6 KiB
Rust

use core::mem::ManuallyDrop;
use objc2::msg_send;
use objc2::rc::{autoreleasepool, Retained};
use objc2::runtime::{NSObject, NSObjectProtocol};
fn create_obj() -> Retained<NSObject> {
let obj = ManuallyDrop::new(NSObject::new());
unsafe {
let obj: *mut NSObject = msg_send![&*obj, autorelease];
// All code between the `msg_send!` and the `retain_autoreleased` must
// be able to be optimized away for this to work.
Retained::retain_autoreleased(obj).unwrap()
}
}
#[test]
fn test_retain_autoreleased() {
autoreleasepool(|_| {
// Run once to allow DYLD to resolve the symbol stubs.
// Required for making `retain_autoreleased` work on x86_64.
let _data = create_obj();
// When compiled in release mode / with optimizations enabled,
// subsequent usage of `retain_autoreleased` will succeed in retaining
// the autoreleased value!
#[allow(clippy::if_same_then_else)]
let expected = if cfg!(feature = "gnustep-1-7") {
1
} else if cfg!(all(target_arch = "arm", panic = "unwind")) {
// 32-bit ARM unwinding interferes with the optimization
2
} else if cfg!(any(debug_assertions, feature = "catch-all")) {
2
} else {
1
};
let data = create_obj();
assert_eq!(data.retainCount(), expected);
let data = create_obj();
assert_eq!(data.retainCount(), expected);
// Here we manually clean up the autorelease, so it will always be 1.
let data = autoreleasepool(|_| create_obj());
assert_eq!(data.retainCount(), 1);
});
}