1use crate::{error::Result, ffi, shared::*};
2
3use std::{
4 ffi::{CStr, CString},
5 fmt::Debug,
6 os::raw::c_void,
7 ptr::{self, NonNull},
8};
9
10wrap_ref_mut!(AVDictionary: ffi::AVDictionary);
11
12impl AVDictionary {
13 pub fn new(key: &CStr, value: &CStr, flags: u32) -> Self {
15 let mut dict = ptr::null_mut();
19 unsafe { ffi::av_dict_set(&mut dict, key.as_ptr(), value.as_ptr(), flags as i32) }
20 .upgrade()
21 .unwrap();
22 unsafe { Self::from_raw(NonNull::new(dict).unwrap()) }
23 }
24
25 pub fn new_int(key: &CStr, value: i64, flags: u32) -> Self {
27 let mut dict = ptr::null_mut();
28 unsafe { ffi::av_dict_set_int(&mut dict, key.as_ptr(), value, flags as i32) }
29 .upgrade()
30 .unwrap();
31 unsafe { Self::from_raw(NonNull::new(dict).unwrap()) }
32 }
33
34 pub fn from_string(
36 str: &CStr,
37 key_val_sep: &CStr,
38 pairs_sep: &CStr,
39 flags: u32,
40 ) -> Option<Self> {
41 let mut dict = ptr::null_mut();
42 unsafe {
43 ffi::av_dict_parse_string(
44 &mut dict,
45 str.as_ptr(),
46 key_val_sep.as_ptr(),
47 pairs_sep.as_ptr(),
48 flags as i32,
49 )
50 }
51 .upgrade()
52 .ok()?;
53 Some(unsafe { Self::from_raw(NonNull::new(dict).unwrap()) })
54 }
55
56 pub fn set(mut self, key: &CStr, value: &CStr, flags: u32) -> Self {
60 let mut dict = self.as_mut_ptr();
61 unsafe { ffi::av_dict_set(&mut dict, key.as_ptr(), value.as_ptr(), flags as i32) }
63 .upgrade()
64 .unwrap();
65 unsafe { self.set_ptr(NonNull::new(dict).unwrap()) };
66 self
67 }
68
69 pub fn set_int(mut self, key: &CStr, value: i64, flags: u32) -> Self {
71 let mut dict = self.as_mut_ptr();
72 unsafe { ffi::av_dict_set_int(&mut dict, key.as_ptr(), value, flags as i32) }
74 .upgrade()
75 .unwrap();
76 unsafe { self.set_ptr(NonNull::new(dict).unwrap()) };
77 self
78 }
79
80 pub fn parse_string(
83 mut self,
84 str: &CStr,
85 key_val_sep: &CStr,
86 pairs_sep: &CStr,
87 flags: u32,
88 ) -> Result<Self> {
89 let mut dict = self.as_mut_ptr();
90 unsafe {
91 ffi::av_dict_parse_string(
92 &mut dict,
93 str.as_ptr(),
94 key_val_sep.as_ptr(),
95 pairs_sep.as_ptr(),
96 flags as i32,
97 )
98 }
99 .upgrade()?;
100 unsafe { self.set_ptr(NonNull::new(dict).unwrap()) };
101 Ok(self)
102 }
103
104 pub fn copy(mut self, another: &AVDictionary, flags: u32) -> Self {
106 let mut dict = self.as_mut_ptr();
107 unsafe { ffi::av_dict_copy(&mut dict, another.as_ptr(), flags as i32) }
109 .upgrade()
110 .unwrap();
111 unsafe { self.set_ptr(NonNull::new(dict).unwrap()) };
112 self
113 }
114
115 pub fn get_string(&self, key_val_sep: u8, pairs_sep: u8) -> Result<CString> {
120 let mut s = ptr::null_mut();
121 unsafe { ffi::av_dict_get_string(self.as_ptr(), &mut s, key_val_sep as _, pairs_sep as _) }
122 .upgrade()?;
123 let result = unsafe { CStr::from_ptr(s).to_owned() };
124 unsafe {
125 ffi::av_freep(&mut s as *mut _ as *mut c_void);
126 }
127 Ok(result)
128 }
129}
130
131impl<'dict> AVDictionary {
132 pub fn get(
140 &'dict self,
141 key: &CStr,
142 prev: Option<AVDictionaryEntryRef>,
143 flags: u32,
144 ) -> Option<AVDictionaryEntryRef<'dict>> {
145 let prev_ptr = match prev {
146 Some(entry) => entry.as_ptr(),
147 None => ptr::null(),
148 };
149 unsafe { ffi::av_dict_get(self.as_ptr(), key.as_ptr(), prev_ptr, flags as i32) }
150 .upgrade()
151 .map(|ptr| unsafe { AVDictionaryEntryRef::from_raw(ptr) })
152 }
153
154 pub fn iter(&'dict self) -> AVDictionaryIter<'dict> {
156 AVDictionaryIter {
157 dict: self,
158 ptr: ptr::null(),
159 _phantom: std::marker::PhantomData,
160 }
161 }
162}
163
164impl Clone for AVDictionary {
165 fn clone(&self) -> Self {
167 let mut newer = ptr::null_mut();
168 unsafe { ffi::av_dict_copy(&mut newer, self.as_ptr(), 0) }
169 .upgrade()
170 .unwrap();
171 unsafe { Self::from_raw(NonNull::new(newer).unwrap()) }
172 }
173}
174
175impl Drop for AVDictionary {
176 fn drop(&mut self) {
177 let mut dict = self.as_mut_ptr();
178 unsafe { ffi::av_dict_free(&mut dict) }
179 }
180}
181
182impl<'dict> IntoIterator for &'dict AVDictionary {
183 type IntoIter = AVDictionaryIter<'dict>;
184 type Item = AVDictionaryEntryRef<'dict>;
185 fn into_iter(self) -> Self::IntoIter {
186 self.iter()
187 }
188}
189
190impl Debug for AVDictionary {
191 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192 let mut out = f.debug_map();
193
194 for entry in self.into_iter() {
195 out.entry(&entry.key(), &entry.value());
196 }
197
198 out.finish()
199 }
200}
201
202pub struct AVDictionaryIter<'dict> {
204 dict: &'dict AVDictionary,
205 ptr: *const ffi::AVDictionaryEntry,
206 _phantom: std::marker::PhantomData<&'dict ()>,
207}
208
209impl<'dict> Iterator for AVDictionaryIter<'dict> {
210 type Item = AVDictionaryEntryRef<'dict>;
211 fn next(&mut self) -> Option<Self::Item> {
212 self.ptr = unsafe { ffi::av_dict_iterate(self.dict.as_ptr(), self.ptr) };
213 self.ptr
214 .upgrade()
215 .map(|x| unsafe { AVDictionaryEntryRef::from_raw(x) })
216 }
217}
218
219wrap_ref_mut!(AVDictionaryEntry: ffi::AVDictionaryEntry);
220
221impl AVDictionaryEntry {
222 pub fn key(&self) -> &CStr {
223 unsafe { CStr::from_ptr(self.key) }
224 }
225
226 pub fn value(&self) -> &CStr {
227 unsafe { CStr::from_ptr(self.value) }
228 }
229}
230
231#[cfg(test)]
232mod test {
233 use super::AVDictionary;
234
235 #[test]
236 fn set() {
237 let _ = AVDictionary::new(c"bob", c"alice", 0);
238
239 let _ = AVDictionary::new(c"bob", c"alice", 0)
240 .set(c"a;dsjfadsfa", c"asdfjal;sdfj", 0)
241 .set(c"foo", c"bar", 0);
242
243 let _ = AVDictionary::new(c"bob", c"alice", 0).set(c"bob", c"alice", 0);
244 }
245
246 #[test]
247 fn set_int() {
248 let dict = AVDictionary::new_int(c"bob", 2233, 0).set_int(c"foo", 123456789123456789, 0);
249 assert_eq!(
250 c"123456789123456789".as_ref(),
251 dict.get(c"foo", None, 0).unwrap().value()
252 );
253 }
254
255 #[test]
256 fn get() {
257 let dict = AVDictionary::new(c"bob", c"alice", 0);
258 assert_eq!(
259 c"alice".as_ref(),
260 dict.get(c"bob", None, 0).unwrap().value()
261 );
262
263 let dict = AVDictionary::new(c"bob", c"alice", 0)
264 .set(c"bob", c"alice", 0)
265 .set(c"bob", c"alice", 0)
266 .set(c"bob", c"alice", 0)
267 .set(c"bob", c"alice", 0);
268 assert_eq!(
269 c"alice".as_ref(),
270 dict.get(c"bob", None, 0).unwrap().value()
271 );
272
273 let dict = AVDictionary::new(c"foo", c"bar", 0).set(c"bob", c"alice", 0);
274 assert_eq!(c"bar".as_ref(), dict.get(c"foo", None, 0).unwrap().value());
275 assert_eq!(
276 c"alice".as_ref(),
277 dict.get(c"bob", None, 0).unwrap().value()
278 );
279
280 let entry = dict.get(c"bob", None, 0).unwrap();
282 assert_eq!(c"alice".as_ref(), entry.value());
283 assert!(dict.get(c"foo", Some(entry), 0).is_none());
284
285 let dict = AVDictionary::new(c"bob", c"alice0", 0)
287 .set(c"bob", c"alice1", 0)
288 .set(c"bob", c"alice2", 0)
289 .set(c"bob", c"alice3", 0)
290 .set(c"bob", c"alice4", 0);
291
292 let entry = dict.get(c"bob", None, 0).unwrap();
293 assert_eq!(c"alice4".as_ref(), entry.value());
294 assert_eq!(c"bob".as_ref(), entry.key());
295 assert!(dict.get(c"bob", Some(entry), 0).is_none());
296 }
297
298 #[test]
299 fn copy() {
300 let dicta = AVDictionary::new(c"a", c"b", 0).set(c"c", c"d", 0);
301
302 let dictc = dicta.clone();
303 assert_eq!(c"a:b-c:d", dictc.get_string(b':', b'-').unwrap().as_c_str());
304
305 let dictb = AVDictionary::new(c"foo", c"bar", 0)
306 .set(c"alice", c"bob", 0)
307 .copy(&dictc, 0);
308 assert_eq!(
309 c"foo:bar-alice:bob-a:b-c:d",
310 dictb.get_string(b':', b'-').unwrap().as_c_str(),
311 );
312
313 let dicta = dicta.set(c"e", c"f", 0);
314
315 assert_eq!(c"b".as_ref(), dicta.get(c"a", None, 0).unwrap().value());
316 assert_eq!(c"d".as_ref(), dicta.get(c"c", None, 0).unwrap().value());
317 assert_eq!(c"f".as_ref(), dicta.get(c"e", None, 0).unwrap().value());
318
319 assert_eq!(c"b".as_ref(), dictb.get(c"a", None, 0).unwrap().value());
320 assert_eq!(c"d".as_ref(), dictb.get(c"c", None, 0).unwrap().value());
321 assert!(dictb.get(c"e", None, 0).is_none());
322 }
323
324 #[test]
325 fn serialization() {
326 let dict = AVDictionary::new(c"a", c"b", 0)
327 .set(c"c", c"d", 0)
328 .set(c"foo", c"bar", 0)
329 .set(c"bob", c"alice", 0);
330 assert_eq!(
331 c"a:b-c:d-foo:bar-bob:alice",
332 dict.get_string(b':', b'-').unwrap().as_c_str()
333 );
334 let dict = dict.set(c"rust", c"c", 0);
335 assert_eq!(
336 c"a:b-c:d-foo:bar-bob:alice-rust:c",
337 dict.get_string(b':', b'-').unwrap().as_c_str()
338 );
339 }
340
341 #[test]
342 fn deserialization() {
343 let dict =
344 AVDictionary::from_string(c"a:b-c:d-foo:bar-bob:alice-rust:c", c":", c"-", 0).unwrap();
345 assert_eq!(
346 c"a:b-c:d-foo:bar-bob:alice-rust:c",
347 dict.get_string(b':', b'-').unwrap().as_c_str()
348 );
349 }
350}