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
126
127
128
129
130
131
132
133
134
135
#![doc = include_str!("../README.md")]
#[derive(Debug, PartialEq)]
pub enum Arg<'a> {
Value,
Option(&'a str),
Separator(&'a str),
}
macro_rules! some_pair {
( $v1:expr, $v2:expr ) => ( Some(($v1, $v2)) )
}
pub fn arg_parse<'a>(arguments: &'a [&str], index: usize) -> (Arg<'a>, Option<usize>, Option<(usize, &'a str)>) {
let a = arguments[index];
if a == "-" {
(Arg::Value, None, some_pair!(1, a))
} else if a == "--" {
(Arg::Separator(a), Some(1), None)
} else if a.starts_with("--") {
if let Some(i) = a.find("=") {
(Arg::Option(&a[..i]), None, some_pair!(1, &a[i+1..]))
} else if index + 1 < arguments.len() {
let a2 = arguments[index + 1];
if a2 == "-" || ! a2.starts_with("-") {
(Arg::Option(a), Some(1), some_pair!(2, a2))
} else {
(Arg::Option(a), Some(1), None)
}
} else {
(Arg::Option(a), Some(1), None)
}
} else if a.starts_with("-") {
if a.len() > 2 {
(Arg::Option(&a[..2]), None, some_pair!(1, &a[2..]))
} else if index + 1 < arguments.len() {
let a2 = arguments[index + 1];
if a2 == "-" || ! a2.starts_with("-") {
(Arg::Option(a), Some(1), some_pair!(2, a2))
} else {
(Arg::Option(a), Some(1), None)
}
} else {
(Arg::Option(a), Some(1), None)
}
} else {
(Arg::Value, None, some_pair!(1, a))
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn short_option_simple() {
let args = vec!["-a", "1", "-f", "-g3"];
let v = arg_parse(&args, 0);
assert_eq!(v, (Arg::Option("-a"), Some(1), some_pair!(2, "1")));
let v = arg_parse(&args, 1);
assert_eq!(v, (Arg::Value, None, some_pair!(1, "1")));
let v = arg_parse(&args, 2);
assert_eq!(v, (Arg::Option("-f"), Some(1), None));
let v = arg_parse(&args, 3);
assert_eq!(v, (Arg::Option("-g"), None, some_pair!(1, "3")));
}
#[test]
fn short_option_complicated() {
let args = vec!["-a=1", "-f", "-", "-g", "--", "-h"];
let v = arg_parse(&args, 0);
assert_eq!(v, (Arg::Option("-a"), None, some_pair!(1, "=1")));
let v = arg_parse(&args, 1);
assert_eq!(v, (Arg::Option("-f"), Some(1), some_pair!(2, "-")));
let v = arg_parse(&args, 2);
assert_eq!(v, (Arg::Value, None, some_pair!(1, "-")));
let v = arg_parse(&args, 3);
assert_eq!(v, (Arg::Option("-g"), Some(1), None));
let v = arg_parse(&args, 4);
assert_eq!(v, (Arg::Separator("--"), Some(1), None));
let v = arg_parse(&args, 5);
assert_eq!(v, (Arg::Option("-h"), Some(1), None));
}
#[test]
fn long_option_simple() {
let args = vec!["--aa", "1", "--ff", "--gg=3"];
let v = arg_parse(&args, 0);
assert_eq!(v, (Arg::Option("--aa"), Some(1), some_pair!(2, "1")));
let v = arg_parse(&args, 1);
assert_eq!(v, (Arg::Value, None, some_pair!(1, "1")));
let v = arg_parse(&args, 2);
assert_eq!(v, (Arg::Option("--ff"), Some(1), None));
let v = arg_parse(&args, 3);
assert_eq!(v, (Arg::Option("--gg"), None, some_pair!(1, "3")));
}
#[test]
fn match_test() {
let args = vec!["--aa", "1", "--bb=3"];
let v = arg_parse(&args, 0);
match v {
(Arg::Option("--aa"), Some(1), Some((2, "1"))) => { }
_ => { panic!("match fails.") }
}
match v {
(Arg::Option("--aa"), _, Some((eat, "1"))) => {
assert_eq!(eat, 2 as usize);
}
_ => { panic!("match fails.") }
}
let v = arg_parse(&args, 2);
match v {
(Arg::Option("--bb"), None, Some((eat, value))) => {
assert_eq!(eat, 1 as usize);
assert_eq!(value, "3");
}
_ => { panic!("match fails.") }
}
}
}