conjure_cp_core/ast/
moo.rs

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
13use std::{collections::VecDeque, fmt::Display, ops::Deref, sync::Arc};
14
15use serde::{Deserialize, Serialize};
16use uniplate::{
17    Biplate, Tree, Uniplate,
18    impl_helpers::{transmute_if_same_type, try_transmute_if_same_type},
19    spez::try_biplate_to,
20};
21
22/// A clone-on-write, reference counted pointer to an AST type.
23///
24/// Cloning values of this type will not clone the underlying value until it is modified, e.g.,
25/// with [`Moo::make_mut`].
26///
27/// Unlike `Rc` and `Arc`, trait implementations on this type do not need to preserve shared
28/// ownership - that is, two pointers that used to point to the same value may not do so after
29/// calling a trait method on them. In particular, calling Uniplate methods may cause a
30/// clone-on-write to occur.
31///
32/// **Note:** like Box` and `Rc`, methods on `Moo` are all associated functions, which means you
33/// have to call them as, e.g. `Moo::make_mut(&value)` instead of `value.make_mut()`. This is so
34/// that there are no conflicts with the inner type `T`, which this type dereferences to.
35#[derive(PartialEq, Eq, Clone, Debug)]
36pub struct Moo<T> {
37    inner: Arc<T>,
38}
39
40impl<T> Moo<T> {
41    /// Constructs a new `Moo<T>`.
42    pub fn new(value: T) -> Moo<T> {
43        Moo {
44            inner: Arc::new(value),
45        }
46    }
47}
48
49impl<T: Clone> Moo<T> {
50    /// Makes a mutable reference into the given `Moo`.
51    ///
52    /// If there are other `Moo` pointers to the same allocation, then `make_mut` will `clone` the
53    /// inner value to a new allocation to ensure unique ownership. This is also referred to as
54    /// clone-on-write.
55    pub fn make_mut(this: &mut Moo<T>) -> &mut T {
56        Arc::make_mut(&mut this.inner)
57    }
58
59    /// If we have the only reference to T then unwrap it. Otherwise, clone T and return the clone.
60    ///
61    /// Assuming moo_t is of type `Moo<T>`, this function is functionally equivalent to
62    /// `(*moo_t).clone()`, but will avoid cloning the inner value where possible.
63    pub fn unwrap_or_clone(this: Moo<T>) -> T {
64        Arc::unwrap_or_clone(this.inner)
65    }
66}
67
68impl<T> AsRef<T> for Moo<T> {
69    fn as_ref(&self) -> &T {
70        self.inner.as_ref()
71    }
72}
73
74impl<T> Deref for Moo<T> {
75    type Target = T;
76
77    fn deref(&self) -> &Self::Target {
78        self.inner.deref()
79    }
80}
81
82impl<T> Uniplate for Moo<T>
83where
84    T: Uniplate,
85{
86    fn uniplate(
87        &self,
88    ) -> (
89        uniplate::Tree<Self>,
90        Box<dyn Fn(uniplate::Tree<Self>) -> Self>,
91    ) {
92        let this = Moo::clone(self);
93
94        // do not need to preserve shared ownership, so treat this identically to values of the
95        // inner type.
96        let (tree, ctx) = try_biplate_to!((**self).clone(), Moo<T>);
97        (
98            Tree::Many(VecDeque::from([tree.clone()])),
99            Box::new(move |x| {
100                let Tree::Many(trees) = x else { panic!() };
101                let new_tree = trees.into_iter().next().unwrap();
102                let mut this = Moo::clone(&this);
103
104                // Only update the pointer with the new value if the value has changed. Without
105                // this check, writing to the pointer might trigger a clone on write, even
106                // though the value inside the pointer remained the same.
107                if new_tree != tree {
108                    let this = Moo::make_mut(&mut this);
109                    *this = ctx(new_tree)
110                }
111
112                this
113            }),
114        )
115    }
116}
117
118impl<To, U> Biplate<To> for Moo<U>
119where
120    To: Uniplate,
121    U: Uniplate + Biplate<To>,
122{
123    fn biplate(&self) -> (Tree<To>, Box<dyn Fn(Tree<To>) -> Self>) {
124        if let Some(self_as_to) = transmute_if_same_type::<Self, To>(self) {
125            // To = Self -> return self
126            let tree = Tree::One(self_as_to.clone());
127            let ctx = Box::new(move |x| {
128                let Tree::One(self_as_to) = x else { panic!() };
129
130                let self_as_self = try_transmute_if_same_type::<To, Self>(&self_as_to);
131
132                Moo::clone(self_as_self)
133            });
134
135            (tree, ctx)
136        } else {
137            // To != Self -> return children of type To
138
139            let this = Moo::clone(self);
140
141            // Do not need to preserve shared ownership, so treat this identically to values of the
142            // inner type.
143            let (tree, ctx) = try_biplate_to!((**self).clone(), To);
144            (
145                Tree::Many(VecDeque::from([tree.clone()])),
146                Box::new(move |x| {
147                    let Tree::Many(trees) = x else { panic!() };
148                    let new_tree = trees.into_iter().next().unwrap();
149                    let mut this = Moo::clone(&this);
150
151                    // Only update the pointer with the new value if the value has changed. Without
152                    // this check, writing to the pointer might trigger a clone on write, even
153                    // though the value inside the pointer remained the same.
154                    if new_tree != tree {
155                        let this = Moo::make_mut(&mut this);
156                        *this = ctx(new_tree)
157                    }
158
159                    this
160                }),
161            )
162        }
163    }
164}
165
166impl<'de, T: Deserialize<'de>> Deserialize<'de> for Moo<T> {
167    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
168    where
169        D: serde::Deserializer<'de>,
170    {
171        Ok(Moo::new(T::deserialize(deserializer)?))
172    }
173}
174
175impl<T: Serialize> Serialize for Moo<T> {
176    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
177    where
178        S: serde::Serializer,
179    {
180        T::serialize(&**self, serializer)
181    }
182}
183
184impl<T: Display> Display for Moo<T> {
185    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186        (**self).fmt(f)
187    }
188}