libspa/pod/
parser.rs

1// Copyright The pipewire-rs Contributors.
2// SPDX-License-Identifier: MIT
3
4use std::{
5    ffi::{c_char, c_double, c_float, c_void, CStr},
6    marker::PhantomData,
7    mem::MaybeUninit,
8};
9
10use nix::errno::Errno;
11
12use crate::utils::{Fraction, Id, Rectangle};
13
14/// Low-level wrapper around `spa_pod_parser`.
15///
16/// Using this may require using `unsafe` and/or working with C types, but
17/// is still more safe and rusty than the raw functions and types.
18#[repr(transparent)]
19pub struct Parser<'d> {
20    parser: spa_sys::spa_pod_parser,
21    data: PhantomData<&'d [u8]>,
22}
23
24impl<'d> Parser<'d> {
25    pub fn new(data: &'d [u8]) -> Self {
26        unsafe {
27            let mut parser: MaybeUninit<spa_sys::spa_pod_parser> = MaybeUninit::uninit();
28            spa_sys::spa_pod_parser_init(
29                parser.as_mut_ptr(),
30                data.as_ptr().cast(),
31                data.len()
32                    .try_into()
33                    .expect("data length does not fit in a u32"),
34            );
35            Self {
36                parser: parser.assume_init(),
37                data: PhantomData,
38            }
39        }
40    }
41
42    pub fn from_pod(pod: &'d crate::pod::Pod) -> Self {
43        unsafe {
44            let mut parser: MaybeUninit<spa_sys::spa_pod_parser> = MaybeUninit::uninit();
45            spa_sys::spa_pod_parser_pod(parser.as_mut_ptr(), pod.as_raw_ptr());
46            Self {
47                parser: parser.assume_init(),
48                data: PhantomData,
49            }
50        }
51    }
52
53    pub fn as_raw(&self) -> &spa_sys::spa_pod_parser {
54        &self.parser
55    }
56
57    pub fn as_raw_ptr(&self) -> *mut spa_sys::spa_pod_parser {
58        std::ptr::addr_of!(self.parser).cast_mut()
59    }
60
61    pub fn into_raw(self) -> spa_sys::spa_pod_parser {
62        self.parser
63    }
64
65    /// # Safety
66    ///
67    /// The parser state may only be used as long as all frames that were pushed
68    /// to the parser at the time of this call are alive and not moved
69    pub unsafe fn state(&self) -> spa_sys::spa_pod_parser_state {
70        let mut state: MaybeUninit<spa_sys::spa_pod_parser_state> = MaybeUninit::uninit();
71        spa_sys::spa_pod_parser_get_state(self.as_raw_ptr(), state.as_mut_ptr());
72        state.assume_init()
73    }
74
75    /// # Safety
76    ///
77    /// TODO: Constraints unknown, use at own risk
78    pub unsafe fn reset(&mut self, state: *mut spa_sys::spa_pod_parser_state) {
79        spa_sys::spa_pod_parser_reset(self.as_raw_ptr(), state)
80    }
81
82    /// # Safety
83    ///
84    /// TODO: Constraints unknown, use at own risk
85    pub unsafe fn deref(&mut self, offset: u32, size: u32) -> *mut spa_sys::spa_pod {
86        spa_sys::spa_pod_parser_deref(self.as_raw_ptr(), offset, size)
87    }
88
89    /// # Safety
90    ///
91    /// TODO: Constraints unknown, use at own risk
92    pub unsafe fn frame(&mut self, frame: *mut spa_sys::spa_pod_frame) -> *mut spa_sys::spa_pod {
93        spa_sys::spa_pod_parser_frame(self.as_raw_ptr(), frame)
94    }
95
96    /// # Safety
97    ///
98    /// TODO: Constraints unknown, use at own risk
99    pub unsafe fn push(
100        &mut self,
101        frame: *mut spa_sys::spa_pod_frame,
102        pod: *const spa_sys::spa_pod,
103        offset: u32,
104    ) {
105        spa_sys::spa_pod_parser_push(self.as_raw_ptr(), frame, pod, offset)
106    }
107
108    pub fn current(&mut self) -> *mut spa_sys::spa_pod {
109        unsafe { spa_sys::spa_pod_parser_current(self.as_raw_ptr()) }
110    }
111
112    /// # Safety
113    ///
114    /// Pod pointed to must we valid, well aligned, and contained in the current frame
115    ///
116    /// TODO: Any other constraints? Use at own risk
117    pub unsafe fn advance(&mut self, pod: *const spa_sys::spa_pod) {
118        spa_sys::spa_pod_parser_advance(self.as_raw_ptr(), pod)
119    }
120
121    /// # Safety
122    ///
123    /// TODO: Constraints unknown, use at own risk
124    pub unsafe fn next(&mut self) -> *mut spa_sys::spa_pod {
125        spa_sys::spa_pod_parser_next(self.as_raw_ptr())
126    }
127
128    /// # Safety
129    ///
130    /// Only the last added frame may be popped
131    pub unsafe fn pop(&mut self, frame: &mut spa_sys::spa_pod_frame) -> Result<(), Errno> {
132        let res = spa_sys::spa_pod_parser_pop(self.as_raw_ptr(), frame as *mut _);
133
134        if res >= 0 {
135            Ok(())
136        } else {
137            Err(Errno::from_raw(-res))
138        }
139    }
140
141    pub fn get_bool(&mut self) -> Result<bool, Errno> {
142        unsafe {
143            let mut b: MaybeUninit<bool> = MaybeUninit::uninit();
144            let res = spa_sys::spa_pod_parser_get_bool(self.as_raw_ptr(), b.as_mut_ptr());
145            if res >= 0 {
146                Ok(b.assume_init())
147            } else {
148                Err(Errno::from_raw(-res))
149            }
150        }
151    }
152
153    pub fn get_id(&mut self) -> Result<Id, Errno> {
154        unsafe {
155            let mut id: MaybeUninit<u32> = MaybeUninit::uninit();
156            let res = spa_sys::spa_pod_parser_get_id(self.as_raw_ptr(), id.as_mut_ptr());
157            if res >= 0 {
158                Ok(Id(id.assume_init()))
159            } else {
160                Err(Errno::from_raw(-res))
161            }
162        }
163    }
164
165    pub fn get_int(&mut self) -> Result<i32, Errno> {
166        unsafe {
167            let mut int: MaybeUninit<i32> = MaybeUninit::uninit();
168            let res = spa_sys::spa_pod_parser_get_int(self.as_raw_ptr(), int.as_mut_ptr());
169            if res >= 0 {
170                Ok(int.assume_init())
171            } else {
172                Err(Errno::from_raw(-res))
173            }
174        }
175    }
176
177    pub fn get_long(&mut self) -> Result<i64, Errno> {
178        unsafe {
179            let mut long: MaybeUninit<i64> = MaybeUninit::uninit();
180            let res = spa_sys::spa_pod_parser_get_long(self.as_raw_ptr(), long.as_mut_ptr());
181            if res >= 0 {
182                Ok(long.assume_init())
183            } else {
184                Err(Errno::from_raw(-res))
185            }
186        }
187    }
188
189    pub fn get_float(&mut self) -> Result<c_float, Errno> {
190        unsafe {
191            let mut float: MaybeUninit<c_float> = MaybeUninit::uninit();
192            let res = spa_sys::spa_pod_parser_get_float(self.as_raw_ptr(), float.as_mut_ptr());
193            if res >= 0 {
194                Ok(float.assume_init())
195            } else {
196                Err(Errno::from_raw(-res))
197            }
198        }
199    }
200
201    pub fn get_double(&mut self) -> Result<c_double, Errno> {
202        unsafe {
203            let mut double: MaybeUninit<c_double> = MaybeUninit::uninit();
204            let res = spa_sys::spa_pod_parser_get_double(self.as_raw_ptr(), double.as_mut_ptr());
205            if res >= 0 {
206                Ok(double.assume_init())
207            } else {
208                Err(Errno::from_raw(-res))
209            }
210        }
211    }
212
213    pub fn get_string_raw(&mut self) -> Result<&'d CStr, Errno> {
214        unsafe {
215            let mut string: MaybeUninit<*const c_char> = MaybeUninit::uninit();
216            let res = spa_sys::spa_pod_parser_get_string(self.as_raw_ptr(), string.as_mut_ptr());
217            if res >= 0 {
218                let string = string.assume_init();
219                // FIXME: Do we need to check string for null?
220                let string = CStr::from_ptr(string);
221                Ok(string)
222            } else {
223                Err(Errno::from_raw(-res))
224            }
225        }
226    }
227
228    pub fn get_bytes(&mut self) -> Result<&'d [u8], Errno> {
229        unsafe {
230            let mut bytes: MaybeUninit<*const u8> = MaybeUninit::uninit();
231            let mut len: MaybeUninit<u32> = MaybeUninit::uninit();
232            let res = spa_sys::spa_pod_parser_get_bytes(
233                self.as_raw_ptr(),
234                bytes.as_mut_ptr().cast(),
235                len.as_mut_ptr(),
236            );
237            if res >= 0 {
238                let bytes = bytes.assume_init();
239                let len = len.assume_init();
240                // TODO: Do we need to check bytes for null?
241                let bytes = std::slice::from_raw_parts(bytes, len.try_into().unwrap());
242                Ok(bytes)
243            } else {
244                Err(Errno::from_raw(-res))
245            }
246        }
247    }
248
249    pub fn get_pointer(&mut self) -> Result<(*const c_void, Id), Errno> {
250        unsafe {
251            let mut ptr: MaybeUninit<*const c_void> = MaybeUninit::uninit();
252            let mut type_: MaybeUninit<u32> = MaybeUninit::uninit();
253            let res = spa_sys::spa_pod_parser_get_pointer(
254                self.as_raw_ptr(),
255                type_.as_mut_ptr(),
256                ptr.as_mut_ptr(),
257            );
258            if res >= 0 {
259                Ok((ptr.assume_init(), Id(type_.assume_init())))
260            } else {
261                Err(Errno::from_raw(-res))
262            }
263        }
264    }
265
266    pub fn get_fd(&mut self) -> Result<i64, Errno> {
267        unsafe {
268            let mut fd: MaybeUninit<i64> = MaybeUninit::uninit();
269            let res = spa_sys::spa_pod_parser_get_fd(self.as_raw_ptr(), fd.as_mut_ptr());
270            if res >= 0 {
271                Ok(fd.assume_init())
272            } else {
273                Err(Errno::from_raw(-res))
274            }
275        }
276    }
277
278    pub fn get_rectangle(&mut self) -> Result<Rectangle, Errno> {
279        unsafe {
280            let mut rect: MaybeUninit<spa_sys::spa_rectangle> = MaybeUninit::uninit();
281            let res = spa_sys::spa_pod_parser_get_rectangle(self.as_raw_ptr(), rect.as_mut_ptr());
282            if res >= 0 {
283                Ok(rect.assume_init())
284            } else {
285                Err(Errno::from_raw(-res))
286            }
287        }
288    }
289
290    pub fn get_fraction(&mut self) -> Result<Fraction, Errno> {
291        unsafe {
292            let mut frac: MaybeUninit<spa_sys::spa_fraction> = MaybeUninit::uninit();
293            let res = spa_sys::spa_pod_parser_get_fraction(self.as_raw_ptr(), frac.as_mut_ptr());
294            if res >= 0 {
295                Ok(frac.assume_init())
296            } else {
297                Err(Errno::from_raw(-res))
298            }
299        }
300    }
301
302    pub fn get_pod(&mut self) -> Result<&'d crate::pod::Pod, Errno> {
303        unsafe {
304            let mut pod: MaybeUninit<*mut spa_sys::spa_pod> = MaybeUninit::uninit();
305            let res = spa_sys::spa_pod_parser_get_pod(self.as_raw_ptr(), pod.as_mut_ptr());
306            if res >= 0 {
307                // Safety:
308                // spa_pod_parser_get_pod() guarantees that if res >= 0, then
309                // the returned pod is valid and fits in the parsed memory slice.
310                let pod = crate::pod::Pod::from_raw(pod.assume_init());
311
312                Ok(pod)
313            } else {
314                Err(Errno::from_raw(-res))
315            }
316        }
317    }
318
319    /// # Safety
320    /// The provided frame must not be moved or destroyed before it is popped again.
321    ///
322    /// The frame may only be assumed as initialized if this method returns `Ok`.
323    pub unsafe fn push_struct(
324        &mut self,
325        frame: &mut MaybeUninit<spa_sys::spa_pod_frame>,
326    ) -> Result<(), Errno> {
327        let res = spa_sys::spa_pod_parser_push_struct(self.as_raw_ptr(), frame.as_mut_ptr());
328
329        if res >= 0 {
330            Ok(())
331        } else {
332            Err(Errno::from_raw(-res))
333        }
334    }
335
336    /// # Safety
337    /// The provided frame must not be moved or destroyed before it is popped again.
338    ///
339    /// The frame may only be assumed as initialized if this method returns `Ok`.
340    pub unsafe fn push_object(
341        &mut self,
342        frame: &mut MaybeUninit<spa_sys::spa_pod_frame>,
343        _type: u32,
344    ) -> Result<Id, Errno> {
345        let mut id: MaybeUninit<u32> = MaybeUninit::uninit();
346        let res = spa_sys::spa_pod_parser_push_object(
347            self.as_raw_ptr(),
348            frame.as_mut_ptr(),
349            _type,
350            id.as_mut_ptr(),
351        );
352
353        if res >= 0 {
354            Ok(Id(id.assume_init()))
355        } else {
356            Err(Errno::from_raw(-res))
357        }
358    }
359}
360
361/// Convenience macro to parse values from a spa pod using a spa pod parser.
362///
363/// For arguments, the macro accepts the parser, and then the structure of the desired pods:
364///
365/// ```ignore
366/// parser_get!(<&mut libspa::pod::parser::Parser>, Bool(<&mut bool>));
367/// parser_get!(<&mut libspa::pod::parser::Parser>, Id(<&mut libspa::utils::Id>));
368/// parser_get!(<&mut libspa::pod::parser::Parser>, Int(<&mut i32>));
369/// parser_get!(<&mut libspa::pod::parser::Parser>, Long(<&mut i64>));
370/// parser_get!(<&mut libspa::pod::parser::Parser>, Float(<&mut f32>));
371/// parser_get!(<&mut libspa::pod::parser::Parser>, Double(<&mut f64>));
372/// parser_get!(<&mut libspa::pod::parser::Parser>, Bytes(<&mut &[u8]>));
373/// parser_get!(<&mut libspa::pod::parser::Parser>, Pointer(<&mut *const c_void>));
374/// parser_get!(<&mut libspa::pod::parser::Parser>, Fd(<&mut i64>));
375/// parser_get!(<&mut libspa::pod::parser::Parser>, Rectangle(<&mut libspa::utils::Rectangle>));
376/// parser_get!(<&mut libspa::pod::parser::Parser>, Fraction(<&mut libspa::utils::Fraction>));
377/// parser_get!(<&mut libspa::pod::parser::Parser>, Pod(<&mut &libspa::pod::Pod>));
378/// parser_get!(<&mut libspa::pod::parser::Parser>,
379///     Struct {
380///         // 0 to n fields, e.g.:
381///         Struct {
382///             Int(<&mut i32>),
383///             Float(<&mut f32>),
384///         },
385///         Bytes(<&mut &[u8]),
386///     }
387/// );
388/// ```
389///
390/// # Returns
391///
392/// The macro returns a `Result<(), Errno>`.
393/// If parsing succeeds, an `Ok(())` is returned.
394/// Otherwise, the `Err(Errno)` from the point where parsing failed is returned, and the rest of the values are not parsed.
395#[macro_export]
396macro_rules! __parser_get__ {
397    ($parser:expr, Bool($val:expr)) => {
398        {
399            let val: &mut bool = $val;
400            let res = $crate::pod::parser::Parser::get_bool($parser);
401            if let Ok(bool) = res {
402                *val = bool;
403            }
404            res.map(|_| {})
405        }
406    };
407    ($parser:expr, Id($val:expr)) => {
408        {
409            let val: &mut $crate::utils::Id = $val;
410            let res = $crate::pod::parser::Parser::get_id($parser);
411            if let Ok(id) = res {
412                *val = id;
413            }
414            res.map(|_| {})
415        }
416    };
417    ($parser:expr, Int($val:expr)) => {
418        {
419            let val: &mut i32 = $val;
420            let res = $crate::pod::parser::Parser::get_int($parser);
421            if let Ok(int) = res {
422                *val = int;
423            }
424            res.map(|_| {})
425        }
426    };
427    ($parser:expr, Long($val:expr)) => {
428        {
429            let val: &mut i64 = $val;
430            let res = $crate::pod::parser::Parser::get_long($parser);
431            if let Ok(long) = res {
432                *val = long;
433            }
434            res.map(|_| {})
435        }
436    };
437    ($parser:expr, Float($val:expr)) => {
438        {
439            let val: &mut f32 = $val;
440            let res = $crate::pod::parser::Parser::get_float($parser);
441            if let Ok(float) = res {
442                *val = float;
443            }
444            res.map(|_| {})
445        }
446    };
447    ($parser:expr, Double($val:expr)) => {
448        {
449            let val: &mut f64 = $val;
450            let res = $crate::pod::parser::Parser::get_double($parser);
451            if let Ok(double) = res {
452                *val = double;
453            }
454            res.map(|_| {})
455        }
456    };
457    // TODO: String
458    ($parser:expr, Bytes($val:expr)) => {
459        {
460            let val: &mut &[u8] = $val;
461            let res = $crate::pod::parser::Parser::get_bytes($parser);
462            if let Ok(bytes) = res {
463                *val = bytes;
464            }
465            res.map(|_| {})
466        }
467    };
468    ($parser:expr, Pointer($val:expr)) => {
469        {
470            let val: &mut (*const c_void, Id) = $val;
471            let res = $crate::pod::parser::Parser::get_pointer($parser);
472            if let Ok(ptr) = res {
473                *val = ptr;
474            }
475            res.map(|_| {})
476        }
477    };
478    ($parser:expr, Fd($val:expr)) => {
479        {
480            let val: &mut i64 = $val;
481            let res = $crate::pod::parser::Parser::get_fd($parser);
482            if let Ok(fd) = res {
483                *val = fd;
484            }
485            res.map(|_| {})
486        }
487    };
488    ($parser:expr, Rectangle($val:expr)) => {
489        {
490            let val: &mut $crate::utils::Rectangle = $val;
491            let res = $crate::pod::parser::Parser::get_rectangle($parser);
492            if let Ok(rect) = res {
493                *val = rect;
494            }
495            res.map(|_| {})
496        }
497    };
498    ($parser:expr, Fraction($val:expr)) => {
499        {
500            let val: &mut $crate::utils::Fraction = $val;
501            let res = $crate::pod::parser::Parser::get_fraction($parser);
502            if let Ok(fraction) = res {
503                *val = fraction;
504            }
505            res.map(|_| {})
506        }
507    };
508    ($parser:expr, Pod($val:expr)) => {
509        {
510            let val: &mut $crate::pod::Pod = $val;
511            let res = $crate::pod::parser::Parser::get_pod($parser);
512            if let Ok(pod) = res {
513                *val = pod;
514            }
515            res.map(|_| {})
516        }
517    };
518    ($parser:expr, Struct { $( $field_type:tt $field:tt ),* $(,)? }) => {
519        'outer: {
520            // Ensure that $parser expansion doesn't contain unsafe code without an unsafe block.
521            if false {
522                let _ = $parser;
523            }
524
525            let mut frame: ::std::mem::MaybeUninit<$crate::sys::spa_pod_frame> = ::std::mem::MaybeUninit::uninit();
526            let res = unsafe { $crate::pod::parser::Parser::push_struct($parser, &mut frame) };
527            if res.is_err() {
528                break 'outer res;
529            }
530
531            $(
532                let res = $crate::__parser_get__!($parser, $field_type $field);
533                if res.is_err() {
534                    // Discard Ok variant value so we can assign to Result<(), Errno>
535                    break 'outer res.map(|_| {});
536                }
537            )*
538
539            unsafe { $crate::pod::parser::Parser::pop($parser, frame.assume_init_mut()) }
540        }
541    };
542    // TODO: Object
543    // TODO: ($parser:expr, Option( $type_:tt $val:tt )) or similar for optional values
544}
545pub use __parser_get__ as parser_get;
546
547#[cfg(test)]
548mod tests {
549    use super::{parser_get, Parser};
550
551    // FIXME: The way we construct raw pods here is rather crude and error-prone.
552    //        Maybe replace it with the pod builder in the future, and share the tests with it.
553
554    #[test]
555    #[cfg_attr(miri, ignore)]
556    fn parse_bool() {
557        let pod: Vec<u8> = [
558            &4u32.to_ne_bytes(), // bool body size
559            &2u32.to_ne_bytes(), // bool type
560            &1u32.to_ne_bytes(), // bool "true"
561            &[0, 0, 0, 0],       // padding
562        ]
563        .into_iter()
564        .flatten()
565        .copied()
566        .collect();
567
568        let mut parser = Parser::new(&pod);
569        let mut bool = false;
570
571        let res = parser_get!(&mut parser, Bool(&mut bool));
572
573        assert!(res.is_ok());
574        assert!(bool);
575    }
576
577    #[test]
578    #[cfg_attr(miri, ignore)]
579    fn parse_empty_struct() {
580        let pod: Vec<u8> = [
581            &0u32.to_ne_bytes(),  // body size: 0 children => 0 bytes
582            &14u32.to_ne_bytes(), // struct type
583        ]
584        .into_iter()
585        .flatten()
586        .copied()
587        .collect();
588
589        let mut parser = Parser::new(&pod);
590
591        let res = parser_get!(&mut parser, Struct {});
592
593        assert!(res.is_ok());
594    }
595
596    #[test]
597    #[cfg_attr(miri, ignore)]
598    fn parse_complicated_struct() {
599        let pod: &[&[u8]] = &[
600            &168u32.to_ne_bytes(), // body size: (1 child * 104 bytes) + (4 children * 16 bytes per child) = 168 bytes
601            &14u32.to_ne_bytes(),  // struct type
602            // begin inner struct
603            &96u32.to_ne_bytes(), // body size: (6 children * 16 bytes per child) = 96 bytes
604            &14u32.to_ne_bytes(), // struct type
605            &4u32.to_ne_bytes(),  // bool body size
606            &2u32.to_ne_bytes(),  // bool type
607            &1u32.to_ne_bytes(),  // bool "true"
608            &[0, 0, 0, 0],        // padding
609            &4u32.to_ne_bytes(),  // id body size
610            &3u32.to_ne_bytes(),  // id type
611            &313u32.to_ne_bytes(), // id 313
612            &[0, 0, 0, 0],        // padding
613            &4u32.to_ne_bytes(),  // int body size
614            &4u32.to_ne_bytes(),  // int type
615            &313i32.to_ne_bytes(), // int 313
616            &[0, 0, 0, 0],        // padding
617            &8u32.to_ne_bytes(),  // long body size
618            &5u32.to_ne_bytes(),  // long type
619            &313i64.to_ne_bytes(), // long 313
620            &4u32.to_ne_bytes(),  // float body size
621            &6u32.to_ne_bytes(),  // float type
622            &31.3f32.to_ne_bytes(), // float 31.3
623            &[0, 0, 0, 0],        // padding
624            &8u32.to_ne_bytes(),  // double body size
625            &7u32.to_ne_bytes(),  // double type
626            &31.3f64.to_ne_bytes(), // double 31.3
627            // end inner struct
628            &3u32.to_ne_bytes(),   // bytes body size
629            &9u32.to_ne_bytes(),   // bytes type
630            &[3, 1, 3],            // bytes [3u8, 1u8, 3u8]
631            &[0, 0, 0, 0, 0],      // padding
632            &8u32.to_ne_bytes(),   // fd body size
633            &18u32.to_ne_bytes(),  // fd type
634            &313i64.to_ne_bytes(), // fd 313
635            &8u32.to_ne_bytes(),   // rectangle body size
636            &10u32.to_ne_bytes(),  // rectangle type
637            &313u32.to_ne_bytes(), // rectangle width 313
638            &131u32.to_ne_bytes(), // rectangle height 131
639            &8u32.to_ne_bytes(),   // fraction body size
640            &11u32.to_ne_bytes(),  // fraction type
641            &313u32.to_ne_bytes(), // fraction num 313
642            &131u32.to_ne_bytes(), // fraction denom 131
643        ];
644        let pod: Vec<u8> = pod.iter().flat_map(|f| *f).copied().collect();
645
646        let mut parser = Parser::new(&pod);
647
648        let mut bool = false;
649        let mut id = crate::utils::Id(0);
650        let mut int = 0i32;
651        let mut long = 0i64;
652        let mut float = 0.0f32;
653        let mut double = 0.0f64;
654        let mut bytes: &[u8] = &[];
655        let mut fd = 0i64;
656        let mut rect = crate::utils::Rectangle {
657            width: 0,
658            height: 0,
659        };
660        let mut frac = crate::utils::Fraction { num: 0, denom: 1 };
661
662        let res = parser_get!(
663            &mut parser,
664            Struct {
665                Struct {
666                    Bool(&mut bool),
667                    Id(&mut id),
668                    Int(&mut int),
669                    Long(&mut long),
670                    Float(&mut float),
671                    Double(&mut double),
672                },
673                Bytes(&mut bytes),
674                Fd(&mut fd),
675                Rectangle(&mut rect),
676                Fraction(&mut frac),
677            }
678        );
679
680        assert!(res.is_ok());
681        assert!(bool);
682        assert_eq!(id, crate::utils::Id(313));
683        assert_eq!(int, 313);
684        assert_eq!(long, 313);
685        assert_eq!(float, 31.3);
686        assert_eq!(double, 31.3);
687        assert_eq!(bytes, &[3, 1, 3]);
688        assert_eq!(fd, 313);
689        assert_eq!(
690            rect,
691            crate::utils::Rectangle {
692                width: 313,
693                height: 131
694            }
695        );
696        assert_eq!(
697            frac,
698            crate::utils::Fraction {
699                num: 313,
700                denom: 131
701            }
702        );
703    }
704}