conjure_cp_core/ast/
records.rs

1use std::collections::VecDeque;
2
3use super::Name;
4use super::literals::AbstractLiteralValue;
5use serde::{Deserialize, Serialize};
6
7use polyquine::Quine;
8use uniplate::{Biplate, Uniplate};
9
10#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash, Quine)]
11#[path_prefix(conjure_cp::ast)]
12pub struct RecordValue<T: AbstractLiteralValue> {
13    pub name: Name,
14    pub value: T,
15}
16
17// Uniplate instance copy and pasted from cargo expand
18
19// derive macro doesn't work as this has a generic type (for the same reasons as AbstractLiteral) ~nd60
20
21impl<T> Uniplate for RecordValue<T>
22where
23    T: AbstractLiteralValue,
24{
25    fn uniplate(
26        &self,
27    ) -> (
28        ::uniplate::Tree<RecordValue<T>>,
29        Box<dyn Fn(::uniplate::Tree<RecordValue<T>>) -> RecordValue<T>>,
30    ) {
31        let _name_copy = self.name.clone();
32        let (tree_value, ctx_value) = <T as Biplate<RecordValue<T>>>::biplate(&self.value);
33        let children = ::uniplate::Tree::Many(::std::collections::VecDeque::from([
34            tree_value,
35            ::uniplate::Tree::Zero,
36        ]));
37        let ctx = Box::new(move |x: ::uniplate::Tree<RecordValue<T>>| {
38            let ::uniplate::Tree::Many(xs) = x else {
39                panic!()
40            };
41            let tree_value = xs[0].clone();
42            let value = ctx_value(tree_value);
43            RecordValue {
44                name: _name_copy.clone(),
45                value,
46            }
47        });
48        (children, ctx)
49    }
50}
51
52// want to be able to go anywhere U can go
53// (I'll follow U wherever U will go)
54impl<To, U> Biplate<To> for RecordValue<U>
55where
56    U: AbstractLiteralValue + Biplate<To>,
57    To: Uniplate,
58{
59    fn biplate(&self) -> (uniplate::Tree<To>, Box<dyn Fn(uniplate::Tree<To>) -> Self>) {
60        use uniplate::Tree;
61
62        if std::any::TypeId::of::<To>() == std::any::TypeId::of::<RecordValue<U>>() {
63            // To ==From => return One(self)
64
65            unsafe {
66                // SAFETY: asserted the type equality above
67                let self_to = std::mem::transmute::<&RecordValue<U>, &To>(self).clone();
68                let tree = Tree::One(self_to);
69                let ctx = Box::new(move |x| {
70                    let Tree::One(x) = x else {
71                        panic!();
72                    };
73
74                    std::mem::transmute::<&To, &RecordValue<U>>(&x).clone()
75                });
76
77                (tree, ctx)
78            }
79        } else if std::any::TypeId::of::<To>() == std::any::TypeId::of::<Name>() {
80            // return name field, as well as any names inside the value
81            let self2: RecordValue<U> = self.clone();
82            let f_name: Name = self2.name;
83            let f_val: U = self2.value;
84
85            let (tree_val, ctx_val) = <U as Biplate<To>>::biplate(&f_val);
86
87            unsafe {
88                // SAFETY: asserted previously that To == Name
89                let f_name_to = std::mem::transmute::<&Name, &To>(&f_name).clone();
90                let tree_name = Tree::One(f_name_to);
91                let tree = Tree::Many(VecDeque::from([tree_name, tree_val]));
92
93                let ctx = Box::new(move |x| {
94                    // deconstruct tree into tree_name and tree_val
95                    let Tree::Many(xs) = x else {
96                        panic!();
97                    };
98
99                    let tree_name = xs[0].clone();
100                    let tree_val = xs[1].clone();
101
102                    let Tree::One(name) = tree_name else {
103                        panic!();
104                    };
105
106                    // SAFETY: asserted previously that To == Name
107                    let name = std::mem::transmute::<&To, &Name>(&name).clone();
108                    let value = ctx_val(tree_val);
109
110                    // reconstruct things
111                    RecordValue { name, value }
112                });
113
114                (tree, ctx)
115            }
116        } else {
117            // walk into To ignoring name field, as Name can only biplate into Name
118
119            let self2: RecordValue<U> = self.clone();
120            let f_name: Name = self2.name;
121            let f_val: U = self2.value;
122
123            let (tree_val, ctx_val) = <U as Biplate<To>>::biplate(&f_val);
124
125            let tree = Tree::Many(VecDeque::from([tree_val]));
126
127            let ctx = Box::new(move |x| {
128                // deconstruct tree into tree_name and tree_val
129                let Tree::Many(xs) = x else {
130                    panic!();
131                };
132
133                let tree_val = xs[0].clone();
134
135                // reconstruct things
136                RecordValue {
137                    name: f_name.clone(),
138                    value: ctx_val(tree_val),
139                }
140            });
141
142            (tree, ctx)
143        }
144    }
145}