use std::fmt;
use super::Rc;
use crate::ImplicitClone;
#[derive(PartialEq, Eq)]
pub enum IArray<T: ImplicitClone + 'static> {
Static(&'static [T]),
Rc(Rc<[T]>),
Single([T; 1]),
}
impl<T: fmt::Debug + ImplicitClone + 'static> fmt::Debug for IArray<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Static(a) => a.fmt(f),
Self::Rc(a) => a.fmt(f),
Self::Single(x) => x.fmt(f),
}
}
}
impl<T: ImplicitClone + 'static> Clone for IArray<T> {
fn clone(&self) -> Self {
match self {
Self::Static(a) => Self::Static(a),
Self::Rc(a) => Self::Rc(a.clone()),
Self::Single(x) => Self::Single(x.clone()),
}
}
}
impl<T: ImplicitClone + 'static> Default for IArray<T> {
fn default() -> Self {
Self::EMPTY
}
}
impl<T: ImplicitClone + 'static> FromIterator<T> for IArray<T> {
fn from_iter<I: IntoIterator<Item = T>>(it: I) -> Self {
let mut it = it.into_iter();
match it.size_hint() {
(_, Some(0)) => Self::EMPTY,
(_, Some(1)) => {
if let Some(element) = it.next() {
Self::Single([element])
} else {
Self::EMPTY
}
}
_ => Self::Rc(Rc::from_iter(it)),
}
}
}
impl<T: ImplicitClone + 'static> ImplicitClone for IArray<T> {}
impl<T: ImplicitClone + 'static> From<&'static [T]> for IArray<T> {
fn from(a: &'static [T]) -> IArray<T> {
IArray::Static(a)
}
}
impl<T: ImplicitClone + 'static> From<Vec<T>> for IArray<T> {
fn from(a: Vec<T>) -> IArray<T> {
IArray::Rc(Rc::from(a))
}
}
impl<T: ImplicitClone + 'static> From<Rc<[T]>> for IArray<T> {
fn from(a: Rc<[T]>) -> IArray<T> {
IArray::Rc(a)
}
}
impl<T: ImplicitClone + 'static> From<&IArray<T>> for IArray<T> {
fn from(a: &IArray<T>) -> IArray<T> {
a.clone()
}
}
impl<T: ImplicitClone + 'static> From<[T; 1]> for IArray<T> {
fn from(a: [T; 1]) -> IArray<T> {
IArray::Single(a)
}
}
#[derive(Debug)]
pub struct Iter<T: ImplicitClone + 'static> {
array: IArray<T>,
index: usize,
}
impl<T: ImplicitClone + 'static> Iter<T> {
fn new(array: IArray<T>) -> Self {
Self { array, index: 0 }
}
}
impl<T: ImplicitClone + 'static> Iterator for Iter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
let item = self.array.get(self.index);
self.index += 1;
item
}
}
impl<T: ImplicitClone + 'static> IArray<T> {
pub const EMPTY: Self = Self::Static(&[]);
#[inline]
pub fn iter(&self) -> Iter<T> {
Iter::new(self.clone())
}
#[inline]
pub fn len(&self) -> usize {
match self {
Self::Static(a) => a.len(),
Self::Rc(a) => a.len(),
Self::Single(_) => 1,
}
}
#[inline]
pub fn is_empty(&self) -> bool {
match self {
Self::Static(a) => a.is_empty(),
Self::Rc(a) => a.is_empty(),
Self::Single(_) => false,
}
}
#[inline]
pub fn as_slice(&self) -> &[T] {
match self {
Self::Static(a) => a,
Self::Rc(a) => a,
Self::Single(a) => a,
}
}
#[inline]
pub fn get(&self, index: usize) -> Option<T> {
match self {
Self::Static(a) => a.get(index).cloned(),
Self::Rc(a) => a.get(index).cloned(),
Self::Single(a) if index == 0 => Some(a[0].clone()),
Self::Single(_) => None,
}
}
#[inline]
pub fn get_mut(&mut self) -> Option<&mut [T]> {
match self {
Self::Rc(ref mut rc) => Rc::get_mut(rc),
Self::Static(_) => None,
Self::Single(ref mut a) => Some(a),
}
}
#[inline]
pub fn make_mut(&mut self) -> &mut [T] {
match self {
Self::Rc(ref mut rc) => {
if Rc::get_mut(rc).is_none() {
*rc = rc.iter().cloned().collect::<Rc<[T]>>();
}
Rc::get_mut(rc).unwrap()
}
Self::Static(slice) => {
*self = Self::Rc(slice.iter().cloned().collect());
match self {
Self::Rc(rc) => Rc::get_mut(rc).unwrap(),
_ => unreachable!(),
}
}
Self::Single(slice) => {
*self = Self::Rc(slice.iter().cloned().collect());
match self {
Self::Rc(rc) => Rc::get_mut(rc).unwrap(),
_ => unreachable!(),
}
}
}
}
}
impl<'a, T, U, const N: usize> PartialEq<&'a [U; N]> for IArray<T>
where
T: PartialEq<U> + ImplicitClone,
{
fn eq(&self, other: &&[U; N]) -> bool {
match self {
Self::Static(a) => a.eq(other),
Self::Rc(a) => a.eq(*other),
Self::Single(a) if N == 1 => a[0].eq(&other[0]),
Self::Single(_) => false,
}
}
}
impl<T, U, const N: usize> PartialEq<[U; N]> for IArray<T>
where
T: PartialEq<U> + ImplicitClone,
{
fn eq(&self, other: &[U; N]) -> bool {
match self {
Self::Static(a) => a.eq(other),
Self::Rc(a) => a.eq(other),
Self::Single(a) if N == 1 => a[0].eq(&other[0]),
Self::Single(_) => false,
}
}
}
impl<T, U> PartialEq<[U]> for IArray<T>
where
T: PartialEq<U> + ImplicitClone,
{
fn eq(&self, other: &[U]) -> bool {
match self {
Self::Static(a) => a.eq(&other),
Self::Rc(a) => a.eq(other),
Self::Single(a) => a.eq(other),
}
}
}
impl<'a, T, U> PartialEq<&'a [U]> for IArray<T>
where
T: PartialEq<U> + ImplicitClone,
{
fn eq(&self, other: &&[U]) -> bool {
match self {
Self::Static(a) => a.eq(other),
Self::Rc(a) => a.eq(*other),
Self::Single(a) => a.eq(*other),
}
}
}
impl<T> std::ops::Deref for IArray<T>
where
T: ImplicitClone,
{
type Target = [T];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
#[cfg(feature = "serde")]
impl<T: serde::Serialize + ImplicitClone> serde::Serialize for IArray<T> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
<[T] as serde::Serialize>::serialize(self, serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, T: serde::Deserialize<'de> + ImplicitClone> serde::Deserialize<'de> for IArray<T> {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
<Vec<T> as serde::Deserialize>::deserialize(deserializer).map(IArray::<T>::from)
}
}
#[cfg(test)]
mod test_array {
use super::*;
#[test]
fn array_in_array() {
let array_1 = [1, 2, 3].into_iter().collect::<IArray<u32>>();
let array_2 = [4, 5, 6].into_iter().collect::<IArray<u32>>();
let array_of_array = [array_1, array_2]
.into_iter()
.collect::<IArray<IArray<u32>>>();
assert_eq!(array_of_array, [[1, 2, 3], [4, 5, 6]]);
}
#[test]
fn array_holding_rc_items() {
struct Item;
let _array = [Rc::new(Item)].into_iter().collect::<IArray<Rc<Item>>>();
}
#[test]
fn from_iter_is_optimized() {
let array_0 = [].into_iter().collect::<IArray<u32>>();
assert!(matches!(array_0, IArray::Static(_)));
let array_1 = [1].into_iter().collect::<IArray<u32>>();
assert!(matches!(array_1, IArray::Single(_)));
let array_2 = [1, 2].into_iter().collect::<IArray<u32>>();
assert!(matches!(array_2, IArray::Rc(_)));
{
let it = [1].into_iter().filter(|x| x % 2 == 0);
assert_eq!(it.size_hint(), (0, Some(1)));
let array_0_to_1 = it.collect::<IArray<u32>>();
assert!(matches!(array_0_to_1, IArray::Static(_)));
}
{
let it = [2].into_iter().filter(|x| x % 2 == 0);
assert_eq!(it.size_hint(), (0, Some(1)));
let array_0_to_1 = it.collect::<IArray<u32>>();
assert!(matches!(array_0_to_1, IArray::Single(_)));
}
}
#[test]
fn static_array() {
const _ARRAY: IArray<u32> = IArray::Static(&[1, 2, 3]);
}
#[test]
fn deref_slice() {
assert!(IArray::Static(&[1, 2, 3]).contains(&1));
}
#[test]
fn tuple_in_array() {
const _ARRAY_2: IArray<(u32, u32)> = IArray::EMPTY;
const _ARRAY_5: IArray<(u32, u32, u32, u32, u32)> = IArray::EMPTY;
}
#[test]
fn floats_in_array() {
const _ARRAY_F32: IArray<f32> = IArray::EMPTY;
const _ARRAY_F64: IArray<f64> = IArray::EMPTY;
}
#[test]
fn from() {
let x: IArray<u32> = IArray::EMPTY;
let _out = IArray::from(&x);
let _array: IArray<u32> = IArray::from(&[1, 2, 3][..]);
let _array: IArray<u32> = IArray::from(vec![1, 2, 3]);
let _array: IArray<u32> = IArray::from(Rc::from(vec![1, 2, 3]));
let _array: IArray<u32> = IArray::from([1]);
}
}