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}