pipewire/properties/
mod.rs1use std::{ffi::CString, fmt, ptr};
5
6mod box_;
7pub use box_::*;
8
9#[repr(transparent)]
11pub struct Properties(pw_sys::pw_properties);
12
13impl Properties {
14 pub fn as_raw(&self) -> &pw_sys::pw_properties {
15 &self.0
16 }
17
18 pub fn as_raw_ptr(&self) -> *mut pw_sys::pw_properties {
25 std::ptr::addr_of!(self.0).cast_mut()
26 }
27
28 pub fn dict(&self) -> &spa::utils::dict::DictRef {
29 unsafe { &*(&self.0.dict as *const spa_sys::spa_dict as *const spa::utils::dict::DictRef) }
30 }
31
32 pub fn to_owned(&self) -> PropertiesBox {
34 unsafe {
35 let ptr = pw_sys::pw_properties_copy(self.as_raw_ptr());
36 PropertiesBox::from_raw(ptr::NonNull::new_unchecked(ptr))
37 }
38 }
39
40 pub fn get(&self, key: &str) -> Option<&str> {
41 let key = CString::new(key).expect("key contains null byte");
42
43 let res =
44 unsafe { pw_sys::pw_properties_get(self.as_raw_ptr().cast_const(), key.as_ptr()) };
45
46 let res = if !res.is_null() {
47 unsafe { Some(std::ffi::CStr::from_ptr(res)) }
48 } else {
49 None
50 };
51
52 res.and_then(|res| res.to_str().ok())
54 }
55
56 pub fn insert<K, V>(&mut self, key: K, value: V)
57 where
58 K: Into<Vec<u8>>,
59 V: Into<Vec<u8>>,
60 {
61 let k = CString::new(key).unwrap();
62 let v = CString::new(value).unwrap();
63 unsafe { pw_sys::pw_properties_set(self.as_raw_ptr(), k.as_ptr(), v.as_ptr()) };
64 }
65
66 pub fn remove<T>(&mut self, key: T)
67 where
68 T: Into<Vec<u8>>,
69 {
70 let key = CString::new(key).unwrap();
71 unsafe { pw_sys::pw_properties_set(self.as_raw_ptr(), key.as_ptr(), std::ptr::null()) };
72 }
73
74 pub fn clear(&mut self) {
75 unsafe { pw_sys::pw_properties_clear(self.as_raw_ptr()) }
76 }
77}
78
79impl AsRef<spa::utils::dict::DictRef> for Properties {
80 fn as_ref(&self) -> &spa::utils::dict::DictRef {
81 self.dict()
82 }
83}
84
85impl fmt::Debug for Properties {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 f.debug_tuple("Properties").field(self.as_ref()).finish()
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn new() {
98 let props = properties! {
99 "K0" => "V0"
100 };
101
102 let mut iter = props.dict().iter();
103 assert_eq!(("K0", "V0"), iter.next().unwrap());
104 assert_eq!(None, iter.next());
105 }
106
107 #[test]
108 fn remove() {
109 let mut props = properties! {
110 "K0" => "V0"
111 };
112
113 assert_eq!(Some("V0"), props.dict().get("K0"));
114 props.remove("K0");
115 assert_eq!(None, props.dict().get("K0"));
116 }
117
118 #[test]
119 fn insert() {
120 let mut props = properties! {
121 "K0" => "V0"
122 };
123
124 assert_eq!(None, props.dict().get("K1"));
125 props.insert("K1", "V1");
126 assert_eq!(Some("V1"), props.dict().get("K1"));
127 }
128
129 #[test]
130 fn clone() {
131 let props1 = properties! {
132 "K0" => "V0"
133 };
134 let mut props2 = props1.clone();
135
136 props2.insert("K1", "V1");
137
138 assert_eq!(None, props1.dict().get("K1"));
141 assert_eq!(Some("V1"), props2.dict().get("K1"));
142 }
143
144 #[test]
145 fn from_dict() {
146 use spa::static_dict;
147
148 let mut props = {
149 let dict = static_dict! { "K0" => "V0" };
150
151 PropertiesBox::from_dict(&dict)
152 };
153
154 assert_eq!(props.dict().len(), 1);
155 assert_eq!(props.dict().get("K0"), Some("V0"));
156
157 props.insert("K1", "V1");
158 assert_eq!(props.dict().len(), 2);
159 assert_eq!(props.dict().get("K1"), Some("V1"));
160 }
161
162 #[test]
163 fn properties_ref() {
164 use std::ops::Deref;
165
166 let props = properties! {
167 "K0" => "V0"
168 };
169 println!("{:?}", &props);
170 let props_ref: &Properties = props.deref();
171
172 assert_eq!(props_ref.dict().len(), 1);
173 assert_eq!(props_ref.dict().get("K0"), Some("V0"));
174 dbg!(&props_ref);
175
176 let props_copy = props_ref.to_owned();
177 assert_eq!(props_copy.dict().len(), 1);
178 assert_eq!(props_copy.dict().get("K0"), Some("V0"));
179 }
180}