Skip to main content

eure_document/
map.rs

1use indexmap::IndexMap;
2
3use crate::{prelude_internal::*, value::PartialObjectKey};
4
5#[derive(Debug, Clone, Plural)]
6#[plural(len, is_empty, iter, into_iter, into_iter_ref, new)]
7pub struct Map<K, V>(IndexMap<K, V>);
8
9impl<K: Eq + std::hash::Hash, V: Eq> Eq for Map<K, V> {}
10impl<K: Eq + std::hash::Hash, V: PartialEq> PartialEq for Map<K, V> {
11    fn eq(&self, other: &Self) -> bool {
12        self.0 == other.0
13    }
14}
15
16impl<K: Eq + std::hash::Hash, V> FromIterator<(K, V)> for Map<K, V> {
17    fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
18        Self(IndexMap::from_iter(iter))
19    }
20}
21
22impl<K, V> Default for Map<K, V> {
23    fn default() -> Self {
24        Self(IndexMap::new())
25    }
26}
27
28impl<K: std::hash::Hash + Eq, V> Map<K, V> {
29    pub fn get(&self, key: &K) -> Option<&V> {
30        self.0.get(key)
31    }
32
33    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
34        self.0.insert(key, value)
35    }
36
37    /// O(1) removal, may reorder remaining keys.
38    /// Use when order doesn't matter (e.g., batch processing).
39    pub fn remove_fast(&mut self, key: &K) -> Option<V> {
40        self.0.swap_remove(key)
41    }
42
43    /// O(n) removal, preserves document order.
44    /// Use when order must be maintained.
45    pub fn remove_ordered(&mut self, key: &K) -> Option<V> {
46        self.0.shift_remove(key)
47    }
48
49    pub fn contains_key(&self, key: &K) -> bool {
50        self.0.contains_key(key)
51    }
52}
53
54impl Map<ObjectKey, NodeId> {
55    pub fn add(&mut self, key: ObjectKey, value: NodeId) -> Result<(), InsertErrorKind> {
56        match self.0.entry(key) {
57            indexmap::map::Entry::Occupied(e) => Err(InsertErrorKind::AlreadyAssigned {
58                key: e.key().clone(),
59            }),
60            indexmap::map::Entry::Vacant(e) => {
61                e.insert(value);
62                Ok(())
63            }
64        }
65    }
66
67    pub fn get_node_id(&self, key: &ObjectKey) -> Option<NodeId> {
68        self.0.get(key).copied()
69    }
70}
71
72/// A map whose keys may contain holes (unresolved placeholders).
73///
74/// Backed by a `Vec` rather than `IndexMap` because hole keys are not
75/// unconditionally deduplicated: anonymous holes (`!`) always create new
76/// entries. Labeled holes (`!label`) and resolved keys are deduplicated
77/// by value on lookup, matching the behavior of regular `Map`.
78///
79/// Use [`PartialMap::find`] to look up an existing entry before inserting.
80#[derive(Debug, Clone, Default)]
81pub struct PartialMap<V>(Vec<(PartialObjectKey, V)>);
82
83pub type PartialNodeMap = PartialMap<NodeId>;
84
85impl<V: PartialEq> PartialEq for PartialMap<V> {
86    fn eq(&self, other: &Self) -> bool {
87        self.0 == other.0
88    }
89}
90
91impl<V> PartialMap<V> {
92    pub fn new() -> Self {
93        Self(Vec::new())
94    }
95
96    /// Append a (key, value) pair unconditionally.
97    /// Callers should call [`Self::find`] first to avoid duplicate labeled entries.
98    pub fn push(&mut self, key: PartialObjectKey, value: V) {
99        self.0.push((key, value));
100    }
101
102    /// Find the first entry matching `key`.
103    ///
104    /// Keys containing anonymous holes never match — they are always unique.
105    pub fn find(&self, key: &PartialObjectKey) -> Option<&V> {
106        if key.contains_anonymous_hole() {
107            return None;
108        }
109        self.0.iter().find(|(k, _)| k == key).map(|(_, v)| v)
110    }
111
112    pub fn iter(&self) -> impl Iterator<Item = (&PartialObjectKey, &V)> {
113        self.0.iter().map(|(k, v)| (k, v))
114    }
115
116    pub fn len(&self) -> usize {
117        self.0.len()
118    }
119
120    pub fn is_empty(&self) -> bool {
121        self.0.is_empty()
122    }
123}