interact/
reflector.rs

1use std::collections::hash_map::Entry;
2use std::collections::HashMap;
3use std::sync::atomic::{AtomicUsize, Ordering};
4use std::sync::mpsc::channel;
5use std::sync::{Arc, Mutex};
6use std::thread::ThreadId;
7
8use crate::access::vec::ReflectVec;
9use crate::access::{
10    derive::{ReflectStruct, Struct, StructKind},
11    iter::ReflectIter,
12    Access,
13};
14use crate::node_tree::{NodeInfo, NodeTree, PtrMeta, Wrap};
15
16type ObjPtr = (usize, usize);
17
18/// `Reflector` operates on types implementing `Access`. Some of its methods are being called
19/// automatically from `#[derive(Interact)]` impls. It provides a thread-safe context, because on
20/// the extreme case, where it is possible that reflection is done via indirection using multiple
21/// process threads (see `ReflectIndirect`).
22pub struct Reflector {
23    limit: usize,
24    used: AtomicUsize,
25
26    seen: Mutex<HashMap<ObjPtr, PtrMeta>>,
27    synced_thread: ThreadId,
28}
29
30impl Reflector {
31    pub fn new(limit: usize) -> Arc<Self> {
32        Arc::new(Self {
33            limit,
34            used: AtomicUsize::new(0),
35            seen: Mutex::new(HashMap::new()),
36            synced_thread: std::thread::current().id(),
37        })
38    }
39
40    pub fn reflect_struct(
41        a_self: &Arc<Self>,
42        desc: &Struct,
43        p_struct: &dyn ReflectStruct,
44        anon: bool,
45    ) -> NodeTree {
46        let meta = try_seen_dyn!(p_struct, a_self);
47
48        match &desc.kind {
49            StructKind::Unit => {
50                NodeInfo::Leaf(std::borrow::Cow::Borrowed(desc.name)).with_meta(meta)
51            }
52            StructKind::Tuple(n) => {
53                let mut v = vec![];
54
55                for i in 0..*n {
56                    if a_self.limit <= a_self.used.load(Ordering::Relaxed) {
57                        v.push(NodeInfo::Limited.into_node());
58                        break;
59                    }
60
61                    let reflect_node = Self::reflect(a_self, p_struct.get_field_by_idx(i).unwrap());
62                    v.push(reflect_node);
63                }
64
65                let grouped =
66                    NodeInfo::Grouped('(', Box::new(NodeInfo::Delimited(',', v).into_node()), ')');
67
68                let elem = if !desc.name.is_empty() && !anon {
69                    NodeInfo::named(desc.name, grouped.into_node())
70                } else {
71                    grouped
72                };
73
74                elem.with_meta(meta)
75            }
76            StructKind::Fields(fields) => {
77                let mut result = vec![];
78                let mut items = vec![];
79                let mut missing_keys = false;
80
81                for field in *fields {
82                    if a_self.limit <= a_self.used.load(Ordering::Relaxed) {
83                        missing_keys = true;
84                        break;
85                    }
86
87                    a_self.used.fetch_add(1, Ordering::SeqCst);
88                    items.push((field, p_struct.get_field_by_name(field).unwrap()));
89                }
90
91                for (key, value) in items.into_iter() {
92                    let node = {
93                        if a_self.limit <= a_self.used.load(Ordering::Relaxed) {
94                            NodeInfo::Limited.into_node()
95                        } else {
96                            Self::reflect(a_self, value)
97                        }
98                    };
99
100                    result.push(
101                        NodeInfo::Tuple(
102                            Box::new(NodeInfo::Leaf(std::borrow::Cow::Borrowed(key)).into_node()),
103                            ":",
104                            Box::new(node),
105                        )
106                        .into_node(),
107                    )
108                }
109
110                if missing_keys {
111                    result.push(NodeInfo::Limited.into_node());
112                }
113
114                let grouped = NodeInfo::Grouped(
115                    '{',
116                    Box::new(NodeInfo::Delimited(',', result).into_node()),
117                    '}',
118                );
119
120                let elem = if !desc.name.is_empty() && !anon {
121                    NodeInfo::named(desc.name, grouped.into_node())
122                } else {
123                    grouped
124                };
125
126                elem.with_meta(meta)
127            }
128        }
129    }
130
131    pub fn reflect_map(
132        a_self: &Arc<Self>,
133        iter: &mut dyn ReflectIter<(&dyn Access, &dyn Access)>,
134        name: &'static str,
135    ) -> NodeTree {
136        let meta = try_seen_dyn!(iter, a_self);
137
138        let mut result = vec![];
139        let mut items = vec![];
140        let mut missing_keys = false;
141
142        while let Some((key, value)) = iter.reflect_next() {
143            if a_self.limit <= a_self.used.load(Ordering::Relaxed) {
144                missing_keys = true;
145                break;
146            }
147
148            a_self.used.fetch_add(1, Ordering::SeqCst);
149            items.push((Self::reflect(a_self, key), value));
150        }
151
152        for (key, value) in items.into_iter() {
153            let node = {
154                if a_self.limit <= a_self.used.load(Ordering::Relaxed) {
155                    NodeInfo::Limited.into_node()
156                } else {
157                    Self::reflect(a_self, value)
158                }
159            };
160
161            let reflect_node = NodeInfo::Tuple(Box::new(key), ":", Box::new(node));
162            result.push(reflect_node.into_node());
163        }
164
165        if missing_keys {
166            result.push(NodeInfo::Limited.into_node());
167        }
168
169        NodeInfo::named(
170            name,
171            NodeInfo::Grouped(
172                '{',
173                Box::new(NodeInfo::Delimited(',', result).into_node()),
174                '}',
175            )
176            .into_node(),
177        )
178        .with_meta(meta)
179    }
180
181    pub fn reflect_set(
182        a_self: &Arc<Self>,
183        iter: &mut dyn ReflectIter<&dyn Access>,
184        name: &'static str,
185    ) -> NodeTree {
186        let mut v = vec![];
187        let meta = try_seen_dyn!(iter, a_self);
188
189        while let Some(member) = iter.reflect_next() {
190            if a_self.limit <= a_self.used.load(Ordering::Relaxed) {
191                v.push(NodeInfo::Limited.into_node());
192                break;
193            }
194
195            let member = Self::reflect(a_self, member);
196            v.push(member);
197        }
198
199        NodeInfo::named(
200            name,
201            NodeInfo::Grouped('{', Box::new(NodeInfo::Delimited(',', v).into_node()), '}')
202                .into_node(),
203        )
204        .with_meta(meta)
205    }
206
207    pub fn reflect_vec(a_self: &Arc<Self>, vec: &dyn ReflectVec, name: &'static str) -> NodeTree {
208        let mut v = vec![];
209
210        let meta = try_seen_dyn!(vec, a_self);
211
212        for i in 0..vec.get_len() {
213            if a_self.limit <= a_self.used.load(Ordering::Relaxed) {
214                v.push(NodeInfo::Limited.into_node());
215                break;
216            }
217
218            let reflect_node = Self::reflect(a_self, vec.get_item(i).unwrap());
219            v.push(reflect_node);
220        }
221
222        let item = NodeInfo::Grouped('[', Box::new(NodeInfo::Delimited(',', v).into_node()), ']');
223
224        let item = if !name.is_empty() {
225            NodeInfo::named(name, item.into_node())
226        } else {
227            item
228        };
229
230        item.with_meta(meta)
231    }
232
233    pub fn seen_ptr(a_self: &Arc<Self>, obj_ptr: ObjPtr) -> Result<NodeTree, PtrMeta> {
234        let mut seen = a_self.seen.lock().unwrap();
235        match seen.entry(obj_ptr) {
236            Entry::Occupied(entry) => {
237                let entry = entry.get();
238                entry.fetch_add(1, Ordering::SeqCst);
239
240                Ok(NodeTree::new(NodeInfo::Repeated, Some(Wrap(entry.clone()))))
241            }
242            Entry::Vacant(entry) => {
243                let meta = Arc::new(AtomicUsize::new(1));
244                entry.insert(meta.clone());
245                Err(meta)
246            }
247        }
248    }
249
250    pub fn reflect(a_self: &Arc<Self>, access: &dyn Access) -> NodeTree {
251        use crate::Reflect::*;
252
253        let immut_access = access.immut_access();
254
255        let reflect_node = match immut_access.reflect {
256            Direct(v) => v.immut_reflector(a_self),
257            Indirect(access) => {
258                let (sender, receiver) = channel();
259                let b_self = a_self.clone();
260
261                access.indirect(Box::new(move |access| {
262                    let res = Self::reflect(&b_self, access);
263                    let _ = sender.send(res);
264                }));
265
266                if a_self.synced_thread == std::thread::current().id() {
267                    receiver.recv().unwrap()
268                } else {
269                    NodeInfo::Hole(Box::new(receiver)).into_node()
270                }
271            }
272        };
273
274        a_self.used.fetch_add(1, Ordering::SeqCst);
275        reflect_node
276    }
277}