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#[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
59pub 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
81unsafe 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 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 pub unsafe fn target(self) -> route::Target<'d, Tag> {
109 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 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};