dope_core/driver/
token.rs1use core::marker::PhantomData;
2use core::num::NonZeroU64;
3
4use o3::collections::{CellSlab, Slab, SlabKey, SlabKeyParts};
5
6pub const ROUTE_FRAMEWORK: u8 = 255;
7
8pub const ROUTE_SHIFT: u32 = 56;
9pub const KIND_SHIFT: u32 = 48;
10const EPOCH_SHIFT: u32 = 24;
11const ROUTE_MASK: u64 = 0xFF << ROUTE_SHIFT;
12const KIND_MASK: u64 = 0xFF << KIND_SHIFT;
13pub const SLOT_BITS: u32 = 24;
14const EPOCH_BITS: u32 = 24;
15pub const SLOT_MASK: u64 = (1 << SLOT_BITS) - 1;
16pub const EPOCH_MASK: u64 = (1 << EPOCH_BITS) - 1;
17
18pub type Key<Tag> = SlabKey<Tag, { EPOCH_MASK as u32 }>;
19pub type TokenCellSlab<T, Tag> = CellSlab<T, Tag, { EPOCH_MASK as u32 }>;
20pub type TokenSlab<T, Tag> = Slab<T, Tag, { EPOCH_MASK as u32 }>;
21
22#[repr(transparent)]
23pub struct KeyParts<Tag> {
24 parts: SlabKeyParts<{ EPOCH_MASK as u32 }>,
25 tag: PhantomData<*mut Tag>,
26}
27
28impl<Tag> Clone for KeyParts<Tag> {
29 fn clone(&self) -> Self {
30 *self
31 }
32}
33
34impl<Tag> Copy for KeyParts<Tag> {}
35
36impl<Tag> KeyParts<Tag> {
37 pub const fn index(self) -> u32 {
38 self.parts.index()
39 }
40
41 pub const fn slab(self) -> SlabKeyParts<{ EPOCH_MASK as u32 }> {
42 self.parts
43 }
44}
45
46pub struct KeyTag<const ROUTE: u8, const KIND: u8 = 0>;
47
48pub trait TokenTag {
49 const ROUTE: u8;
50 const KIND: u8;
51 const MASK: u64;
52 const VALUE: u64;
53}
54
55impl<const ROUTE: u8, const KIND: u8> TokenTag for KeyTag<ROUTE, KIND> {
56 const ROUTE: u8 = ROUTE;
57 const KIND: u8 = KIND;
58 const MASK: u64 = ROUTE_MASK | if KIND == 0 { 0 } else { KIND_MASK };
59 const VALUE: u64 = (ROUTE as u64) << ROUTE_SHIFT | (KIND as u64) << KIND_SHIFT;
60}
61
62pub mod kind {
63 pub const ACCEPT: u8 = 1;
64 pub const RECV: u8 = 2;
65 pub const SEND: u8 = 3;
66 pub const TIMER: u8 = 4;
67 pub const SOCKET: u8 = 5;
68 pub const CONNECT: u8 = 6;
69 pub const SHUTDOWN: u8 = 7;
70 pub const SETSOCKOPT: u8 = 8;
71 pub const WRITE: u8 = 9;
72 pub const SYNC: u8 = 10;
73 pub const OPEN: u8 = 11;
74 pub const READ: u8 = 12;
75 pub const SPLICE: u8 = 13;
76 pub const RECV_DISCARD: u8 = 14;
77 pub const CREATE: u8 = 15;
78 pub const CLOSE_PREP: u8 = 16;
79 pub const CLOSE: u8 = 17;
80 pub const STAT: u8 = 18;
81 pub const ONE_SHOT: u8 = 19;
82 pub const READ_BLOCK: u8 = 20;
83 pub const TASK_QUEUE: u8 = 21;
84}
85
86#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Default)]
87#[repr(transparent)]
88pub struct SlotIndex(u32);
89
90impl SlotIndex {
91 pub const fn new(raw: u32) -> Self {
92 Self(raw)
93 }
94
95 pub const fn raw(self) -> u32 {
96 self.0
97 }
98}
99
100#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Default)]
101#[repr(transparent)]
102pub struct Epoch(u32);
103
104impl Epoch {
105 pub const INITIAL: Self = Self(1);
106 pub const MAX: Self = Self(EPOCH_MASK as u32);
107 pub const ZERO: Self = Self(0);
108
109 pub const fn new(raw: u32) -> Option<Self> {
110 if raw <= EPOCH_MASK as u32 {
111 Some(Self(raw))
112 } else {
113 None
114 }
115 }
116
117 pub const fn raw(self) -> u32 {
118 self.0
119 }
120
121 pub const fn next(self) -> Option<Self> {
122 if self.0 < EPOCH_MASK as u32 {
123 Some(Self(self.0 + 1))
124 } else {
125 None
126 }
127 }
128}
129
130#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
131#[repr(transparent)]
132pub struct Token(NonZeroU64, PhantomData<*mut ()>);
133
134impl Token {
135 pub const fn new(route: u8, slot: SlotIndex, epoch: Epoch) -> Self {
136 assert!((slot.0 as u64) <= SLOT_MASK, "dope: token slot overflow");
137 assert!((epoch.0 as u64) <= EPOCH_MASK, "dope: token epoch overflow");
138 let raw = ((route as u64) << ROUTE_SHIFT)
139 | ((epoch.0 as u64) << EPOCH_SHIFT)
140 | (slot.0 as u64 & SLOT_MASK);
141 Self::from_nonzero(raw)
142 }
143
144 pub const fn with_kind(self, kind: u8) -> Self {
145 let cleared = self.0.get() & !((0xFFu64) << KIND_SHIFT);
146 Self::from_nonzero(cleared | ((kind as u64) << KIND_SHIFT))
147 }
148
149 const fn from_nonzero(raw: u64) -> Self {
150 assert!(
151 raw != 0,
152 "dope: token requires a nonzero route, slot, or epoch"
153 );
154 Self(unsafe { NonZeroU64::new_unchecked(raw) }, PhantomData)
155 }
156
157 pub const fn try_from_raw(raw: u64) -> Option<Self> {
158 match NonZeroU64::new(raw) {
159 Some(v) => Some(Self(v, PhantomData)),
160 None => None,
161 }
162 }
163
164 pub const fn raw(self) -> u64 {
165 self.0.get()
166 }
167
168 pub const fn route(self) -> u8 {
169 (self.0.get() >> ROUTE_SHIFT) as u8
170 }
171
172 pub const fn kind(self) -> u8 {
173 ((self.0.get() & KIND_MASK) >> KIND_SHIFT) as u8
174 }
175
176 pub const fn slot(self) -> SlotIndex {
177 SlotIndex((self.0.get() & SLOT_MASK) as u32)
178 }
179
180 pub const fn epoch(self) -> Epoch {
181 Epoch(((self.0.get() >> EPOCH_SHIFT) & EPOCH_MASK) as u32)
182 }
183
184 pub const fn same_target(self, other: Self) -> bool {
185 self.0.get() & !KIND_MASK == other.0.get() & !KIND_MASK
186 }
187
188 #[allow(private_bounds)]
189 pub const fn parts<Tag: TokenTag>(self) -> Option<KeyParts<Tag>> {
190 if self.raw() & Tag::MASK != Tag::VALUE {
191 return None;
192 }
193 match SlabKeyParts::new(self.slot().raw(), self.epoch().raw()) {
194 Some(parts) => Some(KeyParts {
195 parts,
196 tag: PhantomData,
197 }),
198 None => None,
199 }
200 }
201
202 #[allow(private_bounds)]
203 pub const fn from_key<Tag: TokenTag>(key: Key<Tag>) -> Self {
204 Self::new(
205 Tag::ROUTE,
206 SlotIndex::new(key.index()),
207 Epoch(key.generation().get()),
208 )
209 .with_kind(Tag::KIND)
210 }
211}
212
213pub const SHUTDOWN: Token =
214 Token::new(ROUTE_FRAMEWORK, SlotIndex::new(0), Epoch::ZERO).with_kind(kind::SHUTDOWN);