Skip to main content

interact/util/
node_tree.rs

1use std::borrow::Cow;
2use std::io::Cursor;
3use std::io::Write;
4use std::ops::Deref;
5use std::sync::atomic::AtomicUsize;
6use std::sync::mpsc::Receiver;
7use std::sync::Arc;
8
9type Delimiter = char;
10
11#[derive(Debug)]
12pub enum NodeInfo {
13    Grouped(char, Box<NodeTree>, char),
14    Delimited(Delimiter, Vec<NodeTree>),
15    Named(Box<NodeTree>, Box<NodeTree>),
16    Tuple(Box<NodeTree>, &'static str, Box<NodeTree>),
17    Leaf(Cow<'static, str>),
18    Hole(Box<Receiver<NodeTree>>),
19    BorrowedMut,
20    Locked,
21    Repeated,
22    Limited,
23}
24
25pub type PtrMeta = Arc<AtomicUsize>;
26
27#[derive(Debug)]
28pub struct Wrap(pub PtrMeta);
29
30/// NodeTree represent a reflection of an Interact type that implemented the `Access` trait. It may
31/// be a partial reflection due to limits and indirections (see `Reflector`).
32#[derive(Debug)]
33pub struct NodeTree {
34    pub info: NodeInfo,
35    pub meta: Option<Wrap>,
36    pub size: usize,
37}
38
39impl NodeTree {
40    pub fn new(info: NodeInfo, meta: Option<Wrap>) -> Self {
41        Self {
42            info,
43            meta,
44            size: 0,
45        }
46    }
47}
48
49impl Eq for Wrap {}
50impl PartialEq for Wrap {
51    fn eq(&self, other: &Self) -> bool {
52        Arc::ptr_eq(&self.0, &other.0)
53    }
54}
55
56struct Printer {
57    accum: Cursor<Vec<u8>>,
58}
59
60impl Printer {
61    fn write(&mut self, s: &str) -> Result<(), std::io::Error> {
62        self.accum.write_all(s.as_bytes())?;
63        Ok(())
64    }
65}
66
67impl NodeInfo {
68    pub fn into_node(self) -> NodeTree {
69        NodeTree {
70            info: self,
71            meta: None,
72            size: 0,
73        }
74    }
75
76    pub fn with_meta(self, ptr_meta: PtrMeta) -> NodeTree {
77        NodeTree {
78            info: self,
79            meta: Some(Wrap(ptr_meta)),
80            size: 0,
81        }
82    }
83
84    pub fn named(name: &'static str, a_self: NodeTree) -> Self {
85        NodeInfo::Named(
86            Box::new(NodeTree {
87                info: NodeInfo::Leaf(Cow::Borrowed(name)),
88                meta: None,
89                size: 0,
90            }),
91            Box::new(a_self),
92        )
93    }
94
95    pub fn format(&self) -> Result<Vec<u8>, std::io::Error> {
96        let mut state = Printer {
97            accum: Cursor::new(Vec::new()),
98        };
99
100        self.inner_pretty_print(&mut state)?;
101
102        let Printer { accum, .. } = state;
103
104        Ok(accum.into_inner())
105    }
106
107    fn inner_pretty_print(&self, state: &mut Printer) -> Result<(), std::io::Error> {
108        use crate::NodeInfo::*;
109
110        match self {
111            Grouped(prefix, sub, end) => {
112                let space = match sub.deref().info {
113                    Delimited(_, ref v) if v.is_empty() => "",
114                    _ => " ",
115                };
116
117                state.write(&format!("{}{}", prefix, space))?;
118                sub.info.inner_pretty_print(state)?;
119                state.write(&format!("{}{}", space, end))?;
120            }
121            Delimited(delimiter, v) => {
122                for (idx, i) in v.iter().enumerate() {
123                    if idx > 0 {
124                        state.write(&format!("{} ", delimiter))?;
125                    }
126
127                    i.info.inner_pretty_print(state)?;
128                }
129            }
130            Tuple(key, sep, value) => {
131                key.info.inner_pretty_print(state)?;
132                state.write(&format!(" {} ", sep))?;
133                value.info.inner_pretty_print(state)?;
134            }
135            Named(item, next) => {
136                item.info.inner_pretty_print(state)?;
137                state.write(&" ")?;
138                next.info.inner_pretty_print(state)?;
139            }
140            Leaf(s) => {
141                state.write(s)?;
142            }
143            Hole(_) => {
144                state.write(&format!("<hole>"))?;
145            }
146            BorrowedMut => {
147                state.write(&format!("<borrowed-mut>"))?;
148            }
149            Locked => {
150                state.write(&format!("<locked>"))?;
151            }
152            Limited => {
153                state.write("...")?;
154            }
155            Repeated => {
156                state.write(&format!("<repeated>"))?;
157            }
158        };
159
160        Ok(())
161    }
162}
163
164impl NodeTree {
165    pub fn resolve(&mut self) -> usize {
166        use crate::NodeInfo::*;
167
168        loop {
169            let mut count = 1;
170
171            let r = match &mut self.info {
172                Grouped(_, sub, _) => {
173                    count += 2 + sub.resolve();
174                    None
175                }
176                Delimited(_, v) => {
177                    for i in v.iter_mut() {
178                        count += i.resolve() + 2;
179                    }
180                    None
181                }
182                Tuple(key, sep, value) => {
183                    count += key.resolve();
184                    count += sep.len() + 2;
185                    count += value.resolve();
186                    None
187                }
188                Named(item, next) => {
189                    count += item.resolve();
190                    count += next.resolve();
191                    None
192                }
193                Leaf(v) => {
194                    count += v.len();
195                    None
196                }
197                Hole(receiver) => Some((*receiver).recv().unwrap()),
198                Limited => None,
199                Repeated => None,
200                BorrowedMut => None,
201                Locked => None,
202            };
203
204            if let Some(r) = r {
205                *self = r;
206                continue;
207            }
208
209            self.size = count;
210
211            return count;
212        }
213    }
214}
215
216use std::fmt;
217
218impl fmt::Display for NodeInfo {
219    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
220        let v = self.format().unwrap();
221
222        write!(f, "{}", String::from_utf8_lossy(v.as_slice()))
223    }
224}