1use std::collections::BTreeMap;
6
7#[derive(Debug, Clone, Default, PartialEq, Eq)]
9pub struct Dictionary {
10 entries: BTreeMap<String, String>,
11}
12
13impl Dictionary {
14 pub fn new() -> Dictionary {
15 Dictionary::default()
16 }
17
18 pub fn set(&mut self, key: impl Into<String>, value: impl Into<String>) {
19 self.entries.insert(key.into(), value.into());
20 }
21
22 pub fn get(&self, key: &str) -> Option<&str> {
23 self.entries.get(key).map(String::as_str)
24 }
25
26 pub fn get_int(&self, key: &str) -> Option<i64> {
28 self.get(key).and_then(|v| v.parse().ok())
29 }
30
31 pub fn get_bitrate(&self, key: &str) -> Option<i64> {
35 let v = self.get(key)?.trim();
36 let (num, mult) = match v.chars().last() {
37 Some('k') | Some('K') => (&v[..v.len() - 1], 1_000i64),
38 Some('m') | Some('M') => (&v[..v.len() - 1], 1_000_000i64),
39 _ => (v, 1),
40 };
41 num.trim().parse::<f64>().ok().map(|n| (n * mult as f64) as i64)
42 }
43
44 pub fn is_empty(&self) -> bool {
45 self.entries.is_empty()
46 }
47
48 pub fn len(&self) -> usize {
49 self.entries.len()
50 }
51
52 pub fn iter(&self) -> impl Iterator<Item = (&str, &str)> {
53 self.entries.iter().map(|(k, v)| (k.as_str(), v.as_str()))
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use super::Dictionary;
60
61 #[test]
62 fn get_bitrate_parses_suffixes() {
63 let mut d = Dictionary::new();
64 d.set("b", "128k");
65 assert_eq!(d.get_bitrate("b"), Some(128_000));
66 d.set("b", "1M");
67 assert_eq!(d.get_bitrate("b"), Some(1_000_000));
68 d.set("b", "24000");
69 assert_eq!(d.get_bitrate("b"), Some(24_000));
70 d.set("b", "1.5M");
71 assert_eq!(d.get_bitrate("b"), Some(1_500_000));
72 d.set("b", "96K");
73 assert_eq!(d.get_bitrate("b"), Some(96_000));
74 assert_eq!(d.get_bitrate("missing"), None);
75 d.set("b", "garbage");
76 assert_eq!(d.get_bitrate("b"), None);
77 }
78}