diff --git a/src/api/schema.rs b/src/api/schema.rs index e01f18af..9274dbcf 100644 --- a/src/api/schema.rs +++ b/src/api/schema.rs @@ -251,7 +251,7 @@ impl ArraySchema { pub struct ObjectSchema { pub description: &'static str, pub additional_properties: bool, - pub properties: HashMap<&'static str, (bool, Arc)>, + pub properties: HashMap<&'static str, Arc>, pub default_key: Option<&'static str>, } @@ -278,12 +278,12 @@ impl ObjectSchema { } pub fn required>>(mut self, name: &'static str, schema: S) -> Self { - self.properties.insert(name, (false, schema.into())); + self.properties.insert(name, schema.into()); self } pub fn optional>>(mut self, name: &'static str, schema: S) -> Self { - self.properties.insert(name, (true, schema.into())); + self.properties.insert(name, Arc::new(Schema::Option(schema.into()))); self } } @@ -296,6 +296,7 @@ pub enum Schema { String(StringSchema), Object(ObjectSchema), Array(ArraySchema), + Option(Arc), } impl From for Schema { @@ -455,6 +456,9 @@ pub fn parse_simple_value(value_str: &str, schema: &Schema) -> Result { + parse_simple_value(value_str, option_schema)? + } _ => bail!("unable to parse complex (sub) objects."), }; Ok(value) @@ -472,7 +476,7 @@ pub fn parse_parameter_strings(data: &Vec<(String, String)>, schema: &ObjectSche let additional_properties = schema.additional_properties; for (key, value) in data { - if let Some((_optional, prop_schema)) = properties.get::(key) { + if let Some(prop_schema) = properties.get::(key) { match prop_schema.as_ref() { Schema::Array(array_schema) => { if params[key] == Value::Null { @@ -523,9 +527,14 @@ pub fn parse_parameter_strings(data: &Vec<(String, String)>, schema: &ObjectSche } if test_required && errors.len() == 0 { - for (name, (optional, _prop_schema)) in properties { - if *optional == false && params[name] == Value::Null { - errors.push(format_err!("parameter '{}': parameter is missing and it is not optional.", name)); + for (name, prop_schema) in properties { + match prop_schema.as_ref() { + Schema::Option(_) => {}, + _ => { + if params[name] == Value::Null { + errors.push(format_err!("parameter '{}': parameter is missing and it is not optional.", name)); + } + } } } } @@ -554,6 +563,11 @@ pub fn verify_json(data: &Value, schema: &Schema) -> Result<(), Error> { Schema::Array(array_schema) => { verify_json_array(data, &array_schema)?; } + Schema::Option(option_schema) => { + if !data.is_null() { + verify_json(data, option_schema)?; + } + } Schema::Null => { if !data.is_null() { bail!("Expected Null, but value is not Null."); @@ -618,7 +632,7 @@ pub fn verify_json_object(data: &Value, schema: &ObjectSchema) -> Result<(), Err let additional_properties = schema.additional_properties; for (key, value) in map { - if let Some((_optional, prop_schema)) = properties.get::(key) { + if let Some(prop_schema) = properties.get::(key) { match prop_schema.as_ref() { Schema::Object(object_schema) => { verify_json_object(value, object_schema)?; @@ -635,9 +649,14 @@ pub fn verify_json_object(data: &Value, schema: &ObjectSchema) -> Result<(), Err } } - for (name, (optional, _prop_schema)) in properties { - if *optional == false && data[name] == Value::Null { - bail!("property '{}': property is missing and it is not optional.", name); + for (name, prop_schema) in properties { + match prop_schema.as_ref() { + Schema::Option(_) => {}, + _ => { + if data[name] == Value::Null { + bail!("property '{}': property is missing and it is not optional.", name); + } + } } } diff --git a/src/cli/command.rs b/src/cli/command.rs index 87143d82..3c36e3da 100644 --- a/src/cli/command.rs +++ b/src/cli/command.rs @@ -120,7 +120,7 @@ fn record_done_arguments(done: &mut HashSet, parameters: &ObjectSchema, for arg in list { if arg.starts_with("--") && arg.len() > 2 { let prop_name = arg[2..].to_owned(); - if let Some((_, schema)) = parameters.properties.get::(&prop_name) { + if let Some(schema) = parameters.properties.get::(&prop_name) { match schema.as_ref() { Schema::Array(_) => { /* do nothing */ } _ => { done.insert(prop_name); } @@ -147,7 +147,7 @@ fn print_simple_completion( print_simple_completion(cli_cmd, done, &arg_param[1..], args); return; } else if args.len() == 1 { - if let Some((_, schema)) = cli_cmd.info.parameters.properties.get(prop_name) { + if let Some(schema) = cli_cmd.info.parameters.properties.get(prop_name) { print_property_completion(schema, prop_name, &cli_cmd.completion_functions, &args[0]); } } @@ -164,14 +164,14 @@ fn print_simple_completion( let last = &args[args.len()-1]; if last.starts_with("--") && last.len() > 2 { let prop_name = &last[2..]; - if let Some((_, schema)) = cli_cmd.info.parameters.properties.get(prop_name) { + if let Some(schema) = cli_cmd.info.parameters.properties.get(prop_name) { print_property_completion(schema, prop_name, &cli_cmd.completion_functions, &prefix); } return; } } - for (name, (_optional, _schema)) in &cli_cmd.info.parameters.properties { + for (name, _schema) in &cli_cmd.info.parameters.properties { if done.contains(*name) { continue; } let option = String::from("--") + name; if option.starts_with(&prefix) { diff --git a/src/getopts.rs b/src/getopts.rs index 1293deec..4a276ca1 100644 --- a/src/getopts.rs +++ b/src/getopts.rs @@ -75,7 +75,7 @@ pub fn parse_arguments>( None => { let mut want_bool = false; let mut can_default = false; - if let Some((_optional, param_schema)) = properties.get::(&name) { + if let Some(param_schema) = properties.get::(&name) { if let Schema::Boolean(boolean_schema) = param_schema.as_ref() { want_bool = true; if let Some(default) = boolean_schema.default { diff --git a/src/section_config.rs b/src/section_config.rs index 0a057a73..c6a175f7 100644 --- a/src/section_config.rs +++ b/src/section_config.rs @@ -150,9 +150,14 @@ impl SectionConfig { let mut state = ParseState::BeforeHeader; let test_required_properties = |value: &Value, schema: &ObjectSchema| -> Result<(), Error> { - for (name, (optional, _prop_schema)) in &schema.properties { - if *optional == false && value[name] == Value::Null { - return Err(format_err!("property '{}' is missing and it is not optional.", name)); + for (name, prop_schema) in &schema.properties { + match prop_schema.as_ref() { + Schema::Option(_) => {}, + _ => { + if value[name] == Value::Null { + return Err(format_err!("property '{}' is missing and it is not optional.", name)); + } + } } } Ok(()) @@ -204,7 +209,7 @@ impl SectionConfig { if let Some((key, value)) = (self.parse_section_content)(line) { //println!("CONTENT: key: {} value: {}", key, value); - if let Some((_optional, prop_schema)) = plugin.properties.properties.get::(&key) { + if let Some(prop_schema) = plugin.properties.properties.get::(&key) { match parse_simple_value(&value, prop_schema) { Ok(value) => { if config[&key] == Value::Null {