1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use {EXIT_ERROR, EXIT_SUCCESS, ExitStatus, POLLED_TWICE, Spawn};
use clap::{App, AppSettings, Arg};
use env::{ArgumentsEnvironment, ReportErrorEnvironment, ShiftArgumentsEnvironment, StringWrapper};
use future::{Async, EnvFuture, Poll};
use std::borrow::Cow;
use std::error::Error;
use std::fmt;
use void::Void;
const NUMERIC_ARGUMENT_REQUIRED: &str = "numeric argument required";
#[derive(Debug)]
struct NumericArgumentRequiredError;
impl Error for NumericArgumentRequiredError {
fn description(&self) -> &str {
NUMERIC_ARGUMENT_REQUIRED
}
}
impl fmt::Display for NumericArgumentRequiredError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", self.description())
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Shift<I> {
args: I,
}
pub fn shift<I>(args: I) -> Shift<I::IntoIter>
where I: IntoIterator,
{
Shift {
args: args.into_iter(),
}
}
#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
pub struct SpawnedShift<I> {
args: Option<I>,
}
impl<T, I, E: ?Sized> Spawn<E> for Shift<I>
where T: StringWrapper,
I: Iterator<Item = T>,
E: ArgumentsEnvironment + ShiftArgumentsEnvironment + ReportErrorEnvironment,
{
type EnvFuture = SpawnedShift<I>;
type Future = ExitStatus;
type Error = Void;
fn spawn(self, _env: &E) -> Self::EnvFuture {
SpawnedShift {
args: Some(self.args),
}
}
}
impl<T, I, E: ?Sized> EnvFuture<E> for SpawnedShift<I>
where T: StringWrapper,
I: Iterator<Item = T>,
E: ArgumentsEnvironment + ShiftArgumentsEnvironment + ReportErrorEnvironment,
{
type Item = ExitStatus;
type Error = Void;
fn poll(&mut self, env: &mut E) -> Poll<Self::Item, Self::Error> {
const SHIFT: &str = "shift";
const AMT_ARG_NAME: &str = "n";
const DEFAULT_SHIFT_AMOUNT: &str = "1";
let app = App::new(SHIFT)
.setting(AppSettings::NoBinaryName)
.setting(AppSettings::DisableVersion)
.about("Shifts positional parameters such that (n+1)th parameter becomes $1, and so on")
.arg(Arg::with_name(AMT_ARG_NAME)
.help("the amount of arguments to shift")
.long_help("the amount of arguments to shift. Must be non negative and <= to $#")
.validator(|amt| {
amt.parse::<usize>()
.map(|_| ())
.map_err(|_| NUMERIC_ARGUMENT_REQUIRED.into())
})
.default_value(DEFAULT_SHIFT_AMOUNT)
);
let app_args = self.args.take()
.expect(POLLED_TWICE)
.into_iter()
.map(StringWrapper::into_owned);
let matches = try_and_report!(SHIFT, app.get_matches_from_safe(app_args), env);
let amt_arg = matches.value_of_lossy(AMT_ARG_NAME)
.unwrap_or(Cow::Borrowed(DEFAULT_SHIFT_AMOUNT))
.parse()
.map_err(|_| NumericArgumentRequiredError);
let amt = try_and_report!(SHIFT, amt_arg, env);
let ret = if amt > env.args_len() {
EXIT_ERROR
} else {
env.shift_args(amt);
EXIT_SUCCESS
};
Ok(Async::Ready(ret))
}
fn cancel(&mut self, _env: &mut E) {
self.args.take();
}
}