pawkit_input/
binding_map.rs

1use std::{
2    collections::HashMap,
3    sync::{Arc, RwLock},
4};
5
6use pawkit_holy_array::HolyArray;
7use serde::{Deserialize, Serialize};
8use thiserror::Error;
9
10use crate::bindings::{
11    AnalogBinding, DefaultBinding, DefaultBindingType, DigitalBinding, VectorBinding,
12};
13
14#[repr(u8)]
15#[derive(Error, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
16pub enum BindingMapError {
17    #[error("The requested key already exists")]
18    KeyAlreadyExists,
19    #[error("Bindings updated while locked")]
20    BindingUpdateWhileLocked,
21    #[error("Binding map instantiated while unlocked")]
22    InstantiationWhileUnlocked,
23    #[error("Locking failed")]
24    LockIssue,
25}
26
27#[derive(Debug, Serialize, Deserialize)]
28#[serde(tag = "type", content = "bindings")]
29pub enum BindingList {
30    Digital(RwLock<Vec<DigitalBinding>>),
31    Analog(RwLock<Vec<AnalogBinding>>),
32    Vector(RwLock<Vec<VectorBinding>>),
33}
34
35impl Clone for BindingList {
36    fn clone(&self) -> Self {
37        match self {
38            Self::Digital(bindings) => Self::Digital(RwLock::new(bindings.read().unwrap().clone())),
39            Self::Analog(bindings) => Self::Analog(RwLock::new(bindings.read().unwrap().clone())),
40            Self::Vector(bindings) => Self::Vector(RwLock::new(bindings.read().unwrap().clone())),
41        }
42    }
43}
44
45pub struct DefaultBindingMap {
46    pub(crate) index: HashMap<String, usize>,
47    pub(crate) values: Vec<BindingList>,
48
49    /// Whether the default binding map is locked.
50    ///
51    /// When the binding map is locked, new defaults can't be added,
52    /// and instances can be created.
53    ///
54    /// Once it's locked, it cannot be unlocked.
55    pub(crate) locked: bool,
56
57    pub(crate) instances: RwLock<HolyArray<Arc<BindingMap>>>,
58}
59
60#[derive(Serialize, Deserialize)]
61pub struct BindingMapSerializer {
62    #[serde(flatten)]
63    values: HashMap<String, BindingList>,
64}
65
66impl DefaultBindingMap {
67    pub fn new() -> Self {
68        return Self {
69            index: HashMap::new(),
70            values: Vec::new(),
71            locked: false,
72            instances: RwLock::new(HolyArray::new()),
73        };
74    }
75
76    pub fn lock(&mut self) {
77        self.locked = true;
78    }
79
80    pub fn new_instance(&self) -> Result<usize, BindingMapError> {
81        if !self.locked {
82            return Err(BindingMapError::InstantiationWhileUnlocked);
83        }
84
85        let Ok(mut instances) = self.instances.write() else {
86            return Err(BindingMapError::LockIssue);
87        };
88
89        let index = instances.acquire(Arc::new(BindingMap {
90            values: self.values.clone().into_boxed_slice(),
91        }));
92
93        return Ok(index);
94    }
95
96    pub fn delete_instance(&self, id: usize) -> Result<(), BindingMapError> {
97        if !self.locked {
98            return Err(BindingMapError::InstantiationWhileUnlocked);
99        }
100
101        let Ok(mut instances) = self.instances.write() else {
102            return Err(BindingMapError::LockIssue);
103        };
104
105        instances.release(id);
106
107        return Ok(());
108    }
109
110    pub fn get_map(&self, index: usize) -> Option<Arc<BindingMap>> {
111        let instances = self.instances.read().ok()?;
112
113        return Some(instances.get(index)?.clone());
114    }
115
116    pub fn register_raw<'a>(
117        &mut self,
118        name: &str,
119        bindings: DefaultBindingType<'a>,
120    ) -> Result<(), BindingMapError> {
121        if self.locked {
122            return Err(BindingMapError::BindingUpdateWhileLocked);
123        }
124
125        if self.index.contains_key(name) {
126            return Err(BindingMapError::KeyAlreadyExists);
127        }
128
129        let binding_list = match bindings {
130            DefaultBindingType::Analog(analog) => BindingList::Analog(RwLock::new(analog.to_vec())),
131            DefaultBindingType::Digital(digital) => {
132                BindingList::Digital(RwLock::new(digital.to_vec()))
133            }
134            DefaultBindingType::Vector(vector) => BindingList::Vector(RwLock::new(vector.to_vec())),
135        };
136
137        let index = self.values.len();
138
139        self.index.insert(name.into(), index);
140
141        self.values.push(binding_list);
142
143        return Ok(());
144    }
145
146    pub fn register_digital(
147        &mut self,
148        name: &str,
149        bindings: &[DigitalBinding],
150    ) -> Result<(), BindingMapError> {
151        return self.register_raw(name, DefaultBindingType::Digital(bindings));
152    }
153
154    pub fn register_analog(
155        &mut self,
156        name: &str,
157        bindings: &[AnalogBinding],
158    ) -> Result<(), BindingMapError> {
159        return self.register_raw(name, DefaultBindingType::Analog(bindings));
160    }
161
162    pub fn register_vector(
163        &mut self,
164        name: &str,
165        bindings: &[VectorBinding],
166    ) -> Result<(), BindingMapError> {
167        return self.register_raw(name, DefaultBindingType::Vector(bindings));
168    }
169
170    pub fn register(&mut self, bindings: DefaultBinding) -> Result<(), BindingMapError> {
171        return self.register_raw(bindings.name, bindings.bindings);
172    }
173}
174
175pub struct BindingMap {
176    /// Using a boxed slice, since the size will never change.
177    pub(crate) values: Box<[BindingList]>,
178}
179
180impl BindingMap {
181    pub fn deserialize(&mut self, index: &HashMap<String, usize>, serial: BindingMapSerializer) {
182        for (name, bindings) in serial.values {
183            if let Some(slot) = self.get_binding(index, &name) {
184                match slot {
185                    BindingList::Analog(slot) => {
186                        let BindingList::Analog(bindings) = bindings else {
187                            return;
188                        };
189
190                        let Ok(mut slot) = slot.write() else {
191                            return;
192                        };
193
194                        let Ok(bindings) = bindings.read() else {
195                            return;
196                        };
197
198                        *slot = bindings.clone();
199                    }
200
201                    BindingList::Digital(slot) => {
202                        let BindingList::Digital(bindings) = bindings else {
203                            return;
204                        };
205
206                        let Ok(mut slot) = slot.write() else {
207                            return;
208                        };
209
210                        let Ok(bindings) = bindings.read() else {
211                            return;
212                        };
213
214                        *slot = bindings.clone();
215                    }
216
217                    BindingList::Vector(slot) => {
218                        let BindingList::Vector(bindings) = bindings else {
219                            return;
220                        };
221
222                        let Ok(mut slot) = slot.write() else {
223                            return;
224                        };
225
226                        let Ok(bindings) = bindings.read() else {
227                            return;
228                        };
229
230                        *slot = bindings.clone();
231                    }
232                }
233            }
234        }
235    }
236
237    pub fn serialize(&self, index: &HashMap<String, usize>) -> BindingMapSerializer {
238        let mut serial = BindingMapSerializer {
239            values: HashMap::new(),
240        };
241
242        for (name, index) in index {
243            serial
244                .values
245                .insert(name.clone(), self.values[*index].clone());
246        }
247
248        return serial;
249    }
250
251    pub fn get_binding(&self, index: &HashMap<String, usize>, name: &str) -> Option<&BindingList> {
252        let index = *index.get(name)?;
253
254        return Some(&self.values[index]);
255    }
256}