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}