#![warn(clippy::pedantic)]

pub mod grid;
mod section_range;
pub mod vec2;
pub mod vecn;

use std::{mem, path::Path};

pub use section_range::{EmptyRange, InvalidSectionString, SectionRange};

pub enum UpToTwo<T> {
    Zero,
    One(T),
    Two(T, T),
}

impl<T> UpToTwo<T> {
    pub fn is_empty(&self) -> bool {
        matches!(self, UpToTwo::Zero)
    }

    pub fn first(&self) -> Option<&T> {
        match self {
            UpToTwo::Zero => None,
            UpToTwo::One(x) | UpToTwo::Two(x, _) => Some(x),
        }
    }

    pub fn second(&self) -> Option<&T> {
        match self {
            UpToTwo::Zero | UpToTwo::One(_) => None,
            UpToTwo::Two(_, x) => Some(x),
        }
    }
}

impl<T> IntoIterator for UpToTwo<T> {
    type Item = T;

    type IntoIter = UpToTwoIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        UpToTwoIter(self)
    }
}

pub struct UpToTwoIter<T>(UpToTwo<T>);

impl<T> Iterator for UpToTwoIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        let mut content = UpToTwo::Zero;
        mem::swap(&mut self.0, &mut content);

        let (ret, mut content) = match content {
            UpToTwo::Zero => (None, UpToTwo::Zero),
            UpToTwo::One(x) => (Some(x), UpToTwo::Zero),
            UpToTwo::Two(x, y) => (Some(x), UpToTwo::One(y)),
        };
        mem::swap(&mut self.0, &mut content);

        ret
    }
}

pub trait PathExt {
    type Iter<'a>: Iterator<Item = &'a Path>
    where
        Self: 'a;
    fn parents(&self) -> Self::Iter<'_>;
}

impl PathExt for Path {
    type Iter<'a> = std::iter::Successors<&'a Path, for<'p> fn(&&'p Path) -> Option<&'p Path>>;

    fn parents(&self) -> Self::Iter<'_> {
        std::iter::successors(Some(self), |dir| dir.parent())
    }
}
