Skip to main content

binary_codec/
config.rs

1use std::collections::HashMap;
2
3#[derive(Clone, Debug)]
4pub struct SerializerConfig<T = ()>
5where
6    T: Clone,
7{
8    toggle_keys: HashMap<String, bool>,
9    length_keys: HashMap<String, usize>,
10    variant_keys: HashMap<String, u8>,
11    multi_disc_config: HashMap<String, HashMap<u8, String>>,
12    multi_disc_list: HashMap<String, Vec<u8>>,
13    pub discriminator: Option<u8>,
14    pub data: Option<T>,
15}
16
17impl Default for SerializerConfig {
18    fn default() -> Self {
19        Self::new(None::<()>)
20    }
21}
22
23impl<T: Clone> SerializerConfig<T> {
24    pub fn new(data: Option<T>) -> Self {
25        Self {
26            toggle_keys: HashMap::new(),
27            length_keys: HashMap::new(),
28            variant_keys: HashMap::new(),
29            multi_disc_config: HashMap::new(),
30            multi_disc_list: HashMap::new(),
31            discriminator: None,
32            data,
33        }
34    }
35
36    pub fn configure_multi_disc(&mut self, enum_name: &str, disc: u8, multi_by: &str) {
37        let entry = self
38            .multi_disc_config
39            .entry(enum_name.to_string())
40            .or_insert_with(HashMap::new);
41
42        entry.insert(disc, multi_by.to_string());
43    }
44
45    pub fn get_multi_disc_size(&self, enum_name: &str) -> usize {
46        self.get_toggled_multi_discs(enum_name).len()
47    }
48
49    pub fn get_next_multi_disc(&mut self, field: &str, enum_name: &str) -> Option<u8> {
50        let discs = self.get_toggled_multi_discs(enum_name);
51        let entry = self
52            .multi_disc_list
53            .entry(format!("{}.{}", field, enum_name))
54            .or_insert(discs);
55
56        let res = entry.pop();
57
58        // Cleanup empty entries to prevent issues with multiple calls to get_next_multi_disc for the same field and enum_name
59        if entry.is_empty() {
60            self.multi_disc_list.remove(&format!("{}.{}", field, enum_name));
61        }
62
63        res
64    }
65
66    fn get_toggled_multi_discs(&self, enum_name: &str) -> Vec<u8> {
67        let mut discs = Vec::new();
68        if let Some(disc_map) = self.multi_disc_config.get(enum_name) {
69            for (disc, toggle) in disc_map.iter() {
70                if self.get_toggle(toggle).unwrap_or(false) {
71                    discs.push(*disc);
72                }
73            }
74        }
75        discs.sort();
76        discs.reverse();
77        discs
78    }
79
80    pub fn set_toggle(&mut self, key: &str, value: bool) {
81        self.toggle_keys.insert(key.to_string(), value);
82    }
83
84    pub fn set_length(&mut self, key: &str, value: usize) {
85        self.length_keys.insert(key.to_string(), value);
86    }
87
88    pub fn set_variant(&mut self, key: &str, value: u8) {
89        self.variant_keys.insert(key.to_string(), value);
90    }
91
92     /// Variant toggle setting: key_name=1|2|3|4
93    pub fn get_variant_toggle(&mut self, setting: &str) -> Option<bool> {
94        let mut parts = setting.split("=");
95        let key = parts.next().expect("key=discriminators");
96        let discs: Vec<u8> = parts.next().expect("key=discriminators").split("|")
97            .map(|v| v.parse().expect("a valid u8")).collect();
98
99        let variant = self.get_variant(key)?;
100        Some(discs.contains(&variant))
101    }
102
103    pub fn get_toggle(&self, key: &str) -> Option<bool> {
104        if key.starts_with('!') {
105            let key = &key[1..];
106            return self.toggle_keys.get(key).map(|v| !*v);
107        }
108
109        self.toggle_keys.get(key).copied()
110    }
111
112    pub fn get_length(&self, key: &str) -> Option<usize> {
113        self.length_keys.get(key).copied()
114    }
115
116    pub fn get_variant(&self, key: &str) -> Option<u8> {
117        self.variant_keys
118            .get(key)
119            .copied()
120            .or_else(|| self.toggle_keys.get(key).map(|t| if *t { 1 } else { 0 }))
121    }
122
123    pub fn reset(&mut self) {
124        self.discriminator = None;
125        self.toggle_keys.clear();
126        self.length_keys.clear();
127        self.variant_keys.clear();
128        self.multi_disc_config.clear();
129        self.multi_disc_list.clear();
130    }
131}