1 use crate::api
::schema
::*;
10 Argument { value: String }
,
11 Option { name: String, value: Option<String> }
,
14 fn parse_argument(arg
: &str) -> RawArgument
{
15 let bytes
= arg
.as_bytes();
17 let length
= bytes
.len();
19 if length
< 2 || bytes
[0] != b'
-'
{
20 return RawArgument
::Argument
{
21 value
: arg
.to_string(),
29 return RawArgument
::Separator
;
34 for start
in first
..length
{
35 if bytes
[start
] == b'
='
{
36 // Since we take a &str, we know the contents of it are valid utf8.
37 // Since bytes[start] == b'=', we know the byte beginning at start is a single-byte
38 // code pointer. We also know that 'first' points exactly after a single-byte code
39 // point as it points to the first byte after a hyphen.
40 // Therefore we know arg[first..start] is valid utf-8, therefore it is safe to use
41 // get_unchecked() to speed things up.
42 return RawArgument
::Option
{
43 name
: unsafe { arg.get_unchecked(first..start).to_string() }
,
44 value
: Some(unsafe { arg.get_unchecked((start + 1)..).to_string() }
),
49 return RawArgument
::Option
{
50 name
: unsafe { arg.get_unchecked(first..).to_string() }
,
55 pub fn parse_arguments
<T
: AsRef
<str>>(
57 arg_param
: &Vec
<&'
static str>,
58 schema
: &ObjectSchema
,
59 ) -> Result
<(Value
, Vec
<String
>), ParameterError
> {
60 let mut errors
= ParameterError
::new();
62 let properties
= &schema
.properties
;
64 let mut data
: Vec
<(String
, String
)> = vec
![];
65 let mut rest
: Vec
<String
> = vec
![];
69 while pos
< args
.len() {
70 match parse_argument(args
[pos
].as_ref()) {
71 RawArgument
::Separator
=> {
74 RawArgument
::Option { name, value }
=> match value
{
76 let mut want_bool
= false;
77 let mut can_default
= false;
78 if let Some((_optional
, param_schema
)) = properties
.get
::<str>(&name
) {
79 if let Schema
::Boolean(boolean_schema
) = param_schema
.as_ref() {
81 if let Some(default) = boolean_schema
.default {
91 let mut next_is_argument
= false;
92 let mut next_is_bool
= false;
94 if (pos
+ 1) < args
.len() {
95 let next
= args
[pos
+ 1].as_ref();
96 if let RawArgument
::Argument { value: _ }
= parse_argument(next
) {
97 next_is_argument
= true;
98 if let Ok(_
) = parse_boolean(next
) {
107 data
.push((name
, args
[pos
].as_ref().to_string()));
108 } else if can_default
{
109 data
.push((name
, "true".to_string()));
111 errors
.push(format_err
!("parameter '{}': {}", name
,
112 "missing boolean value."));
117 if next_is_argument
{
119 data
.push((name
, args
[pos
].as_ref().to_string()));
121 errors
.push(format_err
!("parameter '{}': {}", name
,
122 "missing parameter value."));
127 data
.push((name
, v
));
130 RawArgument
::Argument { value }
=> {
138 rest
.reserve(args
.len() - pos
);
139 for i
in &args
[pos
..] {
140 rest
.push(i
.as_ref().to_string());
143 for i
in 0..arg_param
.len() {
145 data
.push((arg_param
[i
].to_string(), rest
[i
].clone()));
147 errors
.push(format_err
!("missing argument '{}'", arg_param
[i
]));
151 if errors
.len() > 0 {
155 if arg_param
.len() > 0 {
156 rest
= rest
[arg_param
.len()..].to_vec();
159 let options
= parse_parameter_strings(&data
, schema
, true)?
;
165 fn test_boolean_arg() {
166 let schema
= ObjectSchema
::new("Parameters:")
168 "enable", BooleanSchema
::new("Enable")
171 let mut variants
: Vec
<(Vec
<&str>, bool
)> = vec
![];
172 variants
.push((vec
!["-enable"], true));
173 variants
.push((vec
!["-enable=1"], true));
174 variants
.push((vec
!["-enable", "yes"], true));
175 variants
.push((vec
!["-enable", "Yes"], true));
176 variants
.push((vec
!["--enable", "1"], true));
177 variants
.push((vec
!["--enable", "ON"], true));
178 variants
.push((vec
!["--enable", "true"], true));
180 variants
.push((vec
!["--enable", "0"], false));
181 variants
.push((vec
!["--enable", "no"], false));
182 variants
.push((vec
!["--enable", "off"], false));
183 variants
.push((vec
!["--enable", "false"], false));
185 for (args
, expect
) in variants
{
186 let res
= parse_arguments(&args
, &vec
![], &schema
);
187 assert
!(res
.is_ok());
188 if let Ok((options
, rest
)) = res
{
189 assert
!(options
["enable"] == expect
);
190 assert
!(rest
.len() == 0);
196 fn test_argument_paramenter() {
197 let schema
= ObjectSchema
::new("Parameters:")
198 .required("enable", BooleanSchema
::new("Enable."))
199 .required("storage", StringSchema
::new("Storage."));
201 let args
= vec
!["-enable", "local"];
202 let res
= parse_arguments(&args
, &vec
!["storage"], &schema
);
203 assert
!(res
.is_ok());
204 if let Ok((options
, rest
)) = res
{
205 assert
!(options
["enable"] == true);
206 assert
!(options
["storage"] == "local");
207 assert
!(rest
.len() == 0);