Skip to main content

gen_map/
error.rs

1use core::fmt;
2
3/// Why a [`GenMap`](crate::GenMap) has no room for another value.
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub enum FullError<S> {
6    /// The map has a slot at every index it can use and none of them are
7    /// free. A map uses every index its keys can hold, except the largest
8    /// value of the index type.
9    IndexExhausted,
10
11    /// None of the slots are free and the storage could not make room for
12    /// another one. The field says why, which for a `Vec` is its
13    /// `TryReserveError`.
14    StorageFull(S),
15}
16
17impl<S> FullError<S> {
18    /// Returns the same error with the storage's reason borrowed instead of
19    /// owned.
20    #[inline]
21    pub fn as_ref(&self) -> FullError<&S> {
22        match self {
23            Self::IndexExhausted => FullError::IndexExhausted,
24            Self::StorageFull(error) => FullError::StorageFull(error),
25        }
26    }
27}
28
29impl<S: fmt::Display> fmt::Display for FullError<S> {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        match self {
32            Self::IndexExhausted => f.write_str("the keys cannot address another slot"),
33            Self::StorageFull(error) => {
34                write!(f, "the storage cannot make room for another slot: {error}")
35            }
36        }
37    }
38}
39
40/// Why [`GenMap::try_insert`](crate::GenMap::try_insert) could not insert.
41/// Each variant hands the value back so that the caller can keep it. `S` is
42/// the map's [`StorageError`](crate::StorageError).
43///
44/// When the keys have no index left for a new slot and the storage is also
45/// full, the error is [`IndexExhausted`](Self::IndexExhausted).
46pub enum InsertError<T, S> {
47    /// The map has a slot at every index it can use and none of them are
48    /// free. A map uses every index its keys can hold, except the largest
49    /// value of the index type.
50    IndexExhausted(T),
51
52    /// None of the slots are free and the storage could not make room for
53    /// another one. The second field says why.
54    StorageFull(T, S),
55}
56
57impl<T, S> InsertError<T, S> {
58    /// Takes the value back out of the error.
59    #[inline]
60    pub fn into_inner(self) -> T {
61        match self {
62            Self::IndexExhausted(value) | Self::StorageFull(value, _) => value,
63        }
64    }
65
66    /// The reason the insert failed, without the value.
67    #[inline]
68    pub fn kind(&self) -> FullError<&S> {
69        match self {
70            Self::IndexExhausted(_) => FullError::IndexExhausted,
71            Self::StorageFull(_, error) => FullError::StorageFull(error),
72        }
73    }
74
75    /// Splits the error into its reason and the value.
76    #[inline]
77    pub fn into_parts(self) -> (FullError<S>, T) {
78        match self {
79            Self::IndexExhausted(value) => (FullError::IndexExhausted, value),
80            Self::StorageFull(value, error) => (FullError::StorageFull(error), value),
81        }
82    }
83}
84
85// This impl is written by hand so that it does not require `T: Debug`.
86impl<T, S: fmt::Debug> fmt::Debug for InsertError<T, S> {
87    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        match self {
89            Self::IndexExhausted(_) => f.write_str("IndexExhausted(..)"),
90            Self::StorageFull(_, error) => write!(f, "StorageFull(.., {error:?})"),
91        }
92    }
93}
94
95impl<T, S: fmt::Display> fmt::Display for InsertError<T, S> {
96    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97        fmt::Display::fmt(&self.kind(), f)
98    }
99}
100
101/// Why [`SecondaryMap::insert`](crate::SecondaryMap::insert) could not
102/// insert. Each variant hands the value back so that the caller can keep it.
103/// `S` is the map's [`SecondaryStorageError`](crate::SecondaryStorageError).
104pub enum SecondaryInsertError<T, S> {
105    /// The slot at the key's index holds a value that was inserted under a
106    /// different generation, and the config's
107    /// [`ReplaceStrategy`](crate::ReplaceStrategy) kept that value.
108    Refused(T),
109
110    /// The key's index is the largest value of the index type. No map gives
111    /// a slot that index, so only a hand-built key can have it.
112    IndexReserved(T),
113
114    /// The storage could not make room for a slot at the key's index. The
115    /// second field says why.
116    StorageFull(T, S),
117}
118
119impl<T, S> SecondaryInsertError<T, S> {
120    /// Takes the value back out of the error.
121    #[inline]
122    pub fn into_inner(self) -> T {
123        match self {
124            Self::Refused(value) | Self::IndexReserved(value) | Self::StorageFull(value, _) => {
125                value
126            }
127        }
128    }
129}
130
131// This impl is written by hand so that it does not require `T: Debug`.
132impl<T, S: fmt::Debug> fmt::Debug for SecondaryInsertError<T, S> {
133    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134        match self {
135            Self::Refused(_) => f.write_str("Refused(..)"),
136            Self::IndexReserved(_) => f.write_str("IndexReserved(..)"),
137            Self::StorageFull(_, error) => write!(f, "StorageFull(.., {error:?})"),
138        }
139    }
140}
141
142impl<T, S: fmt::Display> fmt::Display for SecondaryInsertError<T, S> {
143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144        match self {
145            Self::Refused(_) => f.write_str(
146                "the slot holds a value from a different generation, and the replace strategy kept it",
147            ),
148            Self::IndexReserved(_) => f.write_str(
149                "the key's index is the largest value of the index type, which no slot ever has",
150            ),
151            Self::StorageFull(_, error) => {
152                write!(f, "the storage cannot make room for the slot: {error}")
153            }
154        }
155    }
156}
157
158/// Why [`GenMap::try_insert_with_key`](crate::GenMap::try_insert_with_key)
159/// could not insert. The map can be full before the closure runs, or the
160/// closure can refuse to make a value, and the variant says which of the two
161/// happened. `E` is the closure's error and `S` is the map's
162/// [`StorageError`](crate::StorageError).
163#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
164pub enum InsertWithError<E, S> {
165    /// The map had no room, so the closure was never called.
166    Full(FullError<S>),
167
168    /// The closure returned this error, so nothing was inserted.
169    Rejected(E),
170}
171
172impl<E, S> InsertWithError<E, S> {
173    /// Converts the error into `E`, using `E`'s `From<FullError<S>>` impl
174    /// for a full map, so that a caller with its own error type gets that
175    /// type back.
176    ///
177    /// # Examples
178    ///
179    /// ```
180    /// use gen_map::{FullError, GenMap};
181    /// use std::collections::TryReserveError;
182    ///
183    /// #[derive(Debug)]
184    /// enum MyError {
185    ///     Full(FullError<TryReserveError>),
186    ///     Parse,
187    /// }
188    ///
189    /// impl From<FullError<TryReserveError>> for MyError {
190    ///     fn from(e: FullError<TryReserveError>) -> Self {
191    ///         MyError::Full(e)
192    ///     }
193    /// }
194    ///
195    /// fn add(map: &mut GenMap<u32>, text: &str) -> Result<(), MyError> {
196    ///     map.try_insert_with_key(|_| text.parse().map_err(|_| MyError::Parse))
197    ///         .map_err(|e| e.flatten())?;
198    ///     Ok(())
199    /// }
200    ///
201    /// let mut map = GenMap::new();
202    /// assert!(add(&mut map, "7").is_ok());
203    /// assert!(matches!(add(&mut map, "x"), Err(MyError::Parse)));
204    /// ```
205    #[inline]
206    pub fn flatten(self) -> E
207    where
208        E: From<FullError<S>>,
209    {
210        match self {
211            Self::Full(full) => E::from(full),
212            Self::Rejected(error) => error,
213        }
214    }
215
216    /// Returns the closure's error, or `None` if the map was full.
217    #[inline]
218    pub fn rejected(self) -> Option<E> {
219        match self {
220            Self::Rejected(error) => Some(error),
221            Self::Full(_) => None,
222        }
223    }
224
225    /// Returns `true` if the map was full.
226    #[inline]
227    pub fn is_full(&self) -> bool {
228        matches!(self, Self::Full(_))
229    }
230}
231
232impl<E, S> From<FullError<S>> for InsertWithError<E, S> {
233    #[inline]
234    fn from(full: FullError<S>) -> Self {
235        Self::Full(full)
236    }
237}
238
239impl<E: fmt::Display, S: fmt::Display> fmt::Display for InsertWithError<E, S> {
240    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241        match self {
242            Self::Full(full) => fmt::Display::fmt(full, f),
243            Self::Rejected(error) => fmt::Display::fmt(error, f),
244        }
245    }
246}
247
248/// Why [`GenMap::get_disjoint_mut`](crate::GenMap::get_disjoint_mut) or
249/// [`SecondaryMap::get_disjoint_mut`](crate::SecondaryMap::get_disjoint_mut)
250/// could not hand out its references.
251#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
252pub enum GetDisjointMutError {
253    /// The map has no value for one of the keys, meaning the map's
254    /// `contains_key` returns `false` for it.
255    InvalidKey,
256
257    /// Two or more of the keys point at the same slot, so the references would
258    /// alias.
259    OverlappingKeys,
260}
261
262impl fmt::Display for GetDisjointMutError {
263    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264        match self {
265            Self::InvalidKey => f.write_str("one of the keys is invalid"),
266            Self::OverlappingKeys => f.write_str("two of the keys point at the same slot"),
267        }
268    }
269}
270
271/// Why [`GenMap::get_disjoint_mut_at`](crate::GenMap::get_disjoint_mut_at) or
272/// [`SecondaryMap::get_disjoint_mut_at`](crate::SecondaryMap::get_disjoint_mut_at)
273/// could not hand out its references.
274#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
275pub enum GetDisjointMutAtError {
276    /// There is no slot at one of the indices, or the slot holds no value,
277    /// meaning the map's `key_at` returns `None` for it.
278    NoValue,
279
280    /// Two of the indices are the same, so the references would alias.
281    OverlappingIndices,
282}
283
284impl fmt::Display for GetDisjointMutAtError {
285    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
286        match self {
287            Self::NoValue => f.write_str("one of the indices has no value"),
288            Self::OverlappingIndices => f.write_str("two of the indices are the same"),
289        }
290    }
291}