| 
 | 1 | +use crate::runtime::{objc_autoreleasePoolPop, objc_autoreleasePoolPush};  | 
1 | 2 | use std::os::raw::c_void;  | 
2 |  | -use crate::runtime::{objc_autoreleasePoolPush, objc_autoreleasePoolPop};  | 
3 | 3 | 
 
  | 
4 |  | -// we use a struct to ensure that objc_autoreleasePoolPop during unwinding.  | 
5 |  | -struct AutoReleaseHelper {  | 
 | 4 | +/// An Objective-C autorelease pool.  | 
 | 5 | +///  | 
 | 6 | +/// The pool is drained when dropped.  | 
 | 7 | +///  | 
 | 8 | +/// This is not `Send`, since `objc_autoreleasePoolPop` must be called on the  | 
 | 9 | +/// same thread.  | 
 | 10 | +///  | 
 | 11 | +/// And this is not `Sync`, since you can only autorelease a reference to a  | 
 | 12 | +/// pool on the current thread.  | 
 | 13 | +///  | 
 | 14 | +/// See [the clang documentation][clang-arc] and  | 
 | 15 | +/// [this apple article][memory-mgmt] for more information on automatic  | 
 | 16 | +/// reference counting.  | 
 | 17 | +///  | 
 | 18 | +/// [clang-arc]: https://clang.llvm.org/docs/AutomaticReferenceCounting.html  | 
 | 19 | +/// [memory-mgmt]: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html  | 
 | 20 | +pub struct AutoreleasePool {  | 
6 | 21 |     context: *mut c_void,  | 
7 | 22 | }  | 
8 | 23 | 
 
  | 
9 |  | -impl AutoReleaseHelper {  | 
 | 24 | +impl AutoreleasePool {  | 
 | 25 | +    /// Construct a new autoreleasepool.  | 
 | 26 | +    ///  | 
 | 27 | +    /// Use the [`autoreleasepool`] block for a safe alternative.  | 
 | 28 | +    ///  | 
 | 29 | +    /// # Safety  | 
 | 30 | +    ///  | 
 | 31 | +    /// The caller must ensure that when handing out `&'p AutoreleasePool` to  | 
 | 32 | +    /// functions that this is the innermost pool.  | 
 | 33 | +    ///  | 
 | 34 | +    /// Additionally, the pools must be dropped in the same order they were  | 
 | 35 | +    /// created.  | 
 | 36 | +    #[doc(alias = "objc_autoreleasePoolPush")]  | 
10 | 37 |     unsafe fn new() -> Self {  | 
11 |  | -        AutoReleaseHelper { context: objc_autoreleasePoolPush() }  | 
 | 38 | +        AutoreleasePool {  | 
 | 39 | +            context: objc_autoreleasePoolPush(),  | 
 | 40 | +        }  | 
12 | 41 |     }  | 
 | 42 | + | 
 | 43 | +    // TODO: Add helper functions to ensure (with debug_assertions) that the  | 
 | 44 | +    // pool is innermost when its lifetime is tied to a reference.  | 
13 | 45 | }  | 
14 | 46 | 
 
  | 
15 |  | -impl Drop for AutoReleaseHelper {  | 
 | 47 | +impl Drop for AutoreleasePool {  | 
 | 48 | +    /// Drains the autoreleasepool.  | 
 | 49 | +    #[doc(alias = "objc_autoreleasePoolPop")]  | 
16 | 50 |     fn drop(&mut self) {  | 
17 | 51 |         unsafe { objc_autoreleasePoolPop(self.context) }  | 
18 | 52 |     }  | 
19 | 53 | }  | 
20 | 54 | 
 
  | 
21 |  | -/**  | 
22 |  | -Execute `f` in the context of a new autorelease pool. The pool is drained  | 
23 |  | -after the execution of `f` completes.  | 
 | 55 | +// TODO:  | 
 | 56 | +// #![feature(negative_impls)]  | 
 | 57 | +// #![feature(auto_traits)]  | 
 | 58 | +// /// A trait for the sole purpose of ensuring we can't pass an `&AutoreleasePool`  | 
 | 59 | +// /// through to the closure inside `autoreleasepool`  | 
 | 60 | +// pub unsafe auto trait AutoreleaseSafe {}  | 
 | 61 | +// // TODO: Unsure how negative impls work exactly  | 
 | 62 | +// unsafe impl !AutoreleaseSafe for AutoreleasePool {}  | 
 | 63 | +// unsafe impl !AutoreleaseSafe for &AutoreleasePool {}  | 
 | 64 | +// unsafe impl !AutoreleaseSafe for &mut AutoreleasePool {}  | 
24 | 65 | 
 
  | 
25 |  | -This corresponds to `@autoreleasepool` blocks in Objective-C and Swift.  | 
26 |  | -*/  | 
27 |  | -pub fn autoreleasepool<T, F: FnOnce() -> T>(f: F) -> T {  | 
28 |  | -    let _context = unsafe { AutoReleaseHelper::new() };  | 
29 |  | -    f()  | 
 | 66 | +/// Execute `f` in the context of a new autorelease pool. The pool is drained  | 
 | 67 | +/// after the execution of `f` completes.  | 
 | 68 | +///  | 
 | 69 | +/// This corresponds to `@autoreleasepool` blocks in Objective-C and Swift.  | 
 | 70 | +///  | 
 | 71 | +/// The pool is passed as a reference to the enclosing function to give it a  | 
 | 72 | +/// lifetime parameter that autoreleased objects can refer to.  | 
 | 73 | +///  | 
 | 74 | +/// # Examples  | 
 | 75 | +///  | 
 | 76 | +/// ```rust  | 
 | 77 | +/// use objc::{class, msg_send};  | 
 | 78 | +/// use objc::rc::{autoreleasepool, AutoreleasePool, Owned};  | 
 | 79 | +/// use objc::runtime::Object;  | 
 | 80 | +///  | 
 | 81 | +/// fn needs_lifetime_from_pool<'p>(pool: &'p AutoreleasePool) -> &'p mut Object {  | 
 | 82 | +///     let obj: Owned<Object> = unsafe { Owned::new(msg_send![class!(NSObject), new]) };  | 
 | 83 | +///     obj.autorelease(pool)  | 
 | 84 | +/// }  | 
 | 85 | +///  | 
 | 86 | +/// autoreleasepool(|pool| {  | 
 | 87 | +///     let obj = needs_lifetime_from_pool(pool);  | 
 | 88 | +///     // Use `obj`  | 
 | 89 | +/// });  | 
 | 90 | +///  | 
 | 91 | +/// // `obj` is deallocated when the pool ends  | 
 | 92 | +/// ```  | 
 | 93 | +///  | 
 | 94 | +/// ```rust,compile_fail  | 
 | 95 | +/// # use objc::{class, msg_send};  | 
 | 96 | +/// # use objc::rc::{autoreleasepool, AutoreleasePool, Owned};  | 
 | 97 | +/// # use objc::runtime::Object;  | 
 | 98 | +/// #  | 
 | 99 | +/// # fn needs_lifetime_from_pool<'p>(pool: &'p AutoreleasePool) -> &'p mut Object {  | 
 | 100 | +/// #     let obj: Owned<Object> = unsafe { Owned::new(msg_send![class!(NSObject), new]) };  | 
 | 101 | +/// #     obj.autorelease(pool)  | 
 | 102 | +/// # }  | 
 | 103 | +/// #  | 
 | 104 | +/// // Fails to compile because `obj` does not live long enough for us to  | 
 | 105 | +/// // safely take it out of the pool.  | 
 | 106 | +///  | 
 | 107 | +/// let obj = autoreleasepool(|pool| {  | 
 | 108 | +///     let obj = needs_lifetime_from_pool(pool);  | 
 | 109 | +///     // Use `obj`  | 
 | 110 | +///     obj  | 
 | 111 | +/// });  | 
 | 112 | +/// ```  | 
 | 113 | +///  | 
 | 114 | +/// TODO: More examples.  | 
 | 115 | +pub fn autoreleasepool<T, F>(f: F) -> T  | 
 | 116 | +where  | 
 | 117 | +    for<'p> F: FnOnce(&'p AutoreleasePool) -> T, // + AutoreleaseSafe,  | 
 | 118 | +{  | 
 | 119 | +    let pool = unsafe { AutoreleasePool::new() };  | 
 | 120 | +    f(&pool)  | 
30 | 121 | }  | 
0 commit comments