Skip to main content

dope_core/driver/route/table/
capacity.rs

1use std::num;
2
3use o3::{base::num::bounded, depot::capacity};
4
5use crate::driver::{
6    route,
7    route::{
8        indices,
9        table::{
10            Iter, bounds,
11            bounds::{Outside, Slot},
12        },
13    },
14};
15
16/// Maximum live slot count in one route table.
17#[derive(Clone, Copy, PartialEq, Eq, Debug)]
18#[repr(transparent)]
19pub struct Capacity(pub(in crate::driver) capacity::Count);
20
21impl Capacity {
22    /// Admits a nonempty table count while retaining its lower bound.
23    pub fn try_nonzero(
24        count: num::NonZero<u32>,
25    ) -> Result<bounded::NonZeroU32<1, { route::SLOT_MASK as u32 + 1 }>, super::Invalid> {
26        Self::try_from(count.get() as usize)?;
27        // SAFETY: the input retains nonzero and admission proved the unchanged upper bound.
28        Ok(unsafe { bounded::raw::NonZeroProof::assume(count) }.retain())
29    }
30
31    pub const fn count(self) -> capacity::Count {
32        self.0
33    }
34
35    pub(crate) const fn raw(self) -> u32 {
36        self.0.raw()
37    }
38
39    pub(crate) fn span(self) -> Option<num::NonZero<u32>> {
40        num::NonZero::<u32>::new(self.raw())
41    }
42
43    pub const fn contains(self, index: indices::SlotIndex) -> bool {
44        index.raw() < self.raw()
45    }
46
47    /// The following slot when it remains inside this table.
48    pub const fn next(self, index: indices::SlotIndex) -> Option<indices::SlotIndex> {
49        let raw = index.raw() + 1;
50        if raw < self.raw() {
51            Some(indices::SlotIndex::from_field(raw as u64))
52        } else {
53            None
54        }
55    }
56
57    pub const fn excludes(self, index: indices::SlotIndex) -> Option<bounds::Excluded> {
58        if self.contains(index) {
59            None
60        } else {
61            Some(bounds::Excluded::new(index, self))
62        }
63    }
64
65    pub fn slot(self, index: usize) -> Result<indices::SlotIndex, Slot> {
66        let slot = indices::SlotIndex::try_from(index).map_err(|outside| {
67            Slot::Abi(Outside::new(
68                outside.actual(),
69                route::SLOT_MASK as usize + 1,
70            ))
71        })?;
72        if self.contains(slot) {
73            Ok(slot)
74        } else {
75            Err(Slot::Capacity(Outside::new(index, self.raw() as usize)))
76        }
77    }
78}
79
80impl From<bounded::NonZeroU32<1, { route::SLOT_MASK as u32 + 1 }>> for Capacity {
81    fn from(count: bounded::NonZeroU32<1, { route::SLOT_MASK as u32 + 1 }>) -> Self {
82        Self(capacity::Count::new(count.get()))
83    }
84}
85
86impl TryFrom<usize> for Capacity {
87    type Error = super::Invalid;
88
89    fn try_from(actual: usize) -> Result<Self, Self::Error> {
90        let maximum = route::SLOT_MASK as usize + 1;
91        if actual > maximum {
92            return Err(super::Invalid::from_bounds(actual, 0, maximum));
93        }
94        Ok(Self(capacity::Count::new(actual as u32)))
95    }
96}
97
98impl IntoIterator for Capacity {
99    type Item = indices::SlotIndex;
100    type IntoIter = Iter;
101
102    fn into_iter(self) -> Self::IntoIter {
103        Iter(0..self.raw())
104    }
105}