aoe2_probe/utils/
map.rs

1use std::{
2    collections::HashMap,
3    fmt,
4    ops::{Index, IndexMut},
5    sync::Arc,
6};
7
8use linked_hash_map::{Iter, LinkedHashMap};
9use serde::{Deserialize, Serialize};
10
11use crate::parse::{Encode, Token};
12
13type Patch = Arc<dyn Fn(&mut PatchedMap, &mut Token) + Send + Sync>;
14#[derive(Clone, Default, Serialize, Deserialize)]
15pub struct PatchedMap {
16    #[serde(flatten)]
17    raw_hashmap: LinkedHashMap<String, Token>,
18    #[serde(skip)]
19    pub patches: HashMap<String, Patch>,
20}
21
22impl PatchedMap {
23    pub fn new() -> Self {
24        PatchedMap {
25            raw_hashmap: LinkedHashMap::new(),
26            patches: HashMap::new(),
27        }
28    }
29
30    pub fn with_capacity(capacity: usize) -> Self {
31        PatchedMap {
32            raw_hashmap: LinkedHashMap::with_capacity(capacity),
33            patches: HashMap::new(),
34        }
35    }
36
37    pub fn push_back<T: Into<Token>>(&mut self, key_str: &str, value: T) -> bool {
38        let key = key_str.to_string();
39
40        if self.raw_hashmap.contains_key(&key) {
41            return false;
42        }
43
44        self.raw_hashmap.insert(key, value.into());
45        true
46    }
47
48    pub fn update<T: Into<Token>>(&mut self, key: &str, value: T) -> Result<(), String> {
49        if !self.raw_hashmap.contains_key(key) {
50            return Err("Key doesn't exist!".to_string());
51        }
52
53        self.raw_hashmap[key] = value.into();
54        Ok(())
55    }
56
57    pub fn contains(&self, key: &str) -> bool {
58        self.raw_hashmap.contains_key(&key.to_string())
59    }
60
61    pub fn keys(&self) -> linked_hash_map::Keys<String, Token> {
62        self.raw_hashmap.keys()
63    }
64
65    pub fn iter(&self) -> SeqIter {
66        SeqIter {
67            index: 0,
68            ele: self.raw_hashmap.iter(),
69        }
70    }
71}
72
73impl Index<&str> for PatchedMap {
74    type Output = Token;
75    fn index(&self, index: &str) -> &Self::Output {
76        &self.raw_hashmap[&index.to_string()]
77    }
78}
79
80impl IndexMut<&str> for PatchedMap {
81    fn index_mut(&mut self, index: &str) -> &mut Self::Output {
82        self.raw_hashmap.get_mut(&index.to_string()).unwrap()
83    }
84}
85
86pub struct SeqIter<'a> {
87    index: usize,
88    ele: Iter<'a, String, Token>,
89}
90
91impl<'a> Iterator for SeqIter<'a> {
92    type Item = (&'a String, &'a Token);
93
94    fn next(&mut self) -> Option<Self::Item> {
95        match self.ele.next() {
96            Some((key, value)) => {
97                self.index += 1;
98                Some((key, value))
99            }
100            None => None,
101        }
102    }
103}
104
105impl Encode for PatchedMap {
106    fn to_le_vec(&self) -> Vec<u8> {
107        self.iter()
108            .flat_map(|(_, token)| token.to_le_vec())
109            .collect()
110    }
111}
112
113impl fmt::Debug for PatchedMap {
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        f.write_str("PatchedMap")?;
116        f.debug_map()
117            .entries(self.iter().map(|(key, value)| (key, value)))
118            .finish()
119    }
120}