1use std::{
2 ffi::{CStr, CString},
3 str::Utf8Error,
4};
5
6use libav_sys_ng::{
7 self, av_dict_copy, av_dict_count, av_dict_free, av_dict_get, av_dict_set, AVDictionary,
8 AVDictionaryEntry, AV_DICT_IGNORE_SUFFIX,
9};
10
11pub struct Dictionary {
12 _dict: *mut AVDictionary,
13}
14
15impl Default for Dictionary {
16 fn default() -> Self {
17 Self::new()
18 }
19}
20
21impl Dictionary {
22 pub fn new() -> Dictionary {
23 Self {
24 _dict: core::ptr::null_mut(),
25 }
26 }
27
28 pub fn set(&mut self, key: &str, value: &str) {
29 let k = CString::new(key).expect("Failed to create key for AVDictionary");
30 let v = CString::new(value).expect("Failed to create value for AVDictionary");
31
32 unsafe {
33 av_dict_set(&mut self._dict, k.as_ptr(), v.as_ptr(), 0);
34 }
35 }
36
37 pub fn get(&mut self, key: &str) -> Option<Result<&str, Utf8Error>> {
38 let k = CString::new(key).expect("Failed to create key for AVDictionary");
39
40 unsafe {
41 let value = av_dict_get(self._dict, k.as_ptr(), core::ptr::null(), 0);
42
43 if value.is_null() {
44 return None;
45 }
46
47 let raw_value = (*value).value;
48
49 Some(CStr::from_ptr(raw_value).to_str())
50 }
51 }
52
53 pub fn count(&self) -> i32 {
54 unsafe { av_dict_count(self._dict) }
55 }
56
57 pub(crate) unsafe fn raw(&mut self) -> *mut AVDictionary {
58 self._dict
59 }
60}
61
62#[derive(Debug, Clone)]
63pub struct DictionaryEntry {
64 pub key: String,
65 pub value: String,
66}
67
68impl DictionaryEntry {
69 pub fn from_raw(entry: &AVDictionaryEntry) -> DictionaryEntry {
70 unsafe {
71 let k = CStr::from_ptr(entry.key)
72 .to_str()
73 .expect("Failed to convert!")
74 .to_string();
75 let v = CStr::from_ptr(entry.value)
76 .to_str()
77 .expect("Failed to convert!")
78 .to_string();
79
80 DictionaryEntry { key: k, value: v }
81 }
82 }
83}
84
85impl Clone for Dictionary {
86 fn clone(&self) -> Dictionary {
87 let mut new_av = core::ptr::null_mut::<AVDictionary>();
88
89 let result = unsafe { av_dict_copy(&mut new_av, self._dict, AV_DICT_IGNORE_SUFFIX as i32) };
90
91 if result != 0 {
92 todo!("Failed to clone Dictionary");
95 }
96
97 Dictionary { _dict: new_av }
98 }
99}
100
101pub struct DictionaryIter {
102 dict: Dictionary,
103 prev: *mut AVDictionaryEntry,
104}
105
106impl Iterator for DictionaryIter {
108 type Item = DictionaryEntry;
109
110 fn next(&mut self) -> Option<Self::Item> {
111 unsafe {
112 let k = CString::new("").expect("Failed to create key for AVDictionary");
113 self.prev = av_dict_get(
114 self.dict.raw(),
115 k.as_ptr(),
116 self.prev,
117 AV_DICT_IGNORE_SUFFIX as i32,
118 );
119
120 if self.prev.is_null() {
121 return None;
122 }
123
124 Some(DictionaryEntry::from_raw(&*self.prev))
125 }
126 }
127}
128
129impl IntoIterator for Dictionary {
130 type Item = DictionaryEntry;
131 type IntoIter = DictionaryIter;
132
133 fn into_iter(self) -> Self::IntoIter {
134 DictionaryIter {
135 dict: self,
136 prev: core::ptr::null_mut(),
137 }
138 }
139}
140
141impl Drop for Dictionary {
142 fn drop(&mut self) {
143 unsafe {
144 av_dict_free(&mut self._dict);
145 }
146 }
147}
148
149#[cfg(test)]
151mod tests {
152 use super::Dictionary;
153
154 #[test]
155 fn simple() {
156 let mut dict = Dictionary::new();
157
158 dict.set("hello", "world");
159 dict.set("pokemon", "zeraora");
160 dict.set("thanks", "kiitos");
161 dict.set("you're welcome!", "ole hyvä!");
162
163 for i in dict.clone() {
165 println!("Element: {:?}", i);
166 }
167
168 assert_eq!(dict.get("pokemon"), Some(Ok("zeraora")));
169
170 println!("Finished");
171 }
172
173 #[test]
174 fn oops_undefined() {
175 let mut dict = Dictionary::new();
176
177 dict.set("hello", "world");
178
179 assert_eq!(dict.get("hallo"), None);
180 assert_eq!(dict.get("hello"), Some(Ok("world")));
181 }
182}