blob: a92ff5bfd9a452d7a33dfd234964872d560a1026 [file] [log] [blame]
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Provides an [`ArrayVecOption`] wrapper implementation over [`ArrayVec`],
//! which stores all the elements in an `Option` in order to satisfy
//! `ArrayVec`'s requirement that the elements must implement `Default`.
use tinyvec::{ArrayVec, ArrayVecIterator};
#[cfg(any(test, feature = "alloc"))]
extern crate alloc;
#[cfg(any(test, feature = "alloc"))]
use alloc::vec::Vec;
/// A wrapper of [`ArrayVec`] that stores it values as [`Option`], in order to
/// satisfy `ArrayVec`'s requirement that the elements must implement `Default`.
/// The implementation guarantees that any items in the wrapped `ArrayVec`
/// within `0..len` is `Some`, and therefore will not panic when unwrapped.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ArrayVecOption<A, const N: usize>(ArrayVec<[Option<A>; N]>);
// Cannot derive due to https://github.com/rust-lang/rust/issues/74462
impl<A, const N: usize> Default for ArrayVecOption<A, N> {
fn default() -> Self {
Self(Default::default())
}
}
/// Iterator type returned by `ArrayVecOption.iter()`, which can be used as
/// `impl Iterator<Item = &A>`
pub type ArrayVecOptionRefIter<'a, A> =
core::iter::Map<core::slice::Iter<'a, Option<A>>, fn(&'a Option<A>) -> &'a A>;
/// Iterator type returned by `ArrayVecOption.into_iter()`, which can be used as
/// `impl Iterator<Item = A>`
pub type ArrayVecOptionIntoIter<A, const N: usize> =
core::iter::Map<ArrayVecIterator<[Option<A>; N]>, fn(Option<A>) -> A>;
impl<A, const N: usize> ArrayVecOption<A, N> {
/// Returns an iterator over this vec.
pub fn iter(&self) -> ArrayVecOptionRefIter<A> {
self.0
.iter()
.map(|v| v.as_ref().expect("ArrayVecOption value before .len() should not be None"))
}
/// The length of the vec (in elements).
pub fn len(&self) -> usize {
self.0.len()
}
/// Checks if the length is 0.
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
/// Returns the first element of the vec, or `None` if it is empty.
pub fn first(&self) -> Option<&A> {
self.iter().next()
}
/// Place an element onto the end of the vec.
///
/// # Panics
/// * If the length of the vec would overflow the capacity.
pub fn push(&mut self, value: A) {
self.0.push(Some(value))
}
/// Returns a reference to an element at the given index.
pub fn get(&self, index: usize) -> Option<&A> {
self.0.get(index).and_then(|opt| opt.as_ref())
}
/// Sorts the slice with a key extraction function, but might not preserve
/// the order of equal elements.
///
/// This sort is unstable (i.e., may reorder equal elements), in-place
/// (i.e., does not allocate), and *O*(*m* \* *n* \* log(*n*)) worst-case,
/// where the key function is *O*(*m*).
pub fn sort_unstable_by_key<K: Ord>(&mut self, f: impl Fn(&A) -> K) {
self.0.sort_unstable_by_key(|a| f(a.as_ref().unwrap()))
}
/// Remove an element, swapping the end of the vec into its place.
pub fn swap_remove(&mut self, index: usize) -> A {
self.0.swap_remove(index).unwrap()
}
/// Converts this vector into a regular `Vec`, unwrapping all of the
/// `Option` in the process.
#[cfg(any(test, feature = "alloc"))]
pub fn into_vec(self) -> Vec<A> {
self.into_iter().collect()
}
}
impl<A, const N: usize> IntoIterator for ArrayVecOption<A, N> {
type Item = A;
type IntoIter = ArrayVecOptionIntoIter<A, N>;
fn into_iter(self) -> Self::IntoIter {
self.0
.into_iter()
.map(|v| v.expect("ArrayVecOption value before .len() should not be None"))
}
}
// Implement `FromIterator` to enable `iter.collect::<ArrayVecOption<_>>()`
impl<A, const N: usize> FromIterator<A> for ArrayVecOption<A, N> {
fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
Self(iter.into_iter().map(Some).collect())
}
}
impl<A, const N: usize> core::ops::Index<usize> for ArrayVecOption<A, N> {
type Output = A;
fn index(&self, index: usize) -> &Self::Output {
self.0[index].as_ref().unwrap()
}
}
#[cfg(test)]
mod test {
extern crate std;
use super::ArrayVecOption;
use std::vec;
#[test]
fn test_default_array_vec() {
let vec = ArrayVecOption::<u32, 5>::default();
assert_eq!(0, vec.len());
assert_eq!(None, vec.iter().next());
assert!(vec.is_empty());
assert_eq!(None, vec.first());
assert_eq!(None, vec.get(0));
assert_eq!(vec![0_u32; 0], vec.into_vec());
}
#[test]
fn test_array_vec_with_contents() {
let mut vec = ArrayVecOption::<u32, 5>::default();
vec.push(1);
vec.push(2);
vec.push(3);
vec.push(4);
vec.push(5);
assert_eq!(5, vec.len());
let mut iter = vec.iter();
assert_eq!(Some(&1_u32), iter.next());
assert_eq!(Some(&2_u32), iter.next());
assert_eq!(Some(&3_u32), iter.next());
assert_eq!(Some(&4_u32), iter.next());
assert_eq!(Some(&5_u32), iter.next());
assert_eq!(None, iter.next());
assert!(!vec.is_empty());
assert_eq!(Some(&1_u32), vec.first());
assert_eq!(Some(&5_u32), vec.get(4));
assert_eq!(vec![1_u32, 2, 3, 4, 5], vec.clone().into_vec());
vec.swap_remove(2);
assert_eq!(vec![1_u32, 2, 5, 4], vec.clone().into_vec());
}
#[test]
#[should_panic]
fn test_array_vec_push_overflow() {
let mut vec = ArrayVecOption::<u32, 5>::default();
vec.push(1);
vec.push(2);
vec.push(3);
vec.push(4);
vec.push(5);
vec.push(6);
}
#[test]
fn test_sort() {
let mut vec = ArrayVecOption::<u32, 5>::default();
vec.push(3);
vec.push(1);
vec.push(4);
vec.push(1);
vec.push(2);
vec.sort_unstable_by_key(|k| *k);
assert_eq!(vec![1_u32, 1, 2, 3, 4], vec.clone().into_vec());
}
#[test]
fn test_collect() {
let vec: ArrayVecOption<u32, 5> = [5_u32, 4, 3, 2, 1].into_iter().collect();
assert_eq!(vec![5_u32, 4, 3, 2, 1], vec.clone().into_vec());
}
}