Skip to main content

clone_behavior/
mirrored.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, MaybeSlow, Speed};
6
7
8/// Get clones that share all semantically-important mutable state.
9///
10/// The goal is that mutating one mirrored clone affects every clone. Different mirrored clones
11/// should, from their public interfaces, act identically, with some exceptions like memory
12/// addresses.
13///
14/// This can be achieved via reference counting (e.g., [`Rc`] or [`Arc`]), or by simply
15/// not having any mutable state to share at all (e.g. a zero-sized type like `()`, or a reference
16/// to a type without internal mutability, like `&'static str`).
17///
18/// Per-clone mutable data is permissible, so long as the effects of mutating that data do not
19/// cause mirrored clones to behave differently in a potentially-observable way.
20/// Clones of types like `Option<T>` or `u32` are not considered to be mirrored clones, as
21/// counterexamples.
22///
23/// # Exceptions
24/// - A type implementing `MirroredClone` may specify that certain methods or accesses are not
25///   subject to these guarantees.
26/// - `Debug` should be assumed to be an exception. Intentionally worsening the life of someone
27///   debugging your type is not a goal.
28/// - Memory addresses which are different per-clone, but are not mutated by that clone (except
29///   when a user moves the value). Trivially, mirrored clones do not have the same address,
30///   and some of their data may be inlined into the type. If any reference to that data is exposed,
31///   a user would likely be able to determine what data is inlined into the type and what is
32///   inlined. That's already visible in the source code, anyway. Unless some semantically-important
33///   function of the type depends on the address of it or its data, it's unimportant.
34/// - TLDR of above bullet: users should not assume that references returned from different mirrored
35///   clones refer to the same value, only that those values *behave* the same.
36///
37/// [`Rc`]: std::rc::Rc
38/// [`Arc`]: std::sync::Arc
39pub trait MirroredClone<S: Speed>: Sized {
40    /// Get a clone that shares all semantically-important mutable state with its source.
41    ///
42    /// The goal is that mutating one mirrored clone affects every clone. Different mirrored clones
43    /// should, from their public interfaces, act identically, with some exceptions like memory
44    /// addresses.
45    ///
46    /// Read [`MirroredClone`] for more.
47    #[must_use]
48    fn mirrored_clone(&self) -> Self;
49}
50
51/// Quickly get clones that share all semantically-important mutable state.
52///
53/// See [`MirroredClone`] for more.
54pub trait FastMirroredClone: MirroredClone<Fast> {
55    /// Get a clone that shares all semantically-important mutable state with its source.
56    ///
57    /// The goal is that mutating one mirrored clone affects every clone. Different mirrored clones
58    /// should, from their public interfaces, act identically, with some exceptions like memory
59    /// addresses.
60    ///
61    /// See [`MirroredClone`] for more.
62    #[must_use]
63    fn fast_mirrored_clone(&self) -> Self;
64}
65
66impl<T: MirroredClone<Fast>> FastMirroredClone for T {
67    #[inline]
68    fn fast_mirrored_clone(&self) -> Self {
69        self.mirrored_clone()
70    }
71}
72
73
74macro_rules! non_recursive_fast {
75    ($($({for $($bounds:tt)+})? $type:ty),* $(,)?) => {
76        $(
77            impl<S: Speed, $($($bounds)+)?> MirroredClone<S> for $type {
78                #[inline]
79                fn mirrored_clone(&self) -> Self {
80                    self.clone()
81                }
82            }
83        )*
84    };
85}
86
87non_recursive_fast! {
88    (),
89    {for T} core::iter::Empty<T>,
90    {for T: ?Sized} core::marker::PhantomData<T>,
91    core::marker::PhantomPinned,
92    core::ops::RangeFull,
93}
94
95#[cfg(feature = "alloc")]
96macro_rules! refcounted {
97    ($($t:ident $refcounted:ty),* $(,)?) => {
98        $(
99            impl<S: Speed, $t: ?Sized> MirroredClone<S> for $refcounted {
100                #[inline]
101                fn mirrored_clone(&self) -> Self {
102                    self.clone()
103                }
104            }
105        )*
106    };
107}
108
109#[cfg(feature = "alloc")]
110refcounted!(
111    T alloc::rc::Rc<T>,
112    T alloc::rc::Weak<T>,
113    T alloc::sync::Arc<T>,
114    T alloc::sync::Weak<T>,
115);
116
117macro_rules! function {
118    ($($args:ident),*) => {
119        impl<S: Speed, R, $($args),*> MirroredClone<S> for fn($($args),*) -> R {
120            #[inline]
121            fn mirrored_clone(&self) -> Self {
122                *self
123            }
124        }
125    };
126}
127
128macro_rules! pinned_refcounted {
129    ($($t:ident $refcounted:ty),* $(,)?) => {
130        $(
131            #[cfg(feature = "alloc")]
132            impl<S: Speed, $t: ?Sized> MirroredClone<S> for core::pin::Pin<$refcounted> {
133                #[inline]
134                fn mirrored_clone(&self) -> Self {
135                    self.clone()
136                }
137            }
138        )*
139    };
140}
141
142pinned_refcounted! {
143    T alloc::rc::Rc<T>,
144    T alloc::rc::Weak<T>,
145    T alloc::sync::Arc<T>,
146    T alloc::sync::Weak<T>,
147}
148
149function!();
150call_varargs_macro!(function);
151
152macro_rules! make_tuple_macro {
153    ($name:ident, $speed:ident, $dollar:tt) => {
154        macro_rules! $name {
155            ($dollar($dollar args:ident),+) => {
156                impl<$dollar($dollar args: MirroredClone<$speed>),+> MirroredClone<$speed>
157                for ($dollar($dollar args,)+)
158                {
159                    #[inline]
160                    fn mirrored_clone(&self) -> Self {
161                        #[expect(
162                            non_snake_case,
163                            reason = "using `Tn` as the variable of type `Tn`",
164                        )]
165                        let ($dollar($dollar args,)+) = self;
166                        (
167                            $dollar($dollar args.mirrored_clone(),)+
168                        )
169                    }
170                }
171            };
172        }
173    };
174}
175
176make_tuple_macro!(tuple_fast, Fast, $);
177make_tuple_macro!(tuple_slow, MaybeSlow, $);
178
179call_varargs_macro!(tuple_fast);
180call_varargs_macro!(tuple_slow);
181
182impl<S: Speed> MirroredClone<S> for core::convert::Infallible {
183    #[expect(
184        clippy::missing_inline_in_public_items,
185        clippy::uninhabited_references,
186        reason = "this is unreachable",
187    )]
188    fn mirrored_clone(&self) -> Self {
189        *self
190    }
191}