Skip to main content

fuchsia_rcu/
rcu_droppable.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// Marker trait for types that are safe to be dropped on the RCU worker / drop execution path.
6///
7/// # Safety
8/// Types implementing this trait MUST NOT have Drop side-effects that block or are time or thread
9/// sensitive.
10pub unsafe trait RcuDroppable: Send + 'static {}
11
12macro_rules! impl_rcu_droppable {
13    ($($t:ty),* $(,)?) => {
14        $(
15            // SAFETY: Primitive numeric types, atomics, strings, and standard types without
16            // custom Drop logic do not block or produce drop side effects.
17            unsafe impl RcuDroppable for $t {}
18        )*
19    };
20}
21
22impl_rcu_droppable!(
23    (),
24    bool,
25    char,
26    u8,
27    u16,
28    u32,
29    u64,
30    u128,
31    usize,
32    i8,
33    i16,
34    i32,
35    i64,
36    i128,
37    isize,
38    f32,
39    f64,
40    String,
41    str,
42    bstr::BString,
43    bstr::BStr,
44    fuchsia_runtime::UtcTimeline,
45    fuchsia_trace::Id,
46    shared_buffer::SharedBuffer,
47    std::collections::hash_map::RandomState,
48    std::num::NonZeroU8,
49    std::num::NonZeroU16,
50    std::num::NonZeroU32,
51    std::num::NonZeroU64,
52    std::num::NonZeroU128,
53    std::num::NonZeroUsize,
54    std::num::NonZeroI8,
55    std::num::NonZeroI16,
56    std::num::NonZeroI32,
57    std::num::NonZeroI64,
58    std::num::NonZeroI128,
59    std::num::NonZeroIsize,
60    std::sync::atomic::AtomicBool,
61    std::sync::atomic::AtomicI8,
62    std::sync::atomic::AtomicI16,
63    std::sync::atomic::AtomicI32,
64    std::sync::atomic::AtomicI64,
65    std::sync::atomic::AtomicIsize,
66    std::sync::atomic::AtomicU8,
67    std::sync::atomic::AtomicU16,
68    std::sync::atomic::AtomicU32,
69    std::sync::atomic::AtomicU64,
70    std::sync::atomic::AtomicUsize,
71    std::ops::RangeFull,
72    std::time::Duration,
73    std::time::Instant,
74    zx::BootTimeline,
75    zx::Koid,
76    zx::MonotonicTimeline,
77    zx::Rights,
78    zx::Vmo,
79);
80
81// SAFETY: Static references have no drop implementation and thus no drop side effects.
82unsafe impl<T: ?Sized + Sync + 'static> RcuDroppable for &'static T {}
83// SAFETY: BuildHasherDefault is a zero-sized type with no drop side effects.
84unsafe impl<H: 'static> RcuDroppable for std::hash::BuildHasherDefault<H> {}
85// SAFETY: PhantomData has no drop side effects.
86unsafe impl<T: ?Sized + Send + 'static> RcuDroppable for std::marker::PhantomData<T> {}
87// SAFETY: Option<T> only drops its inner value T when present, which is RcuDroppable.
88unsafe impl<T: RcuDroppable> RcuDroppable for Option<T> {}
89// SAFETY: Result<T, E> only drops its inner T or E value, both of which are RcuDroppable.
90unsafe impl<T: RcuDroppable, E: RcuDroppable> RcuDroppable for Result<T, E> {}
91// SAFETY: Box<T> deallocates heap memory and drops T, which is RcuDroppable.
92unsafe impl<T: ?Sized + RcuDroppable> RcuDroppable for Box<T> {}
93// SAFETY: Arc<T> decrements the reference count and only drops T (which is RcuDroppable + Sync) when the last strong reference is released.
94unsafe impl<T: ?Sized + RcuDroppable + Sync> RcuDroppable for std::sync::Arc<T> {}
95// SAFETY: OnceLock<T> drops its inner value T when the last strong reference is released.
96unsafe impl<T: RcuDroppable + Sync> RcuDroppable for std::sync::OnceLock<T> {}
97// SAFETY: Weak<T> decrements the weak reference count without dropping the inner T value.
98unsafe impl<T: ?Sized + Send + Sync + 'static> RcuDroppable for std::sync::Weak<T> {}
99// SAFETY: Vec<T> deallocates buffer memory and drops elements of type T, which are RcuDroppable.
100unsafe impl<T: RcuDroppable> RcuDroppable for Vec<T> {}
101// SAFETY: Arrays drop their elements of type T, which are RcuDroppable.
102unsafe impl<T: RcuDroppable, const N: usize> RcuDroppable for [T; N] {}
103// SAFETY: Slice drops its elements of type T, which are RcuDroppable.
104unsafe impl<T: RcuDroppable> RcuDroppable for [T] {}
105// SAFETY: std::sync::mpsc::Sender closes the channel on drop without blocking.
106unsafe impl<T: Send + 'static> RcuDroppable for std::sync::mpsc::Sender<T> {}
107// SAFETY: std::sync::mpsc::SyncSender closes the channel on drop without blocking.
108unsafe impl<T: Send + 'static> RcuDroppable for std::sync::mpsc::SyncSender<T> {}
109// SAFETY: futures::channel::mpsc::Sender closes the channel on drop without blocking.
110unsafe impl<T: Send + 'static> RcuDroppable for futures::channel::mpsc::Sender<T> {}
111// SAFETY: futures::channel::mpsc::UnboundedSender closes the channel on drop without blocking.
112unsafe impl<T: Send + 'static> RcuDroppable for futures::channel::mpsc::UnboundedSender<T> {}
113// SAFETY: futures::channel::oneshot::Sender cancels the channel on drop without blocking.
114unsafe impl<T: Send + 'static> RcuDroppable for futures::channel::oneshot::Sender<T> {}
115// SAFETY: AtomicPtr has a trivial drop and does not own or drop the pointee.
116unsafe impl<T: 'static> RcuDroppable for std::sync::atomic::AtomicPtr<T> {}
117// SAFETY: RcuPtr has a trivial drop and does not own or drop the pointee.
118unsafe impl<T: 'static> RcuDroppable for crate::rcu_ptr::RcuPtr<T> {}
119
120// Range types
121// SAFETY: Range only drops its start and end fields of type T, which are RcuDroppable.
122unsafe impl<T: RcuDroppable> RcuDroppable for std::ops::Range<T> {}
123// SAFETY: RangeFrom only drops its start field of type T, which is RcuDroppable.
124unsafe impl<T: RcuDroppable> RcuDroppable for std::ops::RangeFrom<T> {}
125// SAFETY: RangeInclusive only drops its start and end fields of type T, which are RcuDroppable.
126unsafe impl<T: RcuDroppable> RcuDroppable for std::ops::RangeInclusive<T> {}
127// SAFETY: RangeTo only drops its end field of type T, which is RcuDroppable.
128unsafe impl<T: RcuDroppable> RcuDroppable for std::ops::RangeTo<T> {}
129// SAFETY: RangeToInclusive only drops its end field of type T, which is RcuDroppable.
130unsafe impl<T: RcuDroppable> RcuDroppable for std::ops::RangeToInclusive<T> {}
131
132// RCU containers
133// SAFETY: RcuDroppableArc drops its inner type with rcu_drop which is safe if T: RcuDroppable
134unsafe impl<T: RcuDroppable + Sync> RcuDroppable for crate::RcuDroppableArc<T> {}
135// SAFETY: RcuBox drops its inner type with rcu_drop which is safe if T: RcuDroppable
136unsafe impl<T: RcuDroppable + Sync> RcuDroppable for crate::RcuBox<T> {}
137// SAFETY: RcuOptionArc drops its inner type with rcu_drop which is safe if T: RcuDroppable
138unsafe impl<T: RcuDroppable + Sync> RcuDroppable for crate::RcuOptionArc<T> {}
139// SAFETY: RcuOptionBox drops its inner type with rcu_drop which is safe if T: RcuDroppable
140unsafe impl<T: RcuDroppable + Sync> RcuDroppable for crate::RcuOptionBox<T> {}
141// SAFETY: RcuWeak holds a non owning reference and won't deallocate T on rcu_drop.
142unsafe impl<T: Send + Sync + 'static> RcuDroppable for crate::RcuWeak<T> {}
143// SAFETY: rcu_drop of an RcuArc will rcu_drop T which is safe since T: RcuDroppable.
144unsafe impl<T: RcuDroppable + Sync> RcuDroppable for crate::RcuArc<T> {}
145// Synchronization primitives
146// SAFETY: Mutex drops its inner value T, which is RcuDroppable.
147unsafe impl<T: ?Sized + RcuDroppable> RcuDroppable for fuchsia_sync::Mutex<T> {}
148// SAFETY: RwLock drops its inner value T, which is RcuDroppable.
149unsafe impl<T: ?Sized + RcuDroppable> RcuDroppable for fuchsia_sync::RwLock<T> {}
150
151// SAFETY: Dropping `zx::Clock` closes the underlying Zircon kernel handle, which is
152// non-blocking and has no thread affinity. The timeline parameters `T` and `U` are
153// phantom markers with no drop side-effects.
154unsafe impl<T: Send + 'static, U: Send + 'static> RcuDroppable for zx::Clock<T, U> {}
155
156// Tuples
157// SAFETY: 1-element tuple drops its constituent element, which is RcuDroppable.
158unsafe impl<A: RcuDroppable> RcuDroppable for (A,) {}
159// SAFETY: 2-element tuple drops its constituent elements, which are RcuDroppable.
160unsafe impl<A: RcuDroppable, B: RcuDroppable> RcuDroppable for (A, B) {}
161// SAFETY: 3-element tuple drops its constituent elements, which are RcuDroppable.
162unsafe impl<A: RcuDroppable, B: RcuDroppable, C: RcuDroppable> RcuDroppable for (A, B, C) {}
163// SAFETY: 4-element tuple drops its constituent elements, which are RcuDroppable.
164unsafe impl<A: RcuDroppable, B: RcuDroppable, C: RcuDroppable, D: RcuDroppable> RcuDroppable
165    for (A, B, C, D)
166{
167}
168
169// The types we define are dead code as we don't use them. We only care that the macro parses them
170// successfully.
171#[expect(dead_code)]
172#[cfg(test)]
173mod tests {
174    use crate::RcuDroppable;
175
176    #[derive(RcuDroppable)]
177    struct UnitStruct;
178
179    #[derive(RcuDroppable)]
180    struct TupleStruct(u32, String);
181
182    #[derive(RcuDroppable)]
183    struct NamedStruct<T> {
184        foo: T,
185        bar: Vec<u8>,
186    }
187
188    #[derive(RcuDroppable)]
189    enum TestEnum<T> {
190        A(T),
191        B { val: String },
192        C,
193    }
194
195    #[derive(RcuDroppable)]
196    struct ComplexStruct {
197        atomic: std::sync::atomic::AtomicUsize,
198        range: std::ops::Range<usize>,
199        non_zero: std::num::NonZeroU32,
200        mutex: fuchsia_sync::Mutex<u32>,
201        rwlock: fuchsia_sync::RwLock<String>,
202        rcu_arc: crate::RcuArc<u32>,
203        weak: std::sync::Weak<u32>,
204    }
205
206    fn assert_rcu_droppable<T: super::RcuDroppable>() {}
207
208    #[test]
209    fn test_derive_rcu_droppable() {
210        assert_rcu_droppable::<UnitStruct>();
211        assert_rcu_droppable::<TupleStruct>();
212        assert_rcu_droppable::<NamedStruct<u32>>();
213        assert_rcu_droppable::<TestEnum<u64>>();
214        assert_rcu_droppable::<ComplexStruct>();
215        assert_rcu_droppable::<bstr::BString>();
216        assert_rcu_droppable::<futures::channel::mpsc::UnboundedSender<u32>>();
217    }
218}