Skip to main content

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