planus_buffer_inspection/
object_mapping.rs1use 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(¤t) {
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}