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}