use crate::FileSystem;
pub trait FileSystems<'a>: 'a {
    type Iter: IntoIterator<Item = &'a (dyn FileSystem + Send)> + Send + 'a;
    fn filesystems(&'a self) -> Self::Iter;
}
impl<'a, 'b, S> FileSystems<'a> for &'b S
where
    S: FileSystems<'a> + 'b,
    'b: 'a,
{
    type Iter = S::Iter;
    fn filesystems(&'a self) -> Self::Iter {
        (**self).filesystems()
    }
}
impl<'a, T> FileSystems<'a> for Vec<T>
where
    T: FileSystem + Send,
{
    type Iter = <[T] as FileSystems<'a>>::Iter;
    fn filesystems(&'a self) -> Self::Iter {
        self[..].filesystems()
    }
}
impl<'a, T, const N: usize> FileSystems<'a> for [T; N]
where
    T: FileSystem + Send,
{
    type Iter = [&'a (dyn FileSystem + Send); N];
    fn filesystems(&'a self) -> Self::Iter {
        let mut i = 0;
        [(); N].map(|_| {
            let f = &self[i] as &(dyn FileSystem + Send);
            i += 1;
            f
        })
    }
}
impl<'a, T> FileSystems<'a> for [T]
where
    T: FileSystem + Send,
{
    type Iter = std::iter::Map<std::slice::Iter<'a, T>, fn(&T) -> &(dyn FileSystem + Send)>;
    fn filesystems(&'a self) -> Self::Iter {
        self.iter().map(|fs| fs as &(dyn FileSystem + Send))
    }
}
impl<'a> FileSystems<'a> for () {
    type Iter = std::iter::Empty<&'a (dyn FileSystem + Send)>;
    fn filesystems(&'a self) -> Self::Iter {
        std::iter::empty()
    }
}
macro_rules! count {
    ($first:tt $($rest:tt)*) => {
        1 + count!($($rest)*)
    };
    () => { 0 };
}
macro_rules! tuple_filesystems {
    ($first:ident $(, $rest:ident)* $(,)?) => {
        impl<'a, $first, $( $rest ),*> FileSystems<'a> for ($first, $($rest),*)
        where
            $first: FileSystem,
            $($rest: FileSystem),*
        {
            type Iter = [&'a (dyn FileSystem + Send); count!($first $($rest)*)];
            fn filesystems(&'a self) -> Self::Iter {
                #[allow(non_snake_case)]
                let ($first, $($rest),*) = self;
                [
                    $first as &(dyn FileSystem + Send),
                    $($rest),*
                ]
            }
        }
        tuple_filesystems!($($rest),*);
    };
    () => {};
}
tuple_filesystems!(F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16,);