1use std::{
2 ffi::{c_int, c_void, CString},
3 mem::MaybeUninit,
4};
5
6use nix::errno::Errno;
7
8use crate::utils::{Fraction, Id, Rectangle};
9
10static CALLBACKS: spa_sys::spa_pod_builder_callbacks = spa_sys::spa_pod_builder_callbacks {
11 version: spa_sys::SPA_VERSION_POD_BUILDER_CALLBACKS,
12 overflow: Some(Builder::overflow),
13};
14
15struct BuilderInner<'d> {
16 builder: spa_sys::spa_pod_builder,
17 data: &'d mut Vec<u8>,
18}
19
20pub struct Builder<'d> {
21 inner: Box<BuilderInner<'d>>,
25}
26
27impl<'d> Builder<'d> {
28 unsafe extern "C" fn overflow(data: *mut c_void, size: u32) -> c_int {
29 let this: *mut BuilderInner = data.cast();
30
31 assert!(!this.is_null());
32 assert!(size as usize > (*this).data.len());
33
34 (*this).data.resize(size as usize, 0);
38 (*this).builder.data = (*this).data.as_mut_ptr().cast::<c_void>();
39 (*this).builder.size = (*this)
40 .data
41 .len()
42 .try_into()
43 .expect("data length does not fit in a u32");
44
45 0
47 }
48
49 pub fn new(data: &'d mut Vec<u8>) -> Self {
50 unsafe {
51 let mut builder: MaybeUninit<spa_sys::spa_pod_builder> = MaybeUninit::uninit();
52
53 spa_sys::spa_pod_builder_init(
54 builder.as_mut_ptr(),
55 data.as_mut_ptr().cast(),
56 data.len()
57 .try_into()
58 .expect("data length does not fit in a u32"),
59 );
60
61 let inner = Box::new(BuilderInner {
62 builder: builder.assume_init(),
63 data,
64 });
65
66 spa_sys::spa_pod_builder_set_callbacks(
67 std::ptr::addr_of!(inner.builder).cast_mut(),
68 std::ptr::addr_of!(CALLBACKS),
69 std::ptr::addr_of!(*inner).cast::<c_void>().cast_mut(),
70 );
71
72 Self { inner }
73 }
74 }
75
76 pub fn as_raw(&self) -> &spa_sys::spa_pod_builder {
77 &self.inner.builder
78 }
79
80 pub fn as_raw_ptr(&self) -> *mut spa_sys::spa_pod_builder {
81 std::ptr::addr_of!(self.inner.builder).cast_mut()
82 }
83
84 pub unsafe fn state(&self) -> spa_sys::spa_pod_builder_state {
89 let mut state: MaybeUninit<spa_sys::spa_pod_builder_state> = MaybeUninit::uninit();
90 spa_sys::spa_pod_builder_get_state(self.as_raw_ptr(), state.as_mut_ptr());
91 state.assume_init()
92 }
93
94 pub unsafe fn reset(&mut self, state: *mut spa_sys::spa_pod_builder_state) {
101 spa_sys::spa_pod_builder_reset(self.as_raw_ptr(), state)
102 }
103
104 pub unsafe fn deref(&mut self, offset: u32) -> *mut spa_sys::spa_pod {
108 spa_sys::spa_pod_builder_deref(self.as_raw_ptr(), offset)
109 }
110
111 pub unsafe fn frame(&mut self, frame: *mut spa_sys::spa_pod_frame) -> *mut spa_sys::spa_pod {
115 spa_sys::spa_pod_builder_frame(self.as_raw_ptr(), frame)
116 }
117
118 pub unsafe fn push(
122 &mut self,
123 frame: *mut spa_sys::spa_pod_frame,
124 pod: *const spa_sys::spa_pod,
125 offset: u32,
126 ) {
127 spa_sys::spa_pod_builder_push(self.as_raw_ptr(), frame, pod, offset)
128 }
129
130 pub fn raw_padded(&mut self, data: &[u8]) -> Result<(), Errno> {
133 let res = unsafe {
134 spa_sys::spa_pod_builder_raw_padded(
135 self.as_raw_ptr(),
136 data.as_ptr().cast::<c_void>(),
137 data.len().try_into().unwrap(),
138 )
139 };
140
141 if res >= 0 {
142 Ok(())
143 } else {
144 Err(Errno::from_raw(-res))
145 }
146 }
147
148 pub unsafe fn pop(&mut self, frame: &mut spa_sys::spa_pod_frame) {
152 unsafe {
153 spa_sys::spa_pod_builder_pop(self.as_raw_ptr(), frame as *mut _);
154 }
155 }
156
157 pub fn add_none(&mut self) -> Result<(), Errno> {
160 unsafe {
161 let res = spa_sys::spa_pod_builder_none(self.as_raw_ptr());
162
163 if res >= 0 {
164 Ok(())
165 } else {
166 Err(Errno::from_raw(-res))
167 }
168 }
169 }
170
171 pub fn add_bool(&mut self, val: bool) -> Result<(), Errno> {
174 unsafe {
175 let res = spa_sys::spa_pod_builder_bool(self.as_raw_ptr(), val);
176
177 if res >= 0 {
178 Ok(())
179 } else {
180 Err(Errno::from_raw(-res))
181 }
182 }
183 }
184
185 pub fn add_id(&mut self, val: Id) -> Result<(), Errno> {
186 unsafe {
187 let res = spa_sys::spa_pod_builder_id(self.as_raw_ptr(), val.0);
188
189 if res >= 0 {
190 Ok(())
191 } else {
192 Err(Errno::from_raw(-res))
193 }
194 }
195 }
196
197 pub fn add_int(&mut self, val: i32) -> Result<(), Errno> {
198 unsafe {
199 let res = spa_sys::spa_pod_builder_int(self.as_raw_ptr(), val);
200
201 if res >= 0 {
202 Ok(())
203 } else {
204 Err(Errno::from_raw(-res))
205 }
206 }
207 }
208
209 pub fn add_long(&mut self, val: i64) -> Result<(), Errno> {
210 unsafe {
211 let res = spa_sys::spa_pod_builder_long(self.as_raw_ptr(), val);
212
213 if res >= 0 {
214 Ok(())
215 } else {
216 Err(Errno::from_raw(-res))
217 }
218 }
219 }
220
221 pub fn add_float(&mut self, val: f32) -> Result<(), Errno> {
222 unsafe {
223 let res = spa_sys::spa_pod_builder_float(self.as_raw_ptr(), val);
224
225 if res >= 0 {
226 Ok(())
227 } else {
228 Err(Errno::from_raw(-res))
229 }
230 }
231 }
232
233 pub fn add_double(&mut self, val: f64) -> Result<(), Errno> {
234 unsafe {
235 let res = spa_sys::spa_pod_builder_double(self.as_raw_ptr(), val);
236
237 if res >= 0 {
238 Ok(())
239 } else {
240 Err(Errno::from_raw(-res))
241 }
242 }
243 }
244
245 pub fn add_string(&mut self, string: &str) -> Result<(), Errno> {
252 let c_str = CString::new(string).expect("string should not contain an interior null byte");
253
254 let res = unsafe { spa_sys::spa_pod_builder_string(self.as_raw_ptr(), c_str.as_ptr()) };
255
256 if res >= 0 {
257 Ok(())
258 } else {
259 Err(Errno::from_raw(-res))
260 }
261 }
262
263 pub fn add_bytes(&mut self, bytes: &[u8]) -> Result<(), Errno> {
266 let res = unsafe {
267 spa_sys::spa_pod_builder_bytes(
268 self.as_raw_ptr(),
269 bytes.as_ptr().cast::<c_void>(),
270 bytes.len().try_into().unwrap(),
271 )
272 };
273
274 if res >= 0 {
275 Ok(())
276 } else {
277 Err(Errno::from_raw(-res))
278 }
279 }
280
281 pub unsafe fn add_pointer(&mut self, type_: Id, val: *const c_void) -> Result<(), Errno> {
287 unsafe {
288 let res = spa_sys::spa_pod_builder_pointer(self.as_raw_ptr(), type_.0, val);
289
290 if res >= 0 {
291 Ok(())
292 } else {
293 Err(Errno::from_raw(-res))
294 }
295 }
296 }
297
298 pub fn add_fd(&mut self, val: std::os::fd::RawFd) -> Result<(), Errno> {
299 unsafe {
300 let res = spa_sys::spa_pod_builder_fd(self.as_raw_ptr(), val.into());
301
302 if res >= 0 {
303 Ok(())
304 } else {
305 Err(Errno::from_raw(-res))
306 }
307 }
308 }
309
310 pub fn add_rectangle(&mut self, val: Rectangle) -> Result<(), Errno> {
311 unsafe {
312 let res = spa_sys::spa_pod_builder_rectangle(self.as_raw_ptr(), val.width, val.height);
313
314 if res >= 0 {
315 Ok(())
316 } else {
317 Err(Errno::from_raw(-res))
318 }
319 }
320 }
321
322 pub fn add_fraction(&mut self, val: Fraction) -> Result<(), Errno> {
323 unsafe {
324 let res = spa_sys::spa_pod_builder_fraction(self.as_raw_ptr(), val.num, val.denom);
325
326 if res >= 0 {
327 Ok(())
328 } else {
329 Err(Errno::from_raw(-res))
330 }
331 }
332 }
333
334 pub unsafe fn push_array(
339 &mut self,
340 frame: &mut MaybeUninit<spa_sys::spa_pod_frame>,
341 ) -> Result<(), Errno> {
342 let res = spa_sys::spa_pod_builder_push_array(self.as_raw_ptr(), frame.as_mut_ptr());
343
344 if res >= 0 {
345 Ok(())
346 } else {
347 Err(Errno::from_raw(-res))
348 }
349 }
350
351 pub unsafe fn add_array(
356 &mut self,
357 child_size: u32,
358 child_type: u32,
359 n_elems: u32,
360 elems: *const c_void,
361 ) -> Result<(), Errno> {
362 let res = spa_sys::spa_pod_builder_array(
363 self.as_raw_ptr(),
364 child_size,
365 child_type,
366 n_elems,
367 elems,
368 );
369
370 if res >= 0 {
371 Ok(())
372 } else {
373 Err(Errno::from_raw(-res))
374 }
375 }
376
377 pub unsafe fn push_choice(
382 &mut self,
383 frame: &mut MaybeUninit<spa_sys::spa_pod_frame>,
384 type_: u32,
385 flags: u32, ) -> Result<(), Errno> {
387 let res = spa_sys::spa_pod_builder_push_choice(
388 self.as_raw_ptr(),
389 frame.as_mut_ptr(),
390 type_,
391 flags,
392 );
393
394 if res >= 0 {
395 Ok(())
396 } else {
397 Err(Errno::from_raw(-res))
398 }
399 }
400
401 pub unsafe fn push_struct(
406 &mut self,
407 frame: &mut MaybeUninit<spa_sys::spa_pod_frame>,
408 ) -> Result<(), Errno> {
409 unsafe {
410 let res = spa_sys::spa_pod_builder_push_struct(self.as_raw_ptr(), frame.as_mut_ptr());
411
412 if res >= 0 {
413 Ok(())
414 } else {
415 Err(Errno::from_raw(-res))
416 }
417 }
418 }
419
420 pub unsafe fn push_object(
425 &mut self,
426 frame: &mut MaybeUninit<spa_sys::spa_pod_frame>,
427 type_: u32,
428 id: u32,
429 ) -> Result<(), Errno> {
430 unsafe {
431 let res = spa_sys::spa_pod_builder_push_object(
432 self.as_raw_ptr(),
433 frame.as_mut_ptr(),
434 type_,
435 id,
436 );
437
438 if res >= 0 {
439 Ok(())
440 } else {
441 Err(Errno::from_raw(-res))
442 }
443 }
444 }
445
446 pub fn add_prop(&mut self, key: u32, flags: u32) -> Result<(), Errno> {
447 let res = unsafe { spa_sys::spa_pod_builder_prop(self.as_raw_ptr(), key, flags) };
448
449 if res >= 0 {
450 Ok(())
451 } else {
452 Err(Errno::from_raw(-res))
453 }
454 }
455
456 pub unsafe fn push_sequence(
461 &mut self,
462 frame: &mut MaybeUninit<spa_sys::spa_pod_frame>,
463 unit: u32,
464 ) -> Result<(), Errno> {
465 let res =
466 spa_sys::spa_pod_builder_push_sequence(self.as_raw_ptr(), frame.as_mut_ptr(), unit);
467
468 if res >= 0 {
469 Ok(())
470 } else {
471 Err(Errno::from_raw(-res))
472 }
473 }
474
475 pub fn add_control(&mut self, offset: u32, type_: u32) -> c_int {
476 #[allow(clippy::useless_conversion)]
479 unsafe {
480 spa_sys::spa_pod_builder_control(self.as_raw_ptr(), offset, type_)
481 .try_into()
482 .unwrap()
483 }
484 }
485}
486
487#[macro_export]
535macro_rules! __builder_add__ {
536 ($builder:expr, None) => {
537 $crate::pod::builder::Builder::add_none($builder)
538 };
539 ($builder:expr, Bool($val:expr)) => {
540 $crate::pod::builder::Builder::add_bool($builder, $val)
541 };
542 ($builder:expr, Id($val:expr)) => {
543 $crate::pod::builder::Builder::add_id($builder, $val)
544 };
545 ($builder:expr, Int($val:expr)) => {
546 $crate::pod::builder::Builder::add_int($builder, $val)
547 };
548 ($builder:expr, Long($val:expr)) => {
549 $crate::pod::builder::Builder::add_long($builder, $val)
550 };
551 ($builder:expr, Float($val:expr)) => {
552 $crate::pod::builder::Builder::add_float($builder, $val)
553 };
554 ($builder:expr, Double($val:expr)) => {
555 $crate::pod::builder::Builder::add_double($builder, $val)
556 };
557 ($builder:expr, String($val:expr)) => {
558 $crate::pod::builder::Builder::add_string($builder, $val)
559 };
560 ($builder:expr, Bytes($val:expr)) => {
561 $crate::pod::builder::Builder::add_bytes($builder, $val)
562 };
563 ($builder:expr, Pointer($type_:expr, $val:expr)) => {
564 $crate::pod::builder::Builder::add_bool($builder, $type_, $val)
565 };
566 ($builder:expr, Fd($val:expr)) => {
567 $crate::pod::builder::Builder::add_fd($builder, $val)
568 };
569 ($builder:expr, Rectangle($val:expr)) => {
570 $crate::pod::builder::Builder::add_rectangle($builder, $val)
571 };
572 ($builder:expr, Fraction($val:expr)) => {
573 $crate::pod::builder::Builder::add_fraction($builder, $val)
574 };
575 (
577 $builder:expr,
578 Struct {
579 $( $field_type:tt $field:tt ),* $(,)?
580 }
581 ) => {
582 'outer: {
583 if false {
585 let _ = $builder;
586 }
587
588 let mut frame: ::std::mem::MaybeUninit<$crate::sys::spa_pod_frame> = ::std::mem::MaybeUninit::uninit();
589 let res = unsafe { $crate::pod::builder::Builder::push_struct($builder, &mut frame) };
590 if res.is_err() {
591 break 'outer res;
592 }
593
594 $(
595 let res = $crate::__builder_add__!($builder, $field_type $field);
596 if res.is_err() {
597 break 'outer res;
598 }
599 )*
600
601 unsafe { $crate::pod::builder::Builder::pop($builder, frame.assume_init_mut()) }
602
603 Ok(())
604 }
605 };
606 (
607 $builder:expr,
608 Object($type_:expr, $id:expr $(,)?) {
609 $( $key:expr => $value_type:tt $value:tt ),* $(,)?
610 }
611 ) => {
612 'outer: {
613 if false {
615 let _ = $builder;
616 let _ = $type_;
617 let _ = $id;
618 }
619
620 let mut frame: ::std::mem::MaybeUninit<$crate::sys::spa_pod_frame> = ::std::mem::MaybeUninit::uninit();
621 let res = unsafe { $crate::pod::builder::Builder::push_object($builder, &mut frame, $type_, $id) };
622 if res.is_err() {
623 break 'outer res;
624 }
625
626 $(
627 let res = $crate::pod::builder::Builder::add_prop($builder, $key, 0);
628 if res.is_err() {
629 break 'outer res;
630 }
631 let res = $crate::__builder_add__!($builder, $value_type $value);
632 if res.is_err() {
633 break 'outer res;
634 }
635 )*
636
637 unsafe { $crate::pod::builder::Builder::pop($builder, frame.assume_init_mut()) }
638
639 Ok(())
640 }
641 };
642 }
645pub use __builder_add__ as builder_add;
646
647#[cfg(test)]
648mod tests {
649 use super::*;
650
651 #[test]
652 #[cfg_attr(miri, ignore)]
653 fn build_empty_struct() {
654 let mut data = Vec::new();
655
656 let mut builder = Builder::new(&mut data);
657 let res = builder_add!(&mut builder, Struct {});
658
659 assert!(res.is_ok());
660
661 let other: Vec<u8> = [
662 0u32.to_ne_bytes(), 14u32.to_ne_bytes(), ]
665 .iter()
666 .copied()
667 .flatten()
668 .collect();
669
670 assert_eq!(&data, &other)
671 }
672
673 #[test]
674 #[cfg_attr(miri, ignore)]
675 fn build_small_struct() {
676 let mut data = Vec::new();
677
678 let mut builder = Builder::new(&mut data);
679 let res = builder_add!(
680 &mut builder,
681 Struct {
682 Int(3),
683 }
684 );
685
686 assert!(res.is_ok());
687
688 let other: Vec<u8> = [
689 16u32.to_ne_bytes(), 14u32.to_ne_bytes(), 4u32.to_ne_bytes(), 4u32.to_ne_bytes(), 3i32.to_ne_bytes(), [0, 0, 0, 0], ]
696 .iter()
697 .copied()
698 .flatten()
699 .collect();
700
701 assert_eq!(&data, &other)
702 }
703
704 #[test]
705 #[cfg_attr(miri, ignore)]
706 fn build_complex_struct() {
707 let mut data = Vec::new();
708
709 let mut builder = Builder::new(&mut data);
710 let res = builder_add!(
711 &mut builder,
712 Struct {
713 Struct {
714 Float(31.3),
715 String("foo")
716 },
717 Int(3),
718 }
719 );
720
721 dbg!(res.unwrap());
722 assert!(res.is_ok());
723 }
724
725 #[test]
726 #[cfg_attr(miri, ignore)]
727 fn build_empty_object() {
728 use crate::param::ParamType;
729
730 let mut data = Vec::new();
731 let mut builder = Builder::new(&mut data);
732 let res = builder_add!(
733 &mut builder,
734 Object(
735 ParamType::Format.as_raw(),
736 0,
737 ) {}
738 );
739
740 assert!(res.is_ok());
741 }
742
743 #[test]
744 #[cfg_attr(miri, ignore)]
745 fn build_object() {
746 use crate::param::{
747 format::{FormatProperties, MediaSubtype, MediaType},
748 ParamType,
749 };
750
751 let mut data = Vec::new();
752 let mut builder = Builder::new(&mut data);
753 let res = builder_add!(
754 &mut builder,
755 Object(
756 ParamType::Format.as_raw(),
757 0,
758 ) {
759 FormatProperties::MediaType.as_raw() => Id(crate::utils::Id(MediaType::Audio.as_raw())),
760 FormatProperties::MediaSubtype.as_raw() => Id(crate::utils::Id(MediaSubtype::Raw.as_raw())),
761 }
762 );
763
764 assert!(res.is_ok());
765 }
766}