79 lines
1.7 KiB
Rust
79 lines
1.7 KiB
Rust
#![warn(clippy::pedantic)]
|
|
|
|
mod section_range;
|
|
|
|
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())
|
|
}
|
|
}
|