crabslab/
array.rs

1//! A slab-allocated array.
2use core::marker::PhantomData;
3
4use crate::{id::Id, slab::SlabItem};
5
6/// Iterator over [`Id`]s in an [`Array`].
7#[derive(Clone, Copy)]
8pub struct ArrayIter<T> {
9    array: Array<T>,
10    index: usize,
11}
12
13impl<T: SlabItem> Iterator for ArrayIter<T> {
14    type Item = Id<T>;
15
16    fn next(&mut self) -> Option<Self::Item> {
17        if self.index >= self.array.len() {
18            None
19        } else {
20            let id = self.array.at(self.index);
21            self.index += 1;
22            Some(id)
23        }
24    }
25}
26
27/// A pointer to contiguous `T` elements in a slab.
28///
29/// ```rust
30/// use crabslab::{Array, CpuSlab, GrowableSlab, Id, Slab, SlabItem};
31///
32/// let ints = [1, 2, 3, 4, 5u32];
33/// let mut slab = CpuSlab::new(vec![]);
34/// let array = slab.append_array(&ints);
35/// for (i, id) in array.iter().enumerate() {
36///     let value = slab.read(id);
37///     assert_eq!(ints[i], value);
38/// }
39/// ```
40#[repr(C)]
41pub struct Array<T> {
42    // u32 offset in the slab
43    pub index: u32,
44    // number of `T` elements in the array
45    pub len: u32,
46    _phantom: PhantomData<T>,
47}
48
49impl<T> Clone for Array<T> {
50    fn clone(&self) -> Self {
51        *self
52    }
53}
54
55impl<T> Copy for Array<T> {}
56
57/// An `Id<T>` is an `Array<T>` with a length of 1.
58impl<T> From<Id<T>> for Array<T> {
59    fn from(id: Id<T>) -> Self {
60        Self {
61            index: id.inner(),
62            len: 1,
63            _phantom: PhantomData,
64        }
65    }
66}
67
68impl<T> core::fmt::Debug for Array<T> {
69    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
70        if self.is_null() {
71            f.write_fmt(core::format_args!(
72                "Array<{}>(null)",
73                core::any::type_name::<T>()
74            ))
75        } else {
76            f.write_fmt(core::format_args!(
77                "Array<{}>({}, {})",
78                core::any::type_name::<T>(),
79                self.index,
80                self.len
81            ))
82        }
83    }
84}
85
86impl<T> PartialEq for Array<T> {
87    fn eq(&self, other: &Self) -> bool {
88        self.index == other.index && self.len == other.len
89    }
90}
91
92impl<T: SlabItem> SlabItem for Array<T> {
93    const SLAB_SIZE: usize = 2;
94
95    fn write_slab(&self, index: usize, slab: &mut [u32]) -> usize {
96        let index = self.index.write_slab(index, slab);
97        self.len.write_slab(index, slab)
98    }
99
100    fn read_slab(index: usize, slab: &[u32]) -> Self {
101        let start = u32::read_slab(index, slab);
102        let len = u32::read_slab(index + 1, slab);
103        Array::new(start, len)
104    }
105}
106
107impl<T: SlabItem> Default for Array<T> {
108    fn default() -> Self {
109        Array::NONE
110    }
111}
112
113impl<T> Array<T> {
114    pub const NONE: Self = Array::new(u32::MAX, 0);
115
116    pub const fn new(index: u32, len: u32) -> Self {
117        Self {
118            index,
119            len,
120            _phantom: PhantomData,
121        }
122    }
123
124    pub fn len(&self) -> usize {
125        self.len as usize
126    }
127
128    pub fn is_empty(&self) -> bool {
129        self.len == 0
130    }
131
132    pub fn is_null(&self) -> bool {
133        self.index == u32::MAX
134    }
135
136    pub fn contains_index(&self, index: usize) -> bool {
137        index >= self.index as usize && index < (self.index + self.len) as usize
138    }
139
140    pub fn at(&self, index: usize) -> Id<T>
141    where
142        T: SlabItem,
143    {
144        if index >= self.len() {
145            Id::NONE
146        } else {
147            Id::new(self.index + (T::SLAB_SIZE * index) as u32)
148        }
149    }
150
151    pub fn starting_index(&self) -> usize {
152        self.index as usize
153    }
154
155    pub fn iter(&self) -> ArrayIter<T> {
156        ArrayIter {
157            array: *self,
158            index: 0,
159        }
160    }
161
162    /// Convert this array into a `u32` array.
163    pub fn into_u32_array(self) -> Array<u32>
164    where
165        T: SlabItem,
166    {
167        Array {
168            index: self.index,
169            len: self.len * T::SLAB_SIZE as u32,
170            _phantom: PhantomData,
171        }
172    }
173
174    #[cfg(not(target_arch = "spirv"))]
175    /// Return the slice of the slab that this array represents.
176    pub fn sub_slab<'a>(&'a self, slab: &'a [u32]) -> &'a [u32]
177    where
178        T: SlabItem,
179    {
180        let arr = self.into_u32_array();
181        &slab[arr.index as usize..(arr.index + arr.len) as usize]
182    }
183}
184
185impl Array<u32> {
186    pub fn union(&mut self, other: &Array<u32>) {
187        let start = self.index.min(other.index);
188        let end = (self.index + self.len).max(other.index + other.len);
189        self.index = start;
190        self.len = end - start;
191    }
192}