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