use crate::value::Value;
#[derive(Debug, Default)]
pub struct OrderedMap {
entries: Vec<(String, Value)>,
}
impl OrderedMap {
pub fn new() -> Self {
OrderedMap {
entries: Vec::new(),
}
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn get(&self, key: &str) -> Option<&Value> {
self.entries.iter().find(|(k, _)| k == key).map(|(_, v)| v)
}
pub fn contains_key(&self, key: &str) -> bool {
self.entries.iter().any(|(k, _)| k == key)
}
pub fn insert(&mut self, key: String, value: Value) {
if let Some((_, slot)) = self.entries.iter_mut().find(|(k, _)| *k == key) {
*slot = value;
} else {
self.entries.push((key, value));
}
}
pub fn remove(&mut self, key: &str) -> Option<Value> {
let pos = self.entries.iter().position(|(k, _)| k == key)?;
Some(self.entries.remove(pos).1)
}
pub fn clear(&mut self) {
self.entries.clear();
}
pub fn iter(&self) -> impl Iterator<Item = &(String, Value)> {
self.entries.iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
use bigdecimal::ToPrimitive;
#[test]
fn insertion_order_is_preserved() {
let mut m = OrderedMap::new();
m.insert("b".to_string(), Value::int(1));
m.insert("a".to_string(), Value::int(2));
m.insert("c".to_string(), Value::int(3));
let keys: Vec<&str> = m.iter().map(|(k, _)| k.as_str()).collect();
assert_eq!(keys, ["b", "a", "c"]);
}
#[test]
fn reinsert_keeps_position_but_updates_value() {
let mut m = OrderedMap::new();
m.insert("x".to_string(), Value::int(1));
m.insert("y".to_string(), Value::int(2));
m.insert("x".to_string(), Value::int(9));
assert_eq!(m.len(), 2);
let entries: Vec<(&str, i64)> = m
.iter()
.map(|(k, v)| match v {
Value::Int(n) => (k.as_str(), n.to_i64().unwrap()),
_ => panic!("expected an Int"),
})
.collect();
assert_eq!(entries, [("x", 9), ("y", 2)]);
}
#[test]
fn remove_preserves_remaining_order() {
let mut m = OrderedMap::new();
m.insert("a".to_string(), Value::int(1));
m.insert("b".to_string(), Value::int(2));
m.insert("c".to_string(), Value::int(3));
assert!(m
.remove("b")
.is_some_and(|v| crate::values_equal(&v, &Value::int(2))));
assert!(m.remove("z").is_none());
let keys: Vec<&str> = m.iter().map(|(k, _)| k.as_str()).collect();
assert_eq!(keys, ["a", "c"]);
}
#[test]
fn get_and_contains_and_clear() {
let mut m = OrderedMap::new();
m.insert("k".to_string(), Value::str("v"));
assert!(m.contains_key("k"));
assert!(matches!(m.get("k"), Some(Value::Str(s)) if &**s == "v"));
assert!(m.get("nope").is_none());
m.clear();
assert!(m.is_empty());
}
}