Skip to main content

dope_core/driver/
token.rs

1use 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 RECV_DISCARD: u8 = 14;
76    pub const CREATE: u8 = 15;
77    pub const CLOSE_PREP: u8 = 16;
78    pub const CLOSE: u8 = 17;
79    pub const STAT: u8 = 18;
80    pub const ONE_SHOT: u8 = 19;
81    pub const TASK_QUEUE: u8 = 21;
82}
83
84#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Default)]
85#[repr(transparent)]
86pub struct SlotIndex(u32);
87
88impl SlotIndex {
89    pub const fn new(raw: u32) -> Self {
90        Self(raw)
91    }
92
93    pub const fn raw(self) -> u32 {
94        self.0
95    }
96}
97
98#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Default)]
99#[repr(transparent)]
100pub struct Epoch(u32);
101
102impl Epoch {
103    pub const INITIAL: Self = Self(1);
104    pub const MAX: Self = Self(EPOCH_MASK as u32);
105    pub const ZERO: Self = Self(0);
106
107    pub const fn new(raw: u32) -> Option<Self> {
108        if raw <= EPOCH_MASK as u32 {
109            Some(Self(raw))
110        } else {
111            None
112        }
113    }
114
115    pub const fn raw(self) -> u32 {
116        self.0
117    }
118
119    pub const fn next(self) -> Option<Self> {
120        if self.0 < EPOCH_MASK as u32 {
121            Some(Self(self.0 + 1))
122        } else {
123            None
124        }
125    }
126}
127
128#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
129#[repr(transparent)]
130pub struct Token(NonZeroU64, PhantomData<*mut ()>);
131
132impl Token {
133    pub const fn new(route: u8, slot: SlotIndex, epoch: Epoch) -> Self {
134        assert!((slot.0 as u64) <= SLOT_MASK, "dope: token slot overflow");
135        assert!((epoch.0 as u64) <= EPOCH_MASK, "dope: token epoch overflow");
136        let raw = ((route as u64) << ROUTE_SHIFT)
137            | ((epoch.0 as u64) << EPOCH_SHIFT)
138            | (slot.0 as u64 & SLOT_MASK);
139        Self::from_nonzero(raw)
140    }
141
142    pub const fn with_kind(self, kind: u8) -> Self {
143        let cleared = self.0.get() & !((0xFFu64) << KIND_SHIFT);
144        Self::from_nonzero(cleared | ((kind as u64) << KIND_SHIFT))
145    }
146
147    const fn from_nonzero(raw: u64) -> Self {
148        assert!(
149            raw != 0,
150            "dope: token requires a nonzero route, slot, or epoch"
151        );
152        Self(unsafe { NonZeroU64::new_unchecked(raw) }, PhantomData)
153    }
154
155    pub const fn try_from_raw(raw: u64) -> Option<Self> {
156        match NonZeroU64::new(raw) {
157            Some(v) => Some(Self(v, PhantomData)),
158            None => None,
159        }
160    }
161
162    pub const fn raw(self) -> u64 {
163        self.0.get()
164    }
165
166    pub const fn route(self) -> u8 {
167        (self.0.get() >> ROUTE_SHIFT) as u8
168    }
169
170    pub const fn kind(self) -> u8 {
171        ((self.0.get() & KIND_MASK) >> KIND_SHIFT) as u8
172    }
173
174    pub const fn slot(self) -> SlotIndex {
175        SlotIndex((self.0.get() & SLOT_MASK) as u32)
176    }
177
178    pub const fn epoch(self) -> Epoch {
179        Epoch(((self.0.get() >> EPOCH_SHIFT) & EPOCH_MASK) as u32)
180    }
181
182    pub const fn same_target(self, other: Self) -> bool {
183        self.0.get() & !KIND_MASK == other.0.get() & !KIND_MASK
184    }
185
186    #[allow(private_bounds)]
187    pub const fn parts<Tag: TokenTag>(self) -> Option<KeyParts<Tag>> {
188        if self.raw() & Tag::MASK != Tag::VALUE {
189            return None;
190        }
191        match SlabKeyParts::new(self.slot().raw(), self.epoch().raw()) {
192            Some(parts) => Some(KeyParts {
193                parts,
194                tag: PhantomData,
195            }),
196            None => None,
197        }
198    }
199
200    #[allow(private_bounds)]
201    pub const fn from_key<Tag: TokenTag>(key: Key<Tag>) -> Self {
202        Self::new(
203            Tag::ROUTE,
204            SlotIndex::new(key.index()),
205            Epoch(key.generation().get()),
206        )
207        .with_kind(Tag::KIND)
208    }
209}
210
211pub const SHUTDOWN: Token =
212    Token::new(ROUTE_FRAMEWORK, SlotIndex::new(0), Epoch::ZERO).with_kind(kind::SHUTDOWN);