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