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: HashMap deallocates table memory and drops keys, values, and the hasher, all of which are RcuDroppable.
102unsafe impl<K: RcuDroppable, V: RcuDroppable, S: RcuDroppable> RcuDroppable
103    for std::collections::HashMap<K, V, S>
104{
105}
106// SAFETY: Arrays drop their elements of type T, which are RcuDroppable.
107unsafe impl<T: RcuDroppable, const N: usize> RcuDroppable for [T; N] {}
108// SAFETY: Slice drops its elements of type T, which are RcuDroppable.
109unsafe impl<T: RcuDroppable> RcuDroppable for [T] {}
110// SAFETY: std::sync::mpsc::Sender closes the channel on drop without blocking.
111unsafe impl<T: Send + 'static> RcuDroppable for std::sync::mpsc::Sender<T> {}
112// SAFETY: std::sync::mpsc::SyncSender closes the channel on drop without blocking.
113unsafe impl<T: Send + 'static> RcuDroppable for std::sync::mpsc::SyncSender<T> {}
114// SAFETY: futures::channel::mpsc::Sender closes the channel on drop without blocking.
115unsafe impl<T: Send + 'static> RcuDroppable for futures::channel::mpsc::Sender<T> {}
116// SAFETY: futures::channel::mpsc::UnboundedSender closes the channel on drop without blocking.
117unsafe impl<T: Send + 'static> RcuDroppable for futures::channel::mpsc::UnboundedSender<T> {}
118// SAFETY: futures::channel::oneshot::Sender cancels the channel on drop without blocking.
119unsafe impl<T: Send + 'static> RcuDroppable for futures::channel::oneshot::Sender<T> {}
120// SAFETY: AtomicPtr has a trivial drop and does not own or drop the pointee.
121unsafe impl<T: 'static> RcuDroppable for std::sync::atomic::AtomicPtr<T> {}
122// SAFETY: RcuPtr has a trivial drop and does not own or drop the pointee.
123unsafe impl<T: 'static> RcuDroppable for crate::rcu_ptr::RcuPtr<T> {}
124
125// Range types
126// SAFETY: Range only drops its start and end fields of type T, which are RcuDroppable.
127unsafe impl<T: RcuDroppable> RcuDroppable for std::ops::Range<T> {}
128// SAFETY: RangeFrom only drops its start field of type T, which is RcuDroppable.
129unsafe impl<T: RcuDroppable> RcuDroppable for std::ops::RangeFrom<T> {}
130// SAFETY: RangeInclusive only drops its start and end fields of type T, which are RcuDroppable.
131unsafe impl<T: RcuDroppable> RcuDroppable for std::ops::RangeInclusive<T> {}
132// SAFETY: RangeTo only drops its end field of type T, which is RcuDroppable.
133unsafe impl<T: RcuDroppable> RcuDroppable for std::ops::RangeTo<T> {}
134// SAFETY: RangeToInclusive only drops its end field of type T, which is RcuDroppable.
135unsafe impl<T: RcuDroppable> RcuDroppable for std::ops::RangeToInclusive<T> {}
136
137// RCU containers
138// SAFETY: RcuDroppableArc drops its inner type with rcu_drop which is safe if T: RcuDroppable
139unsafe impl<T: RcuDroppable + Sync> RcuDroppable for crate::RcuDroppableArc<T> {}
140// SAFETY: RcuBox drops its inner type with rcu_drop which is safe if T: RcuDroppable
141unsafe impl<T: RcuDroppable + Sync> RcuDroppable for crate::RcuBox<T> {}
142// SAFETY: RcuOptionArc drops its inner type with rcu_drop which is safe if T: RcuDroppable
143unsafe impl<T: RcuDroppable + Sync> RcuDroppable for crate::RcuOptionArc<T> {}
144// SAFETY: RcuOptionBox drops its inner type with rcu_drop which is safe if T: RcuDroppable
145unsafe impl<T: RcuDroppable + Sync> RcuDroppable for crate::RcuOptionBox<T> {}
146// SAFETY: RcuWeak holds a non owning reference and won't deallocate T on rcu_drop.
147unsafe impl<T: Send + Sync + 'static> RcuDroppable for crate::RcuWeak<T> {}
148// SAFETY: rcu_drop of an RcuArc will rcu_drop T which is safe since T: RcuDroppable.
149unsafe impl<T: RcuDroppable + Sync> RcuDroppable for crate::RcuArc<T> {}
150// Synchronization primitives
151// SAFETY: Mutex drops its inner value T, which is RcuDroppable.
152unsafe impl<T: ?Sized + RcuDroppable> RcuDroppable for fuchsia_sync::Mutex<T> {}
153// SAFETY: RwLock drops its inner value T, which is RcuDroppable.
154unsafe impl<T: ?Sized + RcuDroppable> RcuDroppable for fuchsia_sync::RwLock<T> {}
155// SAFETY: Completion does not have custom drop logic and does not block on drop.
156unsafe impl RcuDroppable for fuchsia_sync::Completion {}
157
158// SAFETY: Dropping `zx::Clock` closes the underlying Zircon kernel handle, which is
159// non-blocking and has no thread affinity. The timeline parameters `T` and `U` are
160// phantom markers with no drop side-effects.
161unsafe impl<T: Send + 'static, U: Send + 'static> RcuDroppable for zx::Clock<T, U> {}
162
163// SAFETY: `zx::Instant` is a `Copy` wrapper around an integer, so it has no drop side-effects.
164// The timeline parameters `T` and `U` are phantom markers.
165unsafe impl<T: Send + 'static, U: Send + 'static> RcuDroppable for zx::Instant<T, U> {}
166
167// Tuples
168// SAFETY: 1-element tuple drops its constituent element, which is RcuDroppable.
169unsafe impl<A: RcuDroppable> RcuDroppable for (A,) {}
170// SAFETY: 2-element tuple drops its constituent elements, which are RcuDroppable.
171unsafe impl<A: RcuDroppable, B: RcuDroppable> RcuDroppable for (A, B) {}
172// SAFETY: 3-element tuple drops its constituent elements, which are RcuDroppable.
173unsafe impl<A: RcuDroppable, B: RcuDroppable, C: RcuDroppable> RcuDroppable for (A, B, C) {}
174// SAFETY: 4-element tuple drops its constituent elements, which are RcuDroppable.
175unsafe impl<A: RcuDroppable, B: RcuDroppable, C: RcuDroppable, D: RcuDroppable> RcuDroppable
176    for (A, B, C, D)
177{
178}
179
180// The types we define are dead code as we don't use them. We only care that the macro parses them
181// successfully.
182#[expect(dead_code)]
183#[cfg(test)]
184mod tests {
185    use crate::RcuDroppable;
186
187    #[derive(RcuDroppable)]
188    struct UnitStruct;
189
190    #[derive(RcuDroppable)]
191    struct TupleStruct(u32, String);
192
193    #[derive(RcuDroppable)]
194    struct NamedStruct<T> {
195        foo: T,
196        bar: Vec<u8>,
197    }
198
199    #[derive(RcuDroppable)]
200    enum TestEnum<T> {
201        A(T),
202        B { val: String },
203        C,
204    }
205
206    #[derive(RcuDroppable)]
207    struct ComplexStruct {
208        atomic: std::sync::atomic::AtomicUsize,
209        range: std::ops::Range<usize>,
210        non_zero: std::num::NonZeroU32,
211        mutex: fuchsia_sync::Mutex<u32>,
212        rwlock: fuchsia_sync::RwLock<String>,
213        rcu_arc: crate::RcuArc<u32>,
214        weak: std::sync::Weak<u32>,
215        hash_map: std::collections::HashMap<u32, String>,
216    }
217
218    fn assert_rcu_droppable<T: super::RcuDroppable>() {}
219
220    #[test]
221    fn test_derive_rcu_droppable() {
222        assert_rcu_droppable::<UnitStruct>();
223        assert_rcu_droppable::<TupleStruct>();
224        assert_rcu_droppable::<NamedStruct<u32>>();
225        assert_rcu_droppable::<TestEnum<u64>>();
226        assert_rcu_droppable::<ComplexStruct>();
227        assert_rcu_droppable::<bstr::BString>();
228        assert_rcu_droppable::<fuchsia_sync::Completion>();
229        assert_rcu_droppable::<futures::channel::mpsc::UnboundedSender<u32>>();
230    }
231}