1
use std::collections::VecDeque;
2

            
3
use super::Name;
4
use super::literals::AbstractLiteralValue;
5
use serde::{Deserialize, Serialize};
6

            
7
use polyquine::Quine;
8
use uniplate::{Biplate, Uniplate};
9

            
10
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash, Quine)]
11
#[path_prefix(conjure_cp::ast)]
12
pub 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

            
21
impl<T> Uniplate for RecordValue<T>
22
where
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)
54
impl<To, U> Biplate<To> for RecordValue<U>
55
where
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
}