libspa/pod/
mod.rs

1//! This module deals with SPA pods, providing ways to represent pods using idiomatic types
2//! and serialize them into their raw representation, and the other way around.
3//!
4//! Everything concerning serializing raw pods from rust types is in the [`serialize`] submodule.
5//! and everything about deserializing rust types from raw pods is in the [`deserialize`] submodule.
6//!
7//! The entire serialization and deserialization approach is inspired by and similar to the excellent `serde` crate,
8//! but is much more specialized to fit the SPA pod format.
9
10pub mod builder;
11pub mod deserialize;
12pub mod parser;
13pub mod serialize;
14
15use std::{
16    ffi::{c_char, c_void, CStr},
17    io::{Seek, Write},
18    mem::MaybeUninit,
19    os::fd::RawFd,
20    ptr::addr_of,
21};
22
23use bitflags::bitflags;
24use cookie_factory::{
25    bytes::{ne_f32, ne_f64, ne_i32, ne_i64, ne_u32},
26    gen_simple,
27    sequence::pair,
28    GenError,
29};
30use nix::errno::Errno;
31use nom::{
32    combinator::map,
33    number::{
34        complete::{f32, f64, i32, i64, u32},
35        Endianness,
36    },
37    IResult, Parser,
38};
39
40use deserialize::{BoolVisitor, NoneVisitor, PodDeserialize, PodDeserializer};
41use serialize::{PodSerialize, PodSerializer};
42
43use crate::utils::{Choice, Fd, Fraction, Id, Rectangle, SpaTypes};
44
45use self::deserialize::{
46    ChoiceBoolVisitor, ChoiceDoubleVisitor, ChoiceFdVisitor, ChoiceFloatVisitor,
47    ChoiceFractionVisitor, ChoiceIdVisitor, ChoiceIntVisitor, ChoiceLongVisitor,
48    ChoiceRectangleVisitor, DoubleVisitor, FdVisitor, FloatVisitor, FractionVisitor, IdVisitor,
49    IntVisitor, LongVisitor, PointerVisitor, RectangleVisitor,
50};
51
52/// A transparent wrapper around a `spa_sys::spa_pod`.
53#[repr(transparent)]
54pub struct Pod(spa_sys::spa_pod);
55
56impl Pod {
57    /// # Safety
58    ///
59    /// The provided pointer must point to a valid, well-aligned pod.
60    ///
61    /// The pods allocation must fit the entire size of the pod as indicated
62    /// by the pods header, including header size, body size and any padding.
63    ///
64    /// The provided pod must not be mutated, moved, freed or similar while
65    /// the borrow returned from this function is in use.
66    /// This also means that other nonmutable borrows may be created to this pod,
67    /// but no mutable borrows to this pod may be created until all borrows are dropped.
68    ///
69    /// The returned type has `'static` lifetime.
70    /// It is suggested to shorten the lifetime to whatever is applicable afterwards.
71    pub unsafe fn from_raw(pod: *const spa_sys::spa_pod) -> &'static Self {
72        pod.cast::<Self>().as_ref().unwrap()
73    }
74
75    /// # Safety
76    ///
77    /// The provided pointer must point to a valid, well-aligned pod.
78    ///
79    /// The pods allocation must fit the entire size of the pod as indicated
80    /// by the pods header, including header size, body size and any padding.
81    ///
82    /// The provided pod must not be mutated, moved, freed or similar while
83    /// the borrow returned from this function is in use.
84    /// This also means that no other borrow to this pod may be created until the borrow is dropped.
85    ///
86    /// The returned type has `'static` lifetime.
87    /// It is suggested to shorten the lifetime to whatever is applicable afterwards.
88    pub unsafe fn from_raw_mut(pod: *mut spa_sys::spa_pod) -> &'static mut Self {
89        pod.cast::<Self>().as_mut().unwrap()
90    }
91
92    pub fn as_raw_ptr(&self) -> *mut spa_sys::spa_pod {
93        addr_of!(self.0).cast_mut()
94    }
95
96    /// Returns a pointer to the pods body.
97    ///
98    /// If the pod has an empty body, this can be outside the pods allocation.
99    pub fn body(&self) -> *mut c_void {
100        unsafe {
101            self.as_raw_ptr()
102                .byte_add(std::mem::size_of::<spa_sys::spa_pod>())
103                .cast()
104        }
105    }
106
107    /// Construct a pod from raw bytes.
108    ///
109    /// The provided slice must be big enough to fit the entire pod including padding.
110    pub fn from_bytes(bytes: &[u8]) -> Option<&Self> {
111        // Ensure bytes contains at least a readable pod header
112        // that we can read the pods size from
113
114        const HEADER_SIZE: usize = std::mem::size_of::<spa_sys::spa_pod>();
115
116        if bytes.len() < HEADER_SIZE {
117            return None;
118        }
119
120        let pod: *const spa_sys::spa_pod = bytes.as_ptr().cast();
121
122        // `pod` now points to a valid pod header that we can read
123        let size: usize = unsafe { *pod }.size.try_into().unwrap();
124
125        let padding = (8 - (size % 8)) % 8;
126
127        // Now, ensure that `bytes` is big enough to fit the entire pod
128        if HEADER_SIZE + size + padding <= bytes.len() {
129            // Bytes is big enough to fit the entire header, body and padding.
130            // We can safely convert this to a &Pod
131            Some(unsafe { Self::from_raw(pod) })
132        } else {
133            None
134        }
135    }
136
137    pub fn as_bytes(&self) -> &[u8] {
138        let ptr: *const u8 = self.as_raw_ptr().cast();
139        let size: usize = self.size().try_into().unwrap();
140        let size = size + std::mem::size_of::<spa_sys::spa_pod>();
141
142        unsafe { std::slice::from_raw_parts(ptr, size) }
143    }
144
145    pub fn type_(&self) -> SpaTypes {
146        SpaTypes::from_raw(self.0.type_)
147    }
148
149    pub fn size(&self) -> u32 {
150        self.0.size
151    }
152
153    // TODO: Other methods from iter.h that are still missing
154
155    pub fn is_none(&self) -> bool {
156        let res = unsafe { spa_sys::spa_pod_is_none(self.as_raw_ptr()) };
157        res != 0
158    }
159
160    pub fn is_bool(&self) -> bool {
161        let res = unsafe { spa_sys::spa_pod_is_bool(self.as_raw_ptr()) };
162        res != 0
163    }
164
165    pub fn get_bool(&self) -> Result<bool, Errno> {
166        unsafe {
167            let mut b: MaybeUninit<bool> = MaybeUninit::uninit();
168            let res = spa_sys::spa_pod_get_bool(self.as_raw_ptr(), b.as_mut_ptr());
169
170            if res >= 0 {
171                Ok(b.assume_init())
172            } else {
173                Err(Errno::from_raw(-res))
174            }
175        }
176    }
177
178    pub fn is_id(&self) -> bool {
179        let res = unsafe { spa_sys::spa_pod_is_id(self.as_raw_ptr()) };
180        res != 0
181    }
182
183    pub fn get_id(&self) -> Result<Id, Errno> {
184        unsafe {
185            let mut id: MaybeUninit<u32> = MaybeUninit::uninit();
186            let res = spa_sys::spa_pod_get_id(self.as_raw_ptr(), id.as_mut_ptr());
187
188            if res >= 0 {
189                Ok(Id(id.assume_init()))
190            } else {
191                Err(Errno::from_raw(-res))
192            }
193        }
194    }
195
196    pub fn is_int(&self) -> bool {
197        let res = unsafe { spa_sys::spa_pod_is_int(self.as_raw_ptr()) };
198        res != 0
199    }
200
201    pub fn get_int(&self) -> Result<i32, Errno> {
202        unsafe {
203            let mut int: MaybeUninit<i32> = MaybeUninit::uninit();
204            let res = spa_sys::spa_pod_get_int(self.as_raw_ptr(), int.as_mut_ptr());
205
206            if res >= 0 {
207                Ok(int.assume_init())
208            } else {
209                Err(Errno::from_raw(-res))
210            }
211        }
212    }
213
214    pub fn is_long(&self) -> bool {
215        let res = unsafe { spa_sys::spa_pod_is_long(self.as_raw_ptr()) };
216        res != 0
217    }
218
219    pub fn get_long(&self) -> Result<i64, Errno> {
220        unsafe {
221            let mut long: MaybeUninit<i64> = MaybeUninit::uninit();
222            let res = spa_sys::spa_pod_get_long(self.as_raw_ptr(), long.as_mut_ptr());
223
224            if res >= 0 {
225                Ok(long.assume_init())
226            } else {
227                Err(Errno::from_raw(-res))
228            }
229        }
230    }
231
232    pub fn is_float(&self) -> bool {
233        let res = unsafe { spa_sys::spa_pod_is_float(self.as_raw_ptr()) };
234        res != 0
235    }
236
237    pub fn get_float(&self) -> Result<f32, Errno> {
238        unsafe {
239            let mut float: MaybeUninit<f32> = MaybeUninit::uninit();
240            let res = spa_sys::spa_pod_get_float(self.as_raw_ptr(), float.as_mut_ptr());
241
242            if res >= 0 {
243                Ok(float.assume_init())
244            } else {
245                Err(Errno::from_raw(-res))
246            }
247        }
248    }
249
250    pub fn is_double(&self) -> bool {
251        let res = unsafe { spa_sys::spa_pod_is_double(self.as_raw_ptr()) };
252        res != 0
253    }
254
255    pub fn get_double(&self) -> Result<f64, Errno> {
256        unsafe {
257            let mut double: MaybeUninit<f64> = MaybeUninit::uninit();
258            let res = spa_sys::spa_pod_get_double(self.as_raw_ptr(), double.as_mut_ptr());
259
260            if res >= 0 {
261                Ok(double.assume_init())
262            } else {
263                Err(Errno::from_raw(-res))
264            }
265        }
266    }
267
268    pub fn is_string(&self) -> bool {
269        let res = unsafe { spa_sys::spa_pod_is_string(self.as_raw_ptr()) };
270        res != 0
271    }
272
273    pub fn get_string_raw(&self) -> Result<Option<&CStr>, Errno> {
274        unsafe {
275            let mut value: MaybeUninit<*const c_char> = MaybeUninit::uninit();
276            let res = spa_sys::spa_pod_get_string(self.as_raw_ptr(), value.as_mut_ptr());
277
278            if res >= 0 {
279                let value = value.assume_init();
280                if value.is_null() {
281                    Ok(None)
282                } else {
283                    Ok(Some(CStr::from_ptr(value)))
284                }
285            } else {
286                Err(Errno::from_raw(-res))
287            }
288        }
289    }
290
291    pub fn is_bytes(&self) -> bool {
292        let res = unsafe { spa_sys::spa_pod_is_bytes(self.as_raw_ptr()) };
293        res != 0
294    }
295
296    pub fn get_bytes(&self) -> Result<&[u8], Errno> {
297        unsafe {
298            let mut bytes: MaybeUninit<*const c_void> = MaybeUninit::uninit();
299            let mut len: MaybeUninit<u32> = MaybeUninit::uninit();
300            let res =
301                spa_sys::spa_pod_get_bytes(self.as_raw_ptr(), bytes.as_mut_ptr(), len.as_mut_ptr());
302
303            if res >= 0 {
304                let bytes = bytes.assume_init();
305                let len = len.assume_init();
306                let bytes = std::slice::from_raw_parts(bytes.cast(), len.try_into().unwrap());
307                Ok(bytes)
308            } else {
309                Err(Errno::from_raw(-res))
310            }
311        }
312    }
313
314    pub fn is_pointer(&self) -> bool {
315        let res = unsafe { spa_sys::spa_pod_is_pointer(self.as_raw_ptr()) };
316        res != 0
317    }
318
319    pub fn get_pointer(&self) -> Result<(*const c_void, Id), Errno> {
320        unsafe {
321            let mut _type: MaybeUninit<u32> = MaybeUninit::uninit();
322            let mut pointer: MaybeUninit<*const c_void> = MaybeUninit::uninit();
323            let res = spa_sys::spa_pod_get_pointer(
324                self.as_raw_ptr(),
325                _type.as_mut_ptr(),
326                pointer.as_mut_ptr(),
327            );
328
329            if res >= 0 {
330                let _type = Id(_type.assume_init());
331                let pointer = pointer.assume_init();
332                Ok((pointer, _type))
333            } else {
334                Err(Errno::from_raw(-res))
335            }
336        }
337    }
338
339    pub fn is_fd(&self) -> bool {
340        let res = unsafe { spa_sys::spa_pod_is_fd(self.as_raw_ptr()) };
341        res != 0
342    }
343
344    pub fn get_fd(&self) -> Result<RawFd, Errno> {
345        unsafe {
346            let mut fd: MaybeUninit<i64> = MaybeUninit::uninit();
347            let res = spa_sys::spa_pod_get_fd(self.as_raw_ptr(), fd.as_mut_ptr());
348
349            if res >= 0 {
350                let fd = fd.assume_init();
351                let fd: RawFd = fd.try_into().unwrap();
352                Ok(fd)
353            } else {
354                Err(Errno::from_raw(-res))
355            }
356        }
357    }
358
359    pub fn is_rectangle(&self) -> bool {
360        let res = unsafe { spa_sys::spa_pod_is_rectangle(self.as_raw_ptr()) };
361        res != 0
362    }
363
364    pub fn get_rectangle(&self) -> Result<Rectangle, Errno> {
365        unsafe {
366            let mut rectangle: MaybeUninit<spa_sys::spa_rectangle> = MaybeUninit::uninit();
367            let res = spa_sys::spa_pod_get_rectangle(self.as_raw_ptr(), rectangle.as_mut_ptr());
368
369            if res >= 0 {
370                Ok(rectangle.assume_init())
371            } else {
372                Err(Errno::from_raw(-res))
373            }
374        }
375    }
376
377    pub fn is_fraction(&self) -> bool {
378        let res = unsafe { spa_sys::spa_pod_is_fraction(self.as_raw_ptr()) };
379        res != 0
380    }
381
382    pub fn get_fraction(&self) -> Result<Fraction, Errno> {
383        unsafe {
384            let mut fraction: MaybeUninit<spa_sys::spa_fraction> = MaybeUninit::uninit();
385            let res = spa_sys::spa_pod_get_fraction(self.as_raw_ptr(), fraction.as_mut_ptr());
386
387            if res >= 0 {
388                Ok(fraction.assume_init())
389            } else {
390                Err(Errno::from_raw(-res))
391            }
392        }
393    }
394
395    pub fn is_bitmap(&self) -> bool {
396        let res = unsafe { spa_sys::spa_pod_is_bitmap(self.as_raw_ptr()) };
397        res != 0
398    }
399
400    pub fn is_array(&self) -> bool {
401        let res = unsafe { spa_sys::spa_pod_is_array(self.as_raw_ptr()) };
402        res != 0
403    }
404
405    pub fn is_choice(&self) -> bool {
406        let res = unsafe { spa_sys::spa_pod_is_choice(self.as_raw_ptr()) };
407        res != 0
408    }
409
410    pub fn is_struct(&self) -> bool {
411        let res = unsafe { spa_sys::spa_pod_is_struct(self.as_raw_ptr()) };
412        res != 0
413    }
414
415    pub fn as_struct(&self) -> Result<&PodStruct, Errno> {
416        if self.is_struct() {
417            // Safety: We already know that the pod is valid, and since it is a struct, we can
418            //         safely create a PodStruct from it
419            Ok(unsafe { PodStruct::from_raw(self.as_raw_ptr() as *const spa_sys::spa_pod_struct) })
420        } else {
421            Err(Errno::EINVAL)
422        }
423    }
424
425    pub fn is_object(&self) -> bool {
426        let res = unsafe { spa_sys::spa_pod_is_object(self.as_raw_ptr()) };
427        res != 0
428    }
429
430    // TODO: spa_pod_is_object_type, spa_pod_is_object_id
431
432    pub fn as_object(&self) -> Result<&PodObject, Errno> {
433        if self.is_object() {
434            // Safety: We already know that the pod is valid, and since it is an object, we can
435            //         safely create a PodObject from it
436            Ok(unsafe { PodObject::from_raw(self.as_raw_ptr() as *const spa_sys::spa_pod_object) })
437        } else {
438            Err(Errno::EINVAL)
439        }
440    }
441
442    pub fn is_sequence(&self) -> bool {
443        let res = unsafe { spa_sys::spa_pod_is_sequence(self.as_raw_ptr()) };
444        res != 0
445    }
446}
447
448impl<'p> From<&'p PodStruct> for &'p Pod {
449    fn from(value: &'p PodStruct) -> Self {
450        value.as_pod()
451    }
452}
453
454impl<'p> From<&'p PodObject> for &'p Pod {
455    fn from(value: &'p PodObject) -> Self {
456        value.as_pod()
457    }
458}
459
460/// A transparent wrapper around a `spa_sys::spa_pod_struct`.
461#[repr(transparent)]
462pub struct PodStruct(spa_sys::spa_pod_struct);
463
464impl PodStruct {
465    /// # Safety
466    ///
467    /// The provided pointer must point to a valid, well-aligned pod of type struct.
468    ///
469    /// All restrictions from [`Pod::from_raw`] also apply here.
470    pub unsafe fn from_raw(pod: *const spa_sys::spa_pod_struct) -> &'static Self {
471        pod.cast::<Self>().as_ref().unwrap()
472    }
473
474    /// # Safety
475    ///
476    /// The provided pointer must point to a valid, well-aligned pod of type struct.
477    ///
478    /// All restrictions from [`Pod::from_raw_mut`] also apply here.
479    pub unsafe fn from_raw_mut(pod: *mut spa_sys::spa_pod_struct) -> &'static mut Self {
480        pod.cast::<Self>().as_mut().unwrap()
481    }
482
483    pub fn as_raw_ptr(&self) -> *mut spa_sys::spa_pod_struct {
484        std::ptr::addr_of!(self.0).cast_mut()
485    }
486
487    pub fn as_pod(&self) -> &Pod {
488        // Safety: Since this is a valid spa_pod_object, it must also be a valid spa_pod
489        unsafe { Pod::from_raw(addr_of!(self.0.pod)) }
490    }
491
492    pub fn fields(&self) -> PodStructIter<'_> {
493        PodStructIter::new(self)
494    }
495}
496
497impl<'p> TryFrom<&'p Pod> for &'p PodStruct {
498    type Error = Errno;
499
500    fn try_from(value: &'p Pod) -> Result<Self, Self::Error> {
501        value.as_struct()
502    }
503}
504
505impl AsRef<Pod> for PodStruct {
506    fn as_ref(&self) -> &Pod {
507        self.as_pod()
508    }
509}
510
511pub struct PodStructIter<'s> {
512    struct_pod: &'s PodStruct,
513    next: *mut c_void,
514}
515
516impl<'s> PodStructIter<'s> {
517    fn new(struct_pod: &'s PodStruct) -> Self {
518        let first_field = struct_pod.as_pod().body();
519
520        Self {
521            struct_pod,
522            next: first_field,
523        }
524    }
525}
526
527impl<'s> Iterator for PodStructIter<'s> {
528    type Item = &'s Pod;
529
530    fn next(&mut self) -> Option<Self::Item> {
531        // Check if the iterator has at least one element left that we can return
532        let has_next = unsafe {
533            spa_sys::spa_pod_is_inside(
534                self.struct_pod.as_pod().body(),
535                self.struct_pod.0.pod.size,
536                self.next,
537            )
538        };
539
540        if has_next {
541            let res = unsafe { Pod::from_raw(self.next as *const spa_sys::spa_pod) };
542
543            // Advance iter to next property
544            self.next = unsafe { spa_sys::spa_pod_next(self.next) };
545
546            Some(res)
547        } else {
548            None
549        }
550    }
551}
552
553/// A transparent wrapper around a `spa_sys::spa_pod_object`.
554#[repr(transparent)]
555pub struct PodObject(spa_sys::spa_pod_object);
556
557impl PodObject {
558    /// # Safety
559    ///
560    /// The provided pointer must point to a valid, well-aligned pod of type object.
561    ///
562    /// All restrictions from [`Pod::from_raw`] also apply here.
563    pub unsafe fn from_raw(pod: *const spa_sys::spa_pod_object) -> &'static Self {
564        pod.cast::<Self>().as_ref().unwrap()
565    }
566
567    /// # Safety
568    ///
569    /// The provided pointer must point to a valid, well-aligned pod of type object.
570    ///
571    /// All restrictions from [`Pod::from_raw_mut`] also apply here.
572    pub unsafe fn from_raw_mut(pod: *mut spa_sys::spa_pod_object) -> &'static mut Self {
573        pod.cast::<Self>().as_mut().unwrap()
574    }
575
576    pub fn as_raw_ptr(&self) -> *mut spa_sys::spa_pod_object {
577        std::ptr::addr_of!(self.0).cast_mut()
578    }
579
580    pub fn as_pod(&self) -> &Pod {
581        // Safety: Since this is a valid spa_pod_object, it must also be a valid spa_pod
582        unsafe { Pod::from_raw(addr_of!(self.0.pod)) }
583    }
584
585    pub fn type_(&self) -> SpaTypes {
586        SpaTypes::from_raw(self.0.body.type_)
587    }
588
589    pub fn id(&self) -> Id {
590        Id(self.0.body.id)
591    }
592
593    pub fn props(&self) -> PodObjectIter<'_> {
594        PodObjectIter::new(self)
595    }
596
597    pub fn find_prop(&self, /* TODO: start, */ key: Id) -> Option<&PodProp> {
598        let prop = unsafe {
599            spa_sys::spa_pod_object_find_prop(self.as_raw_ptr(), std::ptr::null(), key.0)
600        };
601
602        if !prop.is_null() {
603            unsafe { Some(PodProp::from_raw(prop)) }
604        } else {
605            None
606        }
607    }
608
609    pub fn fixate(&mut self) {
610        let _res = unsafe { spa_sys::spa_pod_object_fixate(self.as_raw_ptr()) };
611        // C implementation always returns 0
612    }
613
614    #[cfg(feature = "v0_3_40")]
615    pub fn is_fixated(&self) -> bool {
616        let res = unsafe { spa_sys::spa_pod_object_is_fixated(self.as_raw_ptr()) };
617        res != 0
618    }
619}
620
621impl<'p> TryFrom<&'p Pod> for &'p PodObject {
622    type Error = Errno;
623
624    fn try_from(value: &'p Pod) -> Result<Self, Self::Error> {
625        value.as_object()
626    }
627}
628
629impl AsRef<Pod> for PodObject {
630    fn as_ref(&self) -> &Pod {
631        self.as_pod()
632    }
633}
634
635pub struct PodObjectIter<'o> {
636    object: &'o PodObject,
637    next: *mut spa_sys::spa_pod_prop,
638}
639
640impl<'o> PodObjectIter<'o> {
641    fn new(object: &'o PodObject) -> Self {
642        let first_prop = unsafe { spa_sys::spa_pod_prop_first(addr_of!(object.0.body)) };
643
644        Self {
645            object,
646            next: first_prop,
647        }
648    }
649}
650
651impl<'o> Iterator for PodObjectIter<'o> {
652    type Item = &'o PodProp;
653
654    fn next(&mut self) -> Option<Self::Item> {
655        // Check if the iterator has at least one element left that we can return
656        let has_next = unsafe {
657            spa_sys::spa_pod_prop_is_inside(
658                addr_of!(self.object.0.body),
659                self.object.0.pod.size,
660                self.next,
661            )
662        };
663
664        if has_next {
665            let res = unsafe { PodProp::from_raw(self.next.cast_const()) };
666
667            // Advance iter to next property
668            self.next = unsafe { spa_sys::spa_pod_prop_next(self.next) };
669
670            Some(res)
671        } else {
672            None
673        }
674    }
675}
676
677bitflags! {
678    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
679    pub struct PodPropFlags: u32 {
680        const READONLY = spa_sys::SPA_POD_PROP_FLAG_READONLY;
681        const HARDWARE = spa_sys::SPA_POD_PROP_FLAG_HARDWARE;
682        const HINT_DICT = spa_sys::SPA_POD_PROP_FLAG_HINT_DICT;
683        const MANDATORY = spa_sys::SPA_POD_PROP_FLAG_MANDATORY;
684        const DONT_FIXATE = spa_sys::SPA_POD_PROP_FLAG_DONT_FIXATE;
685    }
686}
687
688/// A transparent wrapper around a `spa_sys::spa_pod_prop`.
689#[repr(transparent)]
690pub struct PodProp(spa_sys::spa_pod_prop);
691
692impl PodProp {
693    /// # Safety
694    ///
695    /// The provided pointer must point to a valid, well-aligned [`spa_sys::spa_pod_prop`].
696    ///
697    /// While this struct doesn't represent a full pod, all restrictions from [`Pod::from_raw`] also apply
698    /// to this struct and the contained `value` pod.
699    pub unsafe fn from_raw(prop: *const spa_sys::spa_pod_prop) -> &'static Self {
700        prop.cast::<Self>().as_ref().unwrap()
701    }
702
703    /// # Safety
704    ///
705    /// The provided pointer must point to a valid, well-aligned pod of type object.
706    ///
707    /// While this struct doesn't represent a full pod, all restrictions from [`Pod::from_raw`] also apply
708    /// to this struct and the contained `value` pod.
709    pub unsafe fn from_raw_mut(prop: *mut spa_sys::spa_pod_prop) -> &'static mut Self {
710        prop.cast::<Self>().as_mut().unwrap()
711    }
712
713    pub fn as_raw_ptr(&self) -> *mut spa_sys::spa_pod_prop {
714        std::ptr::addr_of!(self.0).cast_mut()
715    }
716
717    pub fn key(&self) -> Id {
718        Id(self.0.key)
719    }
720
721    pub fn flags(&self) -> PodPropFlags {
722        PodPropFlags::from_bits_retain(self.0.flags)
723    }
724
725    pub fn value(&self) -> &Pod {
726        // Safety: Since PodProp may only be constructed around valid Pods, the contained value must also be valid.
727        //         We don't mutate the pod and neither can the returned reference.
728        //         The returned lifetime is properly shortened by this methods signature.
729        unsafe { Pod::from_raw(addr_of!(self.0.value)) }
730    }
731}
732
733/// Implementors of this trait are the canonical representation of a specific type of fixed sized SPA pod.
734///
735/// They can be used as an output type for [`FixedSizedPod`] implementors
736/// and take care of the actual serialization/deserialization from/to the type of raw SPA pod they represent.
737///
738/// The trait is sealed, so it can't be implemented outside of this crate.
739/// This is to ensure that no invalid pod can be serialized.
740///
741/// If you want to have your type convert from and to a fixed sized pod, implement [`FixedSizedPod`] instead and choose
742/// a fitting implementor of this trait as the `CanonicalType` instead.
743pub trait CanonicalFixedSizedPod: private::CanonicalFixedSizedPodSeal {
744    /// The raw type this serializes into.
745    #[doc(hidden)]
746    const TYPE: u32;
747    /// The size of the pods body.
748    #[doc(hidden)]
749    const SIZE: u32;
750    #[doc(hidden)]
751    fn serialize_body<O: Write>(&self, out: O) -> Result<O, GenError>;
752    #[doc(hidden)]
753    fn deserialize_body(input: &[u8]) -> IResult<&[u8], Self>
754    where
755        Self: Sized;
756}
757
758mod private {
759    /// This trait makes [`super::CanonicalFixedSizedPod`] a "sealed trait", which makes it impossible to implement
760    /// outside of this crate.
761    pub trait CanonicalFixedSizedPodSeal {}
762    impl CanonicalFixedSizedPodSeal for () {}
763    impl CanonicalFixedSizedPodSeal for bool {}
764    impl CanonicalFixedSizedPodSeal for i32 {}
765    impl CanonicalFixedSizedPodSeal for i64 {}
766    impl CanonicalFixedSizedPodSeal for f32 {}
767    impl CanonicalFixedSizedPodSeal for f64 {}
768    impl CanonicalFixedSizedPodSeal for super::Rectangle {}
769    impl CanonicalFixedSizedPodSeal for super::Fraction {}
770    impl CanonicalFixedSizedPodSeal for super::Id {}
771    impl CanonicalFixedSizedPodSeal for super::Fd {}
772}
773
774impl<T: CanonicalFixedSizedPod + Copy> FixedSizedPod for T {
775    type CanonicalType = Self;
776
777    fn as_canonical_type(&self) -> Self::CanonicalType {
778        *self
779    }
780
781    fn from_canonical_type(canonical: &Self::CanonicalType) -> Self {
782        *canonical
783    }
784}
785
786/// Serialize into a `None` type pod.
787impl CanonicalFixedSizedPod for () {
788    const TYPE: u32 = spa_sys::SPA_TYPE_None;
789    const SIZE: u32 = 0;
790
791    fn serialize_body<O: Write>(&self, out: O) -> Result<O, GenError> {
792        Ok(out)
793    }
794
795    fn deserialize_body(input: &[u8]) -> IResult<&[u8], Self>
796    where
797        Self: Sized,
798    {
799        Ok((input, ()))
800    }
801}
802
803/// Serialize into a `Bool` type pod.
804impl CanonicalFixedSizedPod for bool {
805    const TYPE: u32 = spa_sys::SPA_TYPE_Bool;
806    const SIZE: u32 = 4;
807
808    fn serialize_body<O: Write>(&self, out: O) -> Result<O, GenError> {
809        gen_simple(ne_u32(u32::from(*self)), out)
810    }
811
812    fn deserialize_body(input: &[u8]) -> IResult<&[u8], Self>
813    where
814        Self: Sized,
815    {
816        map(u32(Endianness::Native), |b| b != 0).parse(input)
817    }
818}
819
820/// Serialize into a `Int` type pod.
821impl CanonicalFixedSizedPod for i32 {
822    const TYPE: u32 = spa_sys::SPA_TYPE_Int;
823    const SIZE: u32 = 4;
824
825    fn serialize_body<O: Write>(&self, out: O) -> Result<O, GenError> {
826        gen_simple(ne_i32(*self), out)
827    }
828
829    fn deserialize_body(input: &[u8]) -> IResult<&[u8], Self>
830    where
831        Self: Sized,
832    {
833        i32(Endianness::Native)(input)
834    }
835}
836
837/// Serialize into a `Long` type pod.
838impl CanonicalFixedSizedPod for i64 {
839    const TYPE: u32 = spa_sys::SPA_TYPE_Long;
840    const SIZE: u32 = 8;
841
842    fn serialize_body<O: Write>(&self, out: O) -> Result<O, GenError> {
843        gen_simple(ne_i64(*self), out)
844    }
845
846    fn deserialize_body(input: &[u8]) -> IResult<&[u8], Self>
847    where
848        Self: Sized,
849    {
850        i64(Endianness::Native)(input)
851    }
852}
853
854/// Serialize into a `Float` type pod.
855impl CanonicalFixedSizedPod for f32 {
856    const TYPE: u32 = spa_sys::SPA_TYPE_Float;
857    const SIZE: u32 = 4;
858
859    fn serialize_body<O: Write>(&self, out: O) -> Result<O, GenError> {
860        gen_simple(ne_f32(*self), out)
861    }
862
863    fn deserialize_body(input: &[u8]) -> IResult<&[u8], Self>
864    where
865        Self: Sized,
866    {
867        f32(Endianness::Native)(input)
868    }
869}
870
871/// Serialize into a `Double` type pod.
872impl CanonicalFixedSizedPod for f64 {
873    const TYPE: u32 = spa_sys::SPA_TYPE_Double;
874    const SIZE: u32 = 8;
875
876    fn serialize_body<O: Write>(&self, out: O) -> Result<O, GenError> {
877        gen_simple(ne_f64(*self), out)
878    }
879
880    fn deserialize_body(input: &[u8]) -> IResult<&[u8], Self>
881    where
882        Self: Sized,
883    {
884        f64(Endianness::Native)(input)
885    }
886}
887
888/// Serialize into a `Rectangle` type pod.
889impl CanonicalFixedSizedPod for Rectangle {
890    const TYPE: u32 = spa_sys::SPA_TYPE_Rectangle;
891    const SIZE: u32 = 8;
892
893    fn serialize_body<O: Write>(&self, out: O) -> Result<O, GenError> {
894        gen_simple(pair(ne_u32(self.width), ne_u32(self.height)), out)
895    }
896
897    fn deserialize_body(input: &[u8]) -> IResult<&[u8], Self>
898    where
899        Self: Sized,
900    {
901        map(
902            nom::sequence::pair(u32(Endianness::Native), u32(Endianness::Native)),
903            |(width, height)| Rectangle { width, height },
904        )
905        .parse(input)
906    }
907}
908
909/// Serialize into a `Fraction` type pod.
910impl CanonicalFixedSizedPod for Fraction {
911    const TYPE: u32 = spa_sys::SPA_TYPE_Fraction;
912    const SIZE: u32 = 8;
913
914    fn serialize_body<O: Write>(&self, out: O) -> Result<O, GenError> {
915        gen_simple(pair(ne_u32(self.num), ne_u32(self.denom)), out)
916    }
917
918    fn deserialize_body(input: &[u8]) -> IResult<&[u8], Self>
919    where
920        Self: Sized,
921    {
922        map(
923            nom::sequence::pair(u32(Endianness::Native), u32(Endianness::Native)),
924            |(num, denom)| Fraction { num, denom },
925        )
926        .parse(input)
927    }
928}
929
930impl CanonicalFixedSizedPod for Id {
931    const TYPE: u32 = spa_sys::SPA_TYPE_Id;
932    const SIZE: u32 = 4;
933
934    fn serialize_body<O: Write>(&self, out: O) -> Result<O, GenError> {
935        gen_simple(ne_u32(self.0), out)
936    }
937
938    fn deserialize_body(input: &[u8]) -> IResult<&[u8], Self>
939    where
940        Self: Sized,
941    {
942        map(u32(Endianness::Native), Id).parse(input)
943    }
944}
945
946impl CanonicalFixedSizedPod for Fd {
947    const TYPE: u32 = spa_sys::SPA_TYPE_Fd;
948    const SIZE: u32 = 8;
949
950    fn serialize_body<O: Write>(&self, out: O) -> Result<O, GenError> {
951        gen_simple(ne_i64(self.0), out)
952    }
953
954    fn deserialize_body(input: &[u8]) -> IResult<&[u8], Self>
955    where
956        Self: Sized,
957    {
958        map(i64(Endianness::Native), Fd).parse(input)
959    }
960}
961
962/// Implementors of this trait can be serialized into pods that always have the same size.
963/// This lets them be used as elements in `Array` type SPA Pods.
964///
965/// Implementors of this automatically implement [`PodSerialize`].
966///
967/// Serialization is accomplished by having the type convert itself into/from the canonical representation of this pod,
968/// e.g. `i32` for a `Int` type pod.
969///
970/// That type then takes care of the actual serialization.
971///
972/// See the [`CanonicalFixedSizedPod`] trait for a list of possible target types.
973///
974/// Which type to convert in is specified with the traits [`FixedSizedPod::CanonicalType`] type,
975/// while the traits [`as_canonical_type`](`FixedSizedPod::as_canonical_type`)
976/// and [`from_canonical_type`](`FixedSizedPod::from_canonical_type`) methods are responsible for the actual conversion.
977///
978/// # Examples
979/// Implementing the trait on a `i32` newtype wrapper:
980/// ```rust
981/// use libspa::pod::FixedSizedPod;
982///
983/// struct Newtype(i32);
984///
985/// impl FixedSizedPod for Newtype {
986///     // The pod we want to serialize into is a `Int` type pod, which has `i32` as it's canonical representation.
987///     type CanonicalType = i32;
988///
989///     fn as_canonical_type(&self) -> Self::CanonicalType {
990///         // Convert self to the canonical type.
991///         self.0
992///     }
993///
994///     fn from_canonical_type(canonical: &Self::CanonicalType) -> Self {
995///         // Create a new Self instance from the canonical type.
996///         Newtype(*canonical)
997///     }
998/// }
999/// ```
1000pub trait FixedSizedPod {
1001    /// The canonical representation of the type of pod that should be serialized to/deserialized from.
1002    type CanonicalType: CanonicalFixedSizedPod;
1003
1004    /// Convert `self` to the canonical type.
1005    fn as_canonical_type(&self) -> Self::CanonicalType;
1006    /// Convert the canonical type to `Self`.
1007    fn from_canonical_type(_: &Self::CanonicalType) -> Self;
1008}
1009
1010impl<T: FixedSizedPod> PodSerialize for T {
1011    fn serialize<O: Write + Seek>(
1012        &self,
1013        serializer: PodSerializer<O>,
1014    ) -> Result<serialize::SerializeSuccess<O>, GenError> {
1015        serializer.serialized_fixed_sized_pod(self)
1016    }
1017}
1018
1019impl<'de> PodDeserialize<'de> for () {
1020    fn deserialize(
1021        deserializer: PodDeserializer<'de>,
1022    ) -> Result<
1023        (Self, deserialize::DeserializeSuccess<'de>),
1024        deserialize::DeserializeError<&'de [u8]>,
1025    >
1026    where
1027        Self: Sized,
1028    {
1029        deserializer.deserialize_none(NoneVisitor)
1030    }
1031}
1032
1033impl<'de> PodDeserialize<'de> for bool {
1034    fn deserialize(
1035        deserializer: PodDeserializer<'de>,
1036    ) -> Result<
1037        (Self, deserialize::DeserializeSuccess<'de>),
1038        deserialize::DeserializeError<&'de [u8]>,
1039    >
1040    where
1041        Self: Sized,
1042    {
1043        deserializer.deserialize_bool(BoolVisitor)
1044    }
1045}
1046
1047impl<'de> PodDeserialize<'de> for i32 {
1048    fn deserialize(
1049        deserializer: PodDeserializer<'de>,
1050    ) -> Result<
1051        (Self, deserialize::DeserializeSuccess<'de>),
1052        deserialize::DeserializeError<&'de [u8]>,
1053    >
1054    where
1055        Self: Sized,
1056    {
1057        deserializer.deserialize_int(IntVisitor)
1058    }
1059}
1060
1061impl<'de> PodDeserialize<'de> for i64 {
1062    fn deserialize(
1063        deserializer: PodDeserializer<'de>,
1064    ) -> Result<
1065        (Self, deserialize::DeserializeSuccess<'de>),
1066        deserialize::DeserializeError<&'de [u8]>,
1067    >
1068    where
1069        Self: Sized,
1070    {
1071        deserializer.deserialize_long(LongVisitor)
1072    }
1073}
1074
1075impl<'de> PodDeserialize<'de> for f32 {
1076    fn deserialize(
1077        deserializer: PodDeserializer<'de>,
1078    ) -> Result<
1079        (Self, deserialize::DeserializeSuccess<'de>),
1080        deserialize::DeserializeError<&'de [u8]>,
1081    >
1082    where
1083        Self: Sized,
1084    {
1085        deserializer.deserialize_float(FloatVisitor)
1086    }
1087}
1088
1089impl<'de> PodDeserialize<'de> for f64 {
1090    fn deserialize(
1091        deserializer: PodDeserializer<'de>,
1092    ) -> Result<
1093        (Self, deserialize::DeserializeSuccess<'de>),
1094        deserialize::DeserializeError<&'de [u8]>,
1095    >
1096    where
1097        Self: Sized,
1098    {
1099        deserializer.deserialize_double(DoubleVisitor)
1100    }
1101}
1102
1103impl<'de> PodDeserialize<'de> for Rectangle {
1104    fn deserialize(
1105        deserializer: PodDeserializer<'de>,
1106    ) -> Result<
1107        (Self, deserialize::DeserializeSuccess<'de>),
1108        deserialize::DeserializeError<&'de [u8]>,
1109    >
1110    where
1111        Self: Sized,
1112    {
1113        deserializer.deserialize_rectangle(RectangleVisitor)
1114    }
1115}
1116
1117impl<'de> PodDeserialize<'de> for Fraction {
1118    fn deserialize(
1119        deserializer: PodDeserializer<'de>,
1120    ) -> Result<
1121        (Self, deserialize::DeserializeSuccess<'de>),
1122        deserialize::DeserializeError<&'de [u8]>,
1123    >
1124    where
1125        Self: Sized,
1126    {
1127        deserializer.deserialize_fraction(FractionVisitor)
1128    }
1129}
1130
1131impl<'de> PodDeserialize<'de> for Id {
1132    fn deserialize(
1133        deserializer: PodDeserializer<'de>,
1134    ) -> Result<
1135        (Self, deserialize::DeserializeSuccess<'de>),
1136        deserialize::DeserializeError<&'de [u8]>,
1137    >
1138    where
1139        Self: Sized,
1140    {
1141        deserializer.deserialize_id(IdVisitor)
1142    }
1143}
1144
1145impl<'de> PodDeserialize<'de> for Fd {
1146    fn deserialize(
1147        deserializer: PodDeserializer<'de>,
1148    ) -> Result<
1149        (Self, deserialize::DeserializeSuccess<'de>),
1150        deserialize::DeserializeError<&'de [u8]>,
1151    >
1152    where
1153        Self: Sized,
1154    {
1155        deserializer.deserialize_fd(FdVisitor)
1156    }
1157}
1158
1159impl<'de> PodDeserialize<'de> for Choice<bool> {
1160    fn deserialize(
1161        deserializer: PodDeserializer<'de>,
1162    ) -> Result<
1163        (Self, deserialize::DeserializeSuccess<'de>),
1164        deserialize::DeserializeError<&'de [u8]>,
1165    >
1166    where
1167        Self: Sized,
1168    {
1169        deserializer.deserialize_choice(ChoiceBoolVisitor)
1170    }
1171}
1172
1173impl<'de> PodDeserialize<'de> for Choice<i32> {
1174    fn deserialize(
1175        deserializer: PodDeserializer<'de>,
1176    ) -> Result<
1177        (Self, deserialize::DeserializeSuccess<'de>),
1178        deserialize::DeserializeError<&'de [u8]>,
1179    >
1180    where
1181        Self: Sized,
1182    {
1183        deserializer.deserialize_choice(ChoiceIntVisitor)
1184    }
1185}
1186
1187impl<'de> PodDeserialize<'de> for Choice<i64> {
1188    fn deserialize(
1189        deserializer: PodDeserializer<'de>,
1190    ) -> Result<
1191        (Self, deserialize::DeserializeSuccess<'de>),
1192        deserialize::DeserializeError<&'de [u8]>,
1193    >
1194    where
1195        Self: Sized,
1196    {
1197        deserializer.deserialize_choice(ChoiceLongVisitor)
1198    }
1199}
1200
1201impl<'de> PodDeserialize<'de> for Choice<f32> {
1202    fn deserialize(
1203        deserializer: PodDeserializer<'de>,
1204    ) -> Result<
1205        (Self, deserialize::DeserializeSuccess<'de>),
1206        deserialize::DeserializeError<&'de [u8]>,
1207    >
1208    where
1209        Self: Sized,
1210    {
1211        deserializer.deserialize_choice(ChoiceFloatVisitor)
1212    }
1213}
1214
1215impl<'de> PodDeserialize<'de> for Choice<f64> {
1216    fn deserialize(
1217        deserializer: PodDeserializer<'de>,
1218    ) -> Result<
1219        (Self, deserialize::DeserializeSuccess<'de>),
1220        deserialize::DeserializeError<&'de [u8]>,
1221    >
1222    where
1223        Self: Sized,
1224    {
1225        deserializer.deserialize_choice(ChoiceDoubleVisitor)
1226    }
1227}
1228
1229impl<'de> PodDeserialize<'de> for Choice<Id> {
1230    fn deserialize(
1231        deserializer: PodDeserializer<'de>,
1232    ) -> Result<
1233        (Self, deserialize::DeserializeSuccess<'de>),
1234        deserialize::DeserializeError<&'de [u8]>,
1235    >
1236    where
1237        Self: Sized,
1238    {
1239        deserializer.deserialize_choice(ChoiceIdVisitor)
1240    }
1241}
1242
1243impl<'de> PodDeserialize<'de> for Choice<Rectangle> {
1244    fn deserialize(
1245        deserializer: PodDeserializer<'de>,
1246    ) -> Result<
1247        (Self, deserialize::DeserializeSuccess<'de>),
1248        deserialize::DeserializeError<&'de [u8]>,
1249    >
1250    where
1251        Self: Sized,
1252    {
1253        deserializer.deserialize_choice(ChoiceRectangleVisitor)
1254    }
1255}
1256
1257impl<'de> PodDeserialize<'de> for Choice<Fraction> {
1258    fn deserialize(
1259        deserializer: PodDeserializer<'de>,
1260    ) -> Result<
1261        (Self, deserialize::DeserializeSuccess<'de>),
1262        deserialize::DeserializeError<&'de [u8]>,
1263    >
1264    where
1265        Self: Sized,
1266    {
1267        deserializer.deserialize_choice(ChoiceFractionVisitor)
1268    }
1269}
1270
1271impl<'de> PodDeserialize<'de> for Choice<Fd> {
1272    fn deserialize(
1273        deserializer: PodDeserializer<'de>,
1274    ) -> Result<
1275        (Self, deserialize::DeserializeSuccess<'de>),
1276        deserialize::DeserializeError<&'de [u8]>,
1277    >
1278    where
1279        Self: Sized,
1280    {
1281        deserializer.deserialize_choice(ChoiceFdVisitor)
1282    }
1283}
1284
1285impl<'de, T> PodDeserialize<'de> for (u32, *const T) {
1286    fn deserialize(
1287        deserializer: PodDeserializer<'de>,
1288    ) -> Result<
1289        (Self, deserialize::DeserializeSuccess<'de>),
1290        deserialize::DeserializeError<&'de [u8]>,
1291    >
1292    where
1293        Self: Sized,
1294    {
1295        deserializer.deserialize_pointer(PointerVisitor::<T>::default())
1296    }
1297}
1298
1299impl<'de> PodDeserialize<'de> for Value {
1300    fn deserialize(
1301        deserializer: PodDeserializer<'de>,
1302    ) -> Result<
1303        (Self, deserialize::DeserializeSuccess<'de>),
1304        deserialize::DeserializeError<&'de [u8]>,
1305    >
1306    where
1307        Self: Sized,
1308    {
1309        deserializer.deserialize_any()
1310    }
1311}
1312
1313/// A typed pod value.
1314#[derive(Debug, Clone, PartialEq)]
1315pub enum Value {
1316    /// no value or a NULL pointer.
1317    None,
1318    /// a boolean value.
1319    Bool(bool),
1320    /// an enumerated value.
1321    Id(Id),
1322    /// a 32 bits integer.
1323    Int(i32),
1324    /// a 64 bits integer.
1325    Long(i64),
1326    /// a 32 bits floating.
1327    Float(f32),
1328    /// a 64 bits floating.
1329    Double(f64),
1330    /// a string.
1331    String(String),
1332    /// a byte array.
1333    Bytes(Vec<u8>),
1334    /// a rectangle with width and height.
1335    Rectangle(Rectangle),
1336    /// a fraction with numerator and denominator.
1337    Fraction(Fraction),
1338    /// a file descriptor.
1339    Fd(Fd),
1340    /// an array of same type objects.
1341    ValueArray(ValueArray),
1342    /// a collection of types and objects.
1343    Struct(Vec<Value>),
1344    /// an object.
1345    Object(Object),
1346    /// a choice.
1347    Choice(ChoiceValue),
1348    /// a pointer.
1349    Pointer(u32, *const c_void),
1350}
1351
1352/// an array of same type objects.
1353#[derive(Debug, Clone, PartialEq)]
1354pub enum ValueArray {
1355    /// an array of none.
1356    None(Vec<()>),
1357    /// an array of booleans.
1358    Bool(Vec<bool>),
1359    /// an array of Id.
1360    Id(Vec<Id>),
1361    /// an array of 32 bits integer.
1362    Int(Vec<i32>),
1363    /// an array of 64 bits integer.
1364    Long(Vec<i64>),
1365    /// an array of 32 bits floating.
1366    Float(Vec<f32>),
1367    /// an array of 64 bits floating.
1368    Double(Vec<f64>),
1369    /// an array of Rectangle.
1370    Rectangle(Vec<Rectangle>),
1371    /// an array of Fraction.
1372    Fraction(Vec<Fraction>),
1373    /// an array of Fd.
1374    Fd(Vec<Fd>),
1375}
1376
1377/// A typed choice.
1378#[derive(Debug, Clone, PartialEq)]
1379pub enum ChoiceValue {
1380    /// Choice on boolean values.
1381    Bool(Choice<bool>),
1382    /// Choice on 32 bits integer values.
1383    Int(Choice<i32>),
1384    /// Choice on 64 bits integer values.
1385    Long(Choice<i64>),
1386    /// Choice on 32 bits floating values.
1387    Float(Choice<f32>),
1388    /// Choice on 64 bits floating values.
1389    Double(Choice<f64>),
1390    /// Choice on id values.
1391    Id(Choice<Id>),
1392    /// Choice on rectangle values.
1393    Rectangle(Choice<Rectangle>),
1394    /// Choice on fraction values.
1395    Fraction(Choice<Fraction>),
1396    /// Choice on fd values.
1397    Fd(Choice<Fd>),
1398}
1399
1400/// An object from a pod.
1401#[derive(Debug, Clone, PartialEq)]
1402pub struct Object {
1403    /// the object type.
1404    pub type_: u32,
1405    /// the object id.
1406    pub id: u32,
1407    /// the object properties.
1408    pub properties: Vec<Property>,
1409}
1410
1411/// A macro for creating a new [`Object`] with properties.
1412///
1413/// The macro accepts the object type, id and a list of properties, separated by commas.
1414///
1415/// # Examples:
1416/// Create an `Object`.
1417/// ```rust
1418/// use libspa::pod::{object, property};
1419///
1420/// let pod_object = object!{
1421///     libspa::utils::SpaTypes::ObjectParamFormat,
1422///     libspa::param::ParamType::EnumFormat,
1423///     property!(
1424///         libspa::param::format::FormatProperties::MediaType,
1425///         Id,
1426///         libspa::param::format::MediaType::Video
1427///     ),
1428///     property!(
1429///         libspa::param::format::FormatProperties::MediaSubtype,
1430///         Id,
1431///         libspa::param::format::MediaSubtype::Raw
1432///     ),
1433/// };
1434/// ```
1435#[doc(hidden)]
1436#[macro_export]
1437macro_rules! __object__ {
1438    ($type_:expr, $id:expr, $($properties:expr),* $(,)?) => {
1439        pipewire::spa::pod::Object {
1440            type_: $type_.as_raw(),
1441            id: $id.as_raw(),
1442            properties: [ $( $properties, )* ].to_vec(),
1443        }
1444    };
1445}
1446#[doc(inline)]
1447pub use __object__ as object;
1448
1449/// An object property.
1450#[derive(Debug, Clone, PartialEq)]
1451pub struct Property {
1452    /// key of the property, list of valid keys depends on the object type.
1453    pub key: u32,
1454    /// flags for the property.
1455    pub flags: PropertyFlags,
1456    /// value of the property.
1457    pub value: Value,
1458}
1459
1460impl Property {
1461    pub fn new(key: u32, value: Value) -> Self {
1462        Self {
1463            key,
1464            value,
1465            flags: PropertyFlags::empty(),
1466        }
1467    }
1468}
1469
1470bitflags! {
1471    /// Property flags
1472    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
1473    pub struct PropertyFlags: u32 {
1474        // These flags are redefinitions from
1475        // https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/master/spa/include/spa/pod/pod.h
1476        /// Property is read-only.
1477        const READONLY = spa_sys::SPA_POD_PROP_FLAG_READONLY;
1478        /// Property is some sort of hardware parameter.
1479        const HARDWARE = spa_sys::SPA_POD_PROP_FLAG_HARDWARE;
1480        /// Property contains a dictionary struct.
1481        const HINT_DICT = spa_sys::SPA_POD_PROP_FLAG_HINT_DICT;
1482        /// Property is mandatory.
1483        const MANDATORY = spa_sys::SPA_POD_PROP_FLAG_MANDATORY;
1484        /// Property choices need no fixation.
1485        #[cfg(feature = "v0_3_33")]
1486        const DONT_FIXATE = spa_sys::SPA_POD_PROP_FLAG_DONT_FIXATE;
1487    }
1488}
1489
1490/// A macro for creating a new Object [`Property`].
1491///
1492/// The macro accepts the following:
1493/// - properties!(libspa::format::FormatProperties::`<key>`, Id, `<value>`)
1494/// - properties!(libspa::format::FormatProperties::`<key>`, `<type>`, libspa::utils::`<type>`(`<value>`))
1495/// - properties!(libspa::format::FormatProperties::`<key>`, Choice, Enum, Id, `<default>`, `<value>`, ...)
1496/// - properties!(libspa::format::FormatProperties::`<key>`, Choice, Enum, `<type>`,
1497///                 libspa::utils::`<type>`(`<default>`),
1498///                 libspa::utils::`<type>`(`<value>`), ...)
1499/// - properties!(libspa::format::FormatProperties::`<key>`, Choice, Flags, `<type>`,
1500///                 libspa::utils::`<type>`(`<default>`),
1501///                 libspa::utils::`<type>`(`<value>`), ...)
1502/// - properties!(libspa::format::FormatProperties::`<key>`, Choice, Step, `<type>`,
1503///                 libspa::utils::`<type>`(default),
1504///                 libspa::utils::`<type>`(min),
1505///                 libspa::utils::`<type>`(max),
1506///                 libspa::utils::`<type>`(step))
1507/// - properties!(libspa::format::FormatProperties::`<key>`, Choice, Range, `<type>`,
1508///                 libspa::utils::`<type>`(default),
1509///                 libspa::utils::`<type>`(min),
1510///                 libspa::utils::`<type>`(max))
1511#[doc(hidden)]
1512#[macro_export]
1513macro_rules! __property__ {
1514    ($key:expr, $value:expr) => {
1515        pipewire::spa::pod::Property {
1516            key: $key.as_raw(),
1517            flags: pipewire::spa::pod::PropertyFlags::empty(),
1518            value: $value,
1519        }
1520    };
1521
1522    ($key:expr, Id, $value:expr) => {
1523        pipewire::spa::pod::property!($key, pipewire::spa::pod::Value::Id(pipewire::spa::utils::Id($value.as_raw())))
1524    };
1525
1526    ($key:expr, $type_:ident, $value:expr) => {
1527        pipewire::spa::pod::property!($key, pipewire::spa::pod::Value::$type_($value))
1528    };
1529
1530    ($key:expr, Choice, Enum, Id, $default:expr, $($alternative:expr),+ $(,)?) => {
1531        pipewire::spa::pod::property!(
1532            $key,
1533            pipewire::spa::pod::Value::Choice(pipewire::spa::pod::ChoiceValue::Id(
1534                pipewire::spa::utils::Choice::<pipewire::spa::utils::Id>(
1535                    pipewire::spa::utils::ChoiceFlags::empty(),
1536                    pipewire::spa::utils::ChoiceEnum::<pipewire::spa::utils::Id>::Enum {
1537                        default: pipewire::spa::utils::Id($default.as_raw()),
1538                        alternatives: [ $( pipewire::spa::utils::Id($alternative.as_raw()), )+ ].to_vec()
1539                    }
1540                )
1541            ))
1542        )
1543    };
1544
1545    ($key:expr, Choice, Enum, $type_:ident, $default:expr, $($alternative:expr),+ $(,)?) => {
1546        pipewire::spa::pod::property!(
1547            $key,
1548            pipewire::spa::pod::Value::Choice(pipewire::spa::pod::ChoiceValue::$type_(
1549                pipewire::spa::utils::Choice::<pipewire::spa::utils::$type_>(
1550                    pipewire::spa::utils::ChoiceFlags::empty(),
1551                    pipewire::spa::utils::ChoiceEnum::<pipewire::spa::utils::$type_>::Enum {
1552                        default: $default,
1553                        alternatives: [ $( $alternative, )+ ].to_vec()
1554                    }
1555                )
1556            ))
1557        )
1558    };
1559
1560    ($key:expr, Choice, Flags, $type_:ident, $default:expr, $($alternative:expr),+ $(,)?) => {
1561        pipewire::spa::pod::property!(
1562            $key,
1563            pipewire::spa::pod::Value::Choice(pipewire::spa::pod::ChoiceValue::$type_(
1564                pipewire::spa::utils::Choice::<pipewire::spa::utils::$type_>(
1565                    pipewire::spa::utils::ChoiceFlags::empty(),
1566                    pipewire::spa::utils::ChoiceEnum::<pipewire::spa::utils::$type_>::Flags {
1567                        default: $default,
1568                        flags: [ $( $alternative, )+ ].to_vec()
1569                    }
1570                )
1571            ))
1572        )
1573    };
1574
1575    ($key:expr, Choice, Step, $type_:ident, $default:expr, $min:expr, $max:expr, $step:expr) => {
1576        pipewire::spa::pod::property!(
1577            $key,
1578            pipewire::spa::pod::Value::Choice(pipewire::spa::pod::ChoiceValue::$type_(
1579                pipewire::spa::utils::Choice::<pipewire::spa::utils::$type_>(
1580                    pipewire::spa::utils::ChoiceFlags::empty(),
1581                    pipewire::spa::utils::ChoiceEnum::<pipewire::spa::utils::$type_>::Step {
1582                        default: $default,
1583                        min: $min,
1584                        max: $max,
1585                        step: $step,
1586                    }
1587                )
1588            ))
1589        )
1590    };
1591
1592    ($key:expr, Choice, Range, $type_:ident, $default:expr, $min:expr, $max:expr) => {
1593        pipewire::spa::pod::property!(
1594            $key,
1595            pipewire::spa::pod::Value::Choice(pipewire::spa::pod::ChoiceValue::$type_(
1596                pipewire::spa::utils::Choice::<pipewire::spa::utils::$type_>(
1597                    pipewire::spa::utils::ChoiceFlags::empty(),
1598                    pipewire::spa::utils::ChoiceEnum::<pipewire::spa::utils::$type_>::Range {
1599                        default: $default,
1600                        min: $min,
1601                        max: $max,
1602                    }
1603                )
1604            ))
1605        )
1606    };
1607}
1608#[doc(inline)]
1609pub use __property__ as property;