NameVec support
This commit is contained in:
parent
4fa03f2891
commit
9c1709e134
|
@ -3,9 +3,10 @@
|
|||
|
||||
use console::Style;
|
||||
|
||||
pub mod symbols;
|
||||
pub mod lexer;
|
||||
pub mod namevec;
|
||||
pub mod parse;
|
||||
pub mod symbols;
|
||||
|
||||
use lexer::Token;
|
||||
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright (c) 2022 Marceline Cramer
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub trait Named {
|
||||
fn name<'a>(&'a self) -> &'a str;
|
||||
}
|
||||
|
||||
impl Named for String {
|
||||
fn name<'a>(&'a self) -> &'a str {
|
||||
use std::borrow::Borrow;
|
||||
self.borrow()
|
||||
}
|
||||
}
|
||||
|
||||
impl Named for &str {
|
||||
fn name<'a>(&'a self) -> &'a str {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct DuplicationError<T> {
|
||||
pub original_index: usize,
|
||||
pub original_key: String,
|
||||
pub new_index: usize,
|
||||
pub new_val: T,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct NameVec<T: Named> {
|
||||
pub vals: Vec<T>,
|
||||
pub keys: HashMap<String, usize>,
|
||||
}
|
||||
|
||||
impl<T: Named> NameVec<T> {
|
||||
pub fn push(&mut self, val: T) -> Result<usize, usize> {
|
||||
let name = val.name();
|
||||
if let Some(old_index) = self.keys.get(name) {
|
||||
Err(*old_index)
|
||||
} else {
|
||||
let new_index = self.vals.len();
|
||||
self.keys.insert(name.to_string(), new_index);
|
||||
self.vals.push(val);
|
||||
Ok(new_index)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains(&self, name: &str) -> bool {
|
||||
self.keys.contains_key(name)
|
||||
}
|
||||
|
||||
pub fn get(&self, name: &str) -> Option<&T> {
|
||||
if let Some(idx) = self.get_idx(name) {
|
||||
self.vals.get(idx)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_idx(&self, name: &str) -> Option<usize> {
|
||||
self.keys.get(name).map(|x| *x)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO implement and write unit tests!
|
||||
// impl<T: Named> FromIterator<T> for Result<NameVec<T>, DuplicationError<T>> {}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn basic_usage() {
|
||||
let mut nv = NameVec::default();
|
||||
assert_eq!(Ok(0), nv.push("val0"));
|
||||
assert_eq!(Ok(1), nv.push("val1"));
|
||||
assert_eq!(Ok(2), nv.push("val2"));
|
||||
|
||||
assert_eq!(true, nv.contains("val0"));
|
||||
assert_eq!(false, nv.contains("not in set"));
|
||||
|
||||
assert_eq!(Some(&"val0"), nv.get("val0"));
|
||||
assert_eq!(Some(&"val2"), nv.get("val2"));
|
||||
assert_eq!(None, nv.get("val3"));
|
||||
|
||||
assert_eq!(Some(1), nv.get_idx("val1"));
|
||||
assert_eq!(None, nv.get_idx("val4"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deduplicate() {
|
||||
let mut nv = NameVec::default();
|
||||
assert_eq!(Ok(0), nv.push("original"));
|
||||
assert_eq!(Ok(1), nv.push("next"));
|
||||
assert_eq!(Err(0), nv.push("original"));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue