parent
1a8792b4d0
commit
bdbadf60b1
@ -0,0 +1,151 @@
|
|||||||
|
//! Errors for arg parsing
|
||||||
|
use super::*;
|
||||||
|
use flags::*;
|
||||||
|
use std::{
|
||||||
|
error,
|
||||||
|
fmt,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Error without context
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Error
|
||||||
|
{
|
||||||
|
pub(super) flag: Kind<'static>,
|
||||||
|
pub(super) arg: (usize, String),
|
||||||
|
pub(super) desc: Option<String>,
|
||||||
|
pub(super) from: eyre::Report,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An argument parsing error with context
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ContextualError(Error);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct ErrorContext<'a>
|
||||||
|
{
|
||||||
|
/// The error-throwing flag
|
||||||
|
pub flag: &'a Kind<'static>,
|
||||||
|
/// The argument string
|
||||||
|
pub arg: &'a String,
|
||||||
|
/// The index of the argument string
|
||||||
|
pub arg_idx: &'a usize,
|
||||||
|
/// Message from the failing flag callback, if any
|
||||||
|
pub desc: Option<&'a String>,
|
||||||
|
/// The error report
|
||||||
|
pub from: &'a eyre::Report,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContextualError
|
||||||
|
{
|
||||||
|
/// The inner error
|
||||||
|
#[inline] pub fn inner(&self) -> &Error
|
||||||
|
{
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
/// Strips the context and returns the inner error
|
||||||
|
#[inline] fn into_inner(self) -> Error
|
||||||
|
{
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
/// The context of this error
|
||||||
|
pub fn context(&self) -> ErrorContext<'_>
|
||||||
|
{
|
||||||
|
ErrorContext {
|
||||||
|
flag: &self.0.flag,
|
||||||
|
arg: &self.0.arg.1,
|
||||||
|
arg_idx: &self.0.arg.0,
|
||||||
|
desc: self.0.desc.as_ref(),
|
||||||
|
from: &self.0.from
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Which argument was the error thrown for
|
||||||
|
pub fn what(&self) -> (usize, &str)
|
||||||
|
{
|
||||||
|
(self.0.arg.0, &self.0.arg.1[..])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Where did the parsing fail?
|
||||||
|
pub fn which(&self) -> Kind<'_>
|
||||||
|
{
|
||||||
|
self.0.flag.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The message reported by the failing callback, if any
|
||||||
|
pub fn message(&self) -> Option<&str>
|
||||||
|
{
|
||||||
|
self.0.desc.as_ref().map(|x| &x[..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl error::Error for Error
|
||||||
|
{
|
||||||
|
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||||
|
self.from.source()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
writeln!(f, "Failed to parse args")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ContextualError
|
||||||
|
{
|
||||||
|
#[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
self.0.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Error
|
||||||
|
{
|
||||||
|
/// Consume into an `eyre::Report`.
|
||||||
|
pub(super) fn into_report(self) -> eyre::Report
|
||||||
|
{
|
||||||
|
let Error {flag, desc, from ,arg: (idx, arg)} = self;
|
||||||
|
let err = Err::<!, _>(from)
|
||||||
|
//.wrap_err(eyre!("Failed to parse args"))
|
||||||
|
.with_section(move || flag.to_string().header("While attempting to parse for"))
|
||||||
|
.with_note(move || idx.to_string().header("Argument index was"))
|
||||||
|
.with_note(move || format!("{:?}", arg).header("Argument was"));
|
||||||
|
if let Some(desc) = desc {
|
||||||
|
err.with_suggestion(move || desc)
|
||||||
|
} else {
|
||||||
|
err
|
||||||
|
}.unwrap_err()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add context to this error
|
||||||
|
pub fn with_context(self) -> ContextualError
|
||||||
|
{
|
||||||
|
ContextualError(Self {
|
||||||
|
flag: self.flag.clone(),
|
||||||
|
arg: self.arg.clone(),
|
||||||
|
desc: self.desc.clone(),
|
||||||
|
from: self.into_report(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Error> for ContextualError
|
||||||
|
{
|
||||||
|
#[inline] fn from(from: Error) -> Self
|
||||||
|
{
|
||||||
|
from.with_context()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ContextualError> for eyre::Report
|
||||||
|
{
|
||||||
|
#[inline] fn from(from: ContextualError) -> Self
|
||||||
|
{
|
||||||
|
from.0.from
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,9 @@
|
|||||||
//! Parse args
|
//! Parse args
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
|
pub mod flags;
|
||||||
|
|
||||||
pub fn usage() -> !
|
pub fn usage() -> !
|
||||||
{
|
{
|
||||||
println!(r#"Usage: {program} <files...>
|
println!(r#"Usage: {program} <files...>
|
@ -0,0 +1,140 @@
|
|||||||
|
//! Useful iterators
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
|
||||||
|
/// An iterator that can yield `0,1,2+` items
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Either<T,U>
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
One(T),
|
||||||
|
Many(U),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T,U> Either<T,U>
|
||||||
|
{
|
||||||
|
pub fn take(&mut self) -> Self
|
||||||
|
{
|
||||||
|
std::mem::replace(self, Self::None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum EitherIter<T,U>
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
One(std::iter::Once<T>),
|
||||||
|
Many(std::iter::Fuse<U>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T,U> Iterator for EitherIter<T,U>
|
||||||
|
where U: Iterator<Item=T>
|
||||||
|
{
|
||||||
|
type Item = T;
|
||||||
|
fn next(&mut self) -> Option<Self::Item>
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::None => None,
|
||||||
|
Self::One(one) => one.next(),
|
||||||
|
Self::Many(many) => many.next(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
match self {
|
||||||
|
Self::None => (0, Some(0)),
|
||||||
|
Self::One(_) => (1, Some(1)),
|
||||||
|
Self::Many(many) => many.size_hint(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T,U: Iterator<Item=T>> std::iter::FusedIterator for EitherIter<T,U>{}
|
||||||
|
impl<T,U: Iterator<Item=T>> std::iter::ExactSizeIterator for EitherIter<T,U>
|
||||||
|
where U: ExactSizeIterator{}
|
||||||
|
|
||||||
|
impl<T, U: IntoIterator<Item=T>> IntoIterator for Either<T, U>
|
||||||
|
{
|
||||||
|
type Item= T;
|
||||||
|
type IntoIter = EitherIter<T, <U as IntoIterator>::IntoIter>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::None => EitherIter::None,
|
||||||
|
Self::One(one) => EitherIter::One(std::iter::once(one)),
|
||||||
|
Self::Many(many) => EitherIter::Many(many.into_iter().fuse())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A bespoke iterator type with an exact size
|
||||||
|
#[macro_export] macro_rules! over {
|
||||||
|
(@) => (0usize);
|
||||||
|
(@ $x:tt $($xs:tt)* ) => (1usize + $crate::over!(@ $($xs)*));
|
||||||
|
|
||||||
|
($($value:expr),*) => {
|
||||||
|
{
|
||||||
|
use ::std::mem::MaybeUninit;
|
||||||
|
use ::std::ops::Drop;
|
||||||
|
struct Arr<T>([MaybeUninit<T>; $crate::over!(@ $($value)*)], usize);
|
||||||
|
impl<T> Arr<T>
|
||||||
|
{
|
||||||
|
const LEN: usize = $crate::over!(@ $($value)*);
|
||||||
|
}
|
||||||
|
impl<T> Iterator for Arr<T>
|
||||||
|
{
|
||||||
|
type Item = T;
|
||||||
|
fn next(&mut self) -> Option<Self::Item>
|
||||||
|
{
|
||||||
|
if self.1 >= self.0.len() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
//take one
|
||||||
|
let one = unsafe {
|
||||||
|
::std::mem::replace(&mut self.0[self.1], MaybeUninit::uninit()).assume_init()
|
||||||
|
};
|
||||||
|
self.1+=1;
|
||||||
|
Some(one)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline] fn size_hint(&self) -> (usize, Option<usize>)
|
||||||
|
{
|
||||||
|
(Self::LEN, Some(Self::LEN))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> ::std::iter::FusedIterator for Arr<T>{}
|
||||||
|
impl<T> ::std::iter::ExactSizeIterator for Arr<T>{}
|
||||||
|
|
||||||
|
impl<T> Drop for Arr<T>
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if ::std::mem::needs_drop::<T>() {
|
||||||
|
for idx in self.1..self.0.len() {
|
||||||
|
unsafe {
|
||||||
|
::std::mem::replace(&mut self.0[idx], MaybeUninit::uninit()).assume_init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Arr([$(MaybeUninit::new($value)),*], 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests
|
||||||
|
{
|
||||||
|
#[test]
|
||||||
|
fn iter_over()
|
||||||
|
{
|
||||||
|
const EXPECT: usize = 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1;
|
||||||
|
let iter = over![10,9,8,7,6,5,4,3,2,1];
|
||||||
|
|
||||||
|
assert_eq!(iter.len(), 10);
|
||||||
|
assert_eq!(iter.sum::<usize>(), EXPECT);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue