Skip to main content

token_value_map/
token_value_map.rs

1use crate::*;
2use std::{
3    collections::HashMap,
4    hash::{Hash, Hasher},
5};
6
7/// A collection of named values indexed by string tokens.
8///
9/// [`TokenValueMap`] `struct` stores a mapping from string tokens to [`Value`]
10/// instances, allowing efficient lookup of named parameters or attributes by
11/// token.
12#[derive(Clone, Debug, Default, PartialEq)]
13#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
14#[cfg_attr(feature = "facet", derive(Facet))]
15#[cfg_attr(feature = "facet", facet(opaque))]
16#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
17pub struct TokenValueMap {
18    attributes: HashMap<Token, Value>,
19}
20
21impl Hash for TokenValueMap {
22    fn hash<H: Hasher>(&self, state: &mut H) {
23        self.attributes.len().hash(state);
24        // Note: HashMap iteration order is not deterministic,
25        // so we need to sort for consistent hashing
26        let mut items: Vec<_> = self.attributes.iter().collect();
27        items.sort_by_key(|(k, _)| *k);
28        for (token, value) in items {
29            token.hash(state);
30            value.hash(state);
31        }
32    }
33}
34
35impl TokenValueMap {
36    pub fn new() -> Self {
37        Self::default()
38    }
39
40    pub fn with_capacity(capacity: usize) -> Self {
41        Self {
42            attributes: HashMap::with_capacity(capacity),
43        }
44    }
45
46    pub fn insert<V: Into<Value>>(&mut self, token: impl Into<Token>, value: V) {
47        self.attributes.insert(token.into(), value.into());
48    }
49
50    pub fn get(&self, token: &Token) -> Option<&Value> {
51        self.attributes.get(token)
52    }
53
54    pub fn get_mut(&mut self, token: &Token) -> Option<&mut Value> {
55        self.attributes.get_mut(token)
56    }
57
58    pub fn remove(&mut self, token: &Token) -> Option<Value> {
59        self.attributes.remove(token)
60    }
61
62    pub fn contains(&self, token: &Token) -> bool {
63        self.attributes.contains_key(token)
64    }
65
66    pub fn len(&self) -> usize {
67        self.attributes.len()
68    }
69
70    pub fn is_empty(&self) -> bool {
71        self.attributes.is_empty()
72    }
73
74    pub fn clear(&mut self) {
75        self.attributes.clear();
76    }
77
78    pub fn iter(&self) -> impl Iterator<Item = (&Token, &Value)> {
79        self.attributes.iter()
80    }
81
82    pub fn iter_mut(&mut self) -> impl Iterator<Item = (&Token, &mut Value)> {
83        self.attributes.iter_mut()
84    }
85
86    pub fn tokens(&self) -> impl Iterator<Item = &Token> {
87        self.attributes.keys()
88    }
89
90    pub fn values(&self) -> impl Iterator<Item = &Value> {
91        self.attributes.values()
92    }
93
94    pub fn values_mut(&mut self) -> impl Iterator<Item = &mut Value> {
95        self.attributes.values_mut()
96    }
97
98    pub fn extend<I>(&mut self, iter: I)
99    where
100        I: IntoIterator<Item = (Token, Value)>,
101    {
102        self.attributes.extend(iter);
103    }
104
105    pub fn retain<F>(&mut self, mut f: F)
106    where
107        F: FnMut(&Token, &Value) -> bool,
108    {
109        self.attributes.retain(|k, v| f(k, v));
110    }
111}
112
113// Manual Eq implementation for TokenValueMap
114// This is safe because we handle floating point comparison deterministically
115impl Eq for TokenValueMap {}
116
117impl FromIterator<(Token, Value)> for TokenValueMap {
118    fn from_iter<T: IntoIterator<Item = (Token, Value)>>(iter: T) -> Self {
119        Self {
120            attributes: HashMap::from_iter(iter),
121        }
122    }
123}
124
125impl<const N: usize> From<[(Token, Value); N]> for TokenValueMap {
126    fn from(arr: [(Token, Value); N]) -> Self {
127        Self {
128            attributes: HashMap::from(arr),
129        }
130    }
131}