clone_behavior/
independent.rs

1#![expect(clippy::absolute_paths, reason = "there's a lot of random types used")]
2#![warn(clippy::missing_inline_in_public_items, reason = "almost everything is very short")]
3
4use crate::call_varargs_macro;
5use crate::speed::{Speed, NearInstant, ConstantTime, LogTime, AnySpeed};
6
7
8/// Get deep clones of a value, which do not share any semantically-important mutable state.
9///
10/// The goal is that the independent clone and its source appear to act completely independently,
11/// at least from their public interfaces; mutating or dropping one clone (among possible actions)
12/// should have no potentially-observable effect on any other independent clone.
13///
14/// Note also that an independent clone and its source may reference the same immutable data, even
15/// if the public interface of the type could be used to confirm that two independent clones are
16/// (or were) associated. (However, there should not be a way for either the source or any
17/// independent clone to affect that data's value or address in memory.)
18///
19/// Side-channel attacks should be ignored in implementing this trait. The point is to provide deep
20/// clones, not cryptographic-quality guarantees about how those deep clones are performed.
21///
22/// # Exceptions
23/// - A type implementing `IndependentClone` may specify that certain methods or accesses are not
24///   subject to these guarantees.
25/// - `Debug` should be assumed to be an exception. Intentionally worsening the life of someone
26///   debugging your type is not a goal.
27/// - Shared mutable data which is written to but never read, or is read with effects that can only
28///   be publicly observed through exceptions, is acceptable.
29///
30/// # Other edge cases
31/// - A user calling `as_ptr()` and friends on references, to do address comparisons: if the
32///   address returned could change, then even if the underlying value at a new address would be
33///   the same, "the address of the data" should be considered mutable state. If that mutable state
34///   can be affected by the actions of the source of the independent clone or by other clones,
35///   then the address of the data must not be publicly exposed by the type's interface.
36/// - Copy-on-write data: while likely permissible if properly encapsulated, presumably the source,
37///   the independent clone, or both are going to be mutated; it'd be best to give the independent
38///   clone a unique owned copy of the data. Further, if some sort of reference-counted
39///   copy-on-write scheme is used where the last clone to refer to the data doesn't need to copy
40///   it, then the reference count used to determine that is shared mutable state. This can be
41///   avoided by simply giving the new independent clone an unique owned copy of the data, as
42///   should likely be done anyway.
43pub trait IndependentClone<S: Speed>: Sized {
44    /// Get a deep clone of a value, which does not share any semantically-important mutable state.
45    ///
46    /// The goal is that the independent clone and its source appear to act completely
47    /// independently, at least from their public interfaces; mutating or dropping one clone (among
48    /// possible actions) should have no potentially-observable effect on any other independent
49    /// clone.
50    ///
51    /// Read [`IndependentClone`] for more.
52    #[must_use]
53    fn independent_clone(&self) -> Self;
54}
55
56
57macro_rules! impl_copy {
58    ($($types:ty),*) => {
59        $(
60            impl IndependentClone<NearInstant> for $types {
61                #[inline]
62                fn independent_clone(&self) -> Self {
63                    *self
64                }
65            }
66        )*
67    };
68}
69
70macro_rules! int_impls {
71    ($($num:ident),* $(,)?) => {
72        $(
73            impl_copy!($num, ::core::num::NonZero<$num>);
74        )*
75    };
76}
77
78int_impls!(
79    i8, i16, i32, i64, i128, isize,
80    u8, u16, u32, u64, u128, usize,
81);
82
83macro_rules! non_recursive_near_instant {
84    ($($({for $($bounds:tt)+})? $type:ty),* $(,)?) => {
85        $(
86            impl<$($($bounds)+)?> IndependentClone<NearInstant> for $type {
87                #[inline]
88                fn independent_clone(&self) -> Self {
89                    self.clone()
90                }
91            }
92        )*
93    };
94}
95
96non_recursive_near_instant! {
97    f32, f64, bool, char, (),
98    core::alloc::Layout,
99    core::any::TypeId,
100    core::cmp::Ordering,
101    core::convert::Infallible,
102    {for T} core::iter::Empty<T>,
103    {for T: ?Sized} core::marker::PhantomData<T>,
104    core::marker::PhantomPinned,
105    {for T} core::mem::Discriminant<T>,
106    core::ops::RangeFull,
107    core::sync::atomic::Ordering,
108    core::time::Duration,
109}
110
111#[cfg(feature = "std")]
112non_recursive_near_instant! {
113    std::time::Instant,
114    std::thread::ThreadId,
115}
116
117macro_rules! atomic {
118    ($($name:ident $bits:literal),* $(,)?) => {
119        $(
120            #[cfg(target_has_atomic = $bits)]
121            impl IndependentClone<NearInstant> for core::sync::atomic::$name {
122                #[inline]
123                fn independent_clone(&self) -> Self {
124                    Self::new(self.load(core::sync::atomic::Ordering::Relaxed))
125                }
126            }
127        )*
128    };
129}
130
131atomic! {
132    AtomicBool    "8",
133    AtomicI8      "8", AtomicU8      "8",
134    AtomicI16    "16", AtomicU16    "16",
135    AtomicI32    "32", AtomicU32    "32",
136    AtomicI64    "64", AtomicU64    "64",
137    AtomicIsize "ptr", AtomicUsize "ptr",
138}
139
140macro_rules! function {
141    ($($args:ident),*) => {
142        impl<R, $($args),*> IndependentClone<NearInstant> for fn($($args),*) -> R {
143            #[inline]
144            fn independent_clone(&self) -> Self {
145                *self
146            }
147        }
148    };
149}
150
151function!();
152call_varargs_macro!(function);
153
154macro_rules! make_tuple_macro {
155    ($name:ident, $speed:ident, $dollar:tt) => {
156        macro_rules! $name {
157            ($dollar($dollar args:ident),+) => {
158                impl<$dollar($dollar args: IndependentClone<$speed>),+> IndependentClone<$speed>
159                for ($dollar($dollar args,)+)
160                {
161                    #[inline]
162                    fn independent_clone(&self) -> Self {
163                        #[expect(
164                            non_snake_case,
165                            reason = "using `Tn` as the variable of type `Tn`",
166                        )]
167                        let ($dollar($dollar args,)+) = self;
168                        (
169                            $dollar($dollar args.independent_clone(),)+
170                        )
171                    }
172                }
173            };
174        }
175    };
176}
177
178make_tuple_macro!(tuple_constant, ConstantTime, $);
179make_tuple_macro!(tuple_log, LogTime, $);
180make_tuple_macro!(tuple_any, AnySpeed, $);
181
182call_varargs_macro!(tuple_constant);
183call_varargs_macro!(tuple_log);
184call_varargs_macro!(tuple_any);
185
186macro_rules! constant_or_slower {
187    (
188        $(
189            $(#[$meta:meta])*
190            $({for ($($special_bounds:ident)*) {$($where_bounds:tt)*} $($bounds:tt)*})?
191            $type:ty
192            {|$self:ident| $($body:tt)*}
193        ),*
194        $(,)?
195    ) => {
196        $(
197            impl<$($($special_bounds: IndependentClone<ConstantTime>,)* $($bounds)*)?>
198                IndependentClone<ConstantTime>
199            for $type
200            where
201                $($($where_bounds)*)?
202            {
203                $(#[$meta])*
204                #[inline]
205                fn independent_clone(&$self) -> Self {
206                    $($body)*
207                }
208            }
209
210            impl<$($($special_bounds: IndependentClone<LogTime>,)* $($bounds)*)?>
211                IndependentClone<LogTime>
212            for $type
213            where
214                $($($where_bounds)*)?
215            {
216                $(#[$meta])*
217                #[inline]
218                fn independent_clone(&$self) -> Self {
219                    $($body)*
220                }
221            }
222
223            impl<$($($special_bounds: IndependentClone<AnySpeed>,)* $($bounds)*)?>
224                IndependentClone<AnySpeed>
225            for $type
226            where
227                $($($where_bounds)*)?
228            {
229                $(#[$meta])*
230                #[inline]
231                fn independent_clone(&$self) -> Self {
232                    $($body)*
233                }
234            }
235        )*
236    };
237}
238
239constant_or_slower! {
240    {for (T) {T: ?Sized} const N: usize} [T; N] {|self| {
241        self.each_ref().map(T::independent_clone)
242    }},
243    {for (T) {}} Option<T> {|self| {
244        self.as_ref().map(T::independent_clone)
245    }},
246    {for (T E) {}} Result<T, E> {|self| {
247        self.as_ref()
248            .map(T::independent_clone)
249            .map_err(E::independent_clone)
250    }},
251    {for (T) {}} core::mem::ManuallyDrop<T> {|self| {
252        Self::new(T::independent_clone(self))
253    }},
254    {for (T) {T: Copy}} core::cell::Cell<T> {|self| {
255        Self::new(T::independent_clone(&self.get()))
256    }},
257    /// # Panics
258    /// Panics if the value is currently mutably borrowed.
259    {for (T) {}} core::cell::RefCell<T> {|self| {
260        Self::new(T::independent_clone(&self.borrow()))
261    }},
262}
263
264#[cfg(feature = "alloc")]
265constant_or_slower! {
266    {for (T) {T: ?Sized}} alloc::rc::Rc<T> {|self| {
267        Self::new(T::independent_clone(self))
268    }},
269    {for (T) {T: ?Sized}} core::pin::Pin<alloc::rc::Rc<T>> {|self| {
270        alloc::rc::Rc::pin(T::independent_clone(self))
271    }},
272    {for (T) {T: ?Sized}} alloc::rc::Weak<T> {|self| {
273        if let Some(rc) = self.upgrade() {
274            alloc::rc::Rc::downgrade(&alloc::rc::Rc::new(T::independent_clone(&rc)))
275        } else {
276            Self::new()
277        }
278    }},
279    {for (T) {T: ?Sized}} alloc::sync::Arc<T> {|self| {
280        Self::new(T::independent_clone(self))
281    }},
282    {for (T) {T: ?Sized}} core::pin::Pin<alloc::sync::Arc<T>> {|self| {
283        alloc::sync::Arc::pin(T::independent_clone(self))
284    }},
285    {for (T) {T: ?Sized}} alloc::sync::Weak<T> {|self| {
286        if let Some(arc) = self.upgrade() {
287            alloc::sync::Arc::downgrade(&alloc::sync::Arc::new(T::independent_clone(&arc)))
288        } else {
289            Self::new()
290        }
291    }},
292}
293
294#[cfg(feature = "std")]
295constant_or_slower! {
296    /// # Panics
297    /// Panics if the `RwLock` is poisoned.
298    {for (T) {}} std::sync::RwLock<T> {|self| {
299        let lock_result: Result<_, std::sync::PoisonError<_>> = self.read();
300        #[expect(clippy::unwrap_used, reason = "Unwrapping poison")]
301        Self::new(T::independent_clone(&lock_result.unwrap()))
302    }},
303    /// # Panics or Deadlocks
304    /// Panics if the `Mutex` is poisoned.
305    ///
306    /// Will either panic or deadlock if the current thread already holds the mutex.
307    {for (T) {}} std::sync::Mutex<T> {|self| {
308        let lock_result: Result<_, std::sync::PoisonError<_>> = self.lock();
309        #[expect(clippy::unwrap_used, reason = "Unwrapping poison")]
310        Self::new(T::independent_clone(&lock_result.unwrap()))
311    }},
312}
313
314// constant or slower: ranges, ops::Bound,
315
316macro_rules! map_and_collect {
317    ($($t:ident $({$($where_bounds:tt)*})? $type:ty),* $(,)?) => {
318        $(
319            #[cfg(feature = "alloc")]
320            impl<$t: IndependentClone<AnySpeed>> IndependentClone<AnySpeed>
321            for $type
322            where
323                $($($where_bounds)*)?
324            {
325                #[inline]
326                fn independent_clone(&self) -> Self {
327                    self.iter()
328                        .map($t::independent_clone)
329                        .collect()
330                }
331            }
332        )*
333    };
334}
335
336map_and_collect! {
337    T alloc::boxed::Box<[T]>,
338    T alloc::vec::Vec<T>,
339    T alloc::collections::VecDeque<T>,
340    T alloc::collections::LinkedList<T>,
341    T {T: Ord} alloc::collections::BTreeSet<T>,
342    T {T: Ord} alloc::collections::BinaryHeap<T>,
343}
344
345#[cfg(feature = "alloc")]
346impl<T: IndependentClone<AnySpeed>> IndependentClone<AnySpeed>
347for core::pin::Pin<alloc::boxed::Box<[T]>>
348{
349    #[inline]
350    fn independent_clone(&self) -> Self {
351        let new_box = self.iter()
352            .map(T::independent_clone)
353            .collect::<alloc::boxed::Box<[T]>>();
354
355        alloc::boxed::Box::into_pin(new_box)
356    }
357}
358
359#[cfg(feature = "alloc")]
360impl IndependentClone<AnySpeed> for alloc::boxed::Box<str> {
361    #[inline]
362    fn independent_clone(&self) -> Self {
363        self.clone()
364    }
365}
366
367#[cfg(feature = "alloc")]
368impl IndependentClone<AnySpeed> for core::pin::Pin<alloc::boxed::Box<str>> {
369    #[inline]
370    fn independent_clone(&self) -> Self {
371        self.clone()
372    }
373}
374
375#[cfg(feature = "alloc")]
376impl<K, V> IndependentClone<AnySpeed> for alloc::collections::BTreeMap<K, V>
377where
378    K: IndependentClone<AnySpeed> + Ord,
379    V: IndependentClone<AnySpeed>,
380{
381    #[inline]
382    fn independent_clone(&self) -> Self {
383        self.iter()
384            .map(|(key, val)| {
385                (
386                    K::independent_clone(key),
387                    V::independent_clone(val),
388                )
389            })
390            .collect()
391    }
392}
393
394#[cfg(feature = "std")]
395impl<T, S> IndependentClone<AnySpeed> for std::collections::HashSet<T, S>
396where
397    T: IndependentClone<AnySpeed> + Eq + core::hash::Hash,
398    S: core::hash::BuildHasher + Default,
399{
400    #[inline]
401    fn independent_clone(&self) -> Self {
402        self.iter()
403            .map(T::independent_clone)
404            .collect()
405    }
406}
407
408#[cfg(feature = "std")]
409impl<K, V, S> IndependentClone<AnySpeed> for std::collections::HashMap<K, V, S>
410where
411    K: IndependentClone<AnySpeed> + Eq + core::hash::Hash,
412    V: IndependentClone<AnySpeed>,
413    S: core::hash::BuildHasher + Default,
414{
415    #[inline]
416    fn independent_clone(&self) -> Self {
417        self.iter()
418            .map(|(key, val)| {
419                (
420                    K::independent_clone(key),
421                    V::independent_clone(val),
422                )
423            })
424            .collect()
425    }
426}
427
428// TODO: iterators, other boxed things