use {
crate::{
prelude::*,
spa::{SpaPod, SpaPodBuilder, SpaType},
},
glib::{ffi::gboolean, GString},
};
pub trait SpaPrimitive: SpaValue + Copy + Into<<Self as SpaValue>::Owned> {
const TYPE: SpaType;
}
pub trait SpaValue {
fn add_to_builder(&self, builder: &SpaPodBuilder);
type Owned: for<'a> TryFrom<&'a SpaPod>;
}
impl SpaPrimitive for () {
const TYPE: SpaType = SpaType::NONE;
}
impl SpaValue for () {
fn add_to_builder(&self, builder: &SpaPodBuilder) {
builder.add_none()
}
type Owned = Self;
}
impl<'a> TryFrom<&'a SpaPod> for () {
type Error = GlibNoneError;
fn try_from(pod: &'a SpaPod) -> Result<Self, Self::Error> {
if pod.is_none() {
Ok(())
} else {
Err(GlibNoneError)
}
}
}
impl SpaValue for bool {
fn add_to_builder(&self, builder: &SpaPodBuilder) {
builder.add_boolean(*self)
}
type Owned = Self;
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct SpaBool(gboolean);
impl From<SpaBool> for bool {
fn from(v: SpaBool) -> Self {
unsafe { from_glib(v.0) }
}
}
impl From<bool> for SpaBool {
fn from(v: bool) -> Self {
Self(v.into_glib())
}
}
impl SpaPrimitive for SpaBool {
const TYPE: SpaType = SpaType::BOOL;
}
impl SpaValue for SpaBool {
fn add_to_builder(&self, builder: &SpaPodBuilder) {
builder.add_boolean((*self).into())
}
type Owned = bool;
}
impl<'a> TryFrom<&'a SpaPod> for SpaBool {
type Error = GlibNoneError;
fn try_from(pod: &'a SpaPod) -> Result<Self, Self::Error> {
pod.boolean().map(Into::into).ok_or(GlibNoneError)
}
}
impl<'a> TryFrom<&'a SpaPod> for bool {
type Error = GlibNoneError;
fn try_from(pod: &'a SpaPod) -> Result<Self, Self::Error> {
pod.boolean().ok_or(GlibNoneError)
}
}
impl SpaPrimitive for i32 {
const TYPE: SpaType = SpaType::INT;
}
impl SpaValue for i32 {
fn add_to_builder(&self, builder: &SpaPodBuilder) {
builder.add_int(*self)
}
type Owned = Self;
}
impl<'a> TryFrom<&'a SpaPod> for i32 {
type Error = GlibNoneError;
fn try_from(pod: &'a SpaPod) -> Result<Self, Self::Error> {
pod.int().ok_or(GlibNoneError)
}
}
impl<'a> TryFrom<&'a SpaPod> for u32 {
type Error = Error;
fn try_from(pod: &'a SpaPod) -> Result<Self, Self::Error> {
i32::try_from(pod)
.map_err(|e| Error::new(LibraryErrorEnum::InvalidArgument, &format!("{e:?}")))
.and_then(|v| {
v.try_into()
.map_err(|e| Error::new(LibraryErrorEnum::InvalidArgument, &format!("{e:?}")))
})
}
}
impl SpaPrimitive for i64 {
const TYPE: SpaType = SpaType::LONG;
}
impl SpaValue for i64 {
fn add_to_builder(&self, builder: &SpaPodBuilder) {
builder.add_long(*self)
}
type Owned = Self;
}
impl<'a> TryFrom<&'a SpaPod> for i64 {
type Error = GlibNoneError;
fn try_from(pod: &'a SpaPod) -> Result<Self, Self::Error> {
pod.long().ok_or(GlibNoneError)
}
}
impl<'a> TryFrom<&'a SpaPod> for u64 {
type Error = Error;
fn try_from(pod: &'a SpaPod) -> Result<Self, Self::Error> {
i64::try_from(pod)
.map_err(|e| Error::new(LibraryErrorEnum::InvalidArgument, &format!("{e:?}")))
.and_then(|v| {
v.try_into()
.map_err(|e| Error::new(LibraryErrorEnum::InvalidArgument, &format!("{e:?}")))
})
}
}
impl SpaPrimitive for f32 {
const TYPE: SpaType = SpaType::FLOAT;
}
impl SpaValue for f32 {
fn add_to_builder(&self, builder: &SpaPodBuilder) {
builder.add_float(*self)
}
type Owned = Self;
}
impl<'a> TryFrom<&'a SpaPod> for f32 {
type Error = GlibNoneError;
fn try_from(pod: &'a SpaPod) -> Result<Self, Self::Error> {
pod.float().ok_or(GlibNoneError)
}
}
impl SpaPrimitive for f64 {
const TYPE: SpaType = SpaType::DOUBLE;
}
impl SpaValue for f64 {
fn add_to_builder(&self, builder: &SpaPodBuilder) {
builder.add_double(*self)
}
type Owned = f64;
}
impl<'a> TryFrom<&'a SpaPod> for f64 {
type Error = GlibNoneError;
fn try_from(pod: &'a SpaPod) -> Result<Self, Self::Error> {
pod.double().ok_or(GlibNoneError)
}
}
impl SpaValue for str {
fn add_to_builder(&self, builder: &SpaPodBuilder) {
builder.add_string(self)
}
type Owned = GString;
}
impl<'a> TryFrom<&'a SpaPod> for GString {
type Error = GlibNoneError;
fn try_from(pod: &'a SpaPod) -> Result<Self, Self::Error> {
pod.string().ok_or(GlibNoneError)
}
}
impl<'a> TryFrom<&'a SpaPod> for String {
type Error = GlibNoneError;
fn try_from(pod: &'a SpaPod) -> Result<Self, Self::Error> {
<GString as TryFrom<&'a SpaPod>>::try_from(pod).map(Into::into)
}
}
impl SpaValue for [u8] {
fn add_to_builder(&self, builder: &SpaPodBuilder) {
builder.add_bytes(self)
}
type Owned = Vec<u8>;
}
impl<'a> TryFrom<&'a SpaPod> for Vec<u8> {
type Error = GlibNoneError;
fn try_from(pod: &'a SpaPod) -> Result<Self, Self::Error> {
pod.bytes().map(Into::into).ok_or(GlibNoneError)
}
}
impl SpaPrimitive for libspa_sys::spa_rectangle {
const TYPE: SpaType = SpaType::RECTANGLE;
}
impl SpaValue for libspa_sys::spa_rectangle {
fn add_to_builder(&self, builder: &SpaPodBuilder) {
builder.add_rectangle(self.width, self.height)
}
type Owned = Self;
}
impl<'a> TryFrom<&'a SpaPod> for libspa_sys::spa_rectangle {
type Error = GlibNoneError;
fn try_from(pod: &'a SpaPod) -> Result<Self, Self::Error> {
pod.spa_rectangle().ok_or(GlibNoneError)
}
}
impl SpaPrimitive for libspa_sys::spa_fraction {
const TYPE: SpaType = SpaType::FRACTION;
}
impl SpaValue for libspa_sys::spa_fraction {
fn add_to_builder(&self, builder: &SpaPodBuilder) {
builder.add_fraction(self.num, self.denom)
}
type Owned = Self;
}
impl<'a> TryFrom<&'a SpaPod> for libspa_sys::spa_fraction {
type Error = GlibNoneError;
fn try_from(pod: &'a SpaPod) -> Result<Self, Self::Error> {
pod.spa_fraction().ok_or(GlibNoneError)
}
}
impl SpaValue for SpaPod {
fn add_to_builder(&self, builder: &SpaPodBuilder) {
builder.add_pod(self)
}
type Owned = Self;
}
impl<'a> TryFrom<&'a SpaPod> for SpaPod {
type Error = GlibNoneError;
fn try_from(pod: &'a SpaPod) -> Result<Self, Self::Error> {
Ok(pod.copy().unwrap())
}
}
impl<T: SpaPrimitive> SpaValue for [T]
where
Vec<T::Owned>: for<'a> TryFrom<&'a SpaPod>,
{
fn add_to_builder(&self, builder: &SpaPodBuilder) {
let struct_ = SpaPodBuilder::new_array();
for item in self {
item.add_to_builder(&struct_);
}
if let Some(pod) = struct_.end() {
builder.add_pod(&pod)
} else {
wp_critical!("failed to build spa struct with {struct_:?}")
}
}
type Owned = Vec<T::Owned>;
}
impl<'a, T: for<'f> TryFrom<&'f SpaPod>> TryFrom<&'a SpaPod> for Vec<T>
where
for<'f> <T as TryFrom<&'f SpaPod>>::Error: Into<GlibNoneError>,
{
type Error = GlibNoneError;
fn try_from(pod: &'a SpaPod) -> Result<Self, Self::Error> {
if !pod.is_struct() {
return Err(GlibNoneError)
}
pod
.iterator()
.into_iter()
.map(|pod| T::try_from(&pod).map_err(Into::into))
.collect()
}
}
impl<'a, T: Sized> SpaValue for [&'a dyn SpaValue<Owned = T>]
where
Vec<T>: for<'f> TryFrom<&'f SpaPod>,
T: for<'f> TryFrom<&'f SpaPod>,
{
fn add_to_builder(&self, builder: &SpaPodBuilder) {
let struct_ = SpaPodBuilder::new_struct();
for &item in self {
SpaValue::add_to_builder(item, &struct_);
}
if let Some(pod) = struct_.end() {
builder.add_pod(&pod)
} else {
wp_critical!("failed to build spa struct with {struct_:?}")
}
}
type Owned = Vec<T>;
}