planus/vectors/
vector.rs

1use core::{marker::PhantomData, num::NonZeroUsize};
2
3use crate::{
4    errors::{self, ErrorKind},
5    impls::array_from_buffer,
6    slice_helpers::SliceWithStartOffset,
7    traits::VectorRead,
8    TableRead,
9};
10
11/// A [`slice`]-like view into a serialized flatbuffer that deserializes on demand.
12pub struct Vector<'buf, T: ?Sized> {
13    buffer: SliceWithStartOffset<'buf>,
14    len: usize,
15    _marker: PhantomData<&'buf T>,
16}
17
18impl<T: ?Sized> Copy for Vector<'_, T> {}
19impl<T: ?Sized> Clone for Vector<'_, T> {
20    #[inline]
21    fn clone(&self) -> Self {
22        *self
23    }
24}
25
26impl<'buf, T: ?Sized> Vector<'buf, T> {
27    /// Returns an empty `Vector`
28    ///
29    /// This is typically not very useful, since the vector is read-only, but
30    /// has uses for instance as a default value.
31    #[inline]
32    #[must_use]
33    pub const fn new_empty() -> Vector<'buf, T> {
34        Self {
35            buffer: SliceWithStartOffset {
36                buffer: &[],
37                offset_from_start: 0,
38            },
39            len: 0,
40            _marker: PhantomData,
41        }
42    }
43
44    /// Checks if the vector is empty.
45    #[inline]
46    #[must_use]
47    pub fn is_empty(self) -> bool {
48        self.len == 0
49    }
50
51    /// Returns the number of elements in the vector.
52    #[inline]
53    #[must_use]
54    pub fn len(self) -> usize {
55        self.len
56    }
57}
58
59impl<'buf, T: VectorRead<'buf>> Vector<'buf, T> {
60    /// Returns the first element of the `Vector`, or `None` if it is empty.
61    #[inline]
62    #[must_use]
63    pub fn first(self) -> Option<T> {
64        self.get(0)
65    }
66
67    /// Returns the last element of the `Vector`, or `None` if it is empty.
68    #[inline]
69    #[must_use]
70    pub fn last(self) -> Option<T> {
71        self.get(self.len().checked_sub(1)?)
72    }
73
74    /// Returns an element or sub-vector depending on the type of
75    /// index.
76    ///
77    /// - If given a position, returns the element at that
78    ///   position or `None` if out of bounds.
79    /// - If given a range, returns the sub-vector corresponding to that range,
80    ///   or `None` if out of bounds.
81    #[inline]
82    #[must_use]
83    pub fn get<I>(self, index: I) -> Option<I::Output>
84    where
85        I: VectorIndex<'buf, T>,
86    {
87        index.get(self)
88    }
89
90    /// Returns an element or sub-vector, without doing bounds checking.
91    ///
92    /// For a safe alternative see [`get`].
93    ///
94    /// # Safety
95    ///
96    /// Calling this method with an out-of-bounds index is *[undefined behavior]*
97    /// even if the resulting output is not used.
98    ///
99    /// [`get`]: Vector::get
100    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
101    #[inline]
102    #[must_use]
103    pub unsafe fn get_unchecked<I>(self, index: I) -> I::Output
104    where
105        I: VectorIndex<'buf, T>,
106    {
107        index.get_unchecked(self)
108    }
109
110    /// Returns an iterator over the vector.
111    #[inline]
112    #[must_use]
113    pub fn iter(self) -> super::Iter<'buf, T> {
114        super::Iter::new(self)
115    }
116
117    /// Returns an iterator over `chunk_size` elements of the [`Vector`] at a time, starting at the
118    /// beginning of the vector.
119    ///
120    /// The chunks are [`Vector`]s themselves and do not overlap. If `chunk_size` does not
121    /// divide the length of the [`Vector`], then the last chunk will not have length `chunk_size`.
122    ///
123    /// See [`chunks_exact`] for a variant of this iterator that returns chunks of always exactly
124    /// `chunk_size` elements, and [`rchunks`] for the same iterator but starting at the end of the
125    /// vector.
126    ///
127    /// # Panics
128    ///
129    /// Panics if `chunk_size` is 0.
130    ///
131    /// [`chunks_exact`]: Vector::chunks_exact
132    /// [`rchunks`]: Vector::rchunks
133    #[inline]
134    #[must_use]
135    pub fn chunks(self, chunk_size: usize) -> super::Chunks<'buf, T> {
136        let chunk_size = NonZeroUsize::new(chunk_size).expect("chunks cannot have a size of zero");
137        super::Chunks::new(self, chunk_size)
138    }
139
140    /// Returns an iterator over `chunk_size` elements of the [`Vector`] at a time, starting at the end
141    /// of the vector.
142    ///
143    /// The chunks are [`Vector`]s themselves and do not overlap. If `chunk_size` does not
144    /// divide the length of the [`Vector`], then the last chunk will not have length `chunk_size`.
145    ///
146    /// See [`rchunks_exact`] for a variant of this iterator that returns chunks of always exactly
147    /// `chunk_size` elements, and [`chunks`] for the same iterator but starting at the beginning
148    /// of the vector.
149    ///
150    /// # Panics
151    ///
152    /// Panics if `chunk_size` is 0.
153    ///
154    /// [`rchunks_exact`]: Vector::rchunks_exact
155    /// [`chunks`]: Vector::chunks
156    #[inline]
157    #[must_use]
158    pub fn rchunks(self, chunk_size: usize) -> super::RChunks<'buf, T> {
159        let chunk_size = NonZeroUsize::new(chunk_size).expect("chunks cannot have a size of zero");
160        super::RChunks::new(self, chunk_size)
161    }
162
163    /// Returns an iterator over `chunk_size` elements of the [`Vector`] at a time, starting at the
164    /// beginning of the vector.
165    ///
166    /// The chunks are [`Vector`]s themselves and do not overlap. If `chunk_size` does not
167    /// divide the length of the vector, then the last up to `chunk_size-1` elements will
168    /// be omitted and can be retrieved from the `remainder` function of the iterator.
169    ///
170    /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the
171    /// resulting code better than in the case of [`chunks`].
172    ///
173    /// See [`chunks`] for a variant of this iterator that also returns the remainder as a smaller
174    /// chunk, and [`rchunks_exact`] for the same iterator but starting at the end of the vector.
175    ///
176    /// # Panics
177    ///
178    /// Panics if `chunk_size` is 0.
179    ///
180    /// [`chunks`]: Vector::chunks
181    /// [`rchunks_exact`]: Vector::rchunks_exact
182    #[inline]
183    #[must_use]
184    pub fn chunks_exact(self, chunk_size: usize) -> super::ChunksExact<'buf, T> {
185        let chunk_size = NonZeroUsize::new(chunk_size).expect("chunks cannot have a size of zero");
186        super::ChunksExact::new(self, chunk_size)
187    }
188
189    /// Returns an iterator over `chunk_size` elements of the [`Vector`] at a time, starting at the
190    /// end of the vector.
191    ///
192    /// The chunks are [`Vector`]s themselves and do not overlap. If `chunk_size` does not
193    /// divide the length of the vector, then the last up to `chunk_size-1` elements will
194    /// be omitted and can be retrieved from the `remainder` function of the iterator.
195    ///
196    /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the
197    /// resulting code better than in the case of [`rchunks`].
198    ///
199    /// See [`rchunks`] for a variant of this iterator that also returns the remainder as a smaller
200    /// chunk, and [`chunks_exact`] for the same iterator but starting at the beginning of the
201    /// vector.
202    ///
203    /// # Panics
204    ///
205    /// Panics if `chunk_size` is 0.
206    ///
207    /// [`rchunks`]: Vector::rchunks
208    /// [`chunks_exact`]: Vector::chunks_exact
209    #[inline]
210    #[must_use]
211    pub fn rchunks_exact(self, chunk_size: usize) -> super::RChunksExact<'buf, T> {
212        let chunk_size = NonZeroUsize::new(chunk_size).expect("chunks cannot have a size of zero");
213        super::RChunksExact::new(self, chunk_size)
214    }
215
216    /// Returns an iterator over all contiguous windows of length
217    /// `size`. The windows overlap. If the vector is shorter than
218    /// `size`, the iterator returns no values.
219    ///
220    /// # Panics
221    ///
222    /// Panics if `size` is 0.
223    #[inline]
224    #[must_use]
225    pub fn windows(self, size: usize) -> super::Windows<'buf, T> {
226        let size = NonZeroUsize::new(size).expect("windows cannot have a size of zero");
227        super::Windows::new(self, size)
228    }
229
230    /// Returns the first and all the rest of the elements of the `Vector`, or `None` if it is empty
231    #[inline]
232    #[must_use]
233    pub fn split_first(self) -> Option<(T, Vector<'buf, T>)> {
234        if self.is_empty() {
235            None
236        } else {
237            Some(unsafe { (self.get_unchecked(0), self.get_unchecked(1..)) })
238        }
239    }
240
241    /// Returns the last and all the rest of the elements of the `Vector`, or `None` if it is empty
242    #[inline]
243    #[must_use]
244    pub fn split_last(self) -> Option<(T, Vector<'buf, T>)> {
245        if self.is_empty() {
246            None
247        } else {
248            Some(unsafe {
249                (
250                    self.get_unchecked(self.len - 1),
251                    self.get_unchecked(..self.len - 1),
252                )
253            })
254        }
255    }
256
257    /// Divides one `Vector` into two at an index.
258    ///
259    /// The first will contain all indices from `[0, mid)` (excluding
260    /// the index `mid` itself) and the second will contain all
261    /// indices from `[mid, len)` (excluding the index `len` itself).
262    #[inline]
263    #[must_use]
264    pub fn split_at(self, mid: usize) -> Option<(Vector<'buf, T>, Vector<'buf, T>)> {
265        if mid <= self.len {
266            Some(unsafe { self.split_at_unchecked(mid) })
267        } else {
268            None
269        }
270    }
271
272    /// Divides one [`Vector`] into two at an index, without doing bounds checking.
273    ///
274    /// The first will contain all indices from `[0, mid)` (excluding
275    /// the index `mid` itself) and the second will contain all
276    /// indices from `[mid, len)` (excluding the index `len` itself).
277    ///
278    /// For a safe alternative see [`split_at`].
279    ///
280    /// # Safety
281    ///
282    /// Calling this method with an out-of-bounds index is *[undefined behavior]*
283    /// even if the resulting output is not used. The caller has to ensure that
284    /// `0 <= mid <= self.len()`.
285    ///
286    /// [`split_at`]: Vector::split_at
287    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
288    #[inline]
289    #[must_use]
290    pub unsafe fn split_at_unchecked(self, mid: usize) -> (Vector<'buf, T>, Vector<'buf, T>) {
291        (self.get_unchecked(..mid), self.get_unchecked(mid..))
292    }
293}
294
295impl<'buf, T: VectorRead<'buf>> Vector<'buf, T> {
296    /// Copies self into a new `Vec`.
297    pub fn to_vec<O>(self) -> crate::Result<alloc::vec::Vec<O>>
298    where
299        O: core::convert::TryFrom<T>,
300        crate::errors::Error: From<O::Error>,
301    {
302        self.iter()
303            .map(|v| O::try_from(v).map_err(crate::errors::Error::from))
304            .collect()
305    }
306}
307
308impl<'buf, T, E> Vector<'buf, core::result::Result<T, E>> {
309    /// Copies self into a new `Vec`.
310    pub fn to_vec_result<O>(self) -> crate::Result<alloc::vec::Vec<O>>
311    where
312        T: crate::traits::VectorReadInner<'buf>,
313        E: core::convert::From<T::Error>,
314        O: core::convert::TryFrom<T>,
315        crate::errors::Error: From<E> + From<O::Error>,
316    {
317        self.iter()
318            .map(|v| O::try_from(v?).map_err(|e| e.into()))
319            .collect()
320    }
321}
322
323impl<'buf, T: VectorRead<'buf>> IntoIterator for Vector<'buf, T> {
324    type Item = T;
325    type IntoIter = super::Iter<'buf, T>;
326
327    #[inline]
328    fn into_iter(self) -> Self::IntoIter {
329        self.iter()
330    }
331}
332
333impl<'buf, T: VectorRead<'buf> + core::fmt::Debug> core::fmt::Debug for Vector<'buf, T>
334where
335    T: core::fmt::Debug,
336{
337    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
338        f.debug_list().entries(*self).finish()
339    }
340}
341
342/// A helper trait used for indexing operations.
343pub trait VectorIndex<'buf, T: VectorRead<'buf>>: private::Sealed {
344    /// The output type returned by methods.
345    type Output;
346
347    /// Returns a the output at this location, if in bounds.
348    fn get(self, vector: Vector<'buf, T>) -> Option<Self::Output>;
349
350    /// Returns a mutable reference to the output at this location, without
351    /// performing any bounds checking.
352    /// Calling this method with an out-of-bounds index is
353    /// *[undefined behavior]* even if the resulting output is not used.
354    ///
355    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
356    unsafe fn get_unchecked(self, vector: Vector<'buf, T>) -> Self::Output;
357}
358
359/// Convert pair of `ops::Bound`s into `core::ops::Range` without performing any bounds checking and (in debug) overflow checking
360fn into_range_unchecked(
361    len: usize,
362    (start, end): (core::ops::Bound<usize>, core::ops::Bound<usize>),
363) -> core::ops::Range<usize> {
364    use core::ops::Bound;
365    let start = match start {
366        Bound::Included(i) => i,
367        Bound::Excluded(i) => i + 1,
368        Bound::Unbounded => 0,
369    };
370    let end = match end {
371        Bound::Included(i) => i + 1,
372        Bound::Excluded(i) => i,
373        Bound::Unbounded => len,
374    };
375    start..end
376}
377
378/// Convert pair of `core::ops::Bound`s into `core::ops::Range`.
379/// Returns `None` on overflowing indices.
380fn into_range(
381    len: usize,
382    (start, end): (core::ops::Bound<usize>, core::ops::Bound<usize>),
383) -> Option<core::ops::Range<usize>> {
384    use core::ops::Bound;
385    let start = match start {
386        Bound::Included(start) => start,
387        Bound::Excluded(start) => start.checked_add(1)?,
388        Bound::Unbounded => 0,
389    };
390
391    let end = match end {
392        Bound::Included(end) => end.checked_add(1)?,
393        Bound::Excluded(end) => end,
394        Bound::Unbounded => len,
395    };
396
397    // Don't bother with checking `start < end` and `end <= len`
398    // since these checks are handled by `Range` impls
399
400    Some(start..end)
401}
402impl<'buf, T: VectorRead<'buf>> VectorIndex<'buf, T>
403    for (core::ops::Bound<usize>, core::ops::Bound<usize>)
404{
405    type Output = Vector<'buf, T>;
406
407    #[inline]
408    fn get(self, vector: Vector<'buf, T>) -> Option<Self::Output> {
409        into_range(vector.len, self)?.get(vector)
410    }
411
412    #[inline]
413    unsafe fn get_unchecked(self, vector: Vector<'buf, T>) -> Self::Output {
414        into_range_unchecked(vector.len, self).get_unchecked(vector)
415    }
416}
417
418impl<'buf, T: VectorRead<'buf>> VectorIndex<'buf, T> for usize {
419    type Output = T;
420
421    #[inline]
422    fn get(self, vector: Vector<'buf, T>) -> Option<Self::Output> {
423        if self < vector.len {
424            Some(unsafe { self.get_unchecked(vector) })
425        } else {
426            None
427        }
428    }
429
430    #[inline]
431    unsafe fn get_unchecked(self, vector: Vector<'buf, T>) -> Self::Output {
432        debug_assert!(self < vector.len);
433        debug_assert!(vector.len.checked_mul(T::STRIDE).unwrap() <= vector.buffer.len());
434        T::from_buffer(vector.buffer, T::STRIDE * self)
435    }
436}
437
438impl<'buf, T: VectorRead<'buf>> VectorIndex<'buf, T> for core::ops::Range<usize> {
439    type Output = Vector<'buf, T>;
440
441    #[inline]
442    fn get(self, vector: Vector<'buf, T>) -> Option<Self::Output> {
443        if self.start > self.end || self.end > vector.len {
444            None
445        } else {
446            // SAFETY: `self` is checked to be valid and in bounds above.
447            unsafe { Some(self.get_unchecked(vector)) }
448        }
449    }
450
451    #[inline]
452    unsafe fn get_unchecked(self, vector: Vector<'buf, T>) -> Self::Output {
453        debug_assert!(self.start <= self.end);
454        debug_assert!(self.end <= vector.len);
455        Vector {
456            buffer: vector
457                .buffer
458                .advance(T::STRIDE * self.start)
459                .expect("IMPOSSIBLE: the length was checked on creation"),
460            len: self.end - self.start,
461            _marker: PhantomData,
462        }
463    }
464}
465
466impl<'buf, T: VectorRead<'buf>> VectorIndex<'buf, T> for core::ops::RangeFrom<usize> {
467    type Output = Vector<'buf, T>;
468
469    #[inline]
470    fn get(self, vector: Vector<'buf, T>) -> Option<Self::Output> {
471        (self.start..vector.len).get(vector)
472    }
473
474    #[inline]
475    unsafe fn get_unchecked(self, vector: Vector<'buf, T>) -> Self::Output {
476        (self.start..vector.len).get_unchecked(vector)
477    }
478}
479
480impl<'buf, T: VectorRead<'buf>> VectorIndex<'buf, T> for core::ops::RangeFull {
481    type Output = Vector<'buf, T>;
482
483    #[inline]
484    fn get(self, vector: Vector<'buf, T>) -> Option<Self::Output> {
485        Some(vector)
486    }
487
488    #[inline]
489    unsafe fn get_unchecked(self, vector: Vector<'buf, T>) -> Self::Output {
490        vector
491    }
492}
493
494impl<'buf, T: VectorRead<'buf>> VectorIndex<'buf, T> for core::ops::RangeInclusive<usize> {
495    type Output = Vector<'buf, T>;
496
497    #[inline]
498    fn get(self, vector: Vector<'buf, T>) -> Option<Self::Output> {
499        (*self.start()..self.end().checked_add(1)?).get(vector)
500    }
501
502    #[inline]
503    unsafe fn get_unchecked(self, vector: Vector<'buf, T>) -> Self::Output {
504        (*self.start()..self.end() + 1).get_unchecked(vector)
505    }
506}
507
508impl<'buf, T: VectorRead<'buf>> VectorIndex<'buf, T> for core::ops::RangeTo<usize> {
509    type Output = Vector<'buf, T>;
510
511    #[inline]
512    fn get(self, vector: Vector<'buf, T>) -> Option<Self::Output> {
513        (0..self.end).get(vector)
514    }
515
516    #[inline]
517    unsafe fn get_unchecked(self, vector: Vector<'buf, T>) -> Self::Output {
518        (0..self.end).get_unchecked(vector)
519    }
520}
521
522impl<'buf, T: VectorRead<'buf>> VectorIndex<'buf, T> for core::ops::RangeToInclusive<usize> {
523    type Output = Vector<'buf, T>;
524
525    #[inline]
526    fn get(self, vector: Vector<'buf, T>) -> Option<Self::Output> {
527        (0..=self.end).get(vector)
528    }
529
530    #[inline]
531    unsafe fn get_unchecked(self, vector: Vector<'buf, T>) -> Self::Output {
532        (0..=self.end).get_unchecked(vector)
533    }
534}
535
536impl<'buf, T: VectorRead<'buf>, O> TryFrom<Vector<'buf, T>> for alloc::vec::Vec<O>
537where
538    O: core::convert::TryFrom<T>,
539    errors::Error: From<O::Error>,
540{
541    type Error = crate::errors::Error;
542
543    fn try_from(value: Vector<'buf, T>) -> Result<Self, Self::Error> {
544        value
545            .iter()
546            .map(|v| O::try_from(v).map_err(errors::Error::from))
547            .collect()
548    }
549}
550
551impl<'buf, T: ?Sized + VectorRead<'buf>> TableRead<'buf> for Vector<'buf, T> {
552    fn from_buffer(
553        buffer: SliceWithStartOffset<'buf>,
554        offset: usize,
555    ) -> core::result::Result<Self, ErrorKind> {
556        let (buffer, len) = array_from_buffer(buffer, offset)?;
557        if len.checked_mul(T::STRIDE).ok_or(ErrorKind::InvalidLength)? <= buffer.len() {
558            Ok(Vector {
559                buffer,
560                len,
561                _marker: PhantomData,
562            })
563        } else {
564            Err(ErrorKind::InvalidLength)
565        }
566    }
567}
568
569mod private {
570    pub trait Sealed {}
571
572    // Implement for those same types, but no others.
573    impl Sealed for (core::ops::Bound<usize>, core::ops::Bound<usize>) {}
574    impl Sealed for usize {}
575    impl Sealed for core::ops::Range<usize> {}
576    impl Sealed for core::ops::RangeFrom<usize> {}
577    impl Sealed for core::ops::RangeFull {}
578    impl Sealed for core::ops::RangeInclusive<usize> {}
579    impl Sealed for core::ops::RangeTo<usize> {}
580    impl Sealed for core::ops::RangeToInclusive<usize> {}
581}