Skip to main content

planus_buffer_inspection/
children.rs

1use std::borrow::Cow;
2
3use planus_types::{ast::IntegerType, intermediate::TypeKind};
4
5use crate::{
6    object_info::DeclarationInfo, ArrayObject, BoolObject, ByteIndex, EnumObject, FloatObject,
7    InspectableFlatbuffer, IntegerObject, Object, OffsetObject, StringObject, StructObject,
8    TableObject, UnionObject, UnionTagObject, UnionVectorTagsObject, UnionVectorValuesObject,
9    VTableObject, VectorObject,
10};
11
12pub trait Children<'a> {
13    fn children(
14        &self,
15        buffer: &InspectableFlatbuffer<'a>,
16        callback: impl FnMut(Option<Cow<'a, str>>, Object<'a>),
17    );
18}
19
20pub trait Byterange {
21    fn byterange(&self, buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex);
22}
23
24impl<'a> Children<'a> for Object<'a> {
25    fn children(
26        &self,
27        buffer: &InspectableFlatbuffer<'a>,
28        callback: impl FnMut(Option<Cow<'a, str>>, Object<'a>),
29    ) {
30        match self {
31            Object::Offset(_) => (),
32            Object::VTable(obj) => obj.children(buffer, callback),
33            Object::Table(obj) => obj.children(buffer, callback),
34            Object::Struct(obj) => obj.children(buffer, callback),
35            Object::UnionTag(obj) => obj.children(buffer, callback),
36            Object::Union(obj) => obj.children(buffer, callback),
37            Object::Enum(obj) => obj.children(buffer, callback),
38            Object::Vector(obj) => obj.children(buffer, callback),
39            Object::Array(obj) => obj.children(buffer, callback),
40            Object::Integer(obj) => obj.children(buffer, callback),
41            Object::Float(obj) => obj.children(buffer, callback),
42            Object::Bool(obj) => obj.children(buffer, callback),
43            Object::String(obj) => obj.children(buffer, callback),
44            Object::UnionVectorTags(obj) => obj.children(buffer, callback),
45            Object::UnionVectorValues(obj) => obj.children(buffer, callback),
46            Object::Unknown(_) => (),
47        }
48    }
49}
50
51impl<'a> Children<'a> for VTableObject {
52    fn children(
53        &self,
54        buffer: &InspectableFlatbuffer<'a>,
55        mut callback: impl FnMut(Option<Cow<'a, str>>, Object<'a>),
56    ) {
57        let vtable_size = self.get_vtable_size(buffer).unwrap();
58        let decl = self.resolve_declaration(buffer);
59
60        for (i, offset) in (self.offset..self.offset + vtable_size as u32)
61            .step_by(2)
62            .enumerate()
63        {
64            let object = Object::Integer(IntegerObject {
65                offset,
66                type_: IntegerType::U16,
67            });
68            match i {
69                0 => callback(Some(Cow::Borrowed("#vtable_size")), object),
70                1 => callback(Some(Cow::Borrowed("#table_size")), object),
71                n => {
72                    let n = n - 2;
73                    if let Some((k, v)) = decl.fields.get_index(n) {
74                        if matches!(v.type_.kind, TypeKind::Union(_)) {
75                            callback(Some(Cow::Owned(format!("offset[union_tag[{k}]]"))), object)
76                        } else {
77                            callback(Some(Cow::Owned(format!("offset[{k}]"))), object)
78                        }
79                    } else if let Some((k, _v)) = decl
80                        .fields
81                        .get_index(n - 1)
82                        .filter(|(_k, v)| matches!(v.type_.kind, TypeKind::Union(_)))
83                    {
84                        callback(Some(Cow::Owned(format!("offset[union[{k}]]"))), object)
85                    } else {
86                        callback(Some(Cow::Owned(format!("offset[{n}]"))), object)
87                    }
88                }
89            }
90        }
91    }
92}
93
94impl<'a> Children<'a> for TableObject {
95    fn children(
96        &self,
97        buffer: &InspectableFlatbuffer<'a>,
98        mut callback: impl FnMut(Option<Cow<'a, str>>, Object<'a>),
99    ) {
100        callback(
101            Some(Cow::Borrowed("#vtable")),
102            Object::Offset(OffsetObject {
103                offset: self.offset,
104                kind: crate::OffsetObjectKind::VTable(self.declaration),
105            }),
106        );
107
108        let vtable = self.get_vtable(buffer).unwrap();
109        let decl = self.resolve_declaration(buffer);
110        for (i, offset) in vtable.get_offsets(buffer).unwrap().enumerate() {
111            if offset == 0 {
112                continue;
113            }
114            let (field_name, _field_decl, is_union_tag) =
115                decl.get_field_for_vtable_index(i as u32).unwrap();
116            let field_name = if is_union_tag {
117                Cow::Owned(format!("union_key[{field_name}]"))
118            } else {
119                Cow::Borrowed(field_name)
120            };
121            if let Some(field_value) = self.get_field(buffer, i as u32).unwrap() {
122                callback(Some(field_name), field_value);
123            }
124        }
125    }
126}
127
128impl<'a> Children<'a> for StructObject {
129    fn children(
130        &self,
131        buffer: &InspectableFlatbuffer<'a>,
132        mut callback: impl FnMut(Option<Cow<'a, str>>, Object<'a>),
133    ) {
134        let this = *self;
135        let buffer = *buffer;
136        let decl = self.resolve_declaration(&buffer);
137        for (i, field_name) in decl.fields.keys().enumerate() {
138            if let Ok(field) = this.get_field(&buffer, i) {
139                callback(Some(Cow::Borrowed(field_name.as_str())), field);
140            }
141        }
142    }
143}
144
145impl<'a> Children<'a> for UnionTagObject {
146    fn children(
147        &self,
148        _buffer: &InspectableFlatbuffer<'a>,
149        _callback: impl FnMut(Option<Cow<'a, str>>, Object<'a>),
150    ) {
151    }
152}
153
154impl<'a> Children<'a> for UnionObject {
155    fn children(
156        &self,
157        buffer: &InspectableFlatbuffer<'a>,
158        mut callback: impl FnMut(Option<Cow<'a, str>>, Object<'a>),
159    ) {
160        match self.inner_offset(buffer) {
161            Ok(Some(inner_offset)) => callback(None, Object::Offset(inner_offset)),
162            Ok(None) => callback(
163                Some(Cow::Borrowed("unknown offset")),
164                Object::Integer(IntegerObject {
165                    offset: self.offset,
166                    type_: IntegerType::U32,
167                }),
168            ),
169            Err(_) => callback(
170                Some(Cow::Borrowed("error offset")),
171                Object::Integer(IntegerObject {
172                    offset: self.offset,
173                    type_: IntegerType::U32,
174                }),
175            ),
176        }
177    }
178}
179
180impl<'a> Children<'a> for EnumObject {
181    fn children(
182        &self,
183        _buffer: &InspectableFlatbuffer<'a>,
184        _callback: impl FnMut(Option<Cow<'a, str>>, Object<'a>),
185    ) {
186    }
187}
188
189impl<'a> Children<'a> for VectorObject<'a> {
190    fn children(
191        &self,
192        buffer: &InspectableFlatbuffer<'a>,
193        mut callback: impl FnMut(Option<Cow<'a, str>>, Object<'a>),
194    ) {
195        callback(
196            Some(Cow::Borrowed("length")),
197            Object::Integer(IntegerObject {
198                offset: self.offset,
199                type_: IntegerType::U32,
200            }),
201        );
202
203        for i in 0..self.len(buffer).unwrap_or(0) {
204            if let Ok(Some(value)) = self.read(i, buffer) {
205                callback(Some(Cow::Owned(i.to_string())), value);
206            }
207        }
208    }
209}
210
211impl<'a> Children<'a> for ArrayObject<'a> {
212    fn children(
213        &self,
214        _buffer: &InspectableFlatbuffer<'a>,
215        _callback: impl FnMut(Option<Cow<'a, str>>, Object<'a>),
216    ) {
217    }
218}
219
220impl<'a> Children<'a> for IntegerObject {
221    fn children(
222        &self,
223        _buffer: &InspectableFlatbuffer<'a>,
224        _callback: impl FnMut(Option<Cow<'a, str>>, Object<'a>),
225    ) {
226    }
227}
228
229impl<'a> Children<'a> for FloatObject {
230    fn children(
231        &self,
232        _buffer: &InspectableFlatbuffer<'a>,
233        _callback: impl FnMut(Option<Cow<'a, str>>, Object<'a>),
234    ) {
235    }
236}
237
238impl<'a> Children<'a> for BoolObject {
239    fn children(
240        &self,
241        _buffer: &InspectableFlatbuffer<'a>,
242        _callback: impl FnMut(Option<Cow<'a, str>>, Object<'a>),
243    ) {
244    }
245}
246
247impl<'a> Children<'a> for StringObject {
248    fn children(
249        &self,
250        _buffer: &InspectableFlatbuffer<'a>,
251        mut callback: impl FnMut(Option<Cow<'a, str>>, Object<'a>),
252    ) {
253        callback(
254            Some(Cow::Borrowed("length")),
255            Object::Integer(IntegerObject {
256                offset: self.offset,
257                type_: IntegerType::U32,
258            }),
259        );
260    }
261}
262
263impl<'a> Children<'a> for UnionVectorTagsObject {
264    fn children(
265        &self,
266        buffer: &InspectableFlatbuffer<'a>,
267        mut callback: impl FnMut(Option<Cow<'a, str>>, Object<'a>),
268    ) {
269        let offset = self.tags_offset;
270        callback(
271            Some(Cow::Borrowed("length")),
272            Object::Integer(IntegerObject {
273                offset,
274                type_: IntegerType::U32,
275            }),
276        );
277
278        for i in 0..self.len(buffer).unwrap_or(0) {
279            let offset = offset + 4 + i;
280            let value = UnionTagObject {
281                offset,
282                declaration: self.declaration,
283            };
284            callback(Some(Cow::Owned(i.to_string())), Object::UnionTag(value));
285        }
286    }
287}
288
289impl<'a> Children<'a> for UnionVectorValuesObject {
290    fn children(
291        &self,
292        buffer: &InspectableFlatbuffer<'a>,
293        mut callback: impl FnMut(Option<Cow<'a, str>>, Object<'a>),
294    ) {
295        let offset = self.values_offset;
296        callback(
297            Some(Cow::Borrowed("length")),
298            Object::Integer(IntegerObject {
299                offset,
300                type_: IntegerType::U32,
301            }),
302        );
303
304        for i in 0..self.len(buffer).unwrap_or(0) {
305            let offset = offset + 4 + 4 * i;
306            let tag = self
307                .tags_offset
308                .and_then(|tag_offset| buffer.read_u8(tag_offset + 4 + i).ok());
309
310            if let Some(tag) = tag {
311                let value = UnionObject {
312                    offset,
313                    tag,
314                    declaration: self.declaration,
315                };
316                callback(Some(Cow::Owned(i.to_string())), Object::Union(value));
317            } else {
318                callback(
319                    Some(Cow::Owned(i.to_string())),
320                    Object::Offset(OffsetObject {
321                        offset,
322                        kind: crate::OffsetObjectKind::Unknown,
323                    }),
324                );
325            }
326        }
327    }
328}
329
330impl Byterange for Object<'_> {
331    fn byterange(&self, buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex) {
332        match self {
333            Object::Offset(obj) => obj.byterange(buffer),
334            Object::VTable(obj) => obj.byterange(buffer),
335            Object::Table(obj) => obj.byterange(buffer),
336            Object::Struct(obj) => obj.byterange(buffer),
337            Object::UnionTag(obj) => obj.byterange(buffer),
338            Object::Union(obj) => obj.byterange(buffer),
339            Object::Enum(obj) => obj.byterange(buffer),
340            Object::Vector(obj) => obj.byterange(buffer),
341            Object::Array(obj) => obj.byterange(buffer),
342            Object::Integer(obj) => obj.byterange(buffer),
343            Object::Float(obj) => obj.byterange(buffer),
344            Object::Bool(obj) => obj.byterange(buffer),
345            Object::String(obj) => obj.byterange(buffer),
346            Object::UnionVectorTags(obj) => obj.byterange(buffer),
347            Object::UnionVectorValues(obj) => obj.byterange(buffer),
348            Object::Unknown(offset) => (*offset, *offset),
349        }
350    }
351}
352
353impl Byterange for OffsetObject<'_> {
354    fn byterange(&self, _buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex) {
355        (self.offset, self.offset + 4)
356    }
357}
358
359impl Byterange for VTableObject {
360    fn byterange(&self, buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex) {
361        let size = self.get_vtable_size(buffer).unwrap();
362        (self.offset, self.offset + size as ByteIndex)
363    }
364}
365
366impl Byterange for TableObject {
367    fn byterange(&self, _buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex) {
368        (self.offset, self.offset + 4)
369    }
370}
371
372impl Byterange for StructObject {
373    fn byterange(&self, buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex) {
374        let decl = self.resolve_declaration(buffer);
375        (self.offset, self.offset + decl.size)
376    }
377}
378
379impl Byterange for UnionTagObject {
380    fn byterange(&self, _buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex) {
381        (self.offset, self.offset + 1)
382    }
383}
384
385impl Byterange for UnionObject {
386    fn byterange(&self, _buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex) {
387        (self.offset, self.offset + 4)
388    }
389}
390
391impl Byterange for EnumObject {
392    fn byterange(&self, buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex) {
393        let decl = self.resolve_declaration(buffer);
394        (self.offset, self.offset + decl.type_.byte_size())
395    }
396}
397
398impl Byterange for VectorObject<'_> {
399    fn byterange(&self, _buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex) {
400        (self.offset, self.offset)
401    }
402}
403
404impl Byterange for ArrayObject<'_> {
405    fn byterange(&self, _buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex) {
406        (self.offset, self.offset)
407    }
408}
409
410impl Byterange for IntegerObject {
411    fn byterange(&self, _buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex) {
412        (self.offset, self.offset + self.type_.byte_size())
413    }
414}
415
416impl Byterange for FloatObject {
417    fn byterange(&self, _buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex) {
418        (self.offset, self.offset + self.type_.byte_size())
419    }
420}
421
422impl Byterange for BoolObject {
423    fn byterange(&self, _buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex) {
424        (self.offset, self.offset + 1)
425    }
426}
427
428impl Byterange for StringObject {
429    fn byterange(&self, buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex) {
430        (
431            self.offset,
432            self.offset + 4 + self.len(buffer).unwrap() as ByteIndex,
433        )
434    }
435}
436
437impl Byterange for UnionVectorTagsObject {
438    fn byterange(&self, _buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex) {
439        (self.tags_offset, self.tags_offset)
440    }
441}
442
443impl Byterange for UnionVectorValuesObject {
444    fn byterange(&self, _buffer: &InspectableFlatbuffer<'_>) -> (ByteIndex, ByteIndex) {
445        (self.values_offset, self.values_offset)
446    }
447}