Skip to main content

conjure_cp_core/ast/
records.rs

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