Skip to main content

dope_core/driver/route/
sealed.rs

1use core::{marker, mem, num};
2
3use o3::{collections::slab::external, num::bounded};
4
5use crate::driver::route::{self, table};
6
7#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
8#[repr(C)]
9pub struct Token {
10    epoch: num::NonZeroU64,
11    meta: u64,
12    marker: marker::PhantomData<*mut ()>,
13}
14
15pub trait Private {}
16
17#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
18#[repr(transparent)]
19pub struct SlotIndex(BoundedSlotIndex);
20
21type BoundedSlotIndex = bounded::U32<0, { route::SLOT_MASK as u32 }>;
22
23impl SlotIndex {
24    pub const ZERO: Self = Self(BoundedSlotIndex::clamp_from_usize(0));
25
26    pub const fn try_new(raw: u32) -> Option<Self> {
27        match BoundedSlotIndex::new(raw) {
28            Some(raw) => Some(Self(raw)),
29            None => None,
30        }
31    }
32
33    pub(crate) const fn from_bounded(raw: u32) -> Self {
34        debug_assert!((raw as u64) <= route::SLOT_MASK);
35        Self(BoundedSlotIndex::clamp_from_usize(raw as usize))
36    }
37
38    pub const fn raw(self) -> u32 {
39        self.0.get()
40    }
41}
42
43impl Default for SlotIndex {
44    fn default() -> Self {
45        Self::ZERO
46    }
47}
48
49impl From<u16> for SlotIndex {
50    fn from(raw: u16) -> Self {
51        Self::from_bounded(raw as u32)
52    }
53}
54
55#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
56#[repr(transparent)]
57pub struct Epoch(BoundedEpoch, marker::PhantomData<*mut ()>);
58
59type BoundedEpoch = num::NonZeroU64;
60
61impl Epoch {
62    pub const INITIAL: Self = Self(BoundedEpoch::MIN, marker::PhantomData);
63
64    pub const fn new(raw: u64) -> Option<Self> {
65        match BoundedEpoch::new(raw) {
66            Some(_) if raw > route::EPOCH_MASK => None,
67            Some(epoch) => Some(Self(epoch, marker::PhantomData)),
68            None => None,
69        }
70    }
71
72    pub const fn raw(self) -> u64 {
73        self.0.get()
74    }
75
76    pub const fn next(self) -> Option<Self> {
77        match self.raw().checked_add(1) {
78            Some(raw) => Self::new(raw),
79            None => None,
80        }
81    }
82}
83
84impl From<num::NonZeroU16> for Epoch {
85    fn from(raw: num::NonZeroU16) -> Self {
86        Self(raw.into(), marker::PhantomData)
87    }
88}
89
90impl external::Generation for Epoch {
91    const INITIAL: Self = Self::INITIAL;
92
93    fn next(self) -> Option<Self> {
94        match self.raw().checked_add(1) {
95            Some(raw) => Self::new(raw),
96            None => None,
97        }
98    }
99}
100
101const _: () = {
102    assert!(mem::size_of::<SlotIndex>() == mem::size_of::<u32>());
103    assert!(mem::size_of::<Epoch>() == mem::size_of::<u64>());
104    assert!(mem::size_of::<Option<Epoch>>() == mem::size_of::<u64>());
105};
106
107impl Token {
108    pub const fn new(route: u8, slot: route::SlotIndex, epoch: route::Epoch) -> Self {
109        Self::from_components(route, 0, slot, epoch.raw())
110    }
111
112    pub const fn framework(slot: route::SlotIndex) -> Self {
113        Self::from_components(route::FRAMEWORK, 0, slot, 0)
114    }
115
116    pub const fn with_kind(self, kind: u8) -> Self {
117        Self {
118            meta: (self.meta & !(0xFF << route::KIND_SHIFT)) | ((kind as u64) << route::KIND_SHIFT),
119            ..self
120        }
121    }
122
123    const fn from_components(route: u8, kind: u8, slot: route::SlotIndex, epoch: u64) -> Self {
124        debug_assert!(epoch <= route::EPOCH_MASK);
125        Self {
126            epoch: unsafe { num::NonZeroU64::new_unchecked(epoch + 1) },
127            meta: ((route as u64) << route::SHIFT)
128                | ((kind as u64) << route::KIND_SHIFT)
129                | slot.raw() as u64,
130            marker: marker::PhantomData,
131        }
132    }
133
134    pub(crate) const fn try_from_framework_raw(raw: u64) -> Option<Self> {
135        if raw == 0 {
136            return None;
137        }
138        let route = (raw >> route::SHIFT) as u8;
139        let kind = (raw >> route::KIND_SHIFT) as u8;
140        match route::SlotIndex::try_new((raw & route::SLOT_MASK) as u32) {
141            Some(slot) => Some(Self::from_components(route, kind, slot, 0)),
142            None => None,
143        }
144    }
145
146    pub(crate) const fn framework_raw(self) -> u64 {
147        debug_assert!(self.epoch_raw() == 0);
148        self.meta
149    }
150
151    pub const fn route(self) -> u8 {
152        (self.meta >> route::SHIFT) as u8
153    }
154
155    pub const fn kind(self) -> u8 {
156        (self.meta >> route::KIND_SHIFT) as u8
157    }
158
159    pub const fn slot(self) -> route::SlotIndex {
160        route::SlotIndex::from_bounded((self.meta & route::SLOT_MASK) as u32)
161    }
162
163    pub const fn epoch(self) -> Option<route::Epoch> {
164        route::Epoch::new(self.epoch_raw())
165    }
166
167    pub const fn epoch_raw(self) -> u64 {
168        self.epoch.get() - 1
169    }
170
171    pub const fn same_target(self, other: Self) -> bool {
172        self.epoch.get() == other.epoch.get()
173            && self.route() == other.route()
174            && self.slot().raw() == other.slot().raw()
175    }
176
177    pub const fn parts<Tag: route::Tag>(self) -> Option<table::Parts<Tag>> {
178        if self.route() != Tag::ROUTE || (Tag::KIND != 0 && self.kind() != Tag::KIND) {
179            return None;
180        }
181        table::Parts::new(self.slot().raw(), self.epoch_raw())
182    }
183
184    pub const fn from_key<Tag: route::Tag>(key: table::Key<Tag>) -> Self {
185        Self::from_components(Tag::ROUTE, Tag::KIND, key.slot(), key.epoch().raw())
186    }
187
188    pub const fn from_target<Tag: route::Tag>(target: route::Target<'_, Tag>) -> Self {
189        Self::from_parts(target.parts())
190    }
191
192    #[doc(hidden)]
193    pub const fn from_parts<Tag: route::Tag>(parts: table::Parts<Tag>) -> Self {
194        Self::from_components(Tag::ROUTE, Tag::KIND, parts.slot(), parts.epoch().raw())
195    }
196}
197
198impl<Tag: route::Tag> From<route::Target<'_, Tag>> for Token {
199    fn from(target: route::Target<'_, Tag>) -> Self {
200        Self::from_target(target)
201    }
202}