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