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