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    pub(in crate::driver::route) inner: &'a shared::Storage<T, route::Epoch, Tag>,
52}
53
54type Allocation<'a, T, Tag> = depot::raw::Proof<
55    (&'a shared::Storage<T, route::Epoch, Tag>, u32),
56    Initialized<entries::Allocated>,
57>;
58
59type Vacancy<'a, T, Tag> = external::Vacant<
60    entries::Pending<
61        'a,
62        external::Stamped<T, route::Epoch>,
63        { u32::MAX },
64        entries::Interior<true>,
65        1,
66    >,
67    Tag,
68    true,
69    route::Epoch,
70>;
71
72/// A position admitted in the retained route storage allocation.
73pub struct Slot<'a, T, Tag: route::Tag>(Allocation<'a, T, Tag>);
74
75impl<'a, T, Tag: route::Tag> Slot<'a, T, Tag> {
76    pub fn vacancy(self) -> Result<Vacancy<'a, T, Tag>, slab::Vacancy> {
77        self.0.vacancy()
78    }
79
80    pub fn try_entry(
81        self,
82    ) -> Result<table::Current<'a, T, Tag>, lookup::Error<(), convert::Infallible>> {
83        Ok(table::Current(self.0.try_entry()?))
84    }
85
86    pub fn try_key(
87        self,
88        epoch: route::Epoch,
89    ) -> Result<table::Current<'a, T, Tag>, errors::Lookup<route::Epoch, Tag, ()>> {
90        Ok(table::Current(self.0.try_key(epoch)?))
91    }
92}
93
94// SAFETY: this projects the exact retained route table's allocated position.
95unsafe impl<'a, T, Tag: route::Tag> depot::raw::Project<indices::SlotIndex, entries::Allocated>
96    for Cell<'a, T, Tag>
97{
98    type Output = Slot<'a, T, Tag>;
99
100    unsafe fn project(self, index: indices::SlotIndex) -> Self::Output {
101        // SAFETY: the consumed proof retains this identical backing allocation.
102        let live = unsafe { depot::raw::Proof::new((self.inner, index.raw())) };
103        Slot(live.into())
104    }
105}
106
107impl<'d, Tag: route::Tag> Identity<'d, Tag> {
108    pub const VACANT: Self = Self(None);
109
110    pub const fn from_target(target: route::Target<'d, Tag>) -> Self {
111        Self(Some(target))
112    }
113
114    pub fn into_target(self) -> Option<route::Target<'d, Tag>> {
115        self.0
116    }
117
118    /// Reconstructs the exact target retained by a live identity.
119    /// # Safety
120    /// This identity must have been produced by [`Self::from_target`].
121    pub unsafe fn target(self) -> route::Target<'d, Tag> {
122        // SAFETY: the caller proves the niche is occupied by an exact Target.
123        unsafe { mem::transmute(self.0) }
124    }
125}
126
127impl<Tag: route::Tag> PartialEq for Identity<'_, Tag> {
128    fn eq(&self, other: &Self) -> bool {
129        self.0 == other.0
130    }
131}
132
133impl<Tag: route::Tag> Eq for Identity<'_, Tag> {}
134
135#[derive(Clone, Copy)]
136#[repr(transparent)]
137pub(crate) struct Auxiliary(u32);
138
139impl Auxiliary {
140    pub(crate) const fn from_meta(meta: u64) -> Self {
141        Self(((meta & route::AUX_MASK) >> route::AUX_SHIFT) as u32)
142    }
143
144    pub(crate) const fn with_bits(self, mask: u8, value: u8) -> Self {
145        let mask = mask as u32;
146        Self((self.0 & !mask) | (value as u32 & mask))
147    }
148
149    pub(crate) const fn raw(self) -> u32 {
150        self.0
151    }
152}
153
154impl From<u8> for Auxiliary {
155    fn from(raw: u8) -> Self {
156        Self(u32::from(raw))
157    }
158}
159
160#[derive(Clone, Copy)]
161#[repr(C)]
162pub(crate) struct Packed {
163    identity: num::NonZero<u64>,
164    thread: ThreadBound,
165    meta: u64,
166}
167
168impl Packed {
169    pub(crate) const fn new(token: route::Token, aux: Auxiliary) -> Self {
170        let route::Token {
171            epoch,
172            thread,
173            meta,
174        } = token;
175        Self {
176            identity: epoch,
177            thread,
178            meta: (meta & !route::AUX_MASK) | ((aux.raw() as u64) << route::AUX_SHIFT),
179        }
180    }
181
182    pub(crate) const fn words(self) -> [u64; 2] {
183        [self.identity.get(), self.meta]
184    }
185
186    pub(crate) const fn from_words(
187        identity: num::NonZero<u64>,
188        meta: u64,
189        thread: ThreadBound,
190    ) -> Self {
191        Self {
192            identity,
193            thread,
194            meta,
195        }
196    }
197
198    /// # Safety
199    /// `words` must have been written by [`Self::words`] for a dispatch payload.
200    pub(crate) const unsafe fn restore(words: [u64; 2], thread: ThreadBound) -> Self {
201        Self::from_words(
202            unsafe { num::NonZero::<u64>::new_unchecked(words[0]) },
203            words[1],
204            thread,
205        )
206    }
207
208    pub(crate) const fn target(self) -> route::Token {
209        route::Token {
210            epoch: self.identity,
211            thread: self.thread,
212            meta: self.meta & !route::AUX_MASK,
213        }
214    }
215}
216
217const _: () = {
218    assert!(
219        mem::size_of::<Identity<'static, route::KeyTag<1>>>()
220            == mem::size_of::<route::Target<'static, route::KeyTag<1>>>()
221    );
222    assert!(
223        mem::align_of::<Identity<'static, route::KeyTag<1>>>()
224            == mem::align_of::<route::Target<'static, route::KeyTag<1>>>()
225    );
226    assert!(
227        mem::size_of::<Identity<'static, route::KeyTag<1>>>() == mem::size_of::<route::Token>()
228    );
229    assert!(
230        mem::align_of::<Identity<'static, route::KeyTag<1>>>() == mem::align_of::<route::Token>()
231    );
232    assert!(mem::size_of::<Auxiliary>() == mem::size_of::<u32>());
233    assert!(mem::size_of::<Packed>() == 2 * mem::size_of::<u64>());
234    assert!(mem::align_of::<Packed>() == mem::align_of::<u64>());
235};