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}