#![warn(clippy::pedantic)] mod section_range; use std::{mem, path::Path}; pub use section_range::{EmptyRange, InvalidSectionString, SectionRange}; pub enum UpToTwo { Zero, One(T), Two(T, T), } impl UpToTwo { 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 IntoIterator for UpToTwo { type Item = T; type IntoIter = UpToTwoIter; fn into_iter(self) -> Self::IntoIter { UpToTwoIter(self) } } pub struct UpToTwoIter(UpToTwo); impl Iterator for UpToTwoIter { type Item = T; fn next(&mut self) -> Option { 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 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()) } }