Skip to main content

dope_core/driver/route/table/
borrows.rs

1use external::errors;
2use o3::depot::{
3    arena::slab::{self, external},
4    capacity,
5};
6use table::entries::{occupied, vacant};
7
8use crate::driver::{
9    route,
10    route::{indices, table, table::conn},
11};
12
13#[repr(transparent)]
14pub struct View<'a, T, Tag: route::Tag> {
15    inner: &'a table::Storage<T, Tag>,
16}
17
18impl<'a, T, Tag: route::Tag> View<'a, T, Tag> {
19    pub(in crate::driver::route::table) fn new(inner: &'a table::Storage<T, Tag>) -> Self {
20        Self { inner }
21    }
22
23    /// Returns the immutable extent admitted when this route table was allocated.
24    pub fn capacity(&self) -> table::Capacity {
25        table::Capacity(self.inner.capacity())
26    }
27
28    pub fn len(&self) -> capacity::Count {
29        self.inner.len()
30    }
31
32    /// Returns the exact number of vacant slots in this table snapshot.
33    pub fn available(&self) -> capacity::Count {
34        let total = self.inner.capacity();
35        let occupied = self.inner.len();
36        capacity::Count::new(total.raw() - occupied.raw())
37    }
38
39    pub fn is_empty(&self) -> bool {
40        self.inner.is_empty()
41    }
42
43    pub fn get(self, parts: table::Parts<Tag>) -> Option<&'a T> {
44        self.inner.get(parts.external())
45    }
46
47    pub fn contains(self, parts: table::Parts<Tag>) -> bool {
48        self.inner.get(parts.external()).is_some()
49    }
50
51    pub fn key_at(self, slot: indices::SlotIndex) -> Option<table::Key<Tag>> {
52        self.inner.key_at(slot.raw()).map(table::Key::new)
53    }
54}
55
56#[repr(transparent)]
57pub struct Access<'a, T, Tag: route::Tag>(&'a mut table::Storage<T, Tag>);
58
59impl<'a, T, Tag: route::Tag> Access<'a, T, Tag> {
60    pub(in crate::driver::route::table) fn new(inner: &'a mut table::Storage<T, Tag>) -> Self {
61        Self(inner)
62    }
63
64    pub fn get(self, parts: table::Parts<Tag>) -> Option<&'a mut T> {
65        self.0.get_mut(parts.external())
66    }
67
68    pub fn occupied(self, parts: table::Parts<Tag>) -> Option<occupied::Entry<'a, T, Tag>> {
69        self.0.occupied(parts.external()).map(occupied::Entry::new)
70    }
71
72    pub fn try_occupied(
73        self,
74        parts: table::Parts<Tag>,
75    ) -> Result<occupied::Entry<'a, T, Tag>, errors::Lookup<route::Epoch, Tag>> {
76        let entry = self.0.try_occupied(parts.external())?;
77        Ok(occupied::Entry::new(entry))
78    }
79
80    /// Borrows the current owner directly from this table's physical slot.
81    pub fn at(self, index: indices::SlotIndex) -> Option<occupied::Entry<'a, T, Tag>> {
82        self.0.occupied_at(index.raw()).map(occupied::Entry::new)
83    }
84}
85
86#[repr(transparent)]
87pub struct Grant<'a, T, Tag: route::Tag>(
88    external::Grant<'a, T, route::Epoch, Tag, { u32::MAX }, { table::PARTITIONS }>,
89);
90
91impl<'a, T, Tag: route::Tag> Grant<'a, T, Tag> {
92    fn new(
93        inner: external::Grant<'a, T, route::Epoch, Tag, { u32::MAX }, { table::PARTITIONS }>,
94    ) -> Self {
95        Self(inner)
96    }
97
98    pub fn reserve(self) -> vacant::Entry<'a, T, Tag> {
99        vacant::Entry::new(self.0.reserve())
100    }
101}
102
103#[repr(transparent)]
104pub struct Vacancy<'a, T, Tag: route::Tag>(&'a mut table::Storage<T, Tag>);
105
106impl<'a, T, Tag: route::Tag> Vacancy<'a, T, Tag> {
107    pub(in crate::driver::route::table) fn new(inner: &'a mut table::Storage<T, Tag>) -> Self {
108        Self(inner)
109    }
110
111    pub fn try_reserve(self) -> Result<vacant::Entry<'a, T, Tag>, slab::Vacancy> {
112        let grant = self.0.try_grant()?;
113        Ok(vacant::Entry::new(grant.reserve()))
114    }
115
116    pub fn try_at(self, slot: indices::SlotIndex) -> Result<Grant<'a, T, Tag>, slab::Vacancy> {
117        self.0.try_grant_at(slot.raw()).map(Grant::new)
118    }
119
120    pub fn try_head(self, capacity: conn::Capacity) -> Result<Grant<'a, T, Tag>, slab::Vacancy> {
121        self.0
122            .try_grant_in(0..capacity.count().get())
123            .map(Grant::new)
124    }
125
126    /// Selects physical capacity before identity, excluding one held slot.
127    pub fn try_except(
128        self,
129        capacity: conn::Capacity,
130        excluded: indices::SlotIndex,
131    ) -> Result<Grant<'a, T, Tag>, slab::Vacancy> {
132        self.0
133            .try_except(0..capacity.count().get(), excluded.raw())
134            .map(Grant::new)
135    }
136}