Skip to main content

rsmpeg/avutil/
dict.rs

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    /// Create a dictionary while calling `set()`.
14    pub fn new(key: &CStr, value: &CStr, flags: u32) -> Self {
15        // Since AVDictionary is a non-null pointer to ffi::AVDictionary.
16        // Without a new macro `wrap_nullable`, we cannot new a Self containing
17        // null pointer.
18        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    /// Create a dictionary while calling `set_int()`.
26    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    // Create a dictionary while calling `Self::parse_string()`.
35    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    /// The set function is so strange is because adding a new entry to
57    /// AVDictionary invalidates all existing entries.... So this functions
58    /// consumes itself.
59    pub fn set(mut self, key: &CStr, value: &CStr, flags: u32) -> Self {
60        let mut dict = self.as_mut_ptr();
61        // Only error on AVERROR_ENOMEM, so unwrap
62        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    /// Similar to the `set` function.
70    pub fn set_int(mut self, key: &CStr, value: i64, flags: u32) -> Self {
71        let mut dict = self.as_mut_ptr();
72        // Only error on AVERROR_ENOMEM, so unwrap
73        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    /// Parse the key/value pairs list and add the parsed entries to a
81    /// dictionary.
82    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    /// Copy entries from one AVDictionary struct into self.
105    pub fn copy(mut self, another: &AVDictionary, flags: u32) -> Self {
106        let mut dict = self.as_mut_ptr();
107        // Only error on AVERROR_ENOMEM, so unwrap
108        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    /// Get dictionary entries as a string.
116    ///
117    /// Create a string containing dictionary's entries.
118    /// Such string may be passed back to `Self::parse_string()`.
119    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    /// Get a dictionary entry with matching key.
133    ///
134    /// The returned entry key or value must not be changed, or it will
135    /// cause undefined behavior.
136    ///
137    /// To iterate through all the dictionary entries, you can set the matching key
138    /// to the null string "" and set the AV_DICT_IGNORE_SUFFIX flag.
139    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    /// Iterates through all entries in the dictionary by reference.
155    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    /// Similar to `Self::copy()`, while set the copy flag to `0`.
166    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
202/// Iterator over [`AVDictionary`] by reference.
203pub 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        // Find `foo` after after entry of `bob` will fail.
281        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        // Shadowing.
286        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}