[][src]Macro zerogc::unsafe_trace_lock

macro_rules! unsafe_trace_lock {
    ($target:ident, target = $target_type:ident; |$get_mut:ident| $get_mut_expr:expr, |$lock:ident| $acquire_guard:expr) => { ... };
}

Unsafely implement GarbageCollected for the specified type, by acquiring a 'lock' in order to trace the underlying value.

This is good for interior mutability types like RefCell and Mutex where you need to acquire a lock, in order to safely view the interior. Usually unsafe_trace_deref! is sufficient since it also lets you run arbitrary code in order to 'convert' the macro to the necessary type, and the only restriction is that the interior can be directly traced.

However, that isn't sufficient if you need to hold RAII guards (like Ref or MutexGuards) on the values you're tracing in addition to just accessing them. For example, for RefCell you'd call borrow in order to acquire a Ref to the interior. Although tracing garbage collection is already unsafe, it's always completely undefined behavior to bypass the locking of Mutex and RefCell, even if it's just for a 'little bit' since it may cause mutable references to alias. It is currently the most powerful of the unsafe implementation macros, since it lets you not only run an arbitrary expression like unsafe_trace_deref!, but also acquire and hold a RAII guard object.

This macro is usually only useful for types like Mutex and RefCell who use raw pointers internally, since raw pointers can't be automatically traced without additional type information. Otherwise, it's best to use an automatically derived implementation since that's always safe. However, using this macro is always better than a manual implementation, since it makes your intent clearer.

Usage

// You can use an arbitrary expression to acquire a lock's guard
unsafe_trace_lock!(RefCell, target = T, |cell| cell.borrow());
unsafe_trace_lock!(Mutex, target = T, |lock| lock.lock().unwrap());
unsafe_trace_lock!(RwLock, target = T, |lock| lock.lock().unwrap());

Safety

Always prefer automatically derived implementations where possible, since they're just as fast and can never cause undefined behavior. This is basically an unsafe automatically derived implementation, to be used only when a safe automatically derived implementation isn't possible (like with Vec).

Undefined behavior if there could be additional garbage collected objects that are not reachable by dereferencing the specified lock, since the macro only traces the item the lock dereferences to. This usually isn't the case with most locks and would be somewhat rare, but it's still a possibility that causes the macro to be unsafe.

This delegates to unsafe_gc_brand to provide the GcBrand implementation, so that could also trigger undefined behavior.