use std::{ffi::CString, fmt, ptr};
mod box_;
pub use box_::*;
#[repr(transparent)]
pub struct Properties(pw_sys::pw_properties);
impl Properties {
pub fn as_raw(&self) -> &pw_sys::pw_properties {
&self.0
}
pub fn as_raw_ptr(&self) -> *mut pw_sys::pw_properties {
std::ptr::addr_of!(self.0).cast_mut()
}
pub fn dict(&self) -> &spa::utils::dict::DictRef {
unsafe { &*(&self.0.dict as *const spa_sys::spa_dict as *const spa::utils::dict::DictRef) }
}
pub fn to_owned(&self) -> PropertiesBox {
unsafe {
let ptr = pw_sys::pw_properties_copy(self.as_raw_ptr());
PropertiesBox::from_raw(ptr::NonNull::new_unchecked(ptr))
}
}
pub fn get(&self, key: &str) -> Option<&str> {
let key = CString::new(key).expect("key contains null byte");
let res =
unsafe { pw_sys::pw_properties_get(self.as_raw_ptr().cast_const(), key.as_ptr()) };
let res = if !res.is_null() {
unsafe { Some(std::ffi::CStr::from_ptr(res)) }
} else {
None
};
res.and_then(|res| res.to_str().ok())
}
pub fn insert<K, V>(&mut self, key: K, value: V)
where
K: Into<Vec<u8>>,
V: Into<Vec<u8>>,
{
let k = CString::new(key).unwrap();
let v = CString::new(value).unwrap();
unsafe { pw_sys::pw_properties_set(self.as_raw_ptr(), k.as_ptr(), v.as_ptr()) };
}
pub fn remove<T>(&mut self, key: T)
where
T: Into<Vec<u8>>,
{
let key = CString::new(key).unwrap();
unsafe { pw_sys::pw_properties_set(self.as_raw_ptr(), key.as_ptr(), std::ptr::null()) };
}
pub fn clear(&mut self) {
unsafe { pw_sys::pw_properties_clear(self.as_raw_ptr()) }
}
}
impl AsRef<spa::utils::dict::DictRef> for Properties {
fn as_ref(&self) -> &spa::utils::dict::DictRef {
self.dict()
}
}
impl fmt::Debug for Properties {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Properties").field(self.as_ref()).finish()
}
}
impl<K, V> Extend<(K, V)> for Properties
where
K: Into<Vec<u8>>,
V: Into<Vec<u8>>,
{
fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
for (k, v) in iter {
self.insert(k, v);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new() {
let props = properties! {
"K0" => "V0"
};
let mut iter = props.dict().iter();
assert_eq!(("K0", "V0"), iter.next().unwrap());
assert_eq!(None, iter.next());
}
#[test]
fn remove() {
let mut props = properties! {
"K0" => "V0"
};
assert_eq!(Some("V0"), props.dict().get("K0"));
props.remove("K0");
assert_eq!(None, props.dict().get("K0"));
}
#[test]
fn insert() {
let mut props = properties! {
"K0" => "V0"
};
assert_eq!(None, props.dict().get("K1"));
props.insert("K1", "V1");
assert_eq!(Some("V1"), props.dict().get("K1"));
}
#[test]
fn clone() {
let props1 = properties! {
"K0" => "V0"
};
let mut props2 = props1.clone();
props2.insert("K1", "V1");
assert_eq!(None, props1.dict().get("K1"));
assert_eq!(Some("V1"), props2.dict().get("K1"));
}
#[test]
fn from_dict() {
use spa::static_dict;
let mut props = {
let dict = static_dict! { "K0" => "V0" };
PropertiesBox::from_dict(&dict)
};
assert_eq!(props.dict().len(), 1);
assert_eq!(props.dict().get("K0"), Some("V0"));
props.insert("K1", "V1");
assert_eq!(props.dict().len(), 2);
assert_eq!(props.dict().get("K1"), Some("V1"));
}
#[test]
fn properties_ref() {
use std::ops::Deref;
let props = properties! {
"K0" => "V0"
};
println!("{:?}", &props);
let props_ref: &Properties = props.deref();
assert_eq!(props_ref.dict().len(), 1);
assert_eq!(props_ref.dict().get("K0"), Some("V0"));
dbg!(&props_ref);
let props_copy = props_ref.to_owned();
assert_eq!(props_copy.dict().len(), 1);
assert_eq!(props_copy.dict().get("K0"), Some("V0"));
}
}