1use std::{
2 cmp,
3 collections::{BinaryHeap, HashMap},
4 fmt,
5};
6
7use serde::{Deserialize, Serialize};
8use thiserror::Error;
9
10#[derive(Debug, Clone, Copy, Error)]
11#[error("Identifier {0} is not short")]
12pub struct NonShortId(pub Id);
13
14#[derive(Debug, Clone, Copy, Error)]
15#[error("Identifier {0} is not tiny")]
16pub struct NonTinyId(pub Id);
17
18#[derive(Debug, Clone, Copy, Error)]
19#[error("Invalid identifier {0}")]
20pub struct InvalidId(pub Id);
21
22#[derive(Debug, Clone, Copy, Error)]
23#[error("Invalid index {index} out of length {len}")]
24pub struct InvalidIndex {
25 pub index: usize,
26 pub len: usize,
27}
28
29#[derive(Debug, Clone, Copy, Error)]
30pub enum InvalidIndexAs<E> {
31 #[error(transparent)]
32 OutOfBounds(#[from] InvalidIndex),
33 #[error("id is not convertible")]
34 IdConversion(#[source] E),
35}
36
37#[derive(
38 Debug,
39 Clone,
40 Copy,
41 PartialEq,
42 Eq,
43 PartialOrd,
44 Ord,
45 Hash,
46 Default,
47 Serialize,
48 Deserialize,
49)]
50#[serde(transparent)]
51pub struct Id(u32);
52
53impl fmt::Display for Id {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 write!(f, "{}", self.0)
56 }
57}
58
59impl From<ShortId> for Id {
60 fn from(id: ShortId) -> Self {
61 Self(id.0.into())
62 }
63}
64
65impl From<TinyId> for Id {
66 fn from(id: TinyId) -> Self {
67 Self(id.0.into())
68 }
69}
70
71#[derive(
72 Debug,
73 Clone,
74 Copy,
75 PartialEq,
76 Eq,
77 PartialOrd,
78 Ord,
79 Hash,
80 Default,
81 Serialize,
82 Deserialize,
83)]
84#[serde(transparent)]
85pub struct ShortId(u16);
86
87impl fmt::Display for ShortId {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 write!(f, "{}", self.0)
90 }
91}
92
93impl From<TinyId> for ShortId {
94 fn from(id: TinyId) -> Self {
95 Self(id.0.into())
96 }
97}
98
99impl TryFrom<Id> for ShortId {
100 type Error = NonShortId;
101
102 fn try_from(id: Id) -> Result<Self, Self::Error> {
103 match id.0.try_into() {
104 Ok(bits) => Ok(Self(bits)),
105 Err(_) => Err(NonShortId(id)),
106 }
107 }
108}
109
110#[derive(
111 Debug,
112 Clone,
113 Copy,
114 PartialEq,
115 Eq,
116 PartialOrd,
117 Ord,
118 Hash,
119 Default,
120 Serialize,
121 Deserialize,
122)]
123#[serde(transparent)]
124pub struct TinyId(u8);
125
126impl TryFrom<Id> for TinyId {
127 type Error = NonTinyId;
128
129 fn try_from(id: Id) -> Result<Self, Self::Error> {
130 match id.0.try_into() {
131 Ok(bits) => Ok(Self(bits)),
132 Err(_) => Err(NonTinyId(id)),
133 }
134 }
135}
136
137impl TryFrom<ShortId> for TinyId {
138 type Error = NonTinyId;
139
140 fn try_from(id: ShortId) -> Result<Self, Self::Error> {
141 match id.0.try_into() {
142 Ok(bits) => Ok(Self(bits)),
143 Err(_) => Err(NonTinyId(id.into())),
144 }
145 }
146}
147
148impl fmt::Display for TinyId {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 write!(f, "{}", self.0)
151 }
152}
153
154#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct Registry<T> {
156 primary: Vec<(Id, T)>,
157 secondary_pos: HashMap<Id, usize>,
158 secondary_neg: BinaryHeap<cmp::Reverse<Id>>,
159}
160
161impl<T> Registry<T> {
162 pub fn new() -> Self {
163 Self {
164 primary: Vec::new(),
165 secondary_pos: HashMap::new(),
166 secondary_neg: BinaryHeap::new(),
167 }
168 }
169
170 pub fn len(&self) -> usize {
171 self.primary.len()
172 }
173
174 pub fn create(&mut self, data: T) -> Id {
175 let id = self.pop_secondary_neg();
176 self.create_with_id(data, id);
177 id
178 }
179
180 pub fn create_as<I, E>(&mut self, data: T) -> Result<I, E>
181 where
182 Id: TryInto<I, Error = E>,
183 {
184 let id = self.pop_secondary_neg();
185 match id.try_into() {
186 Ok(converted_id) => {
187 self.create_with_id(data, id);
188 Ok(converted_id)
189 },
190 Err(error) => {
191 self.push_secondary_neg(id);
192 Err(error)
193 },
194 }
195 }
196
197 pub fn remove(&mut self, id: impl Into<Id>) -> Result<T, InvalidId> {
198 let id = id.into();
199 let index =
200 self.secondary_pos.get(&id).copied().ok_or(InvalidId(id))?;
201 let last_index = self.primary.len() - 1;
202 if index != last_index {
203 self.primary.swap(index, last_index);
204 let (id, _) = self.primary[index];
205 self.secondary_pos.insert(id, index);
206 }
207 let (_, item) = self.primary.pop().expect("inconsistent tables");
208 self.push_secondary_neg(id);
209 Ok(item)
210 }
211
212 pub fn id_to_index(&self, id: impl Into<Id>) -> Result<usize, InvalidId> {
213 let id = id.into();
214 self.secondary_pos.get(&id).copied().ok_or(InvalidId(id))
215 }
216
217 pub fn get_by_id(&self, id: impl Into<Id>) -> Result<&T, InvalidId> {
218 let index = self.id_to_index(id)?;
219 Ok(&self.primary[index].1)
220 }
221
222 pub fn get_by_id_mut(
223 &mut self,
224 id: impl Into<Id>,
225 ) -> Result<&mut T, InvalidId> {
226 let index = self.id_to_index(id)?;
227 Ok(&mut self.primary[index].1)
228 }
229
230 pub fn get_by_index(&self, index: usize) -> Result<(Id, &T), InvalidIndex> {
231 let error = InvalidIndex { index, len: self.primary.len() };
232 let (id, value) = self.primary.get(index).ok_or(error)?;
233 Ok((*id, value))
234 }
235
236 pub fn get_by_index_mut(
237 &mut self,
238 index: usize,
239 ) -> Result<(Id, &mut T), InvalidIndex> {
240 let error = InvalidIndex { index, len: self.primary.len() };
241 let (id, value) = self.primary.get_mut(index).ok_or(error)?;
242 Ok((*id, value))
243 }
244
245 pub fn get_by_index_as<I, E>(
246 &self,
247 index: usize,
248 ) -> Result<(I, &T), InvalidIndexAs<E>>
249 where
250 Id: TryInto<I, Error = E>,
251 {
252 let (id, data) = self.get_by_index(index)?;
253 let converted_id =
254 id.try_into().map_err(InvalidIndexAs::IdConversion)?;
255 Ok((converted_id, data))
256 }
257
258 pub fn get_by_index_mut_as<I, E>(
259 &mut self,
260 index: usize,
261 ) -> Result<(I, &mut T), InvalidIndexAs<E>>
262 where
263 Id: TryInto<I, Error = E>,
264 {
265 let (id, data) = self.get_by_index_mut(index)?;
266 let converted_id =
267 id.try_into().map_err(InvalidIndexAs::IdConversion)?;
268 Ok((converted_id, data))
269 }
270
271 pub fn iter<'a>(
272 &'a self,
273 ) -> impl DoubleEndedIterator<Item = (Id, &'a T)> + 'a + Send + Sync
274 where
275 T: Send + Sync,
276 {
277 self.primary.iter().map(|(id, elem)| (*id, elem))
278 }
279
280 pub fn iter_mut<'a>(
281 &'a mut self,
282 ) -> impl DoubleEndedIterator<Item = (Id, &'a mut T)> + 'a + Send + Sync
283 where
284 T: Send + Sync,
285 {
286 self.primary.iter_mut().map(|(id, elem)| (*id, elem))
287 }
288
289 pub fn into_iter<'a>(
290 self,
291 ) -> impl DoubleEndedIterator<Item = (Id, T)> + 'a + Send + Sync
292 where
293 T: Send + Sync + 'a,
294 {
295 self.primary.into_iter().map(|(id, elem)| (id, elem))
296 }
297
298 fn create_with_id(&mut self, data: T, id: Id) {
299 let index = self.primary.len();
300 self.primary.push((id, data));
301 self.secondary_pos.insert(id, index);
302 }
303
304 fn pop_secondary_neg(&mut self) -> Id {
305 match self.secondary_neg.pop() {
306 Some(cmp::Reverse(id)) => id,
307 None => Id(self.len().try_into().expect("too much ids")),
308 }
309 }
310
311 fn push_secondary_neg(&mut self, id: Id) {
312 self.secondary_neg.push(cmp::Reverse(id));
313 }
314}