barectf_parser/parser/
types.rs

1use crate::{
2    config::{
3        EnumerationFieldTypeMappingSequence, FeaturesUnsignedIntegerFieldType, FieldType,
4        NativeByteOrder, PreferredDisplayBase, PrimitiveFieldType, StructureMemberFieldType,
5        UnsignedIntegerFieldType,
6    },
7    error::Error,
8    types::{EventId, FieldValue, PrimitiveFieldValue},
9};
10use byteordered::{byteorder::ReadBytesExt, ByteOrdered, Endianness};
11use fxhash::FxHashMap;
12use internment::Intern;
13use uuid::Uuid;
14
15#[derive(Debug)]
16pub struct PacketHeaderParser {
17    pub magic: Option<UIntParser>,
18    pub uuid: Option<UuidParser>,
19    pub stream_id: UIntParser,
20    pub alignment: Size,
21    pub wire_size_hint: AlignedCursor,
22}
23
24impl PacketHeaderParser {
25    pub fn new(
26        magic: Option<UIntParser>,
27        uuid: Option<UuidParser>,
28        stream_id: UIntParser,
29        alignment: Size,
30    ) -> Self {
31        let mut wire_size_hint = AlignedCursor::default();
32
33        // Align for packet header structure
34        wire_size_hint.align_to(alignment);
35
36        // Add fields
37        if let Some(f) = magic.as_ref() {
38            wire_size_hint.aligned_increment(f.desc());
39        }
40        if uuid.is_some() {
41            // This is a 16 byte-packed static array
42            wire_size_hint.align_to(Size::Bits8);
43            wire_size_hint.increment(Size::Bits64);
44            wire_size_hint.increment(Size::Bits64);
45        }
46        wire_size_hint.aligned_increment(stream_id.desc());
47
48        Self {
49            magic,
50            uuid,
51            stream_id,
52            alignment,
53            wire_size_hint,
54        }
55    }
56}
57
58#[derive(Debug)]
59pub struct PacketContextParserArgs {
60    pub packet_size: UIntParser,
61    pub content_size: UIntParser,
62    pub beginning_timestamp: Option<UIntParser>,
63    pub end_timestamp: Option<UIntParser>,
64    pub events_discarded: Option<UIntParser>,
65    pub sequence_number: Option<UIntParser>,
66    pub extra_members: Vec<EventPayloadMemberParser>,
67    pub alignment: Size,
68}
69
70#[derive(Debug)]
71pub struct PacketContextParser {
72    pub packet_size: UIntParser,
73    pub content_size: UIntParser,
74    pub beginning_timestamp: Option<UIntParser>,
75    pub end_timestamp: Option<UIntParser>,
76    pub events_discarded: Option<UIntParser>,
77    pub sequence_number: Option<UIntParser>,
78    pub extra_members: Vec<EventPayloadMemberParser>,
79    pub alignment: Size,
80    pub wire_size_hint: AlignedCursor,
81}
82
83impl PacketContextParser {
84    pub fn new(args: PacketContextParserArgs, packet_header_cursor: &AlignedCursor) -> Self {
85        let mut wire_size_hint = *packet_header_cursor;
86
87        // Align for packet context structure
88        wire_size_hint.align_to(args.alignment);
89
90        // Add fields
91        wire_size_hint.aligned_increment(args.packet_size.desc());
92        wire_size_hint.aligned_increment(args.content_size.desc());
93        if let Some(f) = args.beginning_timestamp.as_ref() {
94            wire_size_hint.aligned_increment(f.desc());
95        }
96        if let Some(f) = args.end_timestamp.as_ref() {
97            wire_size_hint.aligned_increment(f.desc());
98        }
99        if let Some(f) = args.events_discarded.as_ref() {
100            wire_size_hint.aligned_increment(f.desc());
101        }
102        if let Some(f) = args.sequence_number.as_ref() {
103            wire_size_hint.aligned_increment(f.desc());
104        }
105
106        // Add extra members
107        for extra_member in args.extra_members.iter() {
108            wire_size_hint.aligned_increment(extra_member.value.desc());
109        }
110
111        Self {
112            packet_size: args.packet_size,
113            content_size: args.content_size,
114            beginning_timestamp: args.beginning_timestamp,
115            end_timestamp: args.end_timestamp,
116            events_discarded: args.events_discarded,
117            sequence_number: args.sequence_number,
118            extra_members: args.extra_members,
119            alignment: args.alignment,
120            wire_size_hint,
121        }
122    }
123}
124
125#[derive(Debug)]
126pub struct StreamParser {
127    pub stream_name: Intern<String>,
128    pub packet_context: PacketContextParser,
129    pub event_header: EventHeaderParser,
130    pub common_context: Option<EventPayloadParser>,
131    pub events: FxHashMap<EventId, EventParser>,
132}
133
134#[derive(Debug)]
135pub struct EventHeaderParser {
136    pub event_id: UIntParser,
137    pub timestamp: UIntParser,
138    pub alignment: Size,
139}
140
141#[derive(Debug)]
142pub struct EventParser {
143    pub event_name: Intern<String>,
144    pub log_level: Option<i32>,
145    pub specific_context: Option<EventPayloadParser>,
146    pub payload: Option<EventPayloadParser>,
147}
148
149#[derive(Debug)]
150pub struct EventPayloadParser {
151    pub alignment: Size,
152    pub members: Vec<EventPayloadMemberParser>,
153}
154
155#[derive(Debug)]
156pub struct EnumerationMappings(pub Vec<(Intern<String>, Vec<EnumerationFieldTypeMappingSequence>)>);
157
158impl EnumerationMappings {
159    pub(crate) fn from_struct_ft(ft: &StructureMemberFieldType) -> Option<Self> {
160        match ft {
161            StructureMemberFieldType::UnsignedEnumeration(t)
162            | StructureMemberFieldType::SignedEnumeration(t) => {
163                let mut mappings = Vec::new();
164                for (label, seq) in t.mappings.iter() {
165                    mappings.push((Intern::new(label.clone()), seq.clone()));
166                }
167                Some(Self(mappings))
168            }
169            _ => None,
170        }
171    }
172
173    pub fn label(&self, v: i64) -> Option<Intern<String>> {
174        self.0
175            .iter()
176            .find_map(|(label, values)| values.iter().any(|s| s.contains(v)).then_some(*label))
177    }
178}
179
180#[derive(Debug)]
181pub struct EventPayloadMemberParser {
182    pub member_name: Intern<String>,
183    pub preferred_display_base: Option<PreferredDisplayBase>,
184    pub enum_mappings: Option<EnumerationMappings>,
185    pub value: FieldTypeParser,
186}
187
188impl EventPayloadMemberParser {
189    pub fn parse<T: ReadBytesExt>(&self, r: &mut StreamReader<T>) -> Result<FieldValue, Error> {
190        // Parse the value, add preferred display base, if any
191        let val = match self.value.parse(r)? {
192            FieldValue::Primitive(PrimitiveFieldValue::UnsignedInteger(v, _)) => {
193                FieldValue::Primitive(PrimitiveFieldValue::UnsignedInteger(
194                    v,
195                    self.preferred_display_base.unwrap_or_default(),
196                ))
197            }
198            FieldValue::Primitive(PrimitiveFieldValue::SignedInteger(v, _)) => {
199                FieldValue::Primitive(PrimitiveFieldValue::SignedInteger(
200                    v,
201                    self.preferred_display_base.unwrap_or_default(),
202                ))
203            }
204            val => val,
205        };
206
207        // Attempt to extract an enum value label, if any
208        if let Some(mappings) = &self.enum_mappings {
209            match val {
210                // NOTE: we always convert unsigned enums to signed
211                FieldValue::Primitive(PrimitiveFieldValue::UnsignedInteger(v, pdb)) => {
212                    Ok(FieldValue::Primitive(PrimitiveFieldValue::Enumeration(
213                        v as i64,
214                        pdb,
215                        mappings.label(v as i64),
216                    )))
217                }
218                FieldValue::Primitive(PrimitiveFieldValue::SignedInteger(v, pdb)) => {
219                    Ok(FieldValue::Primitive(PrimitiveFieldValue::Enumeration(
220                        v,
221                        pdb,
222                        mappings.label(v),
223                    )))
224                }
225                val => Ok(val),
226            }
227        } else {
228            Ok(val)
229        }
230    }
231}
232
233#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
234pub enum Size {
235    Bits8,
236    Bits16,
237    Bits32,
238    Bits64,
239}
240
241impl Size {
242    pub fn from_bits(bits: usize) -> Option<Self> {
243        Some(match bits {
244            8 => Self::Bits8,
245            16 => Self::Bits16,
246            32 => Self::Bits32,
247            64 => Self::Bits64,
248            _ => return None,
249        })
250    }
251
252    fn bits(&self) -> usize {
253        match self {
254            Self::Bits8 => 8,
255            Self::Bits16 => 16,
256            Self::Bits32 => 32,
257            Self::Bits64 => 64,
258        }
259    }
260}
261
262#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
263pub struct FieldDesc {
264    pub size: Size,
265    pub alignment: Size,
266}
267
268#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, thiserror::Error)]
269#[error("Unsupported field type (width {0}, alignment {1})")]
270pub struct FieldUnsupportedError(pub usize, pub usize);
271
272impl FieldDesc {
273    pub fn from_ft<T: FieldType>(ft: &T) -> Result<Self, FieldUnsupportedError> {
274        if let (Some(size), Some(alignment)) =
275            (Size::from_bits(ft.size()), Size::from_bits(ft.alignment()))
276        {
277            Ok(Self { size, alignment })
278        } else {
279            Err(FieldUnsupportedError(ft.size(), ft.alignment()))
280        }
281    }
282}
283
284#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
285pub struct UuidParser {}
286
287impl UuidParser {
288    pub fn from_bool_ft(uuid_field_type: bool) -> Option<Self> {
289        uuid_field_type.then_some(Self {})
290    }
291
292    pub fn parse<T: ReadBytesExt>(&self, r: &mut StreamReader<T>) -> Result<Uuid, Error> {
293        r.align_to(Size::Bits8)?;
294        let mut bytes = [0_u8; 16];
295        for b in bytes.iter_mut() {
296            *b = r.read_u8(Size::Bits8)?;
297        }
298        Ok(Uuid::from_bytes(bytes))
299    }
300}
301
302#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
303pub struct UIntParser(FieldDesc);
304
305impl UIntParser {
306    pub fn from_uint_ft(ft: &UnsignedIntegerFieldType) -> Result<Self, FieldUnsupportedError> {
307        Ok(Self(FieldDesc::from_ft(&ft.field_type)?))
308    }
309
310    pub fn from_opt_uint_ft(
311        ft: &FeaturesUnsignedIntegerFieldType,
312    ) -> Result<Option<Self>, FieldUnsupportedError> {
313        match ft {
314            FeaturesUnsignedIntegerFieldType::False(_) => Ok(None),
315            FeaturesUnsignedIntegerFieldType::UnsignedInteger(uint) => {
316                Ok(Some(Self::from_uint_ft(uint)?))
317            }
318        }
319    }
320
321    pub fn desc(&self) -> &FieldDesc {
322        &self.0
323    }
324
325    pub fn parse<T: ReadBytesExt>(&self, r: &mut StreamReader<T>) -> Result<u64, Error> {
326        Ok(match self.desc().size {
327            Size::Bits8 => r.read_u8(self.desc().alignment)?.into(),
328            Size::Bits16 => r.read_u16(self.desc().alignment)?.into(),
329            Size::Bits32 => r.read_u32(self.desc().alignment)?.into(),
330            Size::Bits64 => r.read_u64(self.desc().alignment)?,
331        })
332    }
333}
334
335#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
336pub enum PrimitiveFieldTypeParser {
337    UInt(FieldDesc),
338    Int(FieldDesc),
339    String(FieldDesc),
340    Real(FieldDesc),
341    UEnum(FieldDesc),
342    Enum(FieldDesc),
343}
344
345impl PrimitiveFieldTypeParser {
346    pub fn from_ft(ft: &PrimitiveFieldType) -> Result<Self, FieldUnsupportedError> {
347        let desc = FieldDesc::from_ft(ft)?;
348        Ok(match ft {
349            PrimitiveFieldType::UnsignedInteger(_) => Self::UInt(desc),
350            PrimitiveFieldType::SignedInteger(_) => Self::Int(desc),
351            PrimitiveFieldType::String => Self::String(desc),
352            PrimitiveFieldType::Real(_) => Self::Real(desc),
353            PrimitiveFieldType::UnsignedEnumeration(_) => Self::UEnum(desc),
354            PrimitiveFieldType::SignedEnumeration(_) => Self::Enum(desc),
355        })
356    }
357
358    pub fn desc(&self) -> &FieldDesc {
359        match self {
360            Self::UInt(t)
361            | Self::Int(t)
362            | Self::String(t)
363            | Self::Real(t)
364            | Self::UEnum(t)
365            | Self::Enum(t) => t,
366        }
367    }
368
369    pub fn parse<T: ReadBytesExt>(
370        &self,
371        r: &mut StreamReader<T>,
372    ) -> Result<PrimitiveFieldValue, Error> {
373        Ok(match self {
374            Self::UInt(desc) | Self::UEnum(desc) => match desc.size {
375                Size::Bits8 => r.read_u8(desc.alignment)?.into(),
376                Size::Bits16 => r.read_u16(desc.alignment)?.into(),
377                Size::Bits32 => r.read_u32(desc.alignment)?.into(),
378                Size::Bits64 => r.read_u64(desc.alignment)?.into(),
379            },
380            Self::Int(desc) | Self::Enum(desc) => match desc.size {
381                Size::Bits8 => r.read_i8(desc.alignment)?.into(),
382                Size::Bits16 => r.read_i16(desc.alignment)?.into(),
383                Size::Bits32 => r.read_i32(desc.alignment)?.into(),
384                Size::Bits64 => r.read_i64(desc.alignment)?.into(),
385            },
386            Self::String(_) => r.read_string()?.into(),
387            Self::Real(desc) => match desc.size {
388                Size::Bits32 => r.read_f32(desc.alignment)?.into(),
389                Size::Bits64 => r.read_f64(desc.alignment)?.into(),
390                _ => return Err(Error::InvalidFloatSize(desc.size.bits())),
391            },
392        })
393    }
394}
395
396#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
397pub enum FieldTypeParser {
398    Primitive(PrimitiveFieldTypeParser),
399    StaticArray(usize, PrimitiveFieldTypeParser),
400    DynamicArray(PrimitiveFieldTypeParser),
401}
402
403impl FieldTypeParser {
404    pub fn from_ft(ft: &StructureMemberFieldType) -> Result<Self, FieldUnsupportedError> {
405        let desc = FieldDesc::from_ft(ft)?;
406
407        Ok(match ft {
408            StructureMemberFieldType::UnsignedInteger(_) => {
409                Self::Primitive(PrimitiveFieldTypeParser::UInt(desc))
410            }
411            StructureMemberFieldType::SignedInteger(_) => {
412                Self::Primitive(PrimitiveFieldTypeParser::Int(desc))
413            }
414            StructureMemberFieldType::String => {
415                Self::Primitive(PrimitiveFieldTypeParser::String(desc))
416            }
417            StructureMemberFieldType::Real(_) => {
418                Self::Primitive(PrimitiveFieldTypeParser::Real(desc))
419            }
420            StructureMemberFieldType::UnsignedEnumeration(_) => {
421                Self::Primitive(PrimitiveFieldTypeParser::UEnum(desc))
422            }
423            StructureMemberFieldType::SignedEnumeration(_) => {
424                Self::Primitive(PrimitiveFieldTypeParser::Enum(desc))
425            }
426            StructureMemberFieldType::StaticArray(ft) => Self::StaticArray(
427                ft.length,
428                PrimitiveFieldTypeParser::from_ft(&ft.element_field_type)?,
429            ),
430            StructureMemberFieldType::DynamicArray(ft) => {
431                Self::DynamicArray(PrimitiveFieldTypeParser::from_ft(&ft.element_field_type)?)
432            }
433        })
434    }
435
436    pub fn desc(&self) -> &FieldDesc {
437        match self {
438            Self::Primitive(t) => t.desc(),
439            Self::StaticArray(_len, t) => t.desc(),
440            Self::DynamicArray(t) => t.desc(),
441        }
442    }
443
444    pub fn parse<T: ReadBytesExt>(&self, r: &mut StreamReader<T>) -> Result<FieldValue, Error> {
445        match self {
446            Self::Primitive(p) => Ok(p.parse(r)?.into()),
447            Self::StaticArray(len, p) => {
448                // Align for field
449                r.align_to(p.desc().alignment)?;
450
451                // Align for and read elements
452                let mut arr = Vec::new();
453                for _ in 0..*len {
454                    arr.push(p.parse(r)?);
455                }
456                Ok(FieldValue::Array(arr))
457            }
458            Self::DynamicArray(p) => {
459                // NOTE: the u32 len field is always byte-packed
460
461                // Align for and read len
462                let len = r.read_u32(Size::Bits8)?;
463
464                // Align for field
465                r.align_to(p.desc().alignment)?;
466
467                // Align for and read elements
468                let mut arr = Vec::new();
469                for _ in 0..len {
470                    arr.push(p.parse(r)?);
471                }
472                Ok(FieldValue::Array(arr))
473            }
474        }
475    }
476}
477
478/// Used by the [`StreamReader`] and wire size helper utilities.
479/// The [`StreamReader`] uses this do to sync IO reads, where alignment
480/// is handled on the fly.
481/// The [`Parser`] also maintains additional packet header and per-stream
482/// packet context [`AlignedCursor`]'s to provided a way to know how
483/// many bytes to expect so we can implement a `tokio_util::codec::Decoder`
484/// for async streams.
485#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
486pub struct AlignedCursor {
487    bit_index: usize,
488}
489
490impl AlignedCursor {
491    pub fn cursor_bits(&self) -> usize {
492        self.bit_index
493    }
494
495    pub fn cursor_bytes(&self) -> usize {
496        self.bit_index >> 3
497    }
498
499    /// Returns the amount of padding the cursor moved by (bits)
500    pub fn align_to(&mut self, align: Size) -> usize {
501        let align_bits = align.bits();
502        debug_assert!(align_bits % 8 == 0);
503
504        // Compute the next alignment/padding
505        let next_index = (self.bit_index + (align_bits - 1)) & (!align_bits + 1);
506        tracing::trace!(align = align_bits, index = self.bit_index, next_index,);
507        debug_assert!(next_index % 8 == 0);
508
509        // Offset the cursor if necessary
510        let padding = next_index - self.bit_index;
511        self.bit_index += padding;
512        padding
513    }
514
515    /// Align to the given bit alignment and increment the cursor by size bits
516    pub fn aligned_increment(&mut self, desc: &FieldDesc) {
517        let _padding = self.align_to(desc.alignment);
518        self.increment(desc.size);
519    }
520
521    /// Increment the cursor by size bits
522    pub fn increment(&mut self, size: Size) {
523        self.bit_index += size.bits();
524    }
525}
526
527#[derive(Debug)]
528pub struct StreamReader<T> {
529    pub inner: ByteOrdered<T, Endianness>,
530    pub cursor: AlignedCursor,
531}
532
533impl<T> StreamReader<T>
534where
535    T: ReadBytesExt,
536{
537    pub fn new(byte_order: NativeByteOrder, r: T) -> Self {
538        Self::new_with_cursor(byte_order, AlignedCursor::default(), r)
539    }
540
541    pub fn new_with_cursor(byte_order: NativeByteOrder, cursor: AlignedCursor, r: T) -> Self {
542        Self {
543            inner: ByteOrdered::runtime(r, byte_order.into()),
544            cursor,
545        }
546    }
547
548    pub fn into_cursor(self) -> AlignedCursor {
549        let StreamReader { inner: _, cursor } = self;
550        cursor
551    }
552
553    pub fn cursor_bits(&self) -> usize {
554        self.cursor.cursor_bits()
555    }
556
557    pub fn align_to(&mut self, align: Size) -> Result<(), Error> {
558        // Read padding, if any, 1 byte at a time
559        let padding = self.cursor.align_to(align);
560        let padding_bytes = padding >> 3;
561        for _ in 0..padding_bytes {
562            let _ = self.inner.read_u8()?;
563        }
564        Ok(())
565    }
566
567    pub fn read_u8(&mut self, align: Size) -> Result<u8, Error> {
568        self.align_to(align)?;
569        let val = self.inner.read_u8()?;
570        self.cursor.increment(Size::Bits8);
571        Ok(val)
572    }
573
574    pub fn read_i8(&mut self, align: Size) -> Result<i8, Error> {
575        self.align_to(align)?;
576        let val = self.inner.read_i8()?;
577        self.cursor.increment(Size::Bits8);
578        Ok(val)
579    }
580
581    pub fn read_u16(&mut self, align: Size) -> Result<u16, Error> {
582        self.align_to(align)?;
583        let val = self.inner.read_u16()?;
584        self.cursor.increment(Size::Bits16);
585        Ok(val)
586    }
587
588    pub fn read_i16(&mut self, align: Size) -> Result<i16, Error> {
589        self.align_to(align)?;
590        let val = self.inner.read_i16()?;
591        self.cursor.increment(Size::Bits16);
592        Ok(val)
593    }
594
595    pub fn read_u32(&mut self, align: Size) -> Result<u32, Error> {
596        self.align_to(align)?;
597        let val = self.inner.read_u32()?;
598        self.cursor.increment(Size::Bits32);
599        Ok(val)
600    }
601
602    pub fn read_i32(&mut self, align: Size) -> Result<i32, Error> {
603        self.align_to(align)?;
604        let val = self.inner.read_i32()?;
605        self.cursor.increment(Size::Bits32);
606        Ok(val)
607    }
608
609    pub fn read_f32(&mut self, align: Size) -> Result<f32, Error> {
610        self.align_to(align)?;
611        let val = self.inner.read_f32()?;
612        self.cursor.increment(Size::Bits32);
613        Ok(val)
614    }
615
616    pub fn read_u64(&mut self, align: Size) -> Result<u64, Error> {
617        self.align_to(align)?;
618        let val = self.inner.read_u64()?;
619        self.cursor.increment(Size::Bits64);
620        Ok(val)
621    }
622
623    pub fn read_i64(&mut self, align: Size) -> Result<i64, Error> {
624        self.align_to(align)?;
625        let val = self.inner.read_i64()?;
626        self.cursor.increment(Size::Bits64);
627        Ok(val)
628    }
629
630    pub fn read_f64(&mut self, align: Size) -> Result<f64, Error> {
631        self.align_to(align)?;
632        let val = self.inner.read_f64()?;
633        self.cursor.increment(Size::Bits64);
634        Ok(val)
635    }
636
637    pub fn read_string(&mut self) -> Result<String, Error> {
638        let mut cstr = Vec::new();
639        self.align_to(Size::Bits8)?;
640        loop {
641            let b = self.inner.read_u8()?;
642            self.cursor.increment(Size::Bits8);
643            if b == 0 {
644                break;
645            }
646            cstr.push(b);
647        }
648        Ok(String::from_utf8_lossy(&cstr).to_string())
649    }
650}