/*!
Abstract collections of objects.
*/

use crate::loc::Loc;

/// An abstract collection of elements.
pub trait Collection : IntoIterator<Item = Self::Element> {
    /// Type of elements of the collection
    type Element;
    /// Iterator over references to elements of the collection
    type RefsIter<'a> : Iterator<Item=&'a Self::Element> where Self : 'a;

    /// Returns an iterator over references to elements of the collection.
    fn iter_refs(&self) -> Self::RefsIter<'_>;
}

/// An abstract collection of mutable elements.
pub trait CollectionMut : Collection {
    /// Iterator over references to elements of the collection
    type RefsIterMut<'a> : Iterator<Item=&'a mut Self::Element> where Self : 'a;

    /// Returns an iterator over references to elements of the collection.
    fn iter_refs_mut(&mut self) -> Self::RefsIterMut<'_>;
}

/// Helps implement Collection and CollectionMut for slice-like collections.
#[macro_export]
macro_rules! slice_like_collection {
    ($type : ty where $($where:tt)*) => {
        impl<$($where)*> Collection for $type {
            type Element = E;
            type RefsIter<'_a> = std::slice::Iter<'_a, E> where Self : '_a;

            #[inline]
            fn iter_refs(&self) -> Self::RefsIter<'_> {
                self.iter()
            }
        }

        impl<$($where)*> CollectionMut for $type {
            type RefsIterMut<'_a> = std::slice::IterMut<'_a, E> where Self : '_a;

            #[inline]
            fn iter_refs_mut(&mut self) -> Self::RefsIterMut<'_> {
                self.iter_mut()
            }
        }
    }
}

slice_like_collection!(Vec<E> where E);
slice_like_collection!([E; N] where E, const N : usize);
slice_like_collection!(Loc<E, N> where E, const N : usize);
