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#[derive(Clone, Copy)]
24#[repr(transparent)]
25pub struct Identity<'d, Tag: route::Tag>(Option<route::Target<'d, Tag>>);
26
27unsafe 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
41unsafe impl depot::raw::Count<indices::SlotIndex> for table::Capacity {
43 fn count(self) -> capacity::Count {
44 self.count()
45 }
46}
47
48#[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
72pub 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
94unsafe 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 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 pub unsafe fn target(self) -> route::Target<'d, Tag> {
122 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 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};