pui_vec/
lib.rs

1#![no_std]
2#![forbid(missing_docs, clippy::missing_safety_doc)]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4
5//! A append-only vector that uses `pui_core` to brand indicies
6//! to allow for unchecked indexing. (Note: `PuiVec` is only
7//! append-only if there is an associated `Identifier` attached)
8//!
9//! # Features
10//!
11//! `pui` (default) - this hooks into `pui_core` and provides a
12//! branded [`Id`] that can be used to elide bound checks.
13//!
14
15extern crate alloc as std;
16
17use core::ops::{Deref, DerefMut, Index, IndexMut};
18use std::vec::Vec;
19
20#[cfg(feature = "pui-core")]
21#[cfg_attr(docsrs, doc(cfg(feature = "pui")))]
22use pui_core::OneShotIdentifier;
23
24mod pui_vec_index;
25
26pub use pui_vec_index::{BuildPuiVecIndex, PuiVecAccess, PuiVecIndex};
27
28/// A branded index that can be used to elide bounds checks
29#[cfg(feature = "pui-core")]
30#[cfg_attr(docsrs, doc(cfg(feature = "pui")))]
31#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
32pub struct Id<T> {
33    index: usize,
34    token: T,
35}
36
37/// An append only `Vec` whitch returns branded indicies that
38/// can be used to elide bounds checks.
39#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
40pub struct PuiVec<T, I> {
41    ident: I,
42    vec: Vec<T>,
43}
44
45impl<T, I> From<PuiVec<T, I>> for Vec<T> {
46    fn from(pui_vec: PuiVec<T, I>) -> Self { pui_vec.vec }
47}
48
49#[cfg(feature = "pui-core")]
50#[cfg_attr(docsrs, doc(cfg(feature = "pui")))]
51impl<T> Id<T> {
52    /// Create a new branded index
53    ///
54    /// # Safety
55    ///
56    /// The given index must be in bounds for the `PuiVec` whose identifier owns
57    /// the given token
58    pub const unsafe fn new_unchecked(index: usize, token: T) -> Self { Self { index, token } }
59
60    /// Get the index and token from the branded index
61    pub fn into_raw_parts(self) -> (usize, T) { (self.index, self.token) }
62
63    /// Returns the index of this [`Id`]
64    pub const fn get(&self) -> usize { self.index }
65
66    /// Returns a reference to the token of this [`Id`]
67    pub const fn token(&self) -> &T { &self.token }
68}
69
70impl<T, I> PuiVec<T, I> {
71    /// Creates a new `PuiVec` with the given identifier
72    pub const fn new(ident: I) -> Self { Self::from_raw_parts(Vec::new(), ident) }
73
74    /// Creates a new `PuiVec` with the given identifier and `Vec`
75    pub const fn from_raw_parts(vec: Vec<T>, ident: I) -> Self { Self { vec, ident } }
76
77    /// Returns a reference to the underlying identifier
78    pub const fn ident(&self) -> &I { &self.ident }
79
80    /// Returns true if this `PuiVec` is empty
81    pub fn is_empty(&self) -> bool { self.vec.is_empty() }
82
83    /// Returns the length of this `PuiVec`
84    pub fn len(&self) -> usize { self.vec.len() }
85
86    /// Returns the capacity of this `PuiVec`
87    pub fn capacity(&self) -> usize { self.vec.capacity() }
88
89    /// Reserves capacity for at least additional more elements to be inserted
90    /// in the given collection. The collection may reserve more space to avoid
91    /// frequent reallocations. After calling reserve, capacity will be greater
92    /// than or equal to `self.len() + additional`. Does nothing if capacity is
93    /// already sufficient.
94    pub fn reserve(&mut self, additional: usize) { self.vec.reserve(additional) }
95
96    /// Reserves the minimum capacity for exactly additional more elements
97    /// to be inserted in the given collection. After calling reserve_exact,
98    /// capacity will be greater than or equal to `self.len() + additional`.
99    /// Does nothing if the capacity is already sufficient.
100    ///
101    /// Note that the allocator may give the collection more space than it
102    /// requests. Therefore, capacity can not be relied upon to be precisely
103    /// minimal. Prefer reserve if future insertions are expected.
104    pub fn reserve_exact(&mut self, additional: usize) { self.vec.reserve_exact(additional) }
105
106    /// Returns a reference to an element or subslice depending on the type of index.
107    ///
108    /// * If given a position, returns a reference to the element at that position or None if out of bounds.
109    /// * If given a range, returns the subslice corresponding to that range, or None if out of bounds.
110    /// * If given a Id, returns a reference to the element at that position
111    /// * If given a range of Id, returns a the subslice corresponding to that range
112    pub fn get<A: PuiVecAccess<T, I>>(&self, index: A) -> Option<&A::Output> { index.get(self) }
113
114    /// Returns a mutable reference to an element or subslice depending on the type of index.
115    /// See [`get`](PuiVec::get) for details
116    pub fn get_mut<A: PuiVecAccess<T, I>>(&mut self, index: A) -> Option<&mut A::Output> { index.get_mut(self) }
117
118    /// Returns a reference to the identifier and a mutable reference to the underlying slice
119    pub fn as_mut_parts(&mut self) -> (&I, &mut [T]) { (&self.ident, &mut self.vec) }
120
121    /// Decomposes `PuiVec` into a it's identifier and it's underling `Vec`
122    ///
123    /// # Safety
124    ///
125    /// The identifier can't be used to create a new `PuiVec`
126    pub unsafe fn into_raw_parts(self) -> (I, Vec<T>) { (self.ident, self.vec) }
127}
128
129// This is safe because `(): !Identifier`, so you can't create a corrosponding `Id`.
130// Which means there are is no safe unchecked accesses to the `Vec`
131impl<T> PuiVec<T, ()> {
132    /// Get a mutable reference to the underling `Vec`
133    pub fn vec_mut(&mut self) -> &mut Vec<T> { &mut self.vec }
134}
135
136impl<T, I> PuiVec<T, I> {
137    /// Appends an element to the back of a collection.
138    ///
139    /// Returns an [`Id`] or [`usize`]
140    pub fn push<Id: BuildPuiVecIndex<I, SliceIndex = usize>>(&mut self, value: T) -> Id {
141        let index = self.vec.len();
142
143        self.vec.push(value);
144
145        unsafe { Id::new_unchecked(index, &self.ident) }
146    }
147
148    /// Moves all the elements of `other` into `Self`, leaving `other` empty.
149    pub fn append(&mut self, vec: &mut Vec<T>) { self.vec.append(vec); }
150
151    /// Clones and appends all elements in a slice to the `PuiVec`.
152    ///
153    /// Iterates over the slice other, clones each element, and
154    /// then appends it to this Vec. The other vector is traversed in-order.
155    ///
156    /// Note that this function is same as extend except that it
157    /// is specialized to work with slices instead. If and when
158    /// Rust gets specialization this function will likely be
159    /// deprecated (but still available).
160    pub fn extend_from_slice(&mut self, slice: &[T])
161    where
162        T: Clone,
163    {
164        self.vec.extend_from_slice(slice);
165    }
166}
167
168// TODO - move `swap`, `split_at`, and `split_at_mut` out to be based on `PuiVecIndex`
169#[cfg(feature = "pui-core")]
170#[cfg_attr(docsrs, doc(cfg(feature = "pui")))]
171impl<T, I: OneShotIdentifier> PuiVec<T, I> {
172    /// Returns an iterator over all the ids in the `PuiVec`
173    pub fn ids(&self) -> impl ExactSizeIterator<Item = Id<I::Token>> + Clone {
174        let token = self.ident.token();
175        (0..self.len()).map(move |index| Id {
176            index,
177            token: token.clone(),
178        })
179    }
180
181    /// check if the `index` is in bounds, and if it is,
182    /// return the corrosponding `Id`
183    pub fn parse_id(&self, index: usize) -> Option<Id<I::Token>> {
184        if index < self.len() {
185            Some(Id {
186                index,
187                token: self.ident.token(),
188            })
189        } else {
190            None
191        }
192    }
193
194    /// swap two elements, while eliding bounds checks
195    pub fn swap(&mut self, a: Id<I::Token>, b: Id<I::Token>) {
196        assert!(self.ident.owns_token(&a.token) && self.ident.owns_token(&b.token));
197
198        let ptr = self.vec.as_mut_ptr();
199        unsafe { ptr.add(a.index).swap(ptr.add(b.index)) }
200    }
201
202    /// Divides the `PuiVec` into two slices at an index, while eliding bounds checks.
203    ///
204    /// The first will contain all indices from [0, mid)
205    /// (excluding the index mid itself) and the second
206    /// will contain all indices from [mid, len)
207    /// (excluding the index len itself).
208    pub fn split_at(&self, mid: Id<I::Token>) -> (&[T], &[T]) {
209        assert!(self.ident.owns_token(&mid.token));
210        let len = self.len();
211        let ptr = self.vec.as_ptr();
212        unsafe {
213            (
214                core::slice::from_raw_parts(ptr, mid.index),
215                core::slice::from_raw_parts(ptr.add(mid.index), len - mid.index),
216            )
217        }
218    }
219
220    /// Divides the `PuiVec` into two slices at an index, while eliding bounds checks.
221    ///
222    /// The first will contain all indices from [0, mid)
223    /// (excluding the index mid itself) and the second
224    /// will contain all indices from [mid, len)
225    /// (excluding the index len itself).
226    pub fn split_at_mut(&mut self, id: Id<I::Token>) -> (&mut [T], &mut [T]) {
227        assert!(self.ident.owns_token(&id.token));
228        let len = self.len();
229        let ptr = self.vec.as_mut_ptr();
230        unsafe {
231            (
232                core::slice::from_raw_parts_mut(ptr, id.index),
233                core::slice::from_raw_parts_mut(ptr.add(id.index), len - id.index),
234            )
235        }
236    }
237}
238
239impl<T, I> IntoIterator for PuiVec<T, I> {
240    type Item = T;
241    type IntoIter = std::vec::IntoIter<T>;
242
243    fn into_iter(self) -> Self::IntoIter { self.vec.into_iter() }
244}
245
246impl<A, T, I> Extend<A> for PuiVec<T, I>
247where
248    Vec<T>: Extend<A>,
249{
250    fn extend<Iter: IntoIterator<Item = A>>(&mut self, iter: Iter) { self.vec.extend(iter) }
251}
252
253impl<T, I, A> Index<A> for PuiVec<T, I>
254where
255    A: PuiVecAccess<T, I>,
256{
257    type Output = A::Output;
258
259    fn index(&self, index: A) -> &Self::Output { index.index(self) }
260}
261
262impl<T, I, A> IndexMut<A> for PuiVec<T, I>
263where
264    A: PuiVecAccess<T, I>,
265{
266    fn index_mut(&mut self, index: A) -> &mut Self::Output { index.index_mut(self) }
267}
268
269impl<T, I> Deref for PuiVec<T, I> {
270    type Target = [T];
271
272    fn deref(&self) -> &Self::Target { &self.vec }
273}
274
275impl<T, I> DerefMut for PuiVec<T, I> {
276    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.vec }
277}