conjure_core/ast/
records.rs

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