1use byteordered::Endianness;
2use serde::{Deserialize, Deserializer, Serialize};
3use serde_yaml::Value;
4use std::collections::BTreeMap;
5use uuid::Uuid;
6
7#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
8#[serde(rename_all = "kebab-case")]
9pub enum NativeByteOrder {
10 #[serde(alias = "little")]
11 #[serde(alias = "le")]
12 LittleEndian,
13 #[serde(alias = "big")]
14 #[serde(alias = "be")]
15 BigEndian,
16}
17
18impl From<NativeByteOrder> for Endianness {
19 fn from(value: NativeByteOrder) -> Self {
20 match value {
21 NativeByteOrder::LittleEndian => Endianness::Little,
22 NativeByteOrder::BigEndian => Endianness::Big,
23 }
24 }
25}
26
27#[derive(
28 Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Deserialize, Serialize,
29)]
30#[serde(rename_all = "kebab-case")]
31pub enum PreferredDisplayBase {
32 #[serde(alias = "bin")]
33 Binary,
34 #[serde(alias = "oct")]
35 Octal,
36 #[default]
37 #[serde(alias = "dec")]
38 Decimal,
39 #[serde(alias = "hex")]
40 Hexadecimal,
41}
42
43#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
45#[serde(rename_all = "kebab-case")]
46pub struct IntegerFieldType {
47 pub size: usize,
49 #[serde(default = "default_alignment_bits")]
51 pub alignment: usize,
52 #[serde(default)]
54 pub preferred_display_base: PreferredDisplayBase,
55}
56
57impl FieldType for IntegerFieldType {
58 fn size(&self) -> usize {
59 self.size
60 }
61
62 fn alignment(&self) -> usize {
63 self.alignment
64 }
65
66 fn preferred_display_base(&self) -> Option<PreferredDisplayBase> {
67 Some(self.preferred_display_base)
68 }
69}
70
71#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
73#[serde(rename_all = "kebab-case")]
74#[serde(tag = "class", rename = "unsigned-integer")]
75pub struct UnsignedIntegerFieldType {
76 #[serde(flatten)]
77 pub field_type: IntegerFieldType,
78}
79
80#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
82#[serde(rename_all = "kebab-case")]
83#[serde(tag = "class", rename = "signed-integer")]
84pub struct SignedIntegerFieldType {
85 #[serde(flatten)]
86 pub field_type: IntegerFieldType,
87}
88
89#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
91#[serde(rename_all = "kebab-case")]
92pub struct RealFieldType {
93 pub size: usize,
95 #[serde(default = "default_alignment_bits")]
97 pub alignment: usize,
98}
99
100impl FieldType for RealFieldType {
101 fn size(&self) -> usize {
102 self.size
103 }
104
105 fn alignment(&self) -> usize {
106 self.alignment
107 }
108
109 fn preferred_display_base(&self) -> Option<PreferredDisplayBase> {
110 None
111 }
112}
113
114#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
116#[serde(rename_all = "kebab-case")]
117#[serde(untagged)]
118pub enum EnumerationFieldTypeMappingSequence {
119 InclusiveRange(i64, i64),
120 Value(i64),
121}
122
123impl EnumerationFieldTypeMappingSequence {
124 pub fn contains(&self, value: i64) -> bool {
126 match self {
127 Self::InclusiveRange(min, max) => (value >= *min) && (value <= *max),
128 Self::Value(v) => *v == value,
129 }
130 }
131}
132
133#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
135#[serde(rename_all = "kebab-case")]
136pub struct EnumerationFieldType {
137 pub size: usize,
139 #[serde(default = "default_alignment_bits")]
141 pub alignment: usize,
142 #[serde(default)]
144 pub preferred_display_base: PreferredDisplayBase,
145 pub mappings: BTreeMap<String, Vec<EnumerationFieldTypeMappingSequence>>,
147}
148
149impl FieldType for EnumerationFieldType {
150 fn size(&self) -> usize {
151 self.size
152 }
153
154 fn alignment(&self) -> usize {
155 self.alignment
156 }
157
158 fn preferred_display_base(&self) -> Option<PreferredDisplayBase> {
159 Some(self.preferred_display_base)
160 }
161}
162
163#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
165#[serde(rename_all = "kebab-case")]
166#[serde(tag = "class")]
167pub enum PrimitiveFieldType {
168 UnsignedInteger(IntegerFieldType),
169 SignedInteger(IntegerFieldType),
170 String,
171 Real(RealFieldType),
172 UnsignedEnumeration(EnumerationFieldType),
173 SignedEnumeration(EnumerationFieldType),
174}
175
176impl FieldType for PrimitiveFieldType {
177 fn size(&self) -> usize {
178 match self {
179 Self::UnsignedInteger(t) | Self::SignedInteger(t) => t.size,
180 Self::UnsignedEnumeration(t) | Self::SignedEnumeration(t) => t.size,
181 Self::Real(t) => t.size,
182 Self::String => 8,
183 }
184 }
185
186 fn alignment(&self) -> usize {
187 match self {
188 Self::UnsignedInteger(t) | Self::SignedInteger(t) => t.alignment,
189 Self::UnsignedEnumeration(t) | Self::SignedEnumeration(t) => t.alignment,
190 Self::Real(t) => t.alignment,
191 Self::String => 8,
192 }
193 }
194
195 fn preferred_display_base(&self) -> Option<PreferredDisplayBase> {
196 Some(match self {
197 Self::UnsignedInteger(t) | Self::SignedInteger(t) => t.preferred_display_base,
198 Self::UnsignedEnumeration(t) | Self::SignedEnumeration(t) => t.preferred_display_base,
199 Self::String | Self::Real(_) => return None,
200 })
201 }
202}
203
204#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
206#[serde(rename_all = "kebab-case")]
207pub struct StaticArrayFieldType {
208 pub length: usize,
210 pub element_field_type: PrimitiveFieldType,
212}
213
214impl FieldType for StaticArrayFieldType {
215 fn size(&self) -> usize {
216 self.element_field_type.size()
217 }
218
219 fn alignment(&self) -> usize {
220 self.element_field_type.alignment()
221 }
222
223 fn preferred_display_base(&self) -> Option<PreferredDisplayBase> {
224 self.element_field_type.preferred_display_base()
225 }
226}
227
228#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
230#[serde(rename_all = "kebab-case")]
231pub struct DynamicArrayFieldType {
232 pub element_field_type: PrimitiveFieldType,
234}
235
236impl FieldType for DynamicArrayFieldType {
237 fn size(&self) -> usize {
238 self.element_field_type.size()
239 }
240
241 fn alignment(&self) -> usize {
242 self.element_field_type.alignment()
243 }
244
245 fn preferred_display_base(&self) -> Option<PreferredDisplayBase> {
246 self.element_field_type.preferred_display_base()
247 }
248}
249
250#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
252#[serde(rename_all = "kebab-case")]
253#[serde(tag = "class")]
254pub enum StructureMemberFieldType {
255 UnsignedInteger(IntegerFieldType),
256 SignedInteger(IntegerFieldType),
257 String,
258 Real(RealFieldType),
259 UnsignedEnumeration(EnumerationFieldType),
260 SignedEnumeration(EnumerationFieldType),
261 StaticArray(StaticArrayFieldType),
262 DynamicArray(DynamicArrayFieldType),
263}
264
265impl FieldType for StructureMemberFieldType {
266 fn size(&self) -> usize {
267 match self {
268 Self::UnsignedInteger(t) | Self::SignedInteger(t) => t.size,
269 Self::UnsignedEnumeration(t) | Self::SignedEnumeration(t) => t.size,
270 Self::Real(t) => t.size,
271 Self::String => 8, Self::StaticArray(t) => t.size(),
273 Self::DynamicArray(t) => t.size(),
274 }
275 }
276
277 fn alignment(&self) -> usize {
278 match self {
279 Self::UnsignedInteger(t) | Self::SignedInteger(t) => t.alignment,
280 Self::UnsignedEnumeration(t) | Self::SignedEnumeration(t) => t.alignment,
281 Self::Real(t) => t.alignment,
282 Self::String => 8,
283 Self::StaticArray(t) => t.alignment(),
284 Self::DynamicArray(t) => t.alignment(),
285 }
286 }
287
288 fn preferred_display_base(&self) -> Option<PreferredDisplayBase> {
289 Some(match self {
290 Self::UnsignedInteger(t) | Self::SignedInteger(t) => t.preferred_display_base,
291 Self::UnsignedEnumeration(t) | Self::SignedEnumeration(t) => t.preferred_display_base,
292 Self::StaticArray(t) => return t.preferred_display_base(),
293 Self::DynamicArray(t) => return t.preferred_display_base(),
294 Self::String | Self::Real(_) => return None,
295 })
296 }
297}
298
299#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
301#[serde(rename_all = "kebab-case")]
302pub struct StructureFieldTypeMember {
303 pub field_type: StructureMemberFieldType,
305}
306
307#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
309#[serde(rename_all = "kebab-case")]
310#[serde(tag = "class", rename = "structure")]
311pub struct StructureFieldType {
312 #[serde(default = "default_struct_min_alignment")]
314 pub minimum_alignment: usize,
315 pub members: Vec<BTreeMap<String, StructureFieldTypeMember>>,
317}
318
319impl StructureFieldType {
320 pub(crate) fn alignment(&self) -> usize {
322 self.members
323 .iter()
324 .flat_map(|m| m.values())
325 .map(|ftm| ftm.field_type.alignment())
326 .max()
327 .unwrap_or_else(default_alignment_bits)
328 }
329}
330
331#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
334#[serde(rename_all = "kebab-case")]
335#[serde(untagged)]
336pub enum FeaturesUnsignedIntegerFieldType {
337 #[serde(deserialize_with = "de_false")]
338 False(bool),
339 UnsignedInteger(UnsignedIntegerFieldType),
340}
341
342impl FeaturesUnsignedIntegerFieldType {
343 pub(crate) fn alignment(&self) -> usize {
345 match self {
346 Self::False(_) => 0,
347 Self::UnsignedInteger(ft) => ft.field_type.alignment,
348 }
349 }
350
351 pub(crate) fn as_ft(&self) -> Option<&UnsignedIntegerFieldType> {
352 match self {
353 FeaturesUnsignedIntegerFieldType::False(_) => None,
354 FeaturesUnsignedIntegerFieldType::UnsignedInteger(ft) => Some(ft),
355 }
356 }
357}
358
359#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize, Serialize)]
361#[serde(rename_all = "kebab-case")]
362pub struct ClockTypeOffset {
363 pub seconds: i64,
365 pub cycles: u64,
367}
368
369#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize, Serialize)]
371#[serde(rename_all = "kebab-case")]
372pub struct ClockType {
373 pub frequency: u64,
375 pub offset: Option<ClockTypeOffset>,
377 pub origin_is_unix_epoch: bool,
379 pub precision: u64,
381 pub uuid: Option<Uuid>,
383 pub description: Option<String>,
385 #[serde(alias = "$c-type")]
387 pub c_type: String,
388}
389
390#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
392#[serde(rename_all = "kebab-case")]
393pub struct EventRecordType {
394 pub log_level: Option<i32>,
396 pub specific_context_field_type: Option<StructureFieldType>,
398 pub payload_field_type: Option<StructureFieldType>,
400}
401
402#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
404#[serde(rename_all = "kebab-case")]
405pub struct DataStreamTypePacketFeatures {
406 pub total_size_field_type: UnsignedIntegerFieldType,
408 pub content_size_field_type: UnsignedIntegerFieldType,
410 pub beginning_timestamp_field_type: FeaturesUnsignedIntegerFieldType,
412 pub end_timestamp_field_type: FeaturesUnsignedIntegerFieldType,
414 pub discarded_event_records_counter_snapshot_field_type: FeaturesUnsignedIntegerFieldType,
416 pub sequence_number_field_type: FeaturesUnsignedIntegerFieldType,
418}
419
420impl DataStreamTypePacketFeatures {
421 pub(crate) fn alignment(&self) -> usize {
423 let aligns = [
424 self.total_size_field_type.field_type.alignment,
425 self.content_size_field_type.field_type.alignment,
426 self.beginning_timestamp_field_type.alignment(),
427 self.end_timestamp_field_type.alignment(),
428 self.discarded_event_records_counter_snapshot_field_type
429 .alignment(),
430 self.sequence_number_field_type.alignment(),
431 ];
432 *aligns.iter().max().unwrap() }
434}
435
436#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
438#[serde(rename_all = "kebab-case")]
439pub struct DataStreamTypeEventRecordFeatures {
440 pub type_id_field_type: UnsignedIntegerFieldType,
442 pub timestamp_field_type: UnsignedIntegerFieldType,
444}
445
446impl DataStreamTypeEventRecordFeatures {
447 pub(crate) fn alignment(&self) -> usize {
449 let aligns = [
450 self.type_id_field_type.field_type.alignment,
451 self.timestamp_field_type.field_type.alignment,
452 ];
453 *aligns.iter().max().unwrap() }
455}
456
457#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
459#[serde(rename_all = "kebab-case")]
460pub struct DataStreamTypeFeatures {
461 pub packet: DataStreamTypePacketFeatures,
463 pub event_record: DataStreamTypeEventRecordFeatures,
465}
466
467#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Deserialize)]
469#[serde(rename_all = "kebab-case")]
470pub struct PacketContextExtraMembers(pub Vec<BTreeMap<String, StructureFieldTypeMember>>);
471
472impl PacketContextExtraMembers {
473 pub(crate) fn alignment(&self) -> usize {
475 self.0
476 .iter()
477 .flat_map(|m| m.values())
478 .map(|ftm| ftm.field_type.alignment())
479 .max()
480 .unwrap_or_else(default_alignment_bits)
481 }
482}
483
484#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
487#[serde(rename_all = "kebab-case")]
488pub struct DataStreamType {
489 #[serde(alias = "$is-default")]
491 pub is_default: bool,
492 #[serde(alias = "$default-clock-type-name")]
494 pub default_clock_type_name: Option<String>,
495 #[serde(alias = "$features")]
497 pub features: DataStreamTypeFeatures,
498 #[serde(default)]
500 pub packet_context_field_type_extra_members: PacketContextExtraMembers,
501 pub event_record_common_context_field_type: Option<StructureFieldType>,
503 pub event_record_types: BTreeMap<String, EventRecordType>,
505}
506
507#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
511#[serde(rename_all = "kebab-case")]
512pub struct TraceTypeFeatures {
513 pub magic_field_type: FeaturesUnsignedIntegerFieldType,
515 pub uuid_field_type: bool,
517 pub data_stream_type_id_field_type: UnsignedIntegerFieldType,
519}
520
521impl TraceTypeFeatures {
522 pub(crate) fn alignment(&self) -> usize {
524 let aligns = [
525 self.magic_field_type.alignment(),
526 self.uuid_field_type
528 .then(default_alignment_bits)
529 .unwrap_or(0),
530 self.data_stream_type_id_field_type.field_type.alignment,
531 ];
532 *aligns.iter().max().unwrap() }
534}
535
536#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize)]
540#[serde(rename_all = "kebab-case")]
541pub struct TraceType {
542 pub native_byte_order: NativeByteOrder,
544 pub uuid: Option<Uuid>,
546 #[serde(alias = "$features")]
548 pub features: TraceTypeFeatures,
549 pub clock_types: BTreeMap<String, ClockType>,
551 pub data_stream_types: BTreeMap<String, DataStreamType>,
553}
554
555#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug, Deserialize)]
557#[serde(rename_all = "kebab-case")]
558pub struct Trace {
559 pub environment: BTreeMap<String, Value>,
561 #[serde(alias = "type")]
563 pub typ: TraceType,
564}
565
566#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug, Deserialize)]
568#[serde(rename_all = "kebab-case")]
569pub struct CodeGenerationOptions {
570 pub file_name: String,
572 pub identifier: String,
574}
575
576impl Default for CodeGenerationOptions {
577 fn default() -> Self {
578 Self {
579 file_name: "barectf".to_owned(),
580 identifier: "barectf_".to_owned(),
581 }
582 }
583}
584
585#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug, Default, Deserialize)]
587#[serde(rename_all = "kebab-case")]
588pub struct HeaderGenerationOptions {
589 pub identifier_prefix_definition: bool,
593 pub default_data_stream_type_name_definition: bool,
597}
598
599#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug, Default, Deserialize)]
601#[serde(rename_all = "kebab-case")]
602pub struct Options {
603 pub code_generation: CodeGenerationOptions,
605 pub header: HeaderGenerationOptions,
607}
608
609#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug, Deserialize)]
615#[serde(rename_all = "kebab-case")]
616pub struct Config {
617 #[serde(default)]
619 pub options: Options,
620 pub trace: Trace,
622}
623
624pub(crate) trait FieldType {
625 fn size(&self) -> usize;
627
628 fn alignment(&self) -> usize;
630
631 fn preferred_display_base(&self) -> Option<PreferredDisplayBase>;
633}
634
635const fn default_alignment_bits() -> usize {
639 8
640}
641
642const fn default_struct_min_alignment() -> usize {
644 1
645}
646
647fn de_false<'de, D>(deserializer: D) -> Result<bool, D::Error>
648where
649 D: Deserializer<'de>,
650{
651 if bool::deserialize(deserializer)? {
652 Err(serde::de::Error::invalid_value(
653 serde::de::Unexpected::Bool(true),
654 &"the `false` boolean",
655 ))
656 } else {
657 Ok(false)
658 }
659}