fxt/
args.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::error::ParseWarning;
6use crate::fxt_builder::FxtBuilder;
7use crate::session::ResolveCtx;
8use crate::string::{StringRef, STRING_REF_INLINE_BIT};
9use crate::{trace_header, ParseError, ParseResult};
10use flyweights::FlyStr;
11use nom::number::complete::{le_f64, le_i64, le_u64};
12use nom::Parser;
13
14#[derive(Clone, Debug, PartialEq)]
15pub struct Arg {
16    pub name: FlyStr,
17    pub value: ArgValue,
18}
19
20impl Arg {
21    pub(crate) fn resolve_n(ctx: &mut ResolveCtx, raw: Vec<RawArg<'_>>) -> Vec<Self> {
22        raw.into_iter().filter_map(|a| Self::resolve(ctx, a)).collect()
23    }
24
25    fn resolve(ctx: &mut ResolveCtx, raw: RawArg<'_>) -> Option<Self> {
26        let name = ctx.resolve_str(raw.name);
27        if let Some(value) = ArgValue::resolve(ctx, raw.value) {
28            Some(Self { name, value })
29        } else {
30            ctx.add_warning(ParseWarning::SkippingArgWithUnknownType { name });
31            None
32        }
33    }
34}
35
36#[derive(Debug, PartialEq, Clone)]
37pub struct RawArg<'a> {
38    pub name: StringRef<'a>,
39    pub value: RawArgValue<'a>,
40}
41
42impl<'a> RawArg<'a> {
43    pub(crate) fn parse_n(count: u8, buf: &'a [u8]) -> ParseResult<'a, Vec<Self>> {
44        nom::multi::count(Self::parse, count as usize).parse(buf)
45    }
46
47    pub(crate) fn parse(buf: &'a [u8]) -> ParseResult<'a, Self> {
48        use nom::combinator::map;
49
50        let (buf, base_header) = BaseArgHeader::parse(buf)?;
51        let (rem, payload) = base_header.take_payload(buf)?;
52        let (payload, name) = StringRef::parse(base_header.name_ref(), payload)?;
53
54        let arg_ty = base_header.raw_type();
55        let (empty, value) = match arg_ty {
56            NULL_ARG_TYPE => Ok((payload, RawArgValue::Null)),
57            BOOL_ARG_TYPE => {
58                let header = BoolHeader::new(base_header.0).map_err(nom::Err::Failure)?;
59                Ok((payload, RawArgValue::Boolean(header.value() != 0)))
60            }
61            I32_ARG_TYPE => {
62                let header = I32Header::new(base_header.0).map_err(nom::Err::Failure)?;
63                Ok((payload, RawArgValue::Signed32(header.value())))
64            }
65            U32_ARG_TYPE => {
66                let header = U32Header::new(base_header.0).map_err(nom::Err::Failure)?;
67                Ok((payload, RawArgValue::Unsigned32(header.value())))
68            }
69            I64_ARG_TYPE => map(le_i64, |i| RawArgValue::Signed64(i)).parse(payload),
70            U64_ARG_TYPE => map(le_u64, |u| RawArgValue::Unsigned64(u)).parse(payload),
71            F64_ARG_TYPE => map(le_f64, |f| RawArgValue::Double(f)).parse(payload),
72            STR_ARG_TYPE => {
73                let header = StringHeader::new(base_header.0).map_err(nom::Err::Failure)?;
74                map(move |b| StringRef::parse(header.value_ref(), b), |s| RawArgValue::String(s))
75                    .parse(payload)
76            }
77            PTR_ARG_TYPE => map(le_u64, |p| RawArgValue::Pointer(p)).parse(payload),
78            KOBJ_ARG_TYPE => map(le_u64, |k| RawArgValue::KernelObj(k)).parse(payload),
79            unknown => Ok((&[][..], RawArgValue::Unknown { raw_type: unknown, bytes: payload })),
80        }?;
81
82        if empty.is_empty() {
83            Ok((rem, Self { name, value }))
84        } else {
85            Err(nom::Err::Failure(ParseError::InvalidSize))
86        }
87    }
88
89    pub(crate) fn serialize(&self) -> Result<Vec<u8>, String> {
90        let arg_name_ref = match self.name {
91            StringRef::Index(id) => id.into(),
92            StringRef::Inline(name) => name.len() as u16 | STRING_REF_INLINE_BIT,
93            StringRef::Empty => {
94                return Err("Argument is missing a name.".to_string());
95            }
96        };
97
98        match &self.value {
99            RawArgValue::Null => {
100                let mut header = NullHeader::empty();
101                header.set_name_ref(arg_name_ref);
102                let mut builder = FxtBuilder::new(header);
103                if let StringRef::Inline(name_str) = self.name {
104                    builder = builder.atom(name_str);
105                }
106                Ok(builder.build())
107            }
108            RawArgValue::Boolean(val) => {
109                let mut header = BoolHeader::empty();
110                header.set_name_ref(arg_name_ref);
111                header.set_value(*val as u8);
112                let mut builder = FxtBuilder::new(header);
113                if let StringRef::Inline(name_str) = self.name {
114                    builder = builder.atom(name_str);
115                }
116                Ok(builder.build())
117            }
118            RawArgValue::Signed32(val) => {
119                let mut header = I32Header::empty();
120                header.set_name_ref(arg_name_ref);
121                header.set_value(*val);
122                let mut builder = FxtBuilder::new(header);
123                if let StringRef::Inline(name_str) = self.name {
124                    builder = builder.atom(name_str);
125                }
126                Ok(builder.build())
127            }
128            RawArgValue::Unsigned32(val) => {
129                let mut header = U32Header::empty();
130                header.set_name_ref(arg_name_ref);
131                header.set_value(*val);
132                let mut builder = FxtBuilder::new(header);
133                if let StringRef::Inline(name_str) = self.name {
134                    builder = builder.atom(name_str);
135                }
136                Ok(builder.build())
137            }
138            RawArgValue::Signed64(val) => {
139                let mut header = I64Header::empty();
140                header.set_name_ref(arg_name_ref);
141                let mut builder = FxtBuilder::new(header);
142                if let StringRef::Inline(name_str) = self.name {
143                    builder = builder.atom(name_str);
144                }
145                Ok(builder.atom(val.to_le_bytes()).build())
146            }
147            RawArgValue::Unsigned64(val) => {
148                let mut header = U64Header::empty();
149                header.set_name_ref(arg_name_ref);
150                let mut builder = FxtBuilder::new(header);
151                if let StringRef::Inline(name_str) = self.name {
152                    builder = builder.atom(name_str);
153                }
154                Ok(builder.atom(val.to_le_bytes()).build())
155            }
156            RawArgValue::Double(val) => {
157                let mut header = F64Header::empty();
158                header.set_name_ref(arg_name_ref);
159                let mut builder = FxtBuilder::new(header);
160                if let StringRef::Inline(name_str) = self.name {
161                    builder = builder.atom(name_str);
162                }
163                Ok(builder.atom(val.to_le_bytes()).build())
164            }
165            RawArgValue::String(str_val) => {
166                let mut header = StringHeader::empty();
167                header.set_name_ref(arg_name_ref);
168                header.set_value_ref(match str_val {
169                    StringRef::Index(id) => (*id).into(),
170                    StringRef::Inline(val) => val.len() as u16 | STRING_REF_INLINE_BIT,
171                    StringRef::Empty => 0u16,
172                });
173                let mut builder = FxtBuilder::new(header);
174                if let StringRef::Inline(name_str) = self.name {
175                    builder = builder.atom(name_str);
176                }
177                if let StringRef::Inline(value_str) = str_val {
178                    builder = builder.atom(value_str);
179                }
180                Ok(builder.build())
181            }
182            RawArgValue::Pointer(val) => {
183                let mut header = PtrHeader::empty();
184                header.set_name_ref(arg_name_ref);
185                let mut builder = FxtBuilder::new(header);
186                if let StringRef::Inline(name_str) = self.name {
187                    builder = builder.atom(name_str);
188                }
189                Ok(builder.atom(val.to_le_bytes()).build())
190            }
191            RawArgValue::KernelObj(val) => {
192                let mut header = KobjHeader::empty();
193                header.set_name_ref(arg_name_ref);
194                let mut builder = FxtBuilder::new(header);
195                if let StringRef::Inline(name_str) = self.name {
196                    builder = builder.atom(name_str);
197                }
198                Ok(builder.atom(val.to_le_bytes()).build())
199            }
200            RawArgValue::Unknown { raw_type, bytes } => {
201                let mut header = BaseArgHeader::empty();
202                header.set_raw_type(*raw_type);
203                let mut builder = FxtBuilder::new(header);
204                if let StringRef::Inline(name_str) = self.name {
205                    builder = builder.atom(name_str);
206                }
207                Ok(builder.atom(bytes).build())
208            }
209        }
210    }
211}
212
213#[derive(Clone, Debug, PartialEq)]
214pub enum ArgValue {
215    Null,
216    Boolean(bool),
217    Signed32(i32),
218    Unsigned32(u32),
219    Signed64(i64),
220    Unsigned64(u64),
221    Double(f64),
222    String(FlyStr),
223    Pointer(u64),
224    KernelObj(u64),
225}
226
227impl ArgValue {
228    pub fn is_null(&self) -> bool {
229        matches!(self, Self::Null)
230    }
231
232    pub fn boolean(&self) -> Option<bool> {
233        match self {
234            Self::Boolean(b) => Some(*b),
235            _ => None,
236        }
237    }
238
239    pub fn signed_32(&self) -> Option<i32> {
240        match self {
241            Self::Signed32(n) => Some(*n),
242            _ => None,
243        }
244    }
245
246    pub fn unsigned_32(&self) -> Option<u32> {
247        match self {
248            Self::Unsigned32(n) => Some(*n),
249            _ => None,
250        }
251    }
252
253    pub fn signed_64(&self) -> Option<i64> {
254        match self {
255            Self::Signed64(n) => Some(*n),
256            _ => None,
257        }
258    }
259
260    pub fn unsigned_64(&self) -> Option<u64> {
261        match self {
262            Self::Unsigned64(n) => Some(*n),
263            _ => None,
264        }
265    }
266
267    pub fn double(&self) -> Option<f64> {
268        match self {
269            Self::Double(n) => Some(*n),
270            _ => None,
271        }
272    }
273
274    pub fn string(&self) -> Option<&str> {
275        match self {
276            Self::String(s) => Some(s.as_str()),
277            _ => None,
278        }
279    }
280
281    pub fn pointer(&self) -> Option<u64> {
282        match self {
283            Self::Pointer(p) => Some(*p),
284            _ => None,
285        }
286    }
287
288    pub fn kernel_obj(&self) -> Option<u64> {
289        match self {
290            Self::KernelObj(k) => Some(*k),
291            _ => None,
292        }
293    }
294
295    fn resolve(ctx: &mut ResolveCtx, raw: RawArgValue<'_>) -> Option<Self> {
296        Some(match raw {
297            RawArgValue::Null => ArgValue::Null,
298            RawArgValue::Boolean(b) => ArgValue::Boolean(b),
299            RawArgValue::Signed32(s) => ArgValue::Signed32(s),
300            RawArgValue::Unsigned32(u) => ArgValue::Unsigned32(u),
301            RawArgValue::Signed64(s) => ArgValue::Signed64(s),
302            RawArgValue::Unsigned64(u) => ArgValue::Unsigned64(u),
303            RawArgValue::Double(f) => ArgValue::Double(f),
304            RawArgValue::String(s) => ArgValue::String(ctx.resolve_str(s)),
305            RawArgValue::Pointer(p) => ArgValue::Pointer(p),
306            RawArgValue::KernelObj(k) => ArgValue::KernelObj(k),
307            RawArgValue::Unknown { .. } => {
308                return None;
309            }
310        })
311    }
312}
313
314impl std::fmt::Display for ArgValue {
315    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
316        match self {
317            ArgValue::Null => write!(f, "null"),
318            ArgValue::Boolean(v) => write!(f, "{v}"),
319            ArgValue::Signed32(v) => write!(f, "{v}"),
320            ArgValue::Unsigned32(v) => write!(f, "{v}"),
321            ArgValue::Signed64(v) => write!(f, "{v}"),
322            ArgValue::Unsigned64(v) => write!(f, "{v}"),
323            ArgValue::Double(v) => write!(f, "{v}"),
324            ArgValue::String(v) => write!(f, "{v}"),
325            ArgValue::Pointer(v) => write!(f, "{v:#016x}"),
326            ArgValue::KernelObj(v) => write!(f, "{v}"),
327        }
328    }
329}
330
331#[derive(Clone, Debug, PartialEq)]
332pub enum RawArgValue<'a> {
333    Null,
334    Boolean(bool),
335    Signed32(i32),
336    Unsigned32(u32),
337    Signed64(i64),
338    Unsigned64(u64),
339    Double(f64),
340    String(StringRef<'a>),
341    Pointer(u64),
342    KernelObj(u64),
343    Unknown { raw_type: u8, bytes: &'a [u8] },
344}
345
346macro_rules! arg_header {
347    ($name:ident $(($arg_ty:expr))? { $($record_specific:tt)* }) => {
348        trace_header! {
349            $name $(($arg_ty))? {
350                $($record_specific)*
351                u16, name_ref: 16, 31;
352            }
353        }
354    };
355}
356
357pub(crate) const NULL_ARG_TYPE: u8 = 0;
358pub(crate) const I32_ARG_TYPE: u8 = 1;
359pub(crate) const U32_ARG_TYPE: u8 = 2;
360pub(crate) const I64_ARG_TYPE: u8 = 3;
361pub(crate) const U64_ARG_TYPE: u8 = 4;
362pub(crate) const F64_ARG_TYPE: u8 = 5;
363pub(crate) const STR_ARG_TYPE: u8 = 6;
364pub(crate) const PTR_ARG_TYPE: u8 = 7;
365pub(crate) const KOBJ_ARG_TYPE: u8 = 8;
366pub(crate) const BOOL_ARG_TYPE: u8 = 9;
367
368// Used to probe the arg type.
369arg_header! {
370    BaseArgHeader {}
371}
372
373arg_header! {
374    NullHeader (NULL_ARG_TYPE) {}
375}
376
377arg_header! {
378    I32Header (I32_ARG_TYPE) {
379        i32, value: 32, 63;
380    }
381}
382
383arg_header! {
384    U32Header (U32_ARG_TYPE) {
385        u32, value: 32, 63;
386    }
387}
388
389arg_header! {
390    I64Header (I64_ARG_TYPE) {}
391}
392
393arg_header! {
394    U64Header (U64_ARG_TYPE) {}
395}
396
397arg_header! {
398    F64Header (F64_ARG_TYPE) {}
399}
400
401arg_header! {
402    StringHeader (STR_ARG_TYPE) {
403        u16, value_ref: 32, 47;
404    }
405}
406
407arg_header! {
408    PtrHeader (PTR_ARG_TYPE) {}
409}
410
411arg_header! {
412    KobjHeader (KOBJ_ARG_TYPE) {}
413}
414
415arg_header! {
416    BoolHeader (BOOL_ARG_TYPE) {
417        u8, value: 32, 32;
418    }
419}
420
421#[cfg(test)]
422mod tests {
423    use super::*;
424    use std::num::NonZeroU16;
425
426    #[test]
427    fn null_arg_name_index() {
428        let mut header = BaseArgHeader::empty();
429        header.set_name_ref(10);
430
431        let arg_record_bytes = FxtBuilder::new(header).build();
432        let raw_arg_record = RawArg {
433            name: StringRef::Index(NonZeroU16::new(10).unwrap()),
434            value: RawArgValue::Null,
435        };
436
437        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
438        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
439    }
440    #[test]
441    fn null_arg_name_inline() {
442        let name = "hello";
443        let mut header = BaseArgHeader::empty();
444        header.set_name_ref(name.len() as u16 | STRING_REF_INLINE_BIT);
445
446        let arg_record_bytes = FxtBuilder::new(header).atom(name).build();
447        let raw_arg_record = RawArg { name: StringRef::Inline("hello"), value: RawArgValue::Null };
448
449        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
450        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
451    }
452
453    #[test]
454    fn i32_arg_name_index() {
455        let mut header = I32Header::empty();
456        header.set_name_ref(10);
457        header.set_value(-19);
458
459        let arg_record_bytes = FxtBuilder::new(header).build();
460        let raw_arg_record = RawArg {
461            name: StringRef::Index(NonZeroU16::new(10).unwrap()),
462            value: RawArgValue::Signed32(-19),
463        };
464
465        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
466        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
467    }
468
469    #[test]
470    fn i32_arg_name_inline() {
471        let name = "hello";
472        let mut header = I32Header::empty();
473        header.set_name_ref(name.len() as u16 | STRING_REF_INLINE_BIT);
474        header.set_value(-19);
475
476        let arg_record_bytes = FxtBuilder::new(header).atom(name).build();
477        let raw_arg_record =
478            RawArg { name: StringRef::Inline("hello"), value: RawArgValue::Signed32(-19) };
479
480        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
481        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
482    }
483
484    #[test]
485    fn u32_arg_name_index() {
486        let mut header = U32Header::empty();
487        header.set_name_ref(10);
488        header.set_value(23);
489
490        let arg_record_bytes = FxtBuilder::new(header).build();
491        let raw_arg_record = RawArg {
492            name: StringRef::Index(NonZeroU16::new(10).unwrap()),
493            value: RawArgValue::Unsigned32(23),
494        };
495
496        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
497        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
498    }
499
500    #[test]
501    fn u32_arg_name_inline() {
502        let name = "hello";
503        let mut header = U32Header::empty();
504        header.set_name_ref(name.len() as u16 | STRING_REF_INLINE_BIT);
505        header.set_value(23);
506
507        let arg_record_bytes = FxtBuilder::new(header).atom(name).build();
508        let raw_arg_record =
509            RawArg { name: StringRef::Inline("hello"), value: RawArgValue::Unsigned32(23) };
510
511        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
512        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
513    }
514
515    #[test]
516    fn i64_arg_name_index() {
517        let mut header = BaseArgHeader::empty();
518        header.set_name_ref(10);
519        header.set_raw_type(I64_ARG_TYPE);
520
521        let arg_record_bytes = FxtBuilder::new(header).atom((-79i64).to_le_bytes()).build();
522        let raw_arg_record = RawArg {
523            name: StringRef::Index(NonZeroU16::new(10).unwrap()),
524            value: RawArgValue::Signed64(-79),
525        };
526
527        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
528        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
529    }
530
531    #[test]
532    fn i64_arg_name_inline() {
533        let name = "hello";
534        let mut header = BaseArgHeader::empty();
535        header.set_name_ref(name.len() as u16 | STRING_REF_INLINE_BIT);
536        header.set_raw_type(I64_ARG_TYPE);
537
538        let arg_record_bytes =
539            FxtBuilder::new(header).atom(name).atom((-845i64).to_le_bytes()).build();
540        let raw_arg_record =
541            RawArg { name: StringRef::Inline("hello"), value: RawArgValue::Signed64(-845) };
542
543        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
544        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
545    }
546
547    #[test]
548    fn u64_arg_name_index() {
549        let mut header = BaseArgHeader::empty();
550        header.set_name_ref(10);
551        header.set_raw_type(U64_ARG_TYPE);
552
553        let arg_record_bytes = FxtBuilder::new(header).atom(1024u64.to_le_bytes()).build();
554        let raw_arg_record = RawArg {
555            name: StringRef::Index(NonZeroU16::new(10).unwrap()),
556            value: RawArgValue::Unsigned64(1024),
557        };
558
559        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
560        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
561    }
562
563    #[test]
564    fn u64_arg_name_inline() {
565        let name = "hello";
566        let mut header = BaseArgHeader::empty();
567        header.set_name_ref(name.len() as u16 | STRING_REF_INLINE_BIT);
568        header.set_raw_type(U64_ARG_TYPE);
569
570        let arg_record_bytes =
571            FxtBuilder::new(header).atom(name).atom(4096u64.to_le_bytes()).build();
572        let raw_arg_record =
573            RawArg { name: StringRef::Inline("hello"), value: RawArgValue::Unsigned64(4096) };
574
575        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
576        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
577    }
578
579    #[test]
580    fn f64_arg_name_index() {
581        let mut header = BaseArgHeader::empty();
582        header.set_name_ref(10);
583        header.set_raw_type(F64_ARG_TYPE);
584
585        let arg_record_bytes = FxtBuilder::new(header).atom(1007.893f64.to_le_bytes()).build();
586        let raw_arg_record = RawArg {
587            name: StringRef::Index(NonZeroU16::new(10).unwrap()),
588            value: RawArgValue::Double(1007.893),
589        };
590
591        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
592        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
593    }
594
595    #[test]
596    fn f64_arg_name_inline() {
597        let name = "hello";
598        let mut header = BaseArgHeader::empty();
599        header.set_name_ref(name.len() as u16 | STRING_REF_INLINE_BIT);
600        header.set_raw_type(F64_ARG_TYPE);
601
602        let arg_record_bytes =
603            FxtBuilder::new(header).atom(name).atom(23634.1231f64.to_le_bytes()).build();
604        let raw_arg_record =
605            RawArg { name: StringRef::Inline("hello"), value: RawArgValue::Double(23634.1231) };
606
607        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
608        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
609    }
610
611    #[test]
612    fn string_arg_name_index_value_index() {
613        let mut header = StringHeader::empty();
614        header.set_name_ref(10);
615        header.set_value_ref(11);
616
617        let arg_record_bytes = FxtBuilder::new(header).build();
618        let raw_arg_record = RawArg {
619            name: StringRef::Index(NonZeroU16::new(10).unwrap()),
620            value: RawArgValue::String(StringRef::Index(NonZeroU16::new(11).unwrap())),
621        };
622
623        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
624        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
625    }
626
627    #[test]
628    fn string_arg_name_index_value_inline() {
629        let value = "123-456-7890";
630        let mut header = StringHeader::empty();
631        header.set_name_ref(10);
632        header.set_value_ref(value.len() as u16 | STRING_REF_INLINE_BIT);
633
634        let arg_record_bytes = FxtBuilder::new(header).atom(value).build();
635        let raw_arg_record = RawArg {
636            name: StringRef::Index(NonZeroU16::new(10).unwrap()),
637            value: RawArgValue::String(StringRef::Inline(value)),
638        };
639
640        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
641        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
642    }
643
644    #[test]
645    fn string_arg_name_inline_value_index() {
646        let name = "hello";
647        let mut header = StringHeader::empty();
648        header.set_name_ref(name.len() as u16 | STRING_REF_INLINE_BIT);
649        header.set_value_ref(13);
650
651        let arg_record_bytes = FxtBuilder::new(header).atom(name).build();
652        let raw_arg_record = RawArg {
653            name: StringRef::Inline(name),
654            value: RawArgValue::String(StringRef::Index(NonZeroU16::new(13).unwrap())),
655        };
656
657        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
658        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
659    }
660
661    #[test]
662    fn string_arg_name_inline_value_inline() {
663        let name = "hello";
664        let value = "123-456-7890";
665        let mut header = StringHeader::empty();
666        header.set_name_ref(name.len() as u16 | STRING_REF_INLINE_BIT);
667        header.set_value_ref(value.len() as u16 | STRING_REF_INLINE_BIT);
668
669        let arg_record_bytes = FxtBuilder::new(header).atom(name).atom(value).build();
670        let raw_arg_record = RawArg {
671            name: StringRef::Inline(name),
672            value: RawArgValue::String(StringRef::Inline(value)),
673        };
674
675        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
676        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
677    }
678
679    #[test]
680    fn pointer_arg_name_index() {
681        let mut header = BaseArgHeader::empty();
682        header.set_name_ref(10);
683        header.set_raw_type(PTR_ARG_TYPE);
684
685        let arg_record_bytes = FxtBuilder::new(header).atom(256u64.to_le_bytes()).build();
686        let raw_arg_record = RawArg {
687            name: StringRef::Index(NonZeroU16::new(10).unwrap()),
688            value: RawArgValue::Pointer(256),
689        };
690
691        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
692        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
693    }
694
695    #[test]
696    fn pointer_arg_name_inline() {
697        let name = "hello";
698        let mut header = BaseArgHeader::empty();
699        header.set_name_ref(name.len() as u16 | STRING_REF_INLINE_BIT);
700        header.set_raw_type(PTR_ARG_TYPE);
701
702        let arg_record_bytes =
703            FxtBuilder::new(header).atom(name).atom(512u64.to_le_bytes()).build();
704        let raw_arg_record =
705            RawArg { name: StringRef::Inline("hello"), value: RawArgValue::Pointer(512) };
706
707        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
708        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
709    }
710
711    #[test]
712    fn koid_arg_name_index() {
713        let mut header = BaseArgHeader::empty();
714        header.set_name_ref(10);
715        header.set_raw_type(KOBJ_ARG_TYPE);
716
717        let arg_record_bytes = FxtBuilder::new(header).atom(17u64.to_le_bytes()).build();
718        let raw_arg_record = RawArg {
719            name: StringRef::Index(NonZeroU16::new(10).unwrap()),
720            value: RawArgValue::KernelObj(17),
721        };
722
723        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
724        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
725    }
726
727    #[test]
728    fn koid_arg_name_inline() {
729        let name = "hello";
730        let mut header = BaseArgHeader::empty();
731        header.set_name_ref(name.len() as u16 | STRING_REF_INLINE_BIT);
732        header.set_raw_type(KOBJ_ARG_TYPE);
733
734        let arg_record_bytes = FxtBuilder::new(header).atom(name).atom(21u64.to_le_bytes()).build();
735        let raw_arg_record =
736            RawArg { name: StringRef::Inline("hello"), value: RawArgValue::KernelObj(21) };
737
738        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
739        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
740    }
741
742    #[test]
743    fn bool_arg_name_index() {
744        let mut header = BoolHeader::empty();
745        header.set_name_ref(10);
746        header.set_value(true as u8);
747
748        let arg_record_bytes = FxtBuilder::new(header).build();
749        let raw_arg_record = RawArg {
750            name: StringRef::Index(NonZeroU16::new(10).unwrap()),
751            value: RawArgValue::Boolean(true),
752        };
753
754        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
755        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
756    }
757
758    #[test]
759    fn bool_arg_name_inline() {
760        let name = "hello";
761        let mut header = BoolHeader::empty();
762        header.set_name_ref(name.len() as u16 | STRING_REF_INLINE_BIT);
763        header.set_value(true as u8);
764
765        let arg_record_bytes = FxtBuilder::new(header).atom(name).build();
766        let raw_arg_record =
767            RawArg { name: StringRef::Inline("hello"), value: RawArgValue::Boolean(true) };
768
769        assert_parses_to_arg!(arg_record_bytes, raw_arg_record);
770        assert_eq!(raw_arg_record.serialize().unwrap(), arg_record_bytes);
771    }
772}