Skip to main content

ordinal_map/ordinal/
traits.rs

1/// Two-way map from a type to `usize` range from `0..ORDINAL_SIZE`.
2///
3/// Two way ordinal mapping means:
4/// - the type has `ORDINAL_SIZE` possible values
5/// - each value has a unique ordinal number in the range `0..ORDINAL_SIZE`
6/// - each ordinal number corresponds to a unique value
7///
8/// This type is implemented for
9/// - small integer types
10/// - tuples
11/// - some builtin types like [`Option`] and [`Result`]
12/// - and it can be derived with the `#[derive(Ordinal)]` attribute for structs and enums
13///
14/// # Relation to `Ord` and `PartialOrd`
15///
16/// Implementations provided in this crate and generated with `#[derive(Ordinal)]`
17/// are compatible with `Ord` and `PartialOrd`, meaning `a < b <=> a.ordinal() < b.ordinal()`
18/// **with the exception** of derive on enums with explicit discriminants
19/// (derive ignores them and assigns ordinal numbers in order of declaration).
20///
21/// This is not enforced by the trait itself, but it is a good practice to follow.
22///
23/// # Derive
24///
25/// `#[derive(Ordinal)]` works for arbitrary structs and enums.
26/// Generated implementation is compatible with `#[derive(PartialOrd)]`.
27///
28/// ```
29/// use ordinal_map::Ordinal;
30/// #[derive(Ordinal)]
31/// enum Color {
32///     Red,
33///     Cyan,
34///     Blue,
35/// }
36///
37/// #[derive(Ordinal)]
38/// struct Bright(bool);
39///
40/// #[derive(Ordinal)]
41/// enum MaybeColor {
42///     Default,
43///     Colored(Color, Bright),
44///     Invisible,
45/// }
46///
47/// assert_eq!(0, MaybeColor::Default.ordinal());
48/// assert_eq!(1, MaybeColor::Colored(Color::Red, Bright(false)).ordinal());
49/// assert_eq!(2, MaybeColor::Colored(Color::Red, Bright(true)).ordinal());
50/// assert_eq!(3, MaybeColor::Colored(Color::Cyan, Bright(false)).ordinal());
51/// assert_eq!(4, MaybeColor::Colored(Color::Cyan, Bright(true)).ordinal());
52/// ```
53///
54/// # See also
55///
56/// - [`Iter`](crate::OrdinalValues) to iterate over all possible values.
57/// - [`map`](crate::map) module for constant time lookup maps.
58/// - [`set`](crate::set) module for constant time lookup sets.
59pub trait Ordinal: Sized {
60    /// Number of possible values.
61    ///
62    /// It is compile-time error if the number of possible values is greater than `usize::MAX`.
63    const ORDINAL_SIZE: usize;
64    /// Index of the ordinal.
65    ///
66    /// # Example
67    ///
68    /// ```
69    /// use std::num::NonZeroI16;
70    ///
71    /// use ordinal_map::Ordinal;
72    /// assert_eq!(0, None::<u16>.ordinal());
73    /// assert_eq!(1, Some::<u16>(0).ordinal());
74    /// assert_eq!(2, Some::<u16>(1).ordinal());
75    /// ```
76    fn ordinal(&self) -> usize;
77    /// Returns the ordinal from the index.
78    ///
79    /// # Example
80    ///
81    /// ```
82    /// use ordinal_map::Ordinal;
83    ///
84    /// assert_eq!(i16::MIN, i16::from_ordinal(0).unwrap());
85    /// assert_eq!(i16::MIN + 1, i16::from_ordinal(1).unwrap());
86    /// ```
87    fn from_ordinal(ordinal: usize) -> Option<Self>;
88
89    /// Iterate over all possible values.
90    ///
91    /// Values are returned in order of their ordinal numbers.
92    ///
93    /// # Example
94    ///
95    /// ```
96    /// use ordinal_map::Ordinal;
97    /// let mut iter = i16::all_values();
98    /// assert_eq!(Some(i16::MIN), iter.next());
99    /// assert_eq!(Some(i16::MAX), iter.next_back());
100    /// ```
101    fn all_values() -> crate::OrdinalValues<Self> {
102        crate::OrdinalValues::new()
103    }
104}