petr_utils/
index_map.rs

1use std::marker::PhantomData;
2
3pub struct IndexMap<K, V> {
4    _key:    PhantomData<K>,
5    entries: Vec<V>,
6}
7
8impl<K, V> std::fmt::Debug for IndexMap<K, V>
9where
10    V: std::fmt::Debug,
11{
12    fn fmt(
13        &self,
14        f: &mut std::fmt::Formatter<'_>,
15    ) -> std::fmt::Result {
16        {
17            f.debug_struct("IndexMap").field("entries", &self.entries).finish()
18        }
19    }
20}
21
22impl<K, V> Clone for IndexMap<K, V>
23where
24    K: Clone,
25    V: Clone,
26{
27    fn clone(&self) -> Self {
28        IndexMap {
29            _key:    self._key,
30            entries: self.entries.clone(),
31        }
32    }
33}
34
35impl<K, V> IndexMap<K, V> {
36    pub fn len(&self) -> usize {
37        self.entries.len()
38    }
39
40    pub fn is_empty(&self) -> bool {
41        self.entries.is_empty()
42    }
43}
44
45impl<K, V> Default for IndexMap<K, V>
46where
47    K: From<usize> + Into<usize>,
48{
49    fn default() -> Self {
50        Self {
51            entries: Default::default(),
52            _key:    PhantomData,
53        }
54    }
55}
56
57impl<K, V> IndexMap<K, V>
58where
59    K: From<usize> + Into<usize>,
60{
61    pub fn iter(&self) -> impl Iterator<Item = (K, &V)> {
62        self.entries.iter().enumerate().map(|(k, v)| (K::from(k), v))
63    }
64
65    pub fn insert(
66        &mut self,
67        value: V,
68    ) -> K {
69        let key = self.entries.len();
70        self.entries.push(value);
71        key.into()
72    }
73
74    pub fn get(
75        &self,
76        k: K,
77    ) -> &V {
78        &self.entries[k.into()]
79    }
80
81    pub fn get_mut(
82        &mut self,
83        k: K,
84    ) -> &mut V {
85        self.entries
86            .get_mut(k.into())
87            .expect("IDs are handed out by insertion, so this should never fail")
88    }
89
90    // converting this into an IntoIter trait is kind of a pain in the butt...but should be done
91    // eventually.
92    // see https://github.com/sezna/petr/issues/39
93    #[allow(clippy::should_implement_trait)]
94    pub fn into_iter(self) -> impl Iterator<Item = (K, V)> {
95        self.entries.into_iter().enumerate().map(|(i, v)| (i.into(), v))
96    }
97}
98
99impl<K, V> IndexMap<K, V>
100where
101    K: From<usize>,
102    V: PartialEq,
103{
104    pub fn contains_value(
105        &self,
106        value: V,
107    ) -> Option<K> {
108        self.entries.iter().position(|v| *v == value).map(Into::into)
109    }
110}
111
112#[macro_export]
113macro_rules! idx_map_key {
114    ($(#[$attr:meta])*
115        $name:ident) => {
116        #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
117        $(#[$attr])*
118        pub struct $name(usize);
119
120        impl From<usize> for $name {
121            fn from(value: usize) -> Self {
122                Self(value)
123            }
124        }
125
126        impl From<$name> for usize {
127            fn from(value: $name) -> usize {
128                value.0
129            }
130        }
131
132        impl std::fmt::Display for $name {
133            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
134                write!(f, "{}{}", stringify!($name).to_lowercase(), self.0)
135            }
136        }
137    };
138}