intid_core/
lib.rs

1//! Defines the [`IntegerId`] trait, for types that can be identified by an integer value.
2//!
3//! This contains all the same types that the [`intid`] crate does,
4//! but has no dependency on [`intid_derive`] (even when the `intid/derive` feature is enabled).
5//! This reduces compile times, similar to the separation between `serde_core` and `serde` introduced in [serde-rs/serde#2608].
6//!
7//! It may be convenient to rename the `intid_core` dependency to `intid` using [dependency renaming].
8//! ```toml
9//! intid = { version = "0.3", package = "intid_core" }
10//! ```
11//! This renaming comes at no loss of clarity,
12//! since the items in `intid_core` are simply a subset of the items in the `intid` crate.
13//! If for some reason you decide to use `intid_derive` directly without depending on `intid`,
14//! then you will need to do this renaming since the derived code references the `intid` crate.
15//!
16//! [dependency renaming]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml
17//! [serde-rs/serde#2608]: https://github.com/serde-rs/serde/pull/2608
18//! [`intid`]: https://docs.rs/intid/latest/intid
19//! [`intid_derive`]: https://docs.rs/intid-derive/latest/intid_derive
20#![no_std]
21#![cfg_attr(feature = "nightly", feature(never_type,))]
22extern crate alloc;
23
24use core::fmt::Debug;
25
26#[macro_use]
27mod macros;
28#[doc(hidden)]
29pub mod array;
30mod impls;
31pub mod trusted;
32pub mod uint;
33pub mod utils;
34
35pub use uint::UnsignedPrimInt;
36
37/// An identifier which can be sensibly converted to/from an unsigned integer value.
38///
39///
40/// The type should not carry any information beyond that of the integer index,
41/// and be able to losslessly convert back and forth from [`Self::Int`].
42/// It is possible that not all values of the underlying integer type are valid,
43/// allowing [`core::num::NonZero`] and C-like enums to implement this trait.
44///
45///
46/// This is intended mostly for newtype wrappers around integer indexes,
47/// and the primitive integer types themselves.
48///
49/// The value of the underlying integer must be consistent.
50/// It cannot change over the course of the program's lifetime.
51///
52/// ## Safety
53/// With one exception, this trait is safe to implement and cannot be relied upon by memory safety.
54///
55/// If the implementation of [`IntegerId::from_int_unchecked`] makes any sort of unsafe assumptions
56/// about the validity of the input, then the rest of the trait must be implemented correctly.
57/// This means that implementations of this trait fall into two categories:
58/// 1. Potentially incorrect implemented entirely using safe code, where `from_int_unchecked(x)`
59///    is equivalent to calling `from_int_checked(x).unwrap()`;
60/// 2. Traits where `from_int_unchecked` could trigger undefined behavior on an invalid value,
61///    but every other part of this trait can be trusted to be implemented correctly.
62///
63/// In both these cases, the following code is always safe:
64/// ```no_run
65/// # use intid_core::IntegerId;
66/// fn foo<T: IntegerId>(x: T) -> T {
67///     let y = x.to_int();
68///     let z = unsafe { T::from_int_unchecked(y) };
69///     z
70/// }
71/// ```
72/// In case 1,  it doesn't matter if [`x.to_int()`](Self::to_int) produces garbage data,
73/// because `T::from_int_unchecked` method is safe to call.
74/// In case 2, the `to_int` method can be trusted to produce a valid value `y` that cannot fail
75/// when passed to `T::from_int_unchecked`.
76///
77/// The requirement for correctness in this case also apply to all sub-traits in this crate,
78/// including [`IntegerIdContiguous`] and [`IntegerIdCounter`].
79/// So an unsafe implementation of `from_int_unchecked` can be similarly trusted to accept
80/// all integer values between [`IntegerId::MIN_ID`] and [`IntegerId::MAX_ID`].
81///
82/// This restriction allows avoiding unnecessary checks when ids are stored to/from another data structure.
83/// Despite this requirement, I still consider this trait safe to implement,
84/// because safety can only be violated by an unsafe implementation of`from_int_unchecked`.
85///
86/// This type should not have interior mutability.
87/// This is guaranteed by the `Copy` bound.
88pub trait IntegerId: Copy + Eq + Debug + Send + Sync + 'static {
89    /// The underlying integer type.
90    ///
91    /// Every valid instance of `Self` should correspond to a valid `Self::Int`.
92    /// However, the other direction may not always be true.
93    type Int: uint::UnsignedPrimInt;
94    /// The value of this type with the smallest integer value,
95    /// or `None` if this type is uninhabited.
96    const MIN_ID: Option<Self>;
97    /// The value of this type with the largest integer value,
98    /// or `None` if this type is uninhabited.
99    const MAX_ID: Option<Self>;
100    /// The value of [`Self::MIN_ID`] a primitive integer,
101    /// or `None` if this type is uninhabited.
102    ///
103    /// This is necessary because trait methods cannot be marked `const`.
104    const MIN_ID_INT: Option<Self::Int>;
105    /// The value of [`Self::MAX_ID`] a primitive integer,
106    /// or `None` if this type is uninhabited.
107    ///
108    /// This is necessary because trait methods cannot be marked `const`.
109    const MAX_ID_INT: Option<Self::Int>;
110
111    /// Indicates that the type's implementation of [`IntegerId::to_int`] can trusted
112    /// to only return values in the range `MIN_ID_INT..=MAX_ID_INT`.
113    ///
114    /// This can be relied upon by unsafe code, since the token is `unsafe` to construct.
115    const TRUSTED_RANGE: Option<trusted::TrustedRangeToken<Self>> = None;
116
117    /// Create an id from the underlying integer value,
118    /// panicking if the value is invalid.
119    ///
120    /// ## Correctness
121    /// A value returned by this method should never trigger
122    /// an error if passed to [`Self::from_int_checked`].
123    /// This means the validity of certain ids can't change over the course of the program.
124    #[inline]
125    #[track_caller]
126    fn from_int(id: Self::Int) -> Self {
127        match Self::from_int_checked(id) {
128            Some(success) => success,
129            None => uint::invalid_id(id),
130        }
131    }
132
133    /// Create an id from the underlying integer value,
134    /// returning `None` if the value is invalid.
135    fn from_int_checked(id: Self::Int) -> Option<Self>;
136
137    /// Create an id from the underlying integer value,
138    /// triggering undefined behavior if the value is invalid.
139    ///
140    /// ## Safety
141    /// If the corresponding [`Self::from_int_checked`] method would fail,
142    /// this triggers undefined behavior.
143    /// The default implementation just invokes [`Self::from_int`].
144    #[inline]
145    unsafe fn from_int_unchecked(id: Self::Int) -> Self {
146        Self::from_int(id)
147    }
148
149    /// Convert this id into an underlying integer type.
150    ///
151    /// This method can never fail,
152    /// since valid instances `Self` always correspond to valid instances of `Self::Int`.
153    fn to_int(self) -> Self::Int;
154}
155
156/// Indicates that an id occupies contiguous range of contiguous values,
157/// and all values between [`IntegerId::MIN_ID`] and [`IntegerId::MAX_ID`] are valid.
158///
159/// This is similar to [`bytemuck::Contiguous`].
160/// However, since it is safe to implement,
161/// it must not be relied upon for correctness.
162///
163/// ## Safety
164/// This trait is safe to implement, so may not usually be relied upon for memory safety.
165///
166/// However, if [`Self::from_int_unchecked`](IntegerId::from_int_unchecked) makes unsafe assumptions (satisfying the condition set forth in the [`IntegerId`] safety docs),
167/// then this trait must also be implemented correctly.
168/// More specifically, all integers between [`IntegerId::MIN_ID`] and [`IntegerId::MAX_ID`] must be valid
169/// and cannot fail when passed to [`IntegerId::from_int_checked`].
170pub trait IntegerIdContiguous: IntegerId {}
171
172/// An [`IntegerId`] that can be sensibly used as a counter,
173/// starting at a [`Self::START`] value and being incremented from there.
174///
175/// This is used by the `intid-allocator` crate to provide an atomic counter to allocate new ids.
176/// It also provides more complex allocators that can reuse ids that have been freed.
177///
178/// This type cannot be implemented for uninhabited types like [`core::convert::Infallible`] or `!`,
179/// as there is no valid implementation of [`Self::START`].
180pub trait IntegerIdCounter: IntegerId + IntegerIdContiguous {
181    /// Where a counter a should start from.
182    ///
183    /// This should be the [`Default`] value if one is defined.
184    /// It is usually equal to the [`IntegerId::MIN_ID`],
185    /// but this is not required.
186    const START: Self;
187    /// The value of [`Self::START`] as a [`T::Int`](IntegerId::Int).
188    ///
189    /// This is necessary because trait methods ([`IntegerId::to_int`])
190    /// can not currently be const methods.
191    const START_INT: Self::Int;
192
193    /// Increment this value by the specified offset,
194    /// returning `None` if the value overflows or is invalid.
195    ///
196    /// This should behave consistently with [`IntegerIdContiguous`]
197    /// and [`IntegerId::from_int_checked`].
198    /// However, that can not be relied upon for memory safety.
199    ///
200    /// This is implemented as an associated method to avoid namespace pollution.
201    #[inline]
202    fn checked_add(this: Self, offset: Self::Int) -> Option<Self> {
203        uint::checked_add(this.to_int(), offset).and_then(Self::from_int_checked)
204    }
205
206    /// Increment this value by the specified offset,
207    /// returning `None` if the value overflows or is invalid.
208    ///
209    /// This should behave consistently with [`IntegerIdContiguous`]
210    /// and [`IntegerId::from_int_checked`].
211    /// However, that can not be relied upon for memory safety.
212    ///
213    /// This is implemented as an associated method to avoid namespace pollution.
214    #[inline]
215    fn checked_sub(this: Self, offset: Self::Int) -> Option<Self> {
216        uint::checked_sub(this.to_int(), offset).and_then(Self::from_int_checked)
217    }
218}
219
220/// An [`IntegerId`] which are limited to small set of values.
221///
222/// As the name suggests, it is most useful for C-style enums,
223/// and allows using enums as keys for inline map/sets without allocation.
224/// Is not implemented for types like `u32` where inline storage
225/// would require inordinate amounts of space.
226///
227/// All valid indexes and the total [`Self::COUNT`] must fit in a [`u32`] and a [`usize`].
228///
229/// Note that this does *not* imply [`IntegerIdContiguous`],
230/// so not all be integers below [`Self::MAX_ID_INT`](IntegerId::MAX_ID_INT)
231/// are guaranteed to be valid.
232pub trait EnumId: IntegerId {
233    /// The total number of valid values.
234    const COUNT: u32;
235    /// A builtin array of `[T; {Self::MAX_ID_INT + 1}]`.
236    ///
237    /// Necessary to work around the current (Rust 1.90) restrictions on const generics
238    ///
239    /// # Safety
240    /// Since the [`array::Array`] trait is sealed,
241    /// this is guaranteed to be a builtin array of type `T`.
242    /// Since this is a safe trait, the length could be any value.
243    /// However, that is easily checked using a const assertion.
244    type Array<T>: array::Array<T>;
245    /// An array of words, whose bits can store all valid ids.
246    ///
247    /// Necessary to work around the current (Rust 1.90) restrictions on const generics.
248    ///
249    /// # Safety
250    /// Has similar safety guarantees as [`Self::Array`].
251    /// The type is correct, but the length must be checked with a const assertion.
252    type BitSet: array::Array<array::BitsetLimb>;
253}
254
255/// A type that can be for lookup as an [`IntegerId`].
256///
257/// Used for key lookup in maps, similar to [`core::borrow::Borrow`] or [`equivalent::Equivalent`].
258/// These traits are not suitable for id maps,
259/// which need conversion to integers rather than hashing/equality.
260///
261/// [`equivalent::Equivalent`]: https://docs.rs/equivalent/latest/equivalent/trait.Equivalent.html
262pub trait EquivalentId<K: IntegerId> {
263    /// Convert this type to an id `K`.
264    fn as_id(&self) -> K;
265}
266impl<K: IntegerId> EquivalentId<K> for K {
267    #[inline]
268    fn as_id(&self) -> K {
269        *self
270    }
271}
272impl<K: IntegerId> EquivalentId<K> for &'_ K {
273    #[inline]
274    fn as_id(&self) -> K {
275        **self
276    }
277}
278impl<K: IntegerId> EquivalentId<K> for &'_ mut K {
279    #[inline]
280    fn as_id(&self) -> K {
281        **self
282    }
283}