keebrs 0.3.0

Keyboard firmware building blocks
#[rustfmt::skip]
use alloc::vec;
use alloc::{
    string::String,
    vec::Vec,
};

use crate::vecmap::VecMap;

pub struct Locator {
    map: Vec<String>,

    // mapping of position in `map` to actual module position
    assignments: Vec<Option<i8>>,
    // mapping of actual module position to position in the map
    modules: VecMap<i8, u8>,
}

impl Locator {
    pub fn new<'a>(map: impl IntoIterator<Item = &'a str>) -> Self {
        let map: Vec<_> = map.into_iter().map(|s| (*s).into()).collect();
        let assignments = vec![None; map.len()];
        Locator {
            map,
            assignments,
            modules: Default::default(),
        }
    }

    pub fn add_module(&mut self, mut real_pos: i8, module_type: String) {
        // If there was another module here before and a new one is taking its place,
        // clear the old entry
        if let Some(prev) = self.modules.take(&real_pos) {
            self.assignments[prev as usize] = None;
        }
        let mut offset = 0;
        loop {
            if offset >= self.map.len() {
                return;
            }
            // Find the index of the first `module_type` in the map
            if let Some(pos) = self.map[offset..]
                .iter()
                .position(|t| t == &module_type)
                .map(|pos| pos + offset)
            {
                if let Some(current) = self.assignments[pos] {
                    // If there's already a module in that assignment, check to
                    // see if its absolute position is to the left of this one
                    if current > real_pos {
                        // if the new module is to the left of the existing one,
                        // replace it and find a new slot for the previous one.
                        self.assignments[pos] = Some(real_pos);
                        self.modules.take(&current);
                        self.modules.insert(real_pos, pos as u8);
                        real_pos = current;
                    }
                    offset = pos + 1;
                } else {
                    // If there's nothing there, set it to the new module
                    self.assignments[pos] = Some(real_pos);
                    self.modules.insert(real_pos, pos as u8);
                    return;
                }
            } else {
                // If there aren't any instances of `module_type`, don't assign
                // this one to anything
                return;
            }
        }
    }

    /// Find the "real" mapping for the given key
    ///
    /// If no module has been assigned for the key's `z` value, returns `None`
    pub fn remap(&self, addr: i8) -> Option<u8> {
        self.modules.get(&addr).map(Clone::clone)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn test_locator() {
        let mut locator = Locator::new(vec!["ortho5x7", "ortho5x7"]);
        locator.add_module(0, "ortho5x7".into());
        locator.add_module(-1, "ortho5x7".into());

        assert_eq!(Some(0), locator.remap(-1));
    }
}