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, FastSpeed, 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    #[inline]
48    #[must_use]
49    fn fast_mirrored_clone(&self) -> Self where S: FastSpeed {
50        self.mirrored_clone()
51    }
52
53    /// Get a clone that shares all semantically-important mutable state with its source.
54    ///
55    /// The goal is that mutating one mirrored clone affects every clone. Different mirrored clones
56    /// should, from their public interfaces, act identically, with some exceptions like memory
57    /// addresses.
58    ///
59    /// Read [`MirroredClone`] for more.
60    #[must_use]
61    fn mirrored_clone(&self) -> Self;
62}
63
64
65macro_rules! non_recursive_fast {
66    ($($({for $($bounds:tt)+})? $type:ty),* $(,)?) => {
67        $(
68            impl<S: Speed, $($($bounds)+)?> MirroredClone<S> for $type {
69                #[inline]
70                fn mirrored_clone(&self) -> Self {
71                    self.clone()
72                }
73            }
74        )*
75    };
76}
77
78non_recursive_fast! {
79    (),
80    {for T} core::iter::Empty<T>,
81    {for T: ?Sized} core::marker::PhantomData<T>,
82    core::marker::PhantomPinned,
83    core::ops::RangeFull,
84}
85
86#[cfg(feature = "alloc")]
87macro_rules! refcounted {
88    ($($t:ident $refcounted:ty),* $(,)?) => {
89        $(
90            impl<S: Speed, $t: ?Sized> MirroredClone<S> for $refcounted {
91                #[inline]
92                fn mirrored_clone(&self) -> Self {
93                    self.clone()
94                }
95            }
96        )*
97    };
98}
99
100#[cfg(feature = "alloc")]
101refcounted!(
102    T alloc::rc::Rc<T>,
103    T alloc::rc::Weak<T>,
104    T alloc::sync::Arc<T>,
105    T alloc::sync::Weak<T>,
106);
107
108macro_rules! function {
109    ($($args:ident),*) => {
110        impl<S: Speed, R, $($args),*> MirroredClone<S> for fn($($args),*) -> R {
111            #[inline]
112            fn mirrored_clone(&self) -> Self {
113                *self
114            }
115        }
116    };
117}
118
119macro_rules! pinned_refcounted {
120    ($($t:ident $refcounted:ty),* $(,)?) => {
121        $(
122            #[cfg(feature = "alloc")]
123            impl<S: Speed, $t: ?Sized> MirroredClone<S> for core::pin::Pin<$refcounted> {
124                #[inline]
125                fn mirrored_clone(&self) -> Self {
126                    self.clone()
127                }
128            }
129        )*
130    };
131}
132
133pinned_refcounted! {
134    T alloc::rc::Rc<T>,
135    T alloc::rc::Weak<T>,
136    T alloc::sync::Arc<T>,
137    T alloc::sync::Weak<T>,
138}
139
140function!();
141call_varargs_macro!(function);
142
143macro_rules! make_tuple_macro {
144    ($name:ident, $speed:ident, $dollar:tt) => {
145        macro_rules! $name {
146            ($dollar($dollar args:ident),+) => {
147                impl<$dollar($dollar args: MirroredClone<$speed>),+> MirroredClone<$speed>
148                for ($dollar($dollar args,)+)
149                {
150                    #[inline]
151                    fn mirrored_clone(&self) -> Self {
152                        #[expect(
153                            non_snake_case,
154                            reason = "using `Tn` as the variable of type `Tn`",
155                        )]
156                        let ($dollar($dollar args,)+) = self;
157                        (
158                            $dollar($dollar args.mirrored_clone(),)+
159                        )
160                    }
161                }
162            };
163        }
164    };
165}
166
167make_tuple_macro!(tuple_fast, Fast, $);
168make_tuple_macro!(tuple_slow, MaybeSlow, $);
169
170call_varargs_macro!(tuple_fast);
171call_varargs_macro!(tuple_slow);
172
173impl<S: Speed> MirroredClone<S> for core::convert::Infallible {
174    #[expect(
175        clippy::missing_inline_in_public_items,
176        clippy::uninhabited_references,
177        reason = "this is unreachable",
178    )]
179    fn mirrored_clone(&self) -> Self {
180        *self
181    }
182}