|  | 
|  | 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