dope_core/driver/route/
sealed.rs1use 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}