1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#![no_std]
#![forbid(missing_docs, clippy::missing_safety_doc)]
#![cfg_attr(docsrs, feature(doc_cfg))]

//! A append-only vector that uses `pui_core` to brand indicies
//! to allow for unchecked indexing. (Note: `PuiVec` is only
//! append-only if there is an associated `Identifier` attached)
//!
//! # Features
//!
//! `pui` (default) - this hooks into `pui_core` and provides a
//! branded [`Id`] that can be used to elide bound checks.
//!

extern crate alloc as std;

use core::ops::{Deref, DerefMut, Index, IndexMut};
use std::vec::Vec;

#[cfg(feature = "pui-core")]
#[cfg_attr(docsrs, doc(cfg(feature = "pui")))]
use pui_core::OneShotIdentifier;

mod pui_vec_index;

pub use pui_vec_index::{BuildPuiVecIndex, PuiVecAccess, PuiVecIndex};

/// A branded index that can be used to elide bounds checks
#[cfg(feature = "pui-core")]
#[cfg_attr(docsrs, doc(cfg(feature = "pui")))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Id<T> {
    index: usize,
    token: T,
}

/// An append only `Vec` whitch returns branded indicies that
/// can be used to elide bounds checks.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct PuiVec<T, I> {
    ident: I,
    vec: Vec<T>,
}

impl<T, I> From<PuiVec<T, I>> for Vec<T> {
    fn from(pui_vec: PuiVec<T, I>) -> Self { pui_vec.vec }
}

#[cfg(feature = "pui-core")]
#[cfg_attr(docsrs, doc(cfg(feature = "pui")))]
impl<T> Id<T> {
    /// Create a new branded index
    ///
    /// # Safety
    ///
    /// The given index must be in bounds for the `PuiVec` whose identifier owns
    /// the given token
    pub const unsafe fn new_unchecked(index: usize, token: T) -> Self { Self { index, token } }

    /// Get the index and token from the branded index
    pub fn into_raw_parts(self) -> (usize, T) { (self.index, self.token) }

    /// Returns the index of this [`Id`]
    pub const fn get(&self) -> usize { self.index }

    /// Returns a reference to the token of this [`Id`]
    pub const fn token(&self) -> &T { &self.token }
}

impl<T, I> PuiVec<T, I> {
    /// Creates a new `PuiVec` with the given identifier
    pub const fn new(ident: I) -> Self { Self::from_raw_parts(Vec::new(), ident) }

    /// Creates a new `PuiVec` with the given identifier and `Vec`
    pub const fn from_raw_parts(vec: Vec<T>, ident: I) -> Self { Self { vec, ident } }

    /// Returns a reference to the underlying identifier
    pub const fn ident(&self) -> &I { &self.ident }

    /// Returns true if this `PuiVec` is empty
    pub fn is_empty(&self) -> bool { self.vec.is_empty() }

    /// Returns the length of this `PuiVec`
    pub fn len(&self) -> usize { self.vec.len() }

    /// Returns the capacity of this `PuiVec`
    pub fn capacity(&self) -> usize { self.vec.capacity() }

    /// Reserves capacity for at least additional more elements to be inserted
    /// in the given collection. The collection may reserve more space to avoid
    /// frequent reallocations. After calling reserve, capacity will be greater
    /// than or equal to `self.len() + additional`. Does nothing if capacity is
    /// already sufficient.
    pub fn reserve(&mut self, additional: usize) { self.vec.reserve(additional) }

    /// Reserves the minimum capacity for exactly additional more elements
    /// to be inserted in the given collection. After calling reserve_exact,
    /// capacity will be greater than or equal to `self.len() + additional`.
    /// Does nothing if the capacity is already sufficient.
    ///
    /// Note that the allocator may give the collection more space than it
    /// requests. Therefore, capacity can not be relied upon to be precisely
    /// minimal. Prefer reserve if future insertions are expected.
    pub fn reserve_exact(&mut self, additional: usize) { self.vec.reserve_exact(additional) }

    /// Returns a reference to an element or subslice depending on the type of index.
    ///
    /// * If given a position, returns a reference to the element at that position or None if out of bounds.
    /// * If given a range, returns the subslice corresponding to that range, or None if out of bounds.
    /// * If given a Id, returns a reference to the element at that position
    /// * If given a range of Id, returns a the subslice corresponding to that range
    pub fn get<A: PuiVecAccess<T, I>>(&self, index: A) -> Option<&A::Output> { index.get(self) }

    /// Returns a mutable reference to an element or subslice depending on the type of index.
    /// See [`get`](PuiVec::get) for details
    pub fn get_mut<A: PuiVecAccess<T, I>>(&mut self, index: A) -> Option<&mut A::Output> { index.get_mut(self) }

    /// Returns a reference to the identifier and a mutable reference to the underlying slice
    pub fn as_mut_parts(&mut self) -> (&I, &mut [T]) { (&self.ident, &mut self.vec) }

    /// Decomposes `PuiVec` into a it's identifier and it's underling `Vec`
    ///
    /// # Safety
    ///
    /// The identifier can't be used to create a new `PuiVec`
    pub unsafe fn into_raw_parts(self) -> (I, Vec<T>) { (self.ident, self.vec) }
}

// This is safe because `(): !Identifier`, so you can't create a corrosponding `Id`.
// Which means there are is no safe unchecked accesses to the `Vec`
impl<T> PuiVec<T, ()> {
    /// Get a mutable reference to the underling `Vec`
    pub fn vec_mut(&mut self) -> &mut Vec<T> { &mut self.vec }
}

impl<T, I> PuiVec<T, I> {
    /// Appends an element to the back of a collection.
    ///
    /// Returns an [`Id`] or [`usize`]
    pub fn push<Id: BuildPuiVecIndex<I, SliceIndex = usize>>(&mut self, value: T) -> Id {
        let index = self.vec.len();

        self.vec.push(value);

        unsafe { Id::new_unchecked(index, &self.ident) }
    }

    /// Moves all the elements of `other` into `Self`, leaving `other` empty.
    pub fn append(&mut self, vec: &mut Vec<T>) { self.vec.append(vec); }

    /// Clones and appends all elements in a slice to the `PuiVec`.
    ///
    /// Iterates over the slice other, clones each element, and
    /// then appends it to this Vec. The other vector is traversed in-order.
    ///
    /// Note that this function is same as extend except that it
    /// is specialized to work with slices instead. If and when
    /// Rust gets specialization this function will likely be
    /// deprecated (but still available).
    pub fn extend_from_slice(&mut self, slice: &[T])
    where
        T: Clone,
    {
        self.vec.extend_from_slice(slice);
    }
}

// TODO - move `swap`, `split_at`, and `split_at_mut` out to be based on `PuiVecIndex`
#[cfg(feature = "pui-core")]
#[cfg_attr(docsrs, doc(cfg(feature = "pui")))]
impl<T, I: OneShotIdentifier> PuiVec<T, I> {
    /// Returns an iterator over all the ids in the `PuiVec`
    pub fn ids(&self) -> impl ExactSizeIterator<Item = Id<I::Token>> + Clone {
        let token = self.ident.token();
        (0..self.len()).map(move |index| Id {
            index,
            token: token.clone(),
        })
    }

    /// check if the `index` is in bounds, and if it is,
    /// return the corrosponding `Id`
    pub fn parse_id(&self, index: usize) -> Option<Id<I::Token>> {
        if index < self.len() {
            Some(Id {
                index,
                token: self.ident.token(),
            })
        } else {
            None
        }
    }

    /// swap two elements, while eliding bounds checks
    pub fn swap(&mut self, a: Id<I::Token>, b: Id<I::Token>) {
        assert!(self.ident.owns_token(&a.token) && self.ident.owns_token(&b.token));

        let ptr = self.vec.as_mut_ptr();
        unsafe { ptr.add(a.index).swap(ptr.add(b.index)) }
    }

    /// Divides the `PuiVec` into two slices at an index, while eliding bounds checks.
    ///
    /// The first will contain all indices from [0, mid)
    /// (excluding the index mid itself) and the second
    /// will contain all indices from [mid, len)
    /// (excluding the index len itself).
    pub fn split_at(&self, mid: Id<I::Token>) -> (&[T], &[T]) {
        assert!(self.ident.owns_token(&mid.token));
        let len = self.len();
        let ptr = self.vec.as_ptr();
        unsafe {
            (
                core::slice::from_raw_parts(ptr, mid.index),
                core::slice::from_raw_parts(ptr.add(mid.index), len - mid.index),
            )
        }
    }

    /// Divides the `PuiVec` into two slices at an index, while eliding bounds checks.
    ///
    /// The first will contain all indices from [0, mid)
    /// (excluding the index mid itself) and the second
    /// will contain all indices from [mid, len)
    /// (excluding the index len itself).
    pub fn split_at_mut(&mut self, id: Id<I::Token>) -> (&mut [T], &mut [T]) {
        assert!(self.ident.owns_token(&id.token));
        let len = self.len();
        let ptr = self.vec.as_mut_ptr();
        unsafe {
            (
                core::slice::from_raw_parts_mut(ptr, id.index),
                core::slice::from_raw_parts_mut(ptr.add(id.index), len - id.index),
            )
        }
    }
}

impl<T, I> IntoIterator for PuiVec<T, I> {
    type Item = T;
    type IntoIter = std::vec::IntoIter<T>;

    fn into_iter(self) -> Self::IntoIter { self.vec.into_iter() }
}

impl<A, T, I> Extend<A> for PuiVec<T, I>
where
    Vec<T>: Extend<A>,
{
    fn extend<Iter: IntoIterator<Item = A>>(&mut self, iter: Iter) { self.vec.extend(iter) }
}

impl<T, I, A> Index<A> for PuiVec<T, I>
where
    A: PuiVecAccess<T, I>,
{
    type Output = A::Output;

    fn index(&self, index: A) -> &Self::Output { index.index(self) }
}

impl<T, I, A> IndexMut<A> for PuiVec<T, I>
where
    A: PuiVecAccess<T, I>,
{
    fn index_mut(&mut self, index: A) -> &mut Self::Output { index.index_mut(self) }
}

impl<T, I> Deref for PuiVec<T, I> {
    type Target = [T];

    fn deref(&self) -> &Self::Target { &self.vec }
}

impl<T, I> DerefMut for PuiVec<T, I> {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.vec }
}