mirror of
https://codeberg.org/hako/Rosenthal.git
synced 2025-04-14 10:04:32 +00:00
* rosenthal/packages/patches/niri.patch: New file. * rosenthal/packages/patches/rust-libspa-sys.patch: New file. * rosenthal/packages/patches/rust-libspa.patch: New file. * rosenthal/packages/patches/rust-pipewire.patch: New file. * rosenthal/packages/patches/rust-smithay.patch: New file. * rosenthal/packages/rust-crates.scm (niri-cargo-inputs): New variable. * rosenthal/packages/rust-apps.scm (niri): New variable. * README.org (Packages): Add it. * etc/manifest: Add it.
961 lines
27 KiB
Diff
961 lines
27 KiB
Diff
diff --git a/Cargo.toml b/Cargo.toml
|
|
index 1f2cc3e..df2d682 100644
|
|
--- a/Cargo.toml
|
|
+++ b/Cargo.toml
|
|
@@ -49,7 +49,7 @@ version = "0.3.2"
|
|
version = "0.2"
|
|
|
|
[dependencies.nix]
|
|
-version = "0.27"
|
|
+version = "0.29"
|
|
|
|
[dependencies.nom]
|
|
version = "7"
|
|
diff --git a/src/lib.rs b/src/lib.rs
|
|
index 398658b..6b7c995 100644
|
|
--- a/src/lib.rs
|
|
+++ b/src/lib.rs
|
|
@@ -2,7 +2,9 @@
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
//! The `libspa` crate provides a high-level API to interact with
|
|
-//! [libspa](https://gitlab.freedesktop.org/pipewire/pipewire/-/tree/master/doc/spa).
|
|
+//! [libspa].
|
|
+//!
|
|
+//! [libspa]: https://docs.pipewire.org/page_spa.html
|
|
|
|
pub mod buffer;
|
|
pub mod param;
|
|
@@ -11,6 +13,3 @@ pub mod support;
|
|
pub mod utils;
|
|
|
|
pub use spa_sys as sys;
|
|
-
|
|
-/// prelude module re-exporing all the traits providing public API.
|
|
-pub mod prelude {}
|
|
diff --git a/src/param/audio/mod.rs b/src/param/audio/mod.rs
|
|
index 017fc09..f6d731d 100644
|
|
--- a/src/param/audio/mod.rs
|
|
+++ b/src/param/audio/mod.rs
|
|
@@ -51,6 +51,17 @@ impl AudioFormat {
|
|
pub const ULAW: Self = Self(spa_sys::SPA_AUDIO_FORMAT_ULAW);
|
|
pub const ALAW: Self = Self(spa_sys::SPA_AUDIO_FORMAT_ALAW);
|
|
|
|
+ pub const S16: Self = Self(spa_sys::SPA_AUDIO_FORMAT_S16);
|
|
+ pub const U16: Self = Self(spa_sys::SPA_AUDIO_FORMAT_U16);
|
|
+ pub const S18: Self = Self(spa_sys::SPA_AUDIO_FORMAT_S18);
|
|
+ pub const U18: Self = Self(spa_sys::SPA_AUDIO_FORMAT_U18);
|
|
+ pub const S20: Self = Self(spa_sys::SPA_AUDIO_FORMAT_S20);
|
|
+ pub const U20: Self = Self(spa_sys::SPA_AUDIO_FORMAT_U20);
|
|
+ pub const S24: Self = Self(spa_sys::SPA_AUDIO_FORMAT_S24);
|
|
+ pub const U24: Self = Self(spa_sys::SPA_AUDIO_FORMAT_U24);
|
|
+ pub const S32: Self = Self(spa_sys::SPA_AUDIO_FORMAT_S32);
|
|
+ pub const U32: Self = Self(spa_sys::SPA_AUDIO_FORMAT_U32);
|
|
+
|
|
pub const U8P: Self = Self(spa_sys::SPA_AUDIO_FORMAT_U8P);
|
|
pub const S16P: Self = Self(spa_sys::SPA_AUDIO_FORMAT_S16P);
|
|
pub const S24_32P: Self = Self(spa_sys::SPA_AUDIO_FORMAT_S24_32P);
|
|
diff --git a/src/pod/builder.rs b/src/pod/builder.rs
|
|
index 138caec..d0209af 100644
|
|
--- a/src/pod/builder.rs
|
|
+++ b/src/pod/builder.rs
|
|
@@ -141,7 +141,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
|
|
@@ -163,7 +163,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -177,7 +177,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -189,7 +189,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -201,7 +201,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -213,7 +213,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -225,7 +225,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -237,7 +237,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -256,7 +256,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
|
|
@@ -274,7 +274,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
|
|
@@ -290,7 +290,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -302,7 +302,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -314,7 +314,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -326,7 +326,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -344,7 +344,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
|
|
@@ -370,7 +370,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
|
|
@@ -394,7 +394,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
|
|
@@ -412,7 +412,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -438,7 +438,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -449,7 +449,7 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
|
|
@@ -468,13 +468,14 @@ impl<'d> Builder<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
|
|
pub fn add_control(&mut self, offset: u32, type_: u32) -> c_int {
|
|
// Older versions of pipewire mistakenly had the return type as uint32_t,
|
|
// so we need to use try_into().unwrap() to ensure those versions also work
|
|
+ #[allow(clippy::useless_conversion)]
|
|
unsafe {
|
|
spa_sys::spa_pod_builder_control(self.as_raw_ptr(), offset, type_)
|
|
.try_into()
|
|
@@ -511,7 +512,7 @@ impl<'d> Builder<'d> {
|
|
/// Bytes(<&[u8]>),
|
|
/// }
|
|
/// );
|
|
-/// builder_add(<&mut libspa::pod::builder::Builder>,
|
|
+/// builder_add!(<&mut libspa::pod::builder::Builder>,
|
|
/// Object(
|
|
/// <type as u32>,
|
|
/// <id as u32>
|
|
diff --git a/src/pod/mod.rs b/src/pod/mod.rs
|
|
index 98c21ee..9f51ded 100644
|
|
--- a/src/pod/mod.rs
|
|
+++ b/src/pod/mod.rs
|
|
@@ -17,6 +17,7 @@ use std::{
|
|
io::{Seek, Write},
|
|
mem::MaybeUninit,
|
|
os::fd::RawFd,
|
|
+ ptr::addr_of,
|
|
};
|
|
|
|
use bitflags::bitflags;
|
|
@@ -89,7 +90,18 @@ impl Pod {
|
|
}
|
|
|
|
pub fn as_raw_ptr(&self) -> *mut spa_sys::spa_pod {
|
|
- std::ptr::addr_of!(self.0).cast_mut()
|
|
+ addr_of!(self.0).cast_mut()
|
|
+ }
|
|
+
|
|
+ /// Returns a pointer to the pods body.
|
|
+ ///
|
|
+ /// If the pod has an empty body, this can be outside the pods allocation.
|
|
+ pub fn body(&self) -> *mut c_void {
|
|
+ unsafe {
|
|
+ self.as_raw_ptr()
|
|
+ .byte_add(std::mem::size_of::<spa_sys::spa_pod>())
|
|
+ .cast()
|
|
+ }
|
|
}
|
|
|
|
/// Construct a pod from raw bytes.
|
|
@@ -158,7 +170,7 @@ impl Pod {
|
|
if res >= 0 {
|
|
Ok(b.assume_init())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -176,7 +188,7 @@ impl Pod {
|
|
if res >= 0 {
|
|
Ok(Id(id.assume_init()))
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -194,7 +206,7 @@ impl Pod {
|
|
if res >= 0 {
|
|
Ok(int.assume_init())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -212,7 +224,7 @@ impl Pod {
|
|
if res >= 0 {
|
|
Ok(long.assume_init())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -230,7 +242,7 @@ impl Pod {
|
|
if res >= 0 {
|
|
Ok(float.assume_init())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -248,7 +260,7 @@ impl Pod {
|
|
if res >= 0 {
|
|
Ok(double.assume_init())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -278,7 +290,7 @@ impl Pod {
|
|
let bytes = std::slice::from_raw_parts(bytes.cast(), len.try_into().unwrap());
|
|
Ok(bytes)
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -303,7 +315,7 @@ impl Pod {
|
|
let pointer = pointer.assume_init();
|
|
Ok((pointer, _type))
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -323,7 +335,7 @@ impl Pod {
|
|
let fd: RawFd = fd.try_into().unwrap();
|
|
Ok(fd)
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -341,7 +353,7 @@ impl Pod {
|
|
if res >= 0 {
|
|
Ok(rectangle.assume_init())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -359,7 +371,7 @@ impl Pod {
|
|
if res >= 0 {
|
|
Ok(fraction.assume_init())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -384,17 +396,324 @@ impl Pod {
|
|
res != 0
|
|
}
|
|
|
|
+ pub fn as_struct(&self) -> Result<&PodStruct, Errno> {
|
|
+ if self.is_struct() {
|
|
+ // Safety: We already know that the pod is valid, and since it is a struct, we can
|
|
+ // safely create a PodStruct from it
|
|
+ Ok(unsafe { PodStruct::from_raw(self.as_raw_ptr() as *const spa_sys::spa_pod_struct) })
|
|
+ } else {
|
|
+ Err(Errno::EINVAL)
|
|
+ }
|
|
+ }
|
|
+
|
|
pub fn is_object(&self) -> bool {
|
|
let res = unsafe { spa_sys::spa_pod_is_object(self.as_raw_ptr()) };
|
|
res != 0
|
|
}
|
|
|
|
+ // TODO: spa_pod_is_object_type, spa_pod_is_object_id
|
|
+
|
|
+ pub fn as_object(&self) -> Result<&PodObject, Errno> {
|
|
+ if self.is_object() {
|
|
+ // Safety: We already know that the pod is valid, and since it is an object, we can
|
|
+ // safely create a PodObject from it
|
|
+ Ok(unsafe { PodObject::from_raw(self.as_raw_ptr() as *const spa_sys::spa_pod_object) })
|
|
+ } else {
|
|
+ Err(Errno::EINVAL)
|
|
+ }
|
|
+ }
|
|
+
|
|
pub fn is_sequence(&self) -> bool {
|
|
let res = unsafe { spa_sys::spa_pod_is_sequence(self.as_raw_ptr()) };
|
|
res != 0
|
|
}
|
|
}
|
|
|
|
+impl<'p> From<&'p PodStruct> for &'p Pod {
|
|
+ fn from(value: &'p PodStruct) -> Self {
|
|
+ value.as_pod()
|
|
+ }
|
|
+}
|
|
+
|
|
+impl<'p> From<&'p PodObject> for &'p Pod {
|
|
+ fn from(value: &'p PodObject) -> Self {
|
|
+ value.as_pod()
|
|
+ }
|
|
+}
|
|
+
|
|
+/// A transparent wrapper around a `spa_sys::spa_pod_struct`.
|
|
+#[repr(transparent)]
|
|
+pub struct PodStruct(spa_sys::spa_pod_struct);
|
|
+
|
|
+impl PodStruct {
|
|
+ /// # Safety
|
|
+ ///
|
|
+ /// The provided pointer must point to a valid, well-aligned pod of type struct.
|
|
+ ///
|
|
+ /// All restrictions from [`Pod::from_raw`] also apply here.
|
|
+ pub unsafe fn from_raw(pod: *const spa_sys::spa_pod_struct) -> &'static Self {
|
|
+ pod.cast::<Self>().as_ref().unwrap()
|
|
+ }
|
|
+
|
|
+ /// # Safety
|
|
+ ///
|
|
+ /// The provided pointer must point to a valid, well-aligned pod of type struct.
|
|
+ ///
|
|
+ /// All restrictions from [`Pod::from_raw_mut`] also apply here.
|
|
+ pub unsafe fn from_raw_mut(pod: *mut spa_sys::spa_pod_struct) -> &'static mut Self {
|
|
+ pod.cast::<Self>().as_mut().unwrap()
|
|
+ }
|
|
+
|
|
+ pub fn as_raw_ptr(&self) -> *mut spa_sys::spa_pod_struct {
|
|
+ std::ptr::addr_of!(self.0).cast_mut()
|
|
+ }
|
|
+
|
|
+ pub fn as_pod(&self) -> &Pod {
|
|
+ // Safety: Since this is a valid spa_pod_object, it must also be a valid spa_pod
|
|
+ unsafe { Pod::from_raw(addr_of!(self.0.pod)) }
|
|
+ }
|
|
+
|
|
+ pub fn fields(&self) -> PodStructIter<'_> {
|
|
+ PodStructIter::new(self)
|
|
+ }
|
|
+}
|
|
+
|
|
+impl<'p> TryFrom<&'p Pod> for &'p PodStruct {
|
|
+ type Error = Errno;
|
|
+
|
|
+ fn try_from(value: &'p Pod) -> Result<Self, Self::Error> {
|
|
+ value.as_struct()
|
|
+ }
|
|
+}
|
|
+
|
|
+impl AsRef<Pod> for PodStruct {
|
|
+ fn as_ref(&self) -> &Pod {
|
|
+ self.as_pod()
|
|
+ }
|
|
+}
|
|
+
|
|
+pub struct PodStructIter<'s> {
|
|
+ struct_pod: &'s PodStruct,
|
|
+ next: *mut c_void,
|
|
+}
|
|
+
|
|
+impl<'s> PodStructIter<'s> {
|
|
+ fn new(struct_pod: &'s PodStruct) -> Self {
|
|
+ let first_field = struct_pod.as_pod().body();
|
|
+
|
|
+ Self {
|
|
+ struct_pod,
|
|
+ next: first_field,
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+impl<'s> Iterator for PodStructIter<'s> {
|
|
+ type Item = &'s Pod;
|
|
+
|
|
+ fn next(&mut self) -> Option<Self::Item> {
|
|
+ // Check if the iterator has at least one element left that we can return
|
|
+ let has_next = unsafe {
|
|
+ spa_sys::spa_pod_is_inside(
|
|
+ self.struct_pod.as_pod().body(),
|
|
+ self.struct_pod.0.pod.size,
|
|
+ self.next,
|
|
+ )
|
|
+ };
|
|
+
|
|
+ if has_next {
|
|
+ let res = unsafe { Pod::from_raw(self.next as *const spa_sys::spa_pod) };
|
|
+
|
|
+ // Advance iter to next property
|
|
+ self.next = unsafe { spa_sys::spa_pod_next(self.next) };
|
|
+
|
|
+ Some(res)
|
|
+ } else {
|
|
+ None
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/// A transparent wrapper around a `spa_sys::spa_pod_object`.
|
|
+#[repr(transparent)]
|
|
+pub struct PodObject(spa_sys::spa_pod_object);
|
|
+
|
|
+impl PodObject {
|
|
+ /// # Safety
|
|
+ ///
|
|
+ /// The provided pointer must point to a valid, well-aligned pod of type object.
|
|
+ ///
|
|
+ /// All restrictions from [`Pod::from_raw`] also apply here.
|
|
+ pub unsafe fn from_raw(pod: *const spa_sys::spa_pod_object) -> &'static Self {
|
|
+ pod.cast::<Self>().as_ref().unwrap()
|
|
+ }
|
|
+
|
|
+ /// # Safety
|
|
+ ///
|
|
+ /// The provided pointer must point to a valid, well-aligned pod of type object.
|
|
+ ///
|
|
+ /// All restrictions from [`Pod::from_raw_mut`] also apply here.
|
|
+ pub unsafe fn from_raw_mut(pod: *mut spa_sys::spa_pod_object) -> &'static mut Self {
|
|
+ pod.cast::<Self>().as_mut().unwrap()
|
|
+ }
|
|
+
|
|
+ pub fn as_raw_ptr(&self) -> *mut spa_sys::spa_pod_object {
|
|
+ std::ptr::addr_of!(self.0).cast_mut()
|
|
+ }
|
|
+
|
|
+ pub fn as_pod(&self) -> &Pod {
|
|
+ // Safety: Since this is a valid spa_pod_object, it must also be a valid spa_pod
|
|
+ unsafe { Pod::from_raw(addr_of!(self.0.pod)) }
|
|
+ }
|
|
+
|
|
+ pub fn type_(&self) -> SpaTypes {
|
|
+ SpaTypes::from_raw(self.0.body.type_)
|
|
+ }
|
|
+
|
|
+ pub fn id(&self) -> Id {
|
|
+ Id(self.0.body.id)
|
|
+ }
|
|
+
|
|
+ pub fn props(&self) -> PodObjectIter<'_> {
|
|
+ PodObjectIter::new(self)
|
|
+ }
|
|
+
|
|
+ pub fn find_prop(&self, /* TODO: start, */ key: Id) -> Option<&PodProp> {
|
|
+ let prop = unsafe {
|
|
+ spa_sys::spa_pod_object_find_prop(self.as_raw_ptr(), std::ptr::null(), key.0)
|
|
+ };
|
|
+
|
|
+ if !prop.is_null() {
|
|
+ unsafe { Some(PodProp::from_raw(prop)) }
|
|
+ } else {
|
|
+ None
|
|
+ }
|
|
+ }
|
|
+
|
|
+ pub fn fixate(&mut self) {
|
|
+ let _res = unsafe { spa_sys::spa_pod_object_fixate(self.as_raw_ptr()) };
|
|
+ // C implementation always returns 0
|
|
+ }
|
|
+
|
|
+ #[cfg(feature = "v0_3_40")]
|
|
+ pub fn is_fixated(&self) -> bool {
|
|
+ let res = unsafe { spa_sys::spa_pod_object_is_fixated(self.as_raw_ptr()) };
|
|
+ res != 0
|
|
+ }
|
|
+}
|
|
+
|
|
+impl<'p> TryFrom<&'p Pod> for &'p PodObject {
|
|
+ type Error = Errno;
|
|
+
|
|
+ fn try_from(value: &'p Pod) -> Result<Self, Self::Error> {
|
|
+ value.as_object()
|
|
+ }
|
|
+}
|
|
+
|
|
+impl AsRef<Pod> for PodObject {
|
|
+ fn as_ref(&self) -> &Pod {
|
|
+ self.as_pod()
|
|
+ }
|
|
+}
|
|
+
|
|
+pub struct PodObjectIter<'o> {
|
|
+ object: &'o PodObject,
|
|
+ next: *mut spa_sys::spa_pod_prop,
|
|
+}
|
|
+
|
|
+impl<'o> PodObjectIter<'o> {
|
|
+ fn new(object: &'o PodObject) -> Self {
|
|
+ let first_prop = unsafe { spa_sys::spa_pod_prop_first(addr_of!(object.0.body)) };
|
|
+
|
|
+ Self {
|
|
+ object,
|
|
+ next: first_prop,
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+impl<'o> Iterator for PodObjectIter<'o> {
|
|
+ type Item = &'o PodProp;
|
|
+
|
|
+ fn next(&mut self) -> Option<Self::Item> {
|
|
+ // Check if the iterator has at least one element left that we can return
|
|
+ let has_next = unsafe {
|
|
+ spa_sys::spa_pod_prop_is_inside(
|
|
+ addr_of!(self.object.0.body),
|
|
+ self.object.0.pod.size,
|
|
+ self.next,
|
|
+ )
|
|
+ };
|
|
+
|
|
+ if has_next {
|
|
+ let res = unsafe { PodProp::from_raw(self.next.cast_const()) };
|
|
+
|
|
+ // Advance iter to next property
|
|
+ self.next = unsafe { spa_sys::spa_pod_prop_next(self.next) };
|
|
+
|
|
+ Some(res)
|
|
+ } else {
|
|
+ None
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+bitflags! {
|
|
+ #[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
+ pub struct PodPropFlags: u32 {
|
|
+ const READONLY = spa_sys::SPA_POD_PROP_FLAG_READONLY;
|
|
+ const HARDWARE = spa_sys::SPA_POD_PROP_FLAG_HARDWARE;
|
|
+ const HINT_DICT = spa_sys::SPA_POD_PROP_FLAG_HINT_DICT;
|
|
+ const MANDATORY = spa_sys::SPA_POD_PROP_FLAG_MANDATORY;
|
|
+ const DONT_FIXATE = spa_sys::SPA_POD_PROP_FLAG_DONT_FIXATE;
|
|
+ }
|
|
+}
|
|
+
|
|
+/// A transparent wrapper around a `spa_sys::spa_pod_prop`.
|
|
+#[repr(transparent)]
|
|
+pub struct PodProp(spa_sys::spa_pod_prop);
|
|
+
|
|
+impl PodProp {
|
|
+ /// # Safety
|
|
+ ///
|
|
+ /// The provided pointer must point to a valid, well-aligned [`spa_sys::spa_pod_prop`].
|
|
+ ///
|
|
+ /// While this struct doesn't represent a full pod, all restrictions from [`Pod::from_raw`] also apply
|
|
+ /// to this struct and the contained `value` pod.
|
|
+ pub unsafe fn from_raw(prop: *const spa_sys::spa_pod_prop) -> &'static Self {
|
|
+ prop.cast::<Self>().as_ref().unwrap()
|
|
+ }
|
|
+
|
|
+ /// # Safety
|
|
+ ///
|
|
+ /// The provided pointer must point to a valid, well-aligned pod of type object.
|
|
+ ///
|
|
+ /// While this struct doesn't represent a full pod, all restrictions from [`Pod::from_raw`] also apply
|
|
+ /// to this struct and the contained `value` pod.
|
|
+ pub unsafe fn from_raw_mut(prop: *mut spa_sys::spa_pod_prop) -> &'static mut Self {
|
|
+ prop.cast::<Self>().as_mut().unwrap()
|
|
+ }
|
|
+
|
|
+ pub fn as_raw_ptr(&self) -> *mut spa_sys::spa_pod_prop {
|
|
+ std::ptr::addr_of!(self.0).cast_mut()
|
|
+ }
|
|
+
|
|
+ pub fn key(&self) -> Id {
|
|
+ Id(self.0.key)
|
|
+ }
|
|
+
|
|
+ pub fn flags(&self) -> PodPropFlags {
|
|
+ PodPropFlags::from_bits_retain(self.0.flags)
|
|
+ }
|
|
+
|
|
+ pub fn value(&self) -> &Pod {
|
|
+ // Safety: Since PodProp may only be constructed around valid Pods, the contained value must also be valid.
|
|
+ // We don't mutate the pod and neither can the returned reference.
|
|
+ // The returned lifetime is properly shortened by this methods signature.
|
|
+ unsafe { Pod::from_raw(addr_of!(self.0.value)) }
|
|
+ }
|
|
+}
|
|
+
|
|
/// Implementors of this trait are the canonical representation of a specific type of fixed sized SPA pod.
|
|
///
|
|
/// They can be used as an output type for [`FixedSizedPod`] implementors
|
|
diff --git a/src/pod/parser.rs b/src/pod/parser.rs
|
|
index a909d57..7203ce5 100644
|
|
--- a/src/pod/parser.rs
|
|
+++ b/src/pod/parser.rs
|
|
@@ -134,7 +134,7 @@ impl<'d> Parser<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
|
|
@@ -145,7 +145,7 @@ impl<'d> Parser<'d> {
|
|
if res >= 0 {
|
|
Ok(b.assume_init())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -157,7 +157,7 @@ impl<'d> Parser<'d> {
|
|
if res >= 0 {
|
|
Ok(Id(id.assume_init()))
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -169,7 +169,7 @@ impl<'d> Parser<'d> {
|
|
if res >= 0 {
|
|
Ok(int.assume_init())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -181,7 +181,7 @@ impl<'d> Parser<'d> {
|
|
if res >= 0 {
|
|
Ok(long.assume_init())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -193,7 +193,7 @@ impl<'d> Parser<'d> {
|
|
if res >= 0 {
|
|
Ok(float.assume_init())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -205,7 +205,7 @@ impl<'d> Parser<'d> {
|
|
if res >= 0 {
|
|
Ok(double.assume_init())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -220,7 +220,7 @@ impl<'d> Parser<'d> {
|
|
let string = CStr::from_ptr(string);
|
|
Ok(string)
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -241,7 +241,7 @@ impl<'d> Parser<'d> {
|
|
let bytes = std::slice::from_raw_parts(bytes, len.try_into().unwrap());
|
|
Ok(bytes)
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -258,7 +258,7 @@ impl<'d> Parser<'d> {
|
|
if res >= 0 {
|
|
Ok((ptr.assume_init(), Id(type_.assume_init())))
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -270,7 +270,7 @@ impl<'d> Parser<'d> {
|
|
if res >= 0 {
|
|
Ok(fd.assume_init())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -282,7 +282,7 @@ impl<'d> Parser<'d> {
|
|
if res >= 0 {
|
|
Ok(rect.assume_init())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -294,7 +294,7 @@ impl<'d> Parser<'d> {
|
|
if res >= 0 {
|
|
Ok(frac.assume_init())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -311,7 +311,7 @@ impl<'d> Parser<'d> {
|
|
|
|
Ok(pod)
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
@@ -329,7 +329,7 @@ impl<'d> Parser<'d> {
|
|
if res >= 0 {
|
|
Ok(())
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
|
|
@@ -353,7 +353,7 @@ impl<'d> Parser<'d> {
|
|
if res >= 0 {
|
|
Ok(Id(id.assume_init()))
|
|
} else {
|
|
- Err(Errno::from_i32(-res))
|
|
+ Err(Errno::from_raw(-res))
|
|
}
|
|
}
|
|
}
|
|
diff --git a/src/utils/dict.rs b/src/utils/dict.rs
|
|
index 7c02cff..4e99133 100644
|
|
--- a/src/utils/dict.rs
|
|
+++ b/src/utils/dict.rs
|
|
@@ -102,7 +102,6 @@ impl DictRef {
|
|
///
|
|
/// # Examples
|
|
/// ```
|
|
- /// use libspa::prelude::*;
|
|
/// use libspa::{utils::dict::StaticDict, static_dict};
|
|
///
|
|
/// static DICT: StaticDict = static_dict! {
|
|
@@ -145,9 +144,7 @@ impl std::fmt::Debug for DictRef {
|
|
|
|
impl<'a> fmt::Debug for Entries<'a> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
- f.debug_map()
|
|
- .entries(self.0.clone().map(|(k, v)| (k, v)))
|
|
- .finish()
|
|
+ f.debug_map().entries(self.0.clone()).finish()
|
|
}
|
|
}
|
|
|
|
@@ -392,7 +389,7 @@ macro_rules! static_dict {
|
|
};
|
|
|
|
unsafe {
|
|
- let ptr = &RAW as *const _ as *mut _;
|
|
+ let ptr = std::ptr::addr_of!(RAW).cast_mut();
|
|
StaticDict::from_ptr(ptr::NonNull::new_unchecked(ptr))
|
|
}
|
|
}};
|
|
@@ -421,7 +418,7 @@ unsafe impl Sync for StaticDict {}
|
|
mod tests {
|
|
use super::{DictRef, Flags, StaticDict};
|
|
use spa_sys::spa_dict;
|
|
- use std::{ffi::CString, ptr};
|
|
+ use std::ptr;
|
|
|
|
#[test]
|
|
fn test_empty_dict() {
|
|
@@ -447,20 +444,8 @@ mod tests {
|
|
};
|
|
|
|
let mut iter = dict.iter_cstr();
|
|
- assert_eq!(
|
|
- (
|
|
- CString::new("K0").unwrap().as_c_str(),
|
|
- CString::new("V0").unwrap().as_c_str()
|
|
- ),
|
|
- iter.next().unwrap()
|
|
- );
|
|
- assert_eq!(
|
|
- (
|
|
- CString::new("K1").unwrap().as_c_str(),
|
|
- CString::new("V1").unwrap().as_c_str()
|
|
- ),
|
|
- iter.next().unwrap()
|
|
- );
|
|
+ assert_eq!((c"K0", c"V0"), iter.next().unwrap());
|
|
+ assert_eq!((c"K1", c"V1"), iter.next().unwrap());
|
|
assert_eq!(None, iter.next());
|
|
}
|
|
|
|
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
|
|
index c0c4051..6aa83f2 100644
|
|
--- a/src/utils/mod.rs
|
|
+++ b/src/utils/mod.rs
|
|
@@ -144,7 +144,7 @@ impl SpaTypes {
|
|
Self(raw)
|
|
}
|
|
|
|
- /// Get the raw [`c_uint`](std::os::raw::c_uint) representing this `SpaTypes`.
|
|
+ /// Get the raw [`c_uint`] representing this `SpaTypes`.
|
|
pub fn as_raw(&self) -> c_uint {
|
|
self.0
|
|
}
|
|
diff --git a/src/utils/result.rs b/src/utils/result.rs
|
|
index 83d1e87..8d06636 100644
|
|
--- a/src/utils/result.rs
|
|
+++ b/src/utils/result.rs
|
|
@@ -133,7 +133,7 @@ impl Error {
|
|
fn new(e: i32) -> Self {
|
|
assert!(e > 0);
|
|
|
|
- Self(Errno::from_i32(e))
|
|
+ Self(Errno::from_raw(e))
|
|
}
|
|
}
|
|
|