use std::fmt;
use super::Rc;
use crate::ImplicitClone;
#[derive(PartialEq, Eq)]
pub enum IArray<T: ImplicitClone + 'static> {
Static(&'static [T]),
Rc(Rc<[T]>),
}
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),
}
}
}
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()),
}
}
}
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::from([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, const N: usize> From<[T; N]> for IArray<T> {
fn from(a: [T; N]) -> IArray<T> {
IArray::Rc(Rc::from(a))
}
}
#[derive(Debug)]
pub struct IArrayIntoIter<T: ImplicitClone + 'static> {
array: IArray<T>,
left: usize,
right: usize,
}
impl<T: ImplicitClone + 'static> IntoIterator for IArray<T> {
type Item = T;
type IntoIter = IArrayIntoIter<T>;
fn into_iter(self) -> <Self as IntoIterator>::IntoIter {
IArrayIntoIter {
left: 0,
right: self.len(),
array: self,
}
}
}
impl<T: ImplicitClone + 'static> Iterator for IArrayIntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.left >= self.right {
return None;
}
let item = &self.array[self.left];
self.left += 1;
Some(item.clone())
}
}
impl<T: ImplicitClone + 'static> DoubleEndedIterator for IArrayIntoIter<T> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.left >= self.right {
return None;
}
self.right -= 1;
Some(self.array[self.right].clone())
}
}
impl<T: ImplicitClone + 'static> IArray<T> {
pub const EMPTY: Self = Self::Static(&[]);
#[inline]
pub fn len(&self) -> usize {
match self {
Self::Static(a) => a.len(),
Self::Rc(a) => a.len(),
}
}
#[inline]
pub fn is_empty(&self) -> bool {
match self {
Self::Static(a) => a.is_empty(),
Self::Rc(a) => a.is_empty(),
}
}
#[inline]
pub fn as_slice(&self) -> &[T] {
match self {
Self::Static(a) => a,
Self::Rc(a) => a,
}
}
#[inline]
pub fn get(&self, index: usize) -> Option<&T> {
match self {
Self::Static(a) => a.get(index),
Self::Rc(a) => a.get(index),
}
}
#[inline]
pub fn get_mut(&mut self) -> Option<&mut [T]> {
match self {
Self::Rc(ref mut rc) => Rc::get_mut(rc),
Self::Static(_) => None,
}
}
#[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!(),
}
}
}
}
}
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),
}
}
}
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),
}
}
}
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),
}
}
}
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),
}
}
}
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_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::Rc(_)));
}
}
#[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]);
}
#[test]
fn recursion() {
#[derive(Clone)]
struct _Node {
_children: IArray<_Node>,
}
impl ImplicitClone for _Node {}
}
#[test]
fn into_iter() {
let array = IArray::Static(&[1, 2, 3]);
assert_eq!(array.iter().next().unwrap(), &1);
assert_eq!(array.into_iter().next().unwrap(), 1);
}
}