1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/// The 4 possible TNID variants.
///
/// Similar to UUID variants, TNID variants have different construction that makes them useful for different situations.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TnidVariant {
/// V0 is most like UUIDv7, and is meant to be time-sortable. See [`Tnid::new_v0`](crate::Tnid::new_v0).
V0,
/// V1 is most like UUIDv4, and is meant to maximize entropy (randomness). See [`Tnid::new_v1`](crate::Tnid::new_v1).
V1,
/// V2 is undefined but reserved for future use.
V2,
/// V3 is undefined but reserved for future use.
V3,
}
impl TnidVariant {
/// Converts a u8 to a [`TnidVariant`].
///
/// Only the bottom 2 bits are used to determine the variant (ignores the top 6 bits).
/// For example, `0b0000_0000`, `0b0000_0100`, and `0b1111_1100` all have bottom 2 bits of `00`,
/// so they all map to V0.
///
/// # Examples
///
/// ```rust
/// use tnid::TnidVariant;
///
/// // Bottom 2 bits are 0b00 -> V0
/// assert_eq!(TnidVariant::from_u8(0b00000000), TnidVariant::V0);
/// assert_eq!(TnidVariant::from_u8(0b11111100), TnidVariant::V0);
///
/// // Bottom 2 bits are 0b01 -> V1
/// assert_eq!(TnidVariant::from_u8(0b00000001), TnidVariant::V1);
/// assert_eq!(TnidVariant::from_u8(0b11111101), TnidVariant::V1);
/// ```
pub fn from_u8(variant_bits: u8) -> TnidVariant {
let variant_bits = variant_bits & 0b11;
match variant_bits {
0 => TnidVariant::V0,
1 => TnidVariant::V1,
2 => TnidVariant::V2,
3 => TnidVariant::V3,
_ => unreachable!("2 bits can only have 4 values"),
}
}
/// Extracts the TNID variant from a 128-bit ID.
///
/// Reads bits 60-61 of the ID to determine the variant.
///
/// # Examples
///
/// ```rust
/// use tnid::{Tnid, TnidName, NameStr, TnidVariant};
///
/// struct User;
/// impl TnidName for User {
/// const ID_NAME: NameStr<'static> = NameStr::new_const("user");
/// }
///
/// let v0_id = Tnid::<User>::new_v0();
/// assert_eq!(TnidVariant::from_id(v0_id.as_u128()), TnidVariant::V0);
///
/// let v1_id = Tnid::<User>::new_v1();
/// assert_eq!(TnidVariant::from_id(v1_id.as_u128()), TnidVariant::V1);
/// ```
pub fn from_id(id: u128) -> TnidVariant {
let variant_bits = (id >> 60) as u8;
Self::from_u8(variant_bits)
}
/// Returns the u8 representation of this variant.
///
/// # Examples
///
/// ```rust
/// use tnid::TnidVariant;
///
/// assert_eq!(TnidVariant::V0.as_u8(), 0);
/// assert_eq!(TnidVariant::V1.as_u8(), 1);
/// assert_eq!(TnidVariant::V2.as_u8(), 2);
/// assert_eq!(TnidVariant::V3.as_u8(), 3);
/// ```
pub fn as_u8(&self) -> u8 {
match self {
TnidVariant::V0 => 0,
TnidVariant::V1 => 1,
TnidVariant::V2 => 2,
TnidVariant::V3 => 3,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_u8_no_panic() {
for i in u8::MIN..=u8::MAX {
TnidVariant::from_u8(i);
}
}
}