Skip to main content

planus_buffer_inspection/
object_mapping.rs

1use std::borrow::Cow;
2
3use indexmap::IndexMap;
4use planus_types::intermediate::{DeclarationIndex, DeclarationKind};
5
6use crate::{
7    children::{Byterange, Children},
8    object_info::ObjectName,
9    ByteIndex, InspectableFlatbuffer, Object, OffsetObject, OffsetObjectKind,
10};
11
12pub type ObjectIndex = usize;
13pub type LineIndex = usize;
14
15pub struct ObjectMapping<'a> {
16    pub root_object: Object<'a>,
17    pub root_objects: IndexMap<Object<'a>, (ByteIndex, ByteIndex)>,
18    pub root_intervals: rust_lapper::Lapper<ByteIndex, ObjectIndex>,
19}
20
21impl<'a> InspectableFlatbuffer<'a> {
22    pub fn calculate_object_mapping(
23        &self,
24        root_table_index: DeclarationIndex,
25    ) -> ObjectMapping<'a> {
26        assert!(matches!(
27            self.declarations.get_declaration(root_table_index).1.kind,
28            DeclarationKind::Table(_)
29        ));
30
31        let root_offset_object = OffsetObject {
32            offset: 0,
33            kind: crate::OffsetObjectKind::Table(root_table_index),
34        };
35
36        let mut builder = ObjectMappingBuilder::default();
37
38        builder.process_root_object(Object::Offset(root_offset_object), self);
39
40        ObjectMapping {
41            root_object: root_offset_object.follow_offset(self).unwrap(),
42            root_objects: builder.root_objects,
43            root_intervals: rust_lapper::Lapper::new(builder.root_intervals),
44        }
45    }
46}
47
48#[derive(Clone, Debug)]
49pub struct Interpretation {
50    pub root_object_index: ObjectIndex,
51    pub lines: Vec<LineIndex>,
52}
53
54#[derive(Debug)]
55pub struct LineTree<'a> {
56    field_name: Option<Cow<'a, str>>,
57    object: Object<'a>,
58    start_line_index: LineIndex,
59    end_line_index: Option<LineIndex>,
60    range: (ByteIndex, ByteIndex),
61    children: Vec<LineTree<'a>>,
62}
63
64#[derive(Clone, Debug)]
65pub struct Line<'a> {
66    pub indentation: usize,
67    pub start_line_index: LineIndex,
68    pub end_line_index: LineIndex,
69    pub parent_line_index: LineIndex,
70    pub name: String,
71    pub line: String,
72    pub object_width: usize,
73    pub start: ByteIndex,
74    pub end: ByteIndex,
75    pub object: Object<'a>,
76}
77
78impl<'a> LineTree<'a> {
79    fn get_interpretations(
80        &self,
81        root_object_index: ObjectIndex,
82        byte_index: ByteIndex,
83        lines: &mut Vec<LineIndex>,
84        callback: &mut impl FnMut(Interpretation),
85    ) -> bool {
86        if !(self.range.0..self.range.1).contains(&byte_index) {
87            return false;
88        }
89
90        lines.push(self.start_line_index);
91
92        let mut found = false;
93        for child in &self.children {
94            found |= child.get_interpretations(root_object_index, byte_index, lines, callback);
95        }
96        if !found {
97            callback(Interpretation {
98                root_object_index,
99                lines: lines.clone(),
100            });
101        }
102        lines.pop();
103        true
104    }
105
106    fn to_strings_helper(
107        &self,
108        depth: usize,
109        parent_line_index: LineIndex,
110        buffer: &InspectableFlatbuffer<'a>,
111        out: &mut Vec<Line<'a>>,
112    ) {
113        debug_assert_eq!(out.len(), self.start_line_index);
114
115        let mut line = String::new();
116        let name = self.object.print_object(buffer);
117
118        if let Object::Offset(OffsetObject {
119            kind: OffsetObjectKind::VTable(_),
120            ..
121        }) = &self.object
122        {
123            line.push_str("#vtable");
124        } else {
125            if let Some(field_name) = &self.field_name {
126                line.push_str(field_name);
127                line.push_str(": ");
128            }
129
130            line.push_str(&name);
131
132            if self.end_line_index.is_some() {
133                line.push_str(" {");
134            } else if self.object.have_braces() {
135                line.push_str(" {}");
136            }
137        }
138
139        out.push(Line {
140            object_width: line.len(),
141            line,
142            name,
143            indentation: 2 * depth,
144            start_line_index: self.start_line_index,
145            end_line_index: self.end_line_index.unwrap_or(self.start_line_index),
146            parent_line_index,
147            object: self.object,
148            start: self.range.0,
149            end: self.range.1,
150        });
151
152        for child in &self.children {
153            let index = out.len();
154            child.to_strings_helper(depth + 1, self.start_line_index, buffer, out);
155            out[self.start_line_index].object_width = out[self.start_line_index]
156                .object_width
157                .max(out[index].object_width + 2);
158        }
159
160        if let Some(end_line) = self.end_line_index {
161            debug_assert_eq!(out.len(), end_line);
162            out.push(Line {
163                object_width: out[self.start_line_index].object_width,
164                name: String::new(),
165                indentation: 2 * depth,
166                start_line_index: self.start_line_index,
167                end_line_index: self.end_line_index.unwrap_or(self.start_line_index),
168                line: "}".to_string(),
169                parent_line_index,
170                object: self.object,
171                start: self.range.0,
172                end: self.range.1,
173            });
174        }
175    }
176
177    pub fn flatten(&self, buffer: &InspectableFlatbuffer<'a>) -> Vec<Line<'a>> {
178        let mut out = Vec::new();
179        self.to_strings_helper(0, 0, buffer, &mut out);
180        out
181    }
182
183    pub fn last_line(&self) -> usize {
184        if let Some(end_line) = self.end_line_index {
185            end_line
186        } else if let Some(last) = self.children.last() {
187            last.last_line()
188        } else {
189            self.start_line_index
190        }
191    }
192}
193
194impl<'a> ObjectMapping<'a> {
195    pub fn get_interpretations(
196        &self,
197        byte_index: ByteIndex,
198        buffer: &InspectableFlatbuffer<'a>,
199    ) -> Vec<Interpretation> {
200        let mut interpretations = Vec::new();
201        self.get_interpretations_cb(byte_index, buffer, |interpretation| {
202            interpretations.push(interpretation);
203        });
204        interpretations
205    }
206
207    pub fn get_interpretations_cb(
208        &self,
209        byte_index: ByteIndex,
210        buffer: &InspectableFlatbuffer<'a>,
211        mut callback: impl FnMut(Interpretation),
212    ) {
213        for root_object_index in self.root_intervals.find(byte_index, byte_index + 1) {
214            self.line_tree(root_object_index.val, buffer)
215                .get_interpretations(
216                    root_object_index.val,
217                    byte_index,
218                    &mut Vec::new(),
219                    &mut callback,
220                );
221        }
222    }
223
224    pub fn line_tree(
225        &self,
226        root_object_index: ObjectIndex,
227        buffer: &InspectableFlatbuffer<'a>,
228    ) -> LineTree<'a> {
229        fn handler<'a>(
230            field_name: Option<Cow<'a, str>>,
231            current: Object<'a>,
232            buffer: &InspectableFlatbuffer<'a>,
233            next_line: &mut LineIndex,
234        ) -> LineTree<'a> {
235            let current_line = *next_line;
236            *next_line += 1;
237            let mut children = Vec::new();
238            let mut range = current.byterange(buffer);
239            current.children(buffer, |field_name, child| {
240                let child = handler(field_name, child, buffer, next_line);
241                range.0 = range.0.min(child.range.0);
242                range.1 = range.1.max(child.range.1);
243                children.push(child);
244            });
245
246            let mut end_line = None;
247
248            if !children.is_empty() {
249                end_line = Some(*next_line);
250                *next_line += 1;
251            }
252
253            LineTree {
254                field_name,
255                object: current,
256                start_line_index: current_line,
257                end_line_index: end_line,
258                range,
259                children,
260            }
261        }
262        handler(
263            None,
264            *self.root_objects.get_index(root_object_index).unwrap().0,
265            buffer,
266            &mut 0,
267        )
268    }
269}
270
271#[derive(Default)]
272struct ObjectMappingBuilder<'a> {
273    root_objects: IndexMap<Object<'a>, (ByteIndex, ByteIndex)>,
274    root_intervals: Vec<rust_lapper::Interval<ByteIndex, ObjectIndex>>,
275}
276
277impl<'a> ObjectMappingBuilder<'a> {
278    fn process_root_object(&mut self, current: Object<'a>, buffer: &InspectableFlatbuffer<'a>) {
279        if self.root_objects.contains_key(&current) {
280            return;
281        }
282
283        if let Object::Offset(offset_object) = current {
284            if let Ok(inner) = offset_object.follow_offset(buffer) {
285                self.process_root_object(inner, buffer);
286            }
287        }
288
289        let mut range = current.byterange(buffer);
290
291        current.children(buffer, |child_name, child| {
292            std::mem::drop(child_name);
293            self.process_child_object(child, &mut range, buffer);
294        });
295        let (index, old) = self.root_objects.insert_full(current, range);
296        assert!(old.is_none());
297        self.root_intervals.push(rust_lapper::Interval {
298            start: range.0,
299            stop: range.1,
300            val: index,
301        });
302    }
303
304    fn process_child_object(
305        &mut self,
306        current: Object<'a>,
307        range: &mut (u32, u32),
308        buffer: &InspectableFlatbuffer<'a>,
309    ) {
310        let crange = current.byterange(buffer);
311        range.0 = range.0.min(crange.0);
312        range.1 = range.1.max(crange.1);
313
314        if let Object::Offset(offset_object) = current {
315            if let Ok(inner) = offset_object.follow_offset(buffer) {
316                self.process_root_object(inner, buffer);
317            }
318        }
319
320        current.children(buffer, |child_name, child| {
321            std::mem::drop(child_name);
322            self.process_child_object(child, range, buffer);
323        });
324    }
325}