1#[derive(Debug, Clone, Default)]
7pub struct CodecOptions {
8 options: Vec<(String, String)>,
9}
10
11impl CodecOptions {
12 pub fn new() -> Self {
13 Self {
14 options: Vec::new(),
15 }
16 }
17
18 pub fn set(&mut self, key: impl Into<String>, value: impl Into<String>) {
21 let key = key.into();
22 let value = value.into();
23 if let Some(entry) = self.options.iter_mut().find(|(k, _)| k == &key) {
24 entry.1 = value;
25 } else {
26 self.options.push((key, value));
27 }
28 }
29
30 pub fn get(&self, key: &str) -> Option<&str> {
32 self.options
33 .iter()
34 .find(|(k, _)| k == key)
35 .map(|(_, v)| v.as_str())
36 }
37
38 pub fn get_i64(&self, key: &str) -> Option<i64> {
40 self.get(key).and_then(|v| v.parse().ok())
41 }
42
43 pub fn get_f64(&self, key: &str) -> Option<f64> {
45 self.get(key).and_then(|v| v.parse().ok())
46 }
47
48 pub fn get_bool(&self, key: &str) -> Option<bool> {
53 self.get(key).and_then(|v| match v {
54 "1" | "true" | "yes" => Some(true),
55 "0" | "false" | "no" => Some(false),
56 _ => None,
57 })
58 }
59
60 pub fn iter(&self) -> impl Iterator<Item = (&str, &str)> {
62 self.options.iter().map(|(k, v)| (k.as_str(), v.as_str()))
63 }
64
65 pub fn is_empty(&self) -> bool {
67 self.options.is_empty()
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn test_set_and_get() {
77 let mut opts = CodecOptions::new();
78 opts.set("bitrate", "128000");
79 assert_eq!(opts.get("bitrate"), Some("128000"));
80 assert_eq!(opts.get("missing"), None);
81 }
82
83 #[test]
84 fn test_overwrite_preserves_order() {
85 let mut opts = CodecOptions::new();
86 opts.set("a", "1");
87 opts.set("b", "2");
88 opts.set("a", "3");
89
90 let keys: Vec<&str> = opts.iter().map(|(k, _)| k).collect();
91 assert_eq!(keys, vec!["a", "b"]);
92 assert_eq!(opts.get("a"), Some("3"));
93 }
94
95 #[test]
96 fn test_typed_getters() {
97 let mut opts = CodecOptions::new();
98 opts.set("threads", "4");
99 opts.set("quality", "0.95");
100 opts.set("strict", "true");
101 opts.set("experimental", "1");
102 opts.set("disabled", "no");
103 opts.set("bad_int", "abc");
104
105 assert_eq!(opts.get_i64("threads"), Some(4));
106 assert_eq!(opts.get_f64("quality"), Some(0.95));
107 assert_eq!(opts.get_bool("strict"), Some(true));
108 assert_eq!(opts.get_bool("experimental"), Some(true));
109 assert_eq!(opts.get_bool("disabled"), Some(false));
110 assert_eq!(opts.get_i64("bad_int"), None);
111 assert_eq!(opts.get_i64("missing"), None);
112 }
113
114 #[test]
115 fn test_is_empty() {
116 let mut opts = CodecOptions::new();
117 assert!(opts.is_empty());
118 opts.set("key", "value");
119 assert!(!opts.is_empty());
120 }
121
122 #[test]
123 fn test_default() {
124 let opts = CodecOptions::default();
125 assert!(opts.is_empty());
126 }
127}