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::{Speed, NearInstant, ConstantTime, LogTime, AnySpeed};
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///
21/// # Exceptions
22/// - A type implementing `MirroredClone` may specify that certain methods or accesses are not
23///   subject to these guarantees.
24/// - `Debug` should be assumed to be an exception. Intentionally worsening the life of someone
25///   debugging your type is not a goal.
26/// - Memory addresses which are different per-clone, but are not mutated by that clone (except
27///   when a user moves the value). Trivially, mirrored clones do not have the same address,
28///   and some of their data may be inlined into the type. If any reference to that data is exposed,
29///   a user would likely be able to determine what data is inlined into the type and what is
30///   inlined. That's already visible in the source code, anyway. Unless some semantically-important
31///   function of the type depends on the address of it or its data, it's unimportant.
32/// - TLDR of above bullet: users should not assume that references returned from different mirrored
33///   clones refer to the same value, only that those values *behave* the same.
34///
35/// [`Rc`]: std::rc::Rc
36/// [`Arc`]: std::sync::Arc
37pub trait MirroredClone<S: Speed>: Sized {
38    /// Get a clone that shares all semantically-important mutable state with its source.
39    ///
40    /// The goal is that mutating one mirrored clone affects every clone. Different mirrored clones
41    /// should, from their public interfaces, act identically, with some exceptions like memory
42    /// addresses.
43    ///
44    /// Read [`MirroredClone`] for more.
45    #[must_use]
46    fn mirrored_clone(&self) -> Self;
47}
48
49
50macro_rules! non_recursive_near_instant {
51    ($($({for $($bounds:tt)+})? $type:ty),* $(,)?) => {
52        $(
53            impl<$($($bounds)+)?> MirroredClone<NearInstant> for $type {
54                #[inline]
55                fn mirrored_clone(&self) -> Self {
56                    self.clone()
57                }
58            }
59        )*
60    };
61}
62
63non_recursive_near_instant! {
64    (),
65    core::convert::Infallible,
66    {for T} core::iter::Empty<T>,
67    {for T: ?Sized} core::marker::PhantomData<T>,
68    core::marker::PhantomPinned,
69    core::ops::RangeFull,
70}
71
72#[cfg(feature = "alloc")]
73macro_rules! refcounted {
74    ($($t:ident $refcounted:ty),* $(,)?) => {
75        $(
76            impl<S: Speed, $t: ?Sized> MirroredClone<S> for $refcounted {
77                #[inline]
78                fn mirrored_clone(&self) -> Self {
79                    self.clone()
80                }
81            }
82        )*
83    };
84}
85
86#[cfg(feature = "alloc")]
87refcounted!(
88    T alloc::rc::Rc<T>,
89    T alloc::rc::Weak<T>,
90    T alloc::sync::Arc<T>,
91    T alloc::sync::Weak<T>,
92);
93
94macro_rules! function {
95    ($($args:ident),*) => {
96        impl<R, $($args),*> MirroredClone<NearInstant> for fn($($args),*) -> R {
97            #[inline]
98            fn mirrored_clone(&self) -> Self {
99                *self
100            }
101        }
102    };
103}
104
105macro_rules! pinned_refcounted {
106    ($($t:ident $refcounted:ty),* $(,)?) => {
107        $(
108            #[cfg(feature = "alloc")]
109            impl<S: Speed, $t: ?Sized> MirroredClone<S> for core::pin::Pin<$refcounted> {
110                #[inline]
111                fn mirrored_clone(&self) -> Self {
112                    self.clone()
113                }
114            }
115        )*
116    };
117}
118
119pinned_refcounted! {
120    T alloc::rc::Rc<T>,
121    T alloc::rc::Weak<T>,
122    T alloc::sync::Arc<T>,
123    T alloc::sync::Weak<T>,
124}
125
126function!();
127call_varargs_macro!(function);
128
129macro_rules! make_tuple_macro {
130    ($name:ident, $speed:ident, $dollar:tt) => {
131        macro_rules! $name {
132            ($dollar($dollar args:ident),+) => {
133                impl<$dollar($dollar args: MirroredClone<$speed>),+> MirroredClone<$speed>
134                for ($dollar($dollar args,)+)
135                {
136                    #[inline]
137                    fn mirrored_clone(&self) -> Self {
138                        #[expect(
139                            non_snake_case,
140                            reason = "using `Tn` as the variable of type `Tn`",
141                        )]
142                        let ($dollar($dollar args,)+) = self;
143                        (
144                            $dollar($dollar args.mirrored_clone(),)+
145                        )
146                    }
147                }
148            };
149        }
150    };
151}
152
153make_tuple_macro!(tuple_constant, ConstantTime, $);
154make_tuple_macro!(tuple_log, LogTime, $);
155make_tuple_macro!(tuple_any, AnySpeed, $);
156
157call_varargs_macro!(tuple_constant);
158call_varargs_macro!(tuple_log);
159call_varargs_macro!(tuple_any);
160
161impl<S: Speed, T: MirroredClone<S>> MirroredClone<S> for Option<T> {
162    #[inline]
163    fn mirrored_clone(&self) -> Self {
164        self.as_ref().map(T::mirrored_clone)
165    }
166}
167
168impl<S: Speed, T: MirroredClone<S>, E: MirroredClone<S>> MirroredClone<S> for Result<T, E> {
169    #[inline]
170    fn mirrored_clone(&self) -> Self {
171        self.as_ref()
172            .map(T::mirrored_clone)
173            .map_err(E::mirrored_clone)
174    }
175}