gen_value/
lib.rs

1// Copyright 2023 Bryant Luk
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9#![doc = include_str!("../README.md")]
10#![cfg_attr(docsrs, feature(doc_cfg))]
11#![warn(
12    rust_2018_idioms,
13    missing_docs,
14    missing_debug_implementations,
15    unused_lifetimes,
16    unused_qualifications
17)]
18#![cfg_attr(not(feature = "std"), no_std)]
19
20#[cfg(all(feature = "alloc", not(feature = "std")))]
21extern crate alloc;
22
23use core::fmt;
24
25pub mod index;
26pub mod unmanaged;
27pub mod vec;
28
29/// A type which can attempt to return the smallest value which is still bigger
30/// than the current value.
31///
32/// It is used for index and generation type parameters to find the next index
33/// or the next generation respectively.
34///
35/// # Examples
36///
37/// An implementation of `Incrementable` has been made for all integer types.
38///
39/// ```
40/// use gen_value::Incrementable;
41///
42/// let value: u32 = 1;
43/// assert_eq!(value.next(), Some(2));
44/// assert_eq!(u32::MAX.next(), None);
45/// ```
46pub trait Incrementable: PartialOrd + Sized {
47    /// Returns the next value, if available.
48    fn next(&self) -> Option<Self>;
49
50    /// Returns the maximum value, if available.
51    ///
52    /// For generations, the maximum value serves as an indicator that the index
53    /// can no longer be used (tombstone value). The last generation used would
54    /// be `max() - 1`.
55    fn max() -> Option<Self>;
56}
57
58/// Makes an Incremental implementation for an integer type.
59macro_rules! make_incremental_int_impl {
60    ($ty:ident) => {
61        impl Incrementable for $ty {
62            fn next(&self) -> Option<Self> {
63                self.checked_add(1)
64            }
65
66            fn max() -> Option<Self> {
67                Some(Self::MAX)
68            }
69        }
70    };
71}
72
73make_incremental_int_impl!(u8);
74make_incremental_int_impl!(u16);
75make_incremental_int_impl!(u32);
76make_incremental_int_impl!(u64);
77make_incremental_int_impl!(usize);
78make_incremental_int_impl!(i8);
79make_incremental_int_impl!(i16);
80make_incremental_int_impl!(i32);
81make_incremental_int_impl!(i64);
82make_incremental_int_impl!(isize);
83
84#[derive(Debug)]
85enum ErrorCode {
86    IndexOutOfBounds,
87    LessThanExistingGeneration,
88    NotEqualGeneration,
89    CannotAllocateGenerationalIndex,
90    AlreadyEqualGeneration,
91}
92
93impl fmt::Display for ErrorCode {
94    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95        match self {
96            ErrorCode::IndexOutOfBounds => f.write_str("index out of bounds"),
97            ErrorCode::LessThanExistingGeneration => f.write_str(
98                "generational index's generation is less than the existing element's generation",
99            ),
100            ErrorCode::NotEqualGeneration => {
101                f.write_str("element's generation does not equal the generation index's generation")
102            }
103            ErrorCode::CannotAllocateGenerationalIndex => {
104                f.write_str("cannot allocate a generational index")
105            }
106            ErrorCode::AlreadyEqualGeneration => {
107                f.write_str("generation is already equal to existing generation")
108            }
109        }
110    }
111}
112
113/// Errors from calling [`GenVec`] and [`UnmanagedGenVec`][crate::unmanaged::UnmanagedGenVec] functions.
114#[derive(Debug)]
115pub struct Error {
116    code: ErrorCode,
117}
118
119impl fmt::Display for Error {
120    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
121        fmt::Display::fmt(&self.code, f)
122    }
123}
124
125#[cfg(feature = "std")]
126impl std::error::Error for Error {
127    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
128        None
129    }
130}
131
132impl Error {
133    #[inline]
134    pub(crate) fn index_out_of_bounds() -> Self {
135        Error {
136            code: ErrorCode::IndexOutOfBounds,
137        }
138    }
139
140    /// Index is out of bounds.
141    #[must_use]
142    pub fn is_index_out_of_bounds(&self) -> bool {
143        matches!(self.code, ErrorCode::IndexOutOfBounds)
144    }
145
146    #[inline]
147    pub(crate) fn less_than_existing_generation() -> Self {
148        Error {
149            code: ErrorCode::LessThanExistingGeneration,
150        }
151    }
152
153    /// Generation is less than generation associated with element.
154    #[must_use]
155    pub fn is_generation_less_than_existing(&self) -> bool {
156        matches!(self.code, ErrorCode::LessThanExistingGeneration)
157    }
158
159    #[inline]
160    pub(crate) fn not_equal_generation() -> Self {
161        Error {
162            code: ErrorCode::NotEqualGeneration,
163        }
164    }
165
166    /// Generations are not equal.
167    #[must_use]
168    pub fn is_not_equal_generation_error(&self) -> bool {
169        matches!(self.code, ErrorCode::NotEqualGeneration)
170    }
171
172    #[inline]
173    pub(crate) fn cannot_allocate_generational_index() -> Self {
174        Error {
175            code: ErrorCode::CannotAllocateGenerationalIndex,
176        }
177    }
178
179    /// Could not allocate a generation index.
180    #[must_use]
181    pub fn is_generational_index_allocation_error(&self) -> bool {
182        matches!(self.code, ErrorCode::CannotAllocateGenerationalIndex)
183    }
184
185    #[inline]
186    pub(crate) fn already_equal_generation() -> Self {
187        Error {
188            code: ErrorCode::AlreadyEqualGeneration,
189        }
190    }
191
192    /// Generations are already equal.
193    #[must_use]
194    pub fn is_already_equal_generation_error(&self) -> bool {
195        matches!(self.code, ErrorCode::AlreadyEqualGeneration)
196    }
197}
198
199pub use vec::GenVec;
200
201#[cfg(test)]
202mod tests {
203    use super::*;
204
205    #[test]
206    fn incrementable_overflow() {
207        assert_eq!(u8::MAX.next(), None);
208        assert_eq!(u16::MAX.next(), None);
209        assert_eq!(u32::MAX.next(), None);
210        assert_eq!(u64::MAX.next(), None);
211        assert_eq!(usize::MAX.next(), None);
212        assert_eq!(i8::MAX.next(), None);
213        assert_eq!(i16::MAX.next(), None);
214        assert_eq!(i32::MAX.next(), None);
215        assert_eq!(i64::MAX.next(), None);
216        assert_eq!(isize::MAX.next(), None);
217    }
218}