Skip to main content

pawkit_input/binding/
map.rs

1use std::collections::HashMap;
2
3use pawkit_interner::InternString;
4use serde::{Deserialize, Serialize};
5
6use crate::binding::{AnalogBinding, BindingKind, BindingList, DigitalBinding, VectorBinding};
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
9pub struct BindingMap {
10    #[serde(flatten)]
11    map: HashMap<InternString, BindingList>,
12}
13
14pub enum BindingMapModificaitonError {
15    NotFound,
16    TypeMismatch,
17    BindingAlreadyExists,
18    BindingNotExists,
19}
20
21impl BindingMap {
22    pub fn new() -> Self {
23        return Self {
24            map: HashMap::new(),
25        };
26    }
27
28    pub fn load(s: &str) -> serde_json::Result<Self> {
29        return serde_json::from_str(s);
30    }
31
32    pub fn save(&self) -> String {
33        return serde_json::to_string(self).unwrap();
34    }
35
36    pub fn ensure_prototype(&mut self, prototype: &BindingMap) {
37        self.map.retain(|key, _| prototype.map.contains_key(key));
38
39        for (key, value) in &prototype.map {
40            if self.map.contains_key(key) {
41                continue;
42            }
43
44            self.map.insert(key.clone(), value.clone());
45        }
46    }
47
48    pub fn register_binding(&mut self, name: InternString, mut values: BindingList) {
49        match &mut values {
50            BindingList::Digital(list) => list.dedup(),
51            BindingList::Analog(list) => list.dedup(),
52            BindingList::Vector(list) => list.dedup(),
53        }
54
55        self.map.insert(name, values);
56    }
57
58    pub(crate) fn add_digital_binding(
59        &mut self,
60        name: InternString,
61        value: DigitalBinding,
62    ) -> Result<(), BindingMapModificaitonError> {
63        let Some(list) = self.map.get_mut(&name) else {
64            return Err(BindingMapModificaitonError::NotFound);
65        };
66
67        let BindingList::Digital(bindings) = list else {
68            return Err(BindingMapModificaitonError::TypeMismatch);
69        };
70
71        if bindings.contains(&value) {
72            return Err(BindingMapModificaitonError::BindingAlreadyExists);
73        }
74
75        bindings.push(value);
76
77        return Ok(());
78    }
79
80    pub(crate) fn remove_digital_binding(
81        &mut self,
82        name: InternString,
83        value: DigitalBinding,
84    ) -> Result<(), BindingMapModificaitonError> {
85        let Some(list) = self.map.get_mut(&name) else {
86            return Err(BindingMapModificaitonError::NotFound);
87        };
88
89        let BindingList::Digital(bindings) = list else {
90            return Err(BindingMapModificaitonError::TypeMismatch);
91        };
92
93        if !bindings.contains(&value) {
94            return Err(BindingMapModificaitonError::BindingNotExists);
95        }
96
97        bindings.retain(|it| *it != value);
98
99        return Ok(());
100    }
101
102    pub(crate) fn add_analog_binding(
103        &mut self,
104        name: InternString,
105        value: AnalogBinding,
106    ) -> Result<(), BindingMapModificaitonError> {
107        let Some(list) = self.map.get_mut(&name) else {
108            return Err(BindingMapModificaitonError::NotFound);
109        };
110
111        let BindingList::Analog(bindings) = list else {
112            return Err(BindingMapModificaitonError::TypeMismatch);
113        };
114
115        if bindings.contains(&value) {
116            return Err(BindingMapModificaitonError::BindingAlreadyExists);
117        }
118
119        bindings.push(value);
120
121        return Ok(());
122    }
123
124    pub(crate) fn remove_analog_binding(
125        &mut self,
126        name: InternString,
127        value: AnalogBinding,
128    ) -> Result<(), BindingMapModificaitonError> {
129        let Some(list) = self.map.get_mut(&name) else {
130            return Err(BindingMapModificaitonError::NotFound);
131        };
132
133        let BindingList::Analog(bindings) = list else {
134            return Err(BindingMapModificaitonError::TypeMismatch);
135        };
136
137        if !bindings.contains(&value) {
138            return Err(BindingMapModificaitonError::BindingNotExists);
139        }
140
141        bindings.retain(|it| *it != value);
142
143        return Ok(());
144    }
145
146    pub(crate) fn add_vector_binding(
147        &mut self,
148        name: InternString,
149        value: VectorBinding,
150    ) -> Result<(), BindingMapModificaitonError> {
151        let Some(list) = self.map.get_mut(&name) else {
152            return Err(BindingMapModificaitonError::NotFound);
153        };
154
155        let BindingList::Vector(bindings) = list else {
156            return Err(BindingMapModificaitonError::TypeMismatch);
157        };
158
159        if bindings.contains(&value) {
160            return Err(BindingMapModificaitonError::BindingAlreadyExists);
161        }
162
163        bindings.push(value);
164
165        return Ok(());
166    }
167
168    pub(crate) fn remove_vector_binding(
169        &mut self,
170        name: InternString,
171        value: VectorBinding,
172    ) -> Result<(), BindingMapModificaitonError> {
173        let Some(list) = self.map.get_mut(&name) else {
174            return Err(BindingMapModificaitonError::NotFound);
175        };
176
177        let BindingList::Vector(bindings) = list else {
178            return Err(BindingMapModificaitonError::TypeMismatch);
179        };
180
181        if !bindings.contains(&value) {
182            return Err(BindingMapModificaitonError::BindingNotExists);
183        }
184
185        bindings.retain(|it| *it != value);
186
187        return Ok(());
188    }
189
190    pub fn get_bindings(&self, name: &InternString) -> Option<&BindingList> {
191        return self.map.get(name);
192    }
193
194    pub fn get_binding_kind(&self, name: &InternString) -> Option<BindingKind> {
195        let bindings = self.get_bindings(name)?;
196
197        match bindings {
198            BindingList::Digital(_) => return Some(BindingKind::Digital),
199            BindingList::Analog(_) => return Some(BindingKind::Analog),
200            BindingList::Vector(_) => return Some(BindingKind::Vector),
201        };
202    }
203}
204
205impl IntoIterator for BindingMap {
206    fn into_iter(self) -> Self::IntoIter {
207        return self.map.into_iter();
208    }
209
210    type Item = (InternString, BindingList);
211
212    type IntoIter = <HashMap<InternString, BindingList> as IntoIterator>::IntoIter;
213}
214
215impl<'a> IntoIterator for &'a BindingMap {
216    fn into_iter(self) -> Self::IntoIter {
217        return <&'a HashMap<InternString, BindingList> as IntoIterator>::into_iter(&self.map);
218    }
219
220    type Item = (&'a InternString, &'a BindingList);
221
222    type IntoIter = <&'a HashMap<InternString, BindingList> as IntoIterator>::IntoIter;
223}