Skip to main content

dope_core/driver/route/
raw.rs

1use core::{convert, mem, num};
2
3use o3::{
4    base::marker::ThreadBound,
5    depot,
6    depot::{
7        arena::slab::{
8            self, entries, external,
9            external::{errors, shared},
10            lookup,
11        },
12        capacity,
13        index::Initialized,
14    },
15};
16
17use crate::driver::{
18    route,
19    route::{indices, table},
20};
21
22/// Niche-backed target identity for unchecked keyed storage.
23#[derive(Clone, Copy)]
24#[repr(transparent)]
25pub struct Identity<'d, Tag: route::Tag>(Option<route::Target<'d, Tag>>);
26
27// SAFETY: every raw value through SLOT_MASK is one complete route slot;
28// scalar conversions are deterministic and cannot panic or reenter storage.
29unsafe impl depot::raw::Compact for indices::SlotIndex {
30    const MAX: u32 = route::SLOT_MASK as u32;
31
32    fn into_raw(self) -> u32 {
33        self.raw()
34    }
35
36    unsafe fn from_raw(raw: u32) -> Self {
37        indices::SlotIndex::from_field(u64::from(raw))
38    }
39}
40
41// SAFETY: every position admitted by Capacity fits the route slot encoding.
42unsafe impl depot::raw::Count<indices::SlotIndex> for table::Capacity {
43    fn count(self) -> capacity::Count {
44        self.count()
45    }
46}
47
48/// Raw consuming access to one shared route table.
49#[repr(transparent)]
50pub struct Cell<'a, T, Tag: route::Tag> {
51    inner: &'a shared::Storage<T, route::Epoch, Tag>,
52}
53
54impl<'a, T, Tag: route::Tag> Cell<'a, T, Tag> {
55    pub(in crate::driver::route) const fn new(
56        inner: &'a shared::Storage<T, route::Epoch, Tag>,
57    ) -> Self {
58        Self { inner }
59    }
60}
61
62type Allocation<'a, T, Tag> = depot::raw::Proof<
63    (&'a shared::Storage<T, route::Epoch, Tag>, u32),
64    Initialized<entries::Allocated>,
65>;
66
67type Vacancy<'a, T, Tag> = external::Vacant<
68    entries::Pending<
69        'a,
70        external::Stamped<T, route::Epoch>,
71        { u32::MAX },
72        entries::Interior<true>,
73        1,
74    >,
75    Tag,
76    true,
77    route::Epoch,
78>;
79
80/// A position admitted in the retained route storage allocation.
81pub struct Slot<'a, T, Tag: route::Tag>(Allocation<'a, T, Tag>);
82
83impl<'a, T, Tag: route::Tag> Slot<'a, T, Tag> {
84    pub fn vacancy(self) -> Result<Vacancy<'a, T, Tag>, slab::Vacancy> {
85        self.0.vacancy()
86    }
87
88    pub fn try_entry(
89        self,
90    ) -> Result<table::Current<'a, T, Tag>, lookup::Error<(), convert::Infallible>> {
91        Ok(table::Current::new(self.0.try_entry()?))
92    }
93
94    pub fn try_key(
95        self,
96        epoch: route::Epoch,
97    ) -> Result<table::Current<'a, T, Tag>, errors::Lookup<route::Epoch, Tag, ()>> {
98        Ok(table::Current::new(self.0.try_key(epoch)?))
99    }
100}
101
102// SAFETY: this projects the exact retained route table's allocated position.
103unsafe impl<'a, T, Tag: route::Tag> depot::raw::Project<indices::SlotIndex, entries::Allocated>
104    for Cell<'a, T, Tag>
105{
106    type Output = Slot<'a, T, Tag>;
107
108    unsafe fn project(self, index: indices::SlotIndex) -> Self::Output {
109        // SAFETY: the consumed proof retains this identical backing allocation.
110        let live = unsafe { depot::raw::Proof::new((self.inner, index.raw())) };
111        Slot(live.into())
112    }
113}
114
115impl<'d, Tag: route::Tag> Identity<'d, Tag> {
116    pub const VACANT: Self = Self(None);
117
118    pub const fn from_target(target: route::Target<'d, Tag>) -> Self {
119        Self(Some(target))
120    }
121
122    pub fn into_target(self) -> Option<route::Target<'d, Tag>> {
123        self.0
124    }
125
126    /// Reconstructs the exact target retained by a live identity.
127    /// # Safety
128    /// This identity must have been produced by [`Self::from_target`].
129    pub unsafe fn target(self) -> route::Target<'d, Tag> {
130        // SAFETY: the caller proves the niche is occupied by an exact Target.
131        unsafe { mem::transmute(self.0) }
132    }
133}
134
135impl<Tag: route::Tag> PartialEq for Identity<'_, Tag> {
136    fn eq(&self, other: &Self) -> bool {
137        self.0 == other.0
138    }
139}
140
141impl<Tag: route::Tag> Eq for Identity<'_, Tag> {}
142
143#[derive(Clone, Copy)]
144#[repr(transparent)]
145pub(crate) struct Auxiliary(u32);
146
147impl Auxiliary {
148    pub(crate) const fn from_meta(meta: u64) -> Self {
149        Self(((meta & route::AUX_MASK) >> route::AUX_SHIFT) as u32)
150    }
151
152    pub(crate) const fn with_bits(self, mask: u8, value: u8) -> Self {
153        let mask = mask as u32;
154        Self((self.0 & !mask) | (value as u32 & mask))
155    }
156
157    pub(crate) const fn raw(self) -> u32 {
158        self.0
159    }
160}
161
162impl From<u8> for Auxiliary {
163    fn from(raw: u8) -> Self {
164        Self(u32::from(raw))
165    }
166}
167
168#[derive(Clone, Copy)]
169#[repr(C)]
170pub(crate) struct Packed {
171    identity: num::NonZero<u64>,
172    thread: ThreadBound,
173    meta: u64,
174}
175
176impl Packed {
177    pub(crate) const fn new(token: route::Token, aux: Auxiliary) -> Self {
178        let route::Token {
179            epoch,
180            thread,
181            meta,
182        } = token;
183        Self {
184            identity: epoch,
185            thread,
186            meta: (meta & !route::AUX_MASK) | ((aux.raw() as u64) << route::AUX_SHIFT),
187        }
188    }
189
190    pub(crate) const fn words(self) -> [u64; 2] {
191        [self.identity.get(), self.meta]
192    }
193
194    pub(crate) const fn from_words(
195        identity: num::NonZero<u64>,
196        meta: u64,
197        thread: ThreadBound,
198    ) -> Self {
199        Self {
200            identity,
201            thread,
202            meta,
203        }
204    }
205
206    /// # Safety
207    /// `words` must have been written by [`Self::words`] for a dispatch payload.
208    pub(crate) const unsafe fn restore(words: [u64; 2], thread: ThreadBound) -> Self {
209        Self::from_words(
210            unsafe { num::NonZero::<u64>::new_unchecked(words[0]) },
211            words[1],
212            thread,
213        )
214    }
215
216    pub(crate) const fn target(self) -> route::Token {
217        route::Token {
218            epoch: self.identity,
219            thread: self.thread,
220            meta: self.meta & !route::AUX_MASK,
221        }
222    }
223}
224
225const _: () = {
226    assert!(
227        mem::size_of::<Identity<'static, route::KeyTag<1>>>()
228            == mem::size_of::<route::Target<'static, route::KeyTag<1>>>()
229    );
230    assert!(
231        mem::align_of::<Identity<'static, route::KeyTag<1>>>()
232            == mem::align_of::<route::Target<'static, route::KeyTag<1>>>()
233    );
234    assert!(
235        mem::size_of::<Identity<'static, route::KeyTag<1>>>() == mem::size_of::<route::Token>()
236    );
237    assert!(
238        mem::align_of::<Identity<'static, route::KeyTag<1>>>() == mem::align_of::<route::Token>()
239    );
240    assert!(mem::size_of::<Auxiliary>() == mem::size_of::<u32>());
241    assert!(mem::size_of::<Packed>() == 2 * mem::size_of::<u64>());
242    assert!(mem::align_of::<Packed>() == mem::align_of::<u64>());
243};