1
// NOTE
2
//
3
// we use a wrapper type over Arc, instead of just using Arc, so that we can implement traits on it
4
// (e.g. Uniplate, Serialize).
5
//
6
// As we are just using Arc for copy on write, not shared ownership, it is safe to break shared
7
// ownership in Moo's Uniplate implementation, by calling Arc::make_mut and Arc::new on modified
8
// values. In general, this is not safe for all Rc/Arc types, e.g. those that use Cell / RefCell
9
// internally.
10
//
11
// ~niklasdewally 13/08/25
12

            
13
use funcmap::{FuncMap, TryFuncMap};
14
use polyquine::Quine;
15
use proc_macro2::TokenStream;
16
use serde::{Deserialize, Deserializer, Serialize, Serializer};
17
use serde_with::de::DeserializeAsWrap;
18
use serde_with::ser::SerializeAsWrap;
19
use serde_with::{DeserializeAs, SerializeAs};
20
use std::hash::{Hash, Hasher};
21
use std::ops::DerefMut;
22
use std::{collections::VecDeque, fmt::Display, ops::Deref, sync::Arc};
23
use uniplate::{
24
    Biplate, Tree, Uniplate,
25
    impl_helpers::{transmute_if_same_type, try_transmute_if_same_type},
26
    spez::try_biplate_to,
27
};
28

            
29
/// A clone-on-write, reference counted pointer to an AST type.
30
///
31
/// Cloning values of this type will not clone the underlying value until it is modified, e.g.,
32
/// with [`Moo::make_mut`].
33
///
34
/// Unlike `Rc` and `Arc`, trait implementations on this type do not need to preserve shared
35
/// ownership - that is, two pointers that used to point to the same value may not do so after
36
/// calling a trait method on them. In particular, calling Uniplate methods may cause a
37
/// clone-on-write to occur.
38
///
39
/// **Note:** like Box` and `Rc`, methods on `Moo` are all associated functions, which means you
40
/// have to call them as, e.g. `Moo::make_mut(&value)` instead of `value.make_mut()`. This is so
41
/// that there are no conflicts with the inner type `T`, which this type dereferences to.
42
#[derive(PartialEq, Eq, Clone, Debug)]
43
pub struct Moo<T> {
44
    inner: Arc<T>,
45
}
46

            
47
impl<T: Quine> Quine for Moo<T> {
48
3841
    fn ctor_tokens(&self) -> TokenStream {
49
3841
        let inner = self.inner.as_ref().ctor_tokens();
50
3841
        quote::quote! { ::conjure_cp::ast::Moo::new(#inner) }
51
3841
    }
52
}
53

            
54
impl<T> Moo<T> {
55
    /// Constructs a new `Moo<T>`.
56
4186664803
    pub fn new(value: T) -> Moo<T> {
57
4186664803
        Moo {
58
4186664803
            inner: Arc::new(value),
59
4186664803
        }
60
4186664803
    }
61
}
62

            
63
impl<T: Clone> Moo<T> {
64
    /// Makes a mutable reference into the given `Moo`.
65
    ///
66
    /// If there are other `Moo` pointers to the same allocation, then `make_mut` will `clone` the
67
    /// inner value to a new allocation to ensure unique ownership. This is also referred to as
68
    /// clone-on-write.
69
163417204
    pub fn make_mut(this: &mut Moo<T>) -> &mut T {
70
163417204
        Arc::make_mut(&mut this.inner)
71
163417204
    }
72

            
73
    /// If we have the only reference to T then unwrap it. Otherwise, clone T and return the clone.
74
    ///
75
    /// Assuming moo_t is of type `Moo<T>`, this function is functionally equivalent to
76
    /// `(*moo_t).clone()`, but will avoid cloning the inner value where possible.
77
61104133
    pub fn unwrap_or_clone(this: Moo<T>) -> T {
78
61104133
        Arc::unwrap_or_clone(this.inner)
79
61104133
    }
80
}
81

            
82
impl<T> AsRef<T> for Moo<T> {
83
42516099664
    fn as_ref(&self) -> &T {
84
42516099664
        self.inner.as_ref()
85
42516099664
    }
86
}
87

            
88
impl<T> Deref for Moo<T> {
89
    type Target = T;
90

            
91
24079614949
    fn deref(&self) -> &Self::Target {
92
24079614949
        self.inner.deref()
93
24079614949
    }
94
}
95

            
96
impl<T: Clone> DerefMut for Moo<T> {
97
1075
    fn deref_mut(&mut self) -> &mut Self::Target {
98
1075
        Moo::make_mut(self)
99
1075
    }
100
}
101

            
102
impl<T> Uniplate for Moo<T>
103
where
104
    T: Uniplate,
105
{
106
    fn uniplate(
107
        &self,
108
    ) -> (
109
        uniplate::Tree<Self>,
110
        Box<dyn Fn(uniplate::Tree<Self>) -> Self>,
111
    ) {
112
        let this = Moo::clone(self);
113

            
114
        // do not need to preserve shared ownership, so treat this identically to values of the
115
        // inner type.
116
        let (tree, ctx) = try_biplate_to!((**self).clone(), Moo<T>);
117
        (
118
            Tree::Many(VecDeque::from([tree.clone()])),
119
            Box::new(move |x| {
120
                let Tree::Many(trees) = x else { panic!() };
121
                let new_tree = trees.into_iter().next().unwrap();
122
                let mut this = Moo::clone(&this);
123

            
124
                // Only update the pointer with the new value if the value has changed. Without
125
                // this check, writing to the pointer might trigger a clone on write, even
126
                // though the value inside the pointer remained the same.
127
                if new_tree != tree {
128
                    let this = Moo::make_mut(&mut this);
129
                    *this = ctx(new_tree)
130
                }
131

            
132
                this
133
            }),
134
        )
135
    }
136
}
137

            
138
impl<To, U> Biplate<To> for Moo<U>
139
where
140
    To: Uniplate,
141
    U: Uniplate + Biplate<To>,
142
{
143
5186988969
    fn biplate(&self) -> (Tree<To>, Box<dyn Fn(Tree<To>) -> Self>) {
144
5186988969
        if let Some(self_as_to) = transmute_if_same_type::<Self, To>(self) {
145
            // To = Self -> return self
146
            let tree = Tree::One(self_as_to.clone());
147
            let ctx = Box::new(move |x| {
148
                let Tree::One(self_as_to) = x else { panic!() };
149

            
150
                let self_as_self = try_transmute_if_same_type::<To, Self>(&self_as_to);
151

            
152
                Moo::clone(self_as_self)
153
            });
154

            
155
            (tree, ctx)
156
        } else {
157
            // To != Self -> return children of type To
158

            
159
5186988969
            let this = Moo::clone(self);
160

            
161
            // Do not need to preserve shared ownership, so treat this identically to values of the
162
            // inner type.
163
5186988969
            let (tree, ctx) = try_biplate_to!((**self).clone(), To);
164
            (
165
5186988969
                Tree::Many(VecDeque::from([tree.clone()])),
166
5186988969
                Box::new(move |x| {
167
413760044
                    let Tree::Many(trees) = x else { panic!() };
168
413760044
                    let new_tree = trees.into_iter().next().unwrap();
169
413760044
                    let mut this = Moo::clone(&this);
170

            
171
                    // Only update the pointer with the new value if the value has changed. Without
172
                    // this check, writing to the pointer might trigger a clone on write, even
173
                    // though the value inside the pointer remained the same.
174
413760044
                    if new_tree != tree {
175
145515370
                        let this = Moo::make_mut(&mut this);
176
145515370
                        *this = ctx(new_tree)
177
268244674
                    }
178

            
179
413760044
                    this
180
413760044
                }),
181
            )
182
        }
183
5186988969
    }
184

            
185
    /// Counts children through the pointer, without cloning the pointee.
186
    ///
187
    /// The default implementation materialises `children_bi`, which goes via [`Biplate::biplate`]
188
    /// and therefore clones the whole inner value. Payload syncs call this once per tree level, so
189
    /// the default turns a single rewrite under a wide node (e.g. `or` over a large matrix) into
190
    /// O(n) work, and a full rewrite pass into O(n^2).
191
927993958
    fn children_bi_count(&self) -> usize {
192
927993958
        if std::any::TypeId::of::<Self>() == std::any::TypeId::of::<To>() {
193
            // Biplate<T> for T treats the value as its only child.
194
            return 1;
195
927993958
        }
196
927993958
        <U as Biplate<To>>::children_bi_count(&**self)
197
927993958
    }
198

            
199
    /// Replaces a child through the pointer, cloning the pointee only when it is shared.
200
    ///
201
    /// Mirrors [`Biplate::children_bi_count`] above: the default implementation clones the inner
202
    /// value twice (once to list children, once to rebuild) and structurally compares the old and
203
    /// new trees.
204
733637419
    fn try_replace_child_at_bi(&mut self, index: usize, child: To) -> bool {
205
733637419
        if std::any::TypeId::of::<Self>() == std::any::TypeId::of::<To>() {
206
            if index != 0 {
207
                return false;
208
            }
209
            // SAFETY: TypeId equality means `Self` and `To` are the same type.
210
            unsafe {
211
                let child_as_self = std::mem::transmute_copy::<To, Self>(&child);
212
                std::mem::forget(child);
213
                *self = child_as_self;
214
            }
215
            return true;
216
733637419
        }
217
733637419
        if std::any::TypeId::of::<U>() == std::any::TypeId::of::<To>() {
218
733343794
            if index != 0 {
219
1
                return false;
220
733343793
            }
221
            // The child is the whole pointee, not a child inside it. Replace the pointer
222
            // directly: make_mut would clone the old shared value only to discard it.
223
            // SAFETY: TypeId equality means U and To are the same type.
224
733343793
            let value = unsafe { std::mem::transmute_copy::<To, U>(&child) };
225
733343793
            std::mem::forget(child);
226
733343793
            *self = Moo::new(value);
227
733343793
            return true;
228
293625
        }
229
293625
        <U as Biplate<To>>::try_replace_child_at_bi(Moo::make_mut(self), index, child)
230
733637419
    }
231
}
232

            
233
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Moo<T> {
234
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
235
    where
236
        D: serde::Deserializer<'de>,
237
    {
238
        Ok(Moo::new(T::deserialize(deserializer)?))
239
    }
240
}
241

            
242
impl<T: Serialize> Serialize for Moo<T> {
243
3382
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
244
3382
    where
245
3382
        S: serde::Serializer,
246
    {
247
3382
        T::serialize(&**self, serializer)
248
3382
    }
249
}
250

            
251
impl<T: Display> Display for Moo<T> {
252
73019343
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
253
73019343
        (**self).fmt(f)
254
73019343
    }
255
}
256

            
257
impl<T: Hash> Hash for Moo<T> {
258
6115599671
    fn hash<H: Hasher>(&self, state: &mut H) {
259
6115599671
        (**self).hash(state);
260
6115599671
    }
261
}
262

            
263
impl<T> From<T> for Moo<T> {
264
188259
    fn from(value: T) -> Self {
265
188259
        Moo::new(value)
266
188259
    }
267
}
268

            
269
impl<A, B> FuncMap<A, B> for Moo<A>
270
where
271
    A: Clone,
272
{
273
    type Output = Moo<B>;
274

            
275
2653919
    fn func_map<F>(self, mut f: F) -> Self::Output
276
2653919
    where
277
2653919
        F: FnMut(A) -> B,
278
    {
279
2653919
        let inner = Moo::unwrap_or_clone(self);
280
2653919
        Moo::new(f(inner))
281
2653919
    }
282
}
283

            
284
impl<A, B> TryFuncMap<A, B> for Moo<A>
285
where
286
    A: Clone,
287
{
288
    type Output = Moo<B>;
289

            
290
13388210
    fn try_func_map<E, F>(self, mut f: F) -> Result<Self::Output, E>
291
13388210
    where
292
13388210
        F: FnMut(A) -> Result<B, E>,
293
    {
294
13388210
        let inner = Moo::unwrap_or_clone(self);
295
13388210
        let res = f(inner)?;
296
13377290
        Ok(Moo::new(res))
297
13388210
    }
298
}
299

            
300
impl<T, As> SerializeAs<Moo<T>> for Moo<As>
301
where
302
    As: SerializeAs<T>,
303
{
304
    fn serialize_as<S>(source: &Moo<T>, serializer: S) -> Result<S::Ok, S::Error>
305
    where
306
        S: Serializer,
307
    {
308
        let wrap = SerializeAsWrap::<T, As>::new(&**source);
309
        wrap.serialize(serializer)
310
    }
311
}
312

            
313
impl<'de, T, As> DeserializeAs<'de, Moo<T>> for Moo<As>
314
where
315
    As: DeserializeAs<'de, T>,
316
{
317
    fn deserialize_as<D>(deserializer: D) -> Result<Moo<T>, D::Error>
318
    where
319
        D: Deserializer<'de>,
320
    {
321
        let wrap = DeserializeAsWrap::<T, As>::deserialize(deserializer)?;
322
        Ok(Moo::new(wrap.into_inner()))
323
    }
324
}
325

            
326
#[cfg(test)]
327
mod replacement_tests {
328
    use super::*;
329
    use std::sync::atomic::{AtomicUsize, Ordering};
330

            
331
    static CLONES: AtomicUsize = AtomicUsize::new(0);
332

            
333
    #[derive(Debug, PartialEq, Eq)]
334
    struct CloneProbe(i32);
335

            
336
    impl Clone for CloneProbe {
337
        fn clone(&self) -> Self {
338
            CLONES.fetch_add(1, Ordering::Relaxed);
339
            Self(self.0)
340
        }
341
    }
342

            
343
    impl Uniplate for CloneProbe {
344
        fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
345
            let value = self.0;
346
            (Tree::Zero, Box::new(move |_| Self(value)))
347
        }
348
    }
349

            
350
    impl Biplate<CloneProbe> for CloneProbe {
351
        fn biplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
352
            (
353
                Tree::One(self.clone()),
354
                Box::new(|tree| {
355
                    let Tree::One(value) = tree else {
356
                        panic!("expected one child")
357
                    };
358
                    value
359
                }),
360
            )
361
        }
362
    }
363

            
364
    #[test]
365
1
    fn replacing_shared_pointee_does_not_clone_the_discarded_value() {
366
1
        let mut value = Moo::new(CloneProbe(1));
367
1
        let shared = value.clone();
368
1
        CLONES.store(0, Ordering::Relaxed);
369
1
        assert!(!value.try_replace_child_at_bi(1, CloneProbe(2)));
370
1
        assert_eq!(value.0, 1);
371
1
        assert!(value.try_replace_child_at_bi(0, CloneProbe(2)));
372
1
        assert_eq!(value.0, 2);
373
1
        assert_eq!(shared.0, 1);
374
1
        assert_eq!(CLONES.load(Ordering::Relaxed), 0);
375
1
    }
376
}