arg parsing untested

args
Avril 4 years ago
parent 5bb0f854e9
commit a88ed21e17
Signed by: flanchan
GPG Key ID: 284488987C31F630

7
Cargo.lock generated

@ -1,5 +1,11 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "ad-hoc-iter"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5068a429476033d1940f21e21d317afae2fc3a82f412d5d8fe08c13f100a00e8"
[[package]]
name = "addr2line"
version = "0.13.0"
@ -890,6 +896,7 @@ checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
name = "videl"
version = "0.1.0"
dependencies = [
"ad-hoc-iter",
"base64",
"cfg-if",
"chrono",

@ -32,6 +32,7 @@ termprogress = "0.3.4"
uuid = {version = "0.8.1", features=["v4"]}
lazy_format = "1.8.3"
recolored = "1.9.3"
ad-hoc-iter = {version = "^0.2.2", features = ["maybe-many"]}
[build-dependencies]
rustc_version = "0.2"

@ -10,9 +10,11 @@ use super::error::{
Error,
ContextualError,
};
use iterators::*;
use ad_hoc_iter::{
maybe::*,
};
type ShortFlag= (char,);
pub type ShortFlag= (char,);
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Kind<'a>
@ -212,9 +214,13 @@ pub enum ValueKind
{
/// No values, this is a boolean flag
None,
/// A value in the form of `--option=value`
/// A value in the form of `--option=value`.
///
/// If user provides without an `=value` part, the `held` state will be empty.
Equals,
/// The next `n` arguments are the values
///
/// If user provides less than `n` arguments after this one, arg parsing will fail with an error.
Next(usize),
/// The whole rest of the iterator is the values
Rest,
@ -263,7 +269,7 @@ impl<U> ArgState<U>
/// A handle to mutate the arg state.
pub struct StateHandle<'a, T>
{
held: Either<String, Vec<String>>,
held: MaybeMany<String, Vec<String>>,
state: &'a mut T,
args: &'a mut (dyn Iterator<Item=String> + 'a),
@ -322,7 +328,7 @@ impl<'a, T> StateHandle<'a,T>
/// # Note
/// This moves the values, if you want to call this more than once, use `clone_held`.
/// If called more than once will yield no values
pub fn extract_held(&mut self) -> EitherIter<String, std::vec::IntoIter<String>>
pub fn extract_held(&mut self) -> MaybeManyIter<String, std::vec::IntoIter<String>>
{
self.held.take().into_iter()
}
@ -332,7 +338,7 @@ impl<'a, T> StateHandle<'a,T>
/// # Note
/// This clones all the values, instead of moving like `extract_held`, so multiple calls to this will yield the same clones.
/// However, if `extract_held` has been called, this will yield no values.
pub fn clone_held(&self) -> EitherIter<String, std::vec::IntoIter<String>>
pub fn clone_held(&self) -> MaybeManyIter<String, std::vec::IntoIter<String>>
{
self.held.clone().into_iter()
}
@ -360,17 +366,57 @@ impl<U> ArgState<U>
if *single {
*chk = false;
}
//TODO: When value is `Equals`, split at `=` and pass only the first part to `is_match`.
let (arg, held) = {
let arg = &arg[..];
if let ValueKind::Equals = &value {
match arg.split_once("=") {
Some((a,v)) => (a, MaybeMany::one(v.to_owned())),
_ => (arg, MaybeMany::None),
}
} else {
(arg, MaybeMany::None)
}
};
if let Some(kind_match) = kind.is_match(&arg[..]) {
//TODO: Check `value` matches `input` or `kind_match`
let held = {
match value {
ValueKind::Next(n) => {
let n = *n;
let mut held = held.map_single_into_many(|x| vec![x]);
let taken = held.on_many(|vec| {
let l = vec.len();
vec.extend((&mut input).take(n));
vec.len() - l
}).unwrap();
if taken != n {
return Err(Error{flag: kind.clone(),
from: Err::<!,_>(eyre!("Not enough args"))
.with_note(|| format!("Expected {} items, only got {}", n, taken))
.with_suggestion(|| format!("See `-help` for {}", arg)).unwrap_err(),
desc: Some(desc.clone().into_owned()),
arg: (i, arg.to_owned())})?;
}
held
},
ValueKind::Rest => {
let mut held = held.map_single_into_many(|x| vec![x]);
held.on_many(|vec| vec.extend(&mut input));
held
},
_ => held.map_none(),
}
};
output.push(callback(&mut StateHandle{
state: &mut self.user,
args: &mut input,
chk,
idx: i,
held: Either::None, //TODO: This will be for either one `=<value>` or many `<values...>` from args as according to `value`.
held, //This will be for either one `=<value>` or many `<values...>` from args as according to `value`.
}, i, kind_match)
.map_err(|err| Error{flag: kind.clone(), from: err, desc: Some(desc.clone().into_owned()), arg: (i, arg.clone())})?);
.map_err(|err| Error{flag: kind.clone(), from: err, desc: Some(desc.clone().into_owned()), arg: (i, arg.to_owned())})?);
}
}
i+=1;
@ -391,6 +437,7 @@ impl<U> ArgState<U>
mod tests
{
use super::*;
use ad_hoc_iter::iter;
#[test]
fn errors() -> Result<(), eyre::Report>
{
@ -415,7 +462,7 @@ mod tests
{
let kd = Kind::Abrev(&["logging:high", "verbose", "verbose-mode"], &[('V',)], true, true);
let args = over!["--logging:high", "--verbose", "-abcVdfg"];
let args = iter!["--logging:high", "--verbose", "-abcVdfg"];
for arg in args
{

@ -1,139 +0,0 @@
//! 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);
}
}

@ -1,5 +1,6 @@
#![cfg_attr(nightly, feature(never_type))]
#![cfg_attr(nightly, feature(drain_filter))]
#![cfg_attr(nightly, feature(str_split_once))]
#![allow(dead_code)]
@ -30,7 +31,6 @@ mod ext;
use ext::*;
mod util;
mod dedup;
mod iterators;
mod resolve;
mod database;

Loading…
Cancel
Save