clone_behavior/
deep.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::{Fast, FastSpeed, MaybeSlow, Speed};
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 clones and their 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 a deep 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 deep 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 `DeepClone` 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 DeepClone<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 clone and its source appear to act completely independently, at least
47    /// from their public interfaces; mutating or dropping one clone (among possible actions)
48    /// should have no potentially-observable effect on any other deep clone.
49    ///
50    /// Read [`DeepClone`] for more.
51    #[inline]
52    #[must_use]
53    fn fast_deep_clone(&self) -> Self where S: FastSpeed {
54        self.deep_clone()
55    }
56
57    /// Get a deep clone of a value, which does not share any semantically-important mutable state.
58    ///
59    /// The goal is that the clone and its source appear to act completely independently, at least
60    /// from their public interfaces; mutating or dropping one clone (among possible actions)
61    /// should have no potentially-observable effect on any other deep clone.
62    ///
63    /// Read [`DeepClone`] for more.
64    #[must_use]
65    fn deep_clone(&self) -> Self;
66}
67
68
69macro_rules! impl_copy {
70    ($($types:ty),*) => {
71        $(
72            impl<S: Speed> DeepClone<S> for $types {
73                #[inline]
74                fn deep_clone(&self) -> Self {
75                    *self
76                }
77            }
78        )*
79    };
80}
81
82macro_rules! int_impls {
83    ($($num:ident),* $(,)?) => {
84        $(
85            impl_copy!($num, ::core::num::NonZero<$num>);
86        )*
87    };
88}
89
90int_impls!(
91    i8, i16, i32, i64, i128, isize,
92    u8, u16, u32, u64, u128, usize,
93);
94
95macro_rules! non_recursive_fast {
96    ($($({for $($bounds:tt)+})? $type:ty),* $(,)?) => {
97        $(
98            impl<S: Speed, $($($bounds)+)?> DeepClone<S> for $type {
99                #[inline]
100                fn deep_clone(&self) -> Self {
101                    self.clone()
102                }
103            }
104        )*
105    };
106}
107
108non_recursive_fast! {
109    f32, f64, bool, char, (),
110    core::alloc::Layout,
111    core::any::TypeId,
112    core::cmp::Ordering,
113    {for T} core::iter::Empty<T>,
114    {for T: ?Sized} core::marker::PhantomData<T>,
115    core::marker::PhantomPinned,
116    {for T} core::mem::Discriminant<T>,
117    core::ops::RangeFull,
118    core::sync::atomic::Ordering,
119    core::time::Duration,
120}
121
122#[cfg(feature = "std")]
123non_recursive_fast! {
124    std::time::Instant,
125    std::thread::ThreadId,
126}
127
128macro_rules! atomic {
129    ($($name:ident $bits:literal),* $(,)?) => {
130        $(
131            #[cfg(target_has_atomic = $bits)]
132            impl<S: Speed> DeepClone<S> for core::sync::atomic::$name {
133                #[inline]
134                fn deep_clone(&self) -> Self {
135                    Self::new(self.load(core::sync::atomic::Ordering::Relaxed))
136                }
137            }
138        )*
139    };
140}
141
142atomic! {
143    AtomicBool    "8",
144    AtomicI8      "8", AtomicU8      "8",
145    AtomicI16    "16", AtomicU16    "16",
146    AtomicI32    "32", AtomicU32    "32",
147    AtomicI64    "64", AtomicU64    "64",
148    AtomicIsize "ptr", AtomicUsize "ptr",
149}
150
151macro_rules! function {
152    ($($args:ident),*) => {
153        impl<S: Speed, R, $($args),*> DeepClone<S> for fn($($args),*) -> R {
154            #[inline]
155            fn deep_clone(&self) -> Self {
156                *self
157            }
158        }
159    };
160}
161
162function!();
163call_varargs_macro!(function);
164
165macro_rules! make_tuple_macro {
166    ($name:ident, $speed:ident, $dollar:tt) => {
167        macro_rules! $name {
168            ($dollar($dollar args:ident),+) => {
169                impl<$dollar($dollar args: DeepClone<$speed>),+> DeepClone<$speed>
170                for ($dollar($dollar args,)+)
171                {
172                    #[inline]
173                    fn deep_clone(&self) -> Self {
174                        #[expect(
175                            non_snake_case,
176                            reason = "using `Tn` as the variable of type `Tn`",
177                        )]
178                        let ($dollar($dollar args,)+) = self;
179                        (
180                            $dollar($dollar args.deep_clone(),)+
181                        )
182                    }
183                }
184            };
185        }
186    };
187}
188
189make_tuple_macro!(tuple_fast, Fast, $);
190make_tuple_macro!(tuple_slow, MaybeSlow, $);
191
192call_varargs_macro!(tuple_fast);
193call_varargs_macro!(tuple_slow);
194
195macro_rules! recursive {
196    (
197        $(
198            $(#[$meta:meta])*
199            $({for ($($special_bounds:ident)*) {$($where_bounds:tt)*} $($bounds:tt)*})?
200            $type:ty
201            {|$self:ident| $($body:tt)*}
202        ),*
203        $(,)?
204    ) => {
205        $(
206            impl<$($($special_bounds: DeepClone<Fast>,)* $($bounds)*)?> DeepClone<Fast>
207            for $type
208            where
209                $($($where_bounds)*)?
210            {
211                $(#[$meta])*
212                #[inline]
213                fn deep_clone(&$self) -> Self {
214                    $($body)*
215                }
216            }
217
218
219            impl<$($($special_bounds: DeepClone<MaybeSlow>,)* $($bounds)*)?> DeepClone<MaybeSlow>
220            for $type
221            where
222                $($($where_bounds)*)?
223            {
224                $(#[$meta])*
225                #[inline]
226                fn deep_clone(&$self) -> Self {
227                    $($body)*
228                }
229            }
230        )*
231    };
232}
233
234recursive! {
235    {for (T) {T: ?Sized} const N: usize} [T; N] {|self| {
236        self.each_ref().map(T::deep_clone)
237    }},
238    {for (T) {}} Option<T> {|self| {
239        self.as_ref().map(T::deep_clone)
240    }},
241    {for (T E) {}} Result<T, E> {|self| {
242        self.as_ref()
243            .map(T::deep_clone)
244            .map_err(E::deep_clone)
245    }},
246    {for (T) {}} core::mem::ManuallyDrop<T> {|self| {
247        Self::new(T::deep_clone(self))
248    }},
249    {for (T) {T: Copy}} core::cell::Cell<T> {|self| {
250        Self::new(T::deep_clone(&self.get()))
251    }},
252    /// # Panics
253    /// Panics if the value is currently mutably borrowed.
254    {for (T) {}} core::cell::RefCell<T> {|self| {
255        Self::new(T::deep_clone(&self.borrow()))
256    }},
257}
258
259#[cfg(feature = "alloc")]
260recursive! {
261    {for (T) {T: ?Sized}} alloc::rc::Rc<T> {|self| {
262        Self::new(T::deep_clone(self))
263    }},
264    {for (T) {T:}} alloc::boxed::Box<T> {|self| {
265        Self::new(T::deep_clone(self))
266    }},
267    {for (T) {T: ?Sized}} core::pin::Pin<alloc::rc::Rc<T>> {|self| {
268        alloc::rc::Rc::pin(T::deep_clone(self))
269    }},
270    {for (T) {T: ?Sized}} alloc::rc::Weak<T> {|self| {
271        if let Some(rc) = self.upgrade() {
272            alloc::rc::Rc::downgrade(&alloc::rc::Rc::new(T::deep_clone(&rc)))
273        } else {
274            Self::new()
275        }
276    }},
277    {for (T) {T: ?Sized}} alloc::sync::Arc<T> {|self| {
278        Self::new(T::deep_clone(self))
279    }},
280    {for (T) {T: ?Sized}} core::pin::Pin<alloc::sync::Arc<T>> {|self| {
281        alloc::sync::Arc::pin(T::deep_clone(self))
282    }},
283    {for (T) {T: ?Sized}} alloc::sync::Weak<T> {|self| {
284        if let Some(arc) = self.upgrade() {
285            alloc::sync::Arc::downgrade(&alloc::sync::Arc::new(T::deep_clone(&arc)))
286        } else {
287            Self::new()
288        }
289    }},
290}
291
292#[cfg(feature = "std")]
293recursive! {
294    /// # Panics
295    /// Panics if the `RwLock` is poisoned.
296    {for (T) {}} std::sync::RwLock<T> {|self| {
297        let lock_result: Result<_, std::sync::PoisonError<_>> = self.read();
298        #[expect(clippy::unwrap_used, reason = "Unwrapping poison")]
299        Self::new(T::deep_clone(&lock_result.unwrap()))
300    }},
301    /// # Panics or Deadlocks
302    /// Panics if the `Mutex` is poisoned.
303    ///
304    /// Will either panic or deadlock if the current thread already holds the mutex.
305    {for (T) {}} std::sync::Mutex<T> {|self| {
306        let lock_result: Result<_, std::sync::PoisonError<_>> = self.lock();
307        #[expect(clippy::unwrap_used, reason = "Unwrapping poison")]
308        Self::new(T::deep_clone(&lock_result.unwrap()))
309    }},
310}
311
312// constant or slower: ranges, ops::Bound,
313
314macro_rules! map_and_collect {
315    ($($t:ident $({$($where_bounds:tt)*})? $type:ty),* $(,)?) => {
316        $(
317            #[cfg(feature = "alloc")]
318            impl<$t: DeepClone<MaybeSlow>> DeepClone<MaybeSlow>
319            for $type
320            where
321                $($($where_bounds)*)?
322            {
323                #[inline]
324                fn deep_clone(&self) -> Self {
325                    self.iter()
326                        .map($t::deep_clone)
327                        .collect()
328                }
329            }
330        )*
331    };
332}
333
334map_and_collect! {
335    T alloc::boxed::Box<[T]>,
336    T alloc::vec::Vec<T>,
337    T alloc::collections::VecDeque<T>,
338    T alloc::collections::LinkedList<T>,
339    T {T: Ord} alloc::collections::BTreeSet<T>,
340    T {T: Ord} alloc::collections::BinaryHeap<T>,
341}
342
343#[cfg(feature = "alloc")]
344impl<T: DeepClone<MaybeSlow>> DeepClone<MaybeSlow>
345for core::pin::Pin<alloc::boxed::Box<[T]>>
346{
347    #[inline]
348    fn deep_clone(&self) -> Self {
349        let new_box = self.iter()
350            .map(T::deep_clone)
351            .collect::<alloc::boxed::Box<[T]>>();
352
353        alloc::boxed::Box::into_pin(new_box)
354    }
355}
356
357#[cfg(feature = "alloc")]
358impl DeepClone<MaybeSlow> for alloc::boxed::Box<str> {
359    #[inline]
360    fn deep_clone(&self) -> Self {
361        self.clone()
362    }
363}
364
365#[cfg(feature = "alloc")]
366impl DeepClone<MaybeSlow> for core::pin::Pin<alloc::boxed::Box<str>> {
367    #[inline]
368    fn deep_clone(&self) -> Self {
369        self.clone()
370    }
371}
372
373#[cfg(feature = "alloc")]
374impl<K, V> DeepClone<MaybeSlow> for alloc::collections::BTreeMap<K, V>
375where
376    K: DeepClone<MaybeSlow> + Ord,
377    V: DeepClone<MaybeSlow>,
378{
379    #[inline]
380    fn deep_clone(&self) -> Self {
381        self.iter()
382            .map(|(key, val)| {
383                (
384                    K::deep_clone(key),
385                    V::deep_clone(val),
386                )
387            })
388            .collect()
389    }
390}
391
392#[cfg(feature = "std")]
393impl<T, S> DeepClone<MaybeSlow> for std::collections::HashSet<T, S>
394where
395    T: DeepClone<MaybeSlow> + Eq + core::hash::Hash,
396    S: core::hash::BuildHasher + Default,
397{
398    #[inline]
399    fn deep_clone(&self) -> Self {
400        self.iter()
401            .map(T::deep_clone)
402            .collect()
403    }
404}
405
406#[cfg(feature = "std")]
407impl<K, V, S> DeepClone<MaybeSlow> for std::collections::HashMap<K, V, S>
408where
409    K: DeepClone<MaybeSlow> + Eq + core::hash::Hash,
410    V: DeepClone<MaybeSlow>,
411    S: core::hash::BuildHasher + Default,
412{
413    #[inline]
414    fn deep_clone(&self) -> Self {
415        self.iter()
416            .map(|(key, val)| {
417                (
418                    K::deep_clone(key),
419                    V::deep_clone(val),
420                )
421            })
422            .collect()
423    }
424}
425
426impl<S: Speed> DeepClone<S> for core::convert::Infallible {
427    #[expect(
428        clippy::missing_inline_in_public_items,
429        clippy::uninhabited_references,
430        reason = "this is unreachable",
431    )]
432    fn deep_clone(&self) -> Self {
433        *self
434    }
435}
436
437// TODO: iterators, other pinned things