pub mod validators;
use crate::errors::InvalidOption;
use std::fmt;
pub struct OptCfg {
pub store_key: String,
pub names: Vec<String>,
pub has_arg: bool,
pub is_array: bool,
pub defaults: Option<Vec<String>>,
pub desc: String,
pub arg_in_help: String,
pub validator: fn(store_key: &str, name: &str, arg: &str) -> Result<(), InvalidOption>,
}
impl fmt::Debug for OptCfg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("OptCfg")
.field("store_key", &self.store_key)
.field("names", &self.names)
.field("has_arg", &self.has_arg)
.field("is_array", &self.is_array)
.field("defaults", &self.defaults)
.field("desc", &self.desc)
.field("arg_in_help", &self.arg_in_help)
.finish()
}
}
impl OptCfg {
pub fn with<'a>(params: impl IntoIterator<Item = OptCfgParam<'a>>) -> OptCfg {
let empty_string = String::from("");
let empty_vec = Vec::with_capacity(0);
let mut _store_key: &str = &empty_string;
let mut _names: &[&str] = &empty_vec;
let mut _has_arg = false;
let mut _is_array = false;
let mut _defaults = None;
let mut _desc: &str = &empty_string;
let mut _arg_in_help: &str = &empty_string;
let mut _validator: fn(
store_key: &str,
name: &str,
arg: &str,
) -> Result<(), InvalidOption> = |_, _, _| Ok(());
for param in params.into_iter() {
match param {
OptCfgParam::store_key(s) => _store_key = s,
OptCfgParam::names(v) => _names = v,
OptCfgParam::has_arg(b) => _has_arg = b,
OptCfgParam::is_array(b) => _is_array = b,
OptCfgParam::defaults(v) => _defaults = Some(v),
OptCfgParam::desc(s) => _desc = s,
OptCfgParam::arg_in_help(s) => _arg_in_help = s,
OptCfgParam::validator(f) => _validator = f,
}
}
OptCfg {
store_key: _store_key.to_string(),
names: _names.iter().map(|s| s.to_string()).collect(),
has_arg: _has_arg,
is_array: _is_array,
defaults: if let Some(sl) = _defaults {
Some(sl.iter().map(|s| s.to_string()).collect())
} else {
None
},
desc: _desc.to_string(),
arg_in_help: _arg_in_help.to_string(),
validator: _validator,
}
}
}
#[allow(non_camel_case_types)]
pub enum OptCfgParam<'a> {
store_key(&'a str),
names(&'a [&'a str]),
has_arg(bool),
is_array(bool),
defaults(&'a [&'a str]),
desc(&'a str),
arg_in_help(&'a str),
validator(fn(&str, &str, &str) -> Result<(), InvalidOption>),
}
#[cfg(test)]
mod tests_of_opt_cfg {
use super::*;
mod tests_of_named_param {
use super::*;
#[test]
fn test_of_store_key() {
let cfg = OptCfg::with([OptCfgParam::store_key("fooBar")]);
assert_eq!(cfg.store_key, "fooBar");
assert_eq!(cfg.names, Vec::<String>::new());
assert_eq!(cfg.has_arg, false);
assert_eq!(cfg.is_array, false);
assert_eq!(cfg.defaults, None);
assert_eq!(cfg.desc, "");
assert_eq!(cfg.arg_in_help, "");
assert_eq!((cfg.validator)("a", "b", "c"), Ok(()));
}
#[test]
fn test_of_names() {
let cfg = OptCfg::with([OptCfgParam::names(&["foo-bar", "f"])]);
assert_eq!(cfg.store_key, "");
assert_eq!(cfg.names, vec!["foo-bar".to_string(), "f".to_string()]);
assert_eq!(cfg.has_arg, false);
assert_eq!(cfg.is_array, false);
assert_eq!(cfg.defaults, None);
assert_eq!(cfg.desc, "");
assert_eq!(cfg.arg_in_help, "");
assert_eq!((cfg.validator)("a", "b", "c"), Ok(()));
}
#[test]
fn test_of_has_arg() {
let cfg = OptCfg::with([OptCfgParam::has_arg(true)]);
assert_eq!(cfg.store_key, "");
assert_eq!(cfg.names, Vec::<String>::new());
assert_eq!(cfg.has_arg, true);
assert_eq!(cfg.is_array, false);
assert_eq!(cfg.defaults, None);
assert_eq!(cfg.desc, "");
assert_eq!(cfg.arg_in_help, "");
assert_eq!((cfg.validator)("a", "b", "c"), Ok(()));
}
#[test]
fn test_of_is_array() {
let cfg = OptCfg::with([OptCfgParam::is_array(true)]);
assert_eq!(cfg.store_key, "");
assert_eq!(cfg.names, Vec::<String>::new());
assert_eq!(cfg.has_arg, false);
assert_eq!(cfg.is_array, true);
assert_eq!(cfg.defaults, None);
assert_eq!(cfg.desc, "");
assert_eq!(cfg.arg_in_help, "");
assert_eq!((cfg.validator)("a", "b", "c"), Ok(()));
}
#[test]
fn test_of_defaults() {
let cfg = OptCfg::with([OptCfgParam::defaults(&["123", "456"])]);
assert_eq!(cfg.store_key, "");
assert_eq!(cfg.names, Vec::<String>::new());
assert_eq!(cfg.has_arg, false);
assert_eq!(cfg.is_array, false);
assert_eq!(
cfg.defaults,
Some(vec!["123".to_string(), "456".to_string()])
);
assert_eq!(cfg.desc, "");
assert_eq!(cfg.arg_in_help, "");
assert_eq!((cfg.validator)("a", "b", "c"), Ok(()));
}
#[test]
fn test_of_desc() {
let cfg = OptCfg::with([OptCfgParam::desc("description")]);
assert_eq!(cfg.store_key, "");
assert_eq!(cfg.names, Vec::<String>::new());
assert_eq!(cfg.has_arg, false);
assert_eq!(cfg.is_array, false);
assert_eq!(cfg.defaults, None);
assert_eq!(cfg.desc, "description");
assert_eq!(cfg.arg_in_help, "");
assert_eq!((cfg.validator)("a", "b", "c"), Ok(()));
}
#[test]
fn test_of_arg_in_help() {
let cfg = OptCfg::with([OptCfgParam::arg_in_help("<num>")]);
assert_eq!(cfg.store_key, "");
assert_eq!(cfg.names, Vec::<String>::new());
assert_eq!(cfg.has_arg, false);
assert_eq!(cfg.is_array, false);
assert_eq!(cfg.defaults, None);
assert_eq!(cfg.desc, "");
assert_eq!(cfg.arg_in_help, "<num>");
assert_eq!((cfg.validator)("a", "b", "c"), Ok(()));
}
#[test]
fn test_of_validator() {
let cfg = OptCfg::with([OptCfgParam::validator(|key, name, arg| {
Err(InvalidOption::OptionArgIsInvalid {
store_key: key.to_string(),
option: name.to_string(),
opt_arg: arg.to_string(),
details: "fail to parse integer".to_string(),
})
})]);
assert_eq!(cfg.store_key, "");
assert_eq!(cfg.names, Vec::<String>::new());
assert_eq!(cfg.has_arg, false);
assert_eq!(cfg.is_array, false);
assert_eq!(cfg.defaults, None);
assert_eq!(cfg.desc, "");
assert_eq!(cfg.arg_in_help, "");
match (cfg.validator)("a", "b", "c") {
Ok(_) => assert!(false),
Err(InvalidOption::OptionArgIsInvalid {
store_key,
option,
opt_arg,
details,
}) => {
assert_eq!(store_key, "a");
assert_eq!(option, "b");
assert_eq!(opt_arg, "c");
assert_eq!(details, "fail to parse integer");
}
Err(_) => assert!(false),
}
}
#[test]
fn test_of_debug() {
let cfg = OptCfg {
store_key: "fooBar".to_string(),
names: vec!["foo-bar".to_string(), "baz".to_string()],
has_arg: true,
is_array: true,
defaults: Some(vec![123.to_string(), 456.to_string()]),
desc: "option description".to_string(),
arg_in_help: "<num>".to_string(),
validator: |_, _, _| Ok(()),
};
assert_eq!(
format!("{cfg:?}"),
"OptCfg { store_key: \"fooBar\", names: [\"foo-bar\", \"baz\"], has_arg: true, \
is_array: true, defaults: Some([\"123\", \"456\"]), desc: \"option description\", \
arg_in_help: \"<num>\" }"
);
}
}
}