Skip to main content

dope_core/
token.rs

1use crate::driver::BackendToken;
2
3#[repr(transparent)]
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5pub struct TokenSlot(u16);
6
7impl TokenSlot {
8    #[inline(always)]
9    pub fn from_index(index: usize) -> Self {
10        Self(u16::try_from(index).expect("dope: token slot index exceeds u16 range"))
11    }
12
13    #[inline(always)]
14    pub const fn from_raw(raw: u16) -> Self {
15        Self(raw)
16    }
17
18    #[inline(always)]
19    pub const fn as_usize(self) -> usize {
20        self.0 as usize
21    }
22
23    #[inline(always)]
24    pub const fn raw(self) -> u16 {
25        self.0
26    }
27}
28
29#[repr(transparent)]
30#[derive(Clone, Copy, Debug, PartialEq, Eq)]
31pub struct TokenEpoch(u32);
32
33impl TokenEpoch {
34    pub const MAX: u32 = (1 << 24) - 1;
35
36    #[inline(always)]
37    pub const fn from_raw(raw: u32) -> Self {
38        assert!(
39            raw <= Self::MAX,
40            "dope: token epoch exceeds 24-bit user_data budget",
41        );
42        Self(raw)
43    }
44
45    #[inline(always)]
46    pub const fn raw(self) -> u32 {
47        self.0
48    }
49
50    #[inline(always)]
51    pub fn next(seq: &mut u32) -> Self {
52        *seq = seq.wrapping_add(1) & Self::MAX;
53        Self::from_raw(*seq)
54    }
55}
56
57pub trait WirePad: Copy + 'static {
58    const ZERO: Self;
59}
60
61impl WirePad for () {
62    const ZERO: () = ();
63}
64impl WirePad for u8 {
65    const ZERO: u8 = 0;
66}
67
68#[repr(C, packed)]
69#[derive(Clone, Copy, Debug, PartialEq, Eq)]
70pub struct Token<P: WirePad> {
71    slot: TokenSlot,
72    epoch: TokenEpoch,
73    _pad: P,
74}
75
76impl<P: WirePad> Token<P> {
77    #[inline(always)]
78    pub const fn new(slot: TokenSlot, epoch: TokenEpoch) -> Self {
79        Self {
80            slot,
81            epoch,
82            _pad: P::ZERO,
83        }
84    }
85
86    #[inline(always)]
87    pub fn from_index(index: usize, epoch: TokenEpoch) -> Self {
88        Self::new(TokenSlot::from_index(index), epoch)
89    }
90
91    #[inline(always)]
92    pub fn from_index_raw(index: usize, epoch: u32) -> Self {
93        Self::from_index(index, TokenEpoch::from_raw(epoch))
94    }
95
96    #[inline(always)]
97    pub fn next_for_slot(index: usize, seq: &mut u32) -> Self {
98        Self::from_index(index, TokenEpoch::next(seq))
99    }
100
101    #[inline(always)]
102    pub const fn parts(self) -> (usize, u32) {
103        (self.slot.as_usize(), self.epoch.raw())
104    }
105
106    #[inline(always)]
107    pub fn slot_raw(self) -> u16 {
108        self.slot.raw()
109    }
110
111    #[inline(always)]
112    pub fn epoch_raw(self) -> u32 {
113        self.epoch.raw()
114    }
115}
116
117impl<P: WirePad> BackendToken for Token<P> {
118    #[inline(always)]
119    fn parts(self) -> (usize, u32) {
120        Self::parts(self)
121    }
122
123    #[inline(always)]
124    fn next_for_slot(index: usize, seq: &mut u32) -> Self {
125        Self::next_for_slot(index, seq)
126    }
127
128    #[inline(always)]
129    fn from_index_raw(index: usize, epoch: u32) -> Self {
130        Self::from_index_raw(index, epoch)
131    }
132}