use std::any::TypeId;
use crate::error;
use crate::opt::Action;
#[allow(unused)]
use crate::opt::Cmd;
#[allow(unused)]
use crate::opt::Creator;
use crate::opt::Help;
use crate::opt::Index;
#[allow(unused)]
use crate::opt::Main;
use crate::opt::Opt;
#[allow(unused)]
use crate::opt::Pos;
use crate::opt::Style;
use crate::value::ErasedValue;
use crate::value::ValAccessor;
use crate::Error;
use crate::Uid;
use super::ConfigValue;
use super::OptConfig;
#[derive(Debug)]
pub struct AOpt {
uid: Uid,
name: String,
r#type: TypeId,
help: Help,
styles: Vec<Style>,
index: Option<Index>,
accessor: ValAccessor,
alias: Option<Vec<String>>,
action: Action,
matched: bool,
force: bool,
ignore_name: bool,
ignore_alias: bool,
ignore_index: bool,
}
impl AOpt {
pub fn new(name: String, type_id: TypeId, accessor: ValAccessor) -> Self {
Self {
uid: 0,
name,
r#type: type_id,
help: Default::default(),
matched: false,
force: false,
action: Default::default(),
styles: vec![],
index: None,
accessor,
alias: None,
ignore_name: false,
ignore_alias: false,
ignore_index: false,
}
}
pub fn with_uid(mut self, uid: Uid) -> Self {
self.uid = uid;
self
}
pub fn with_name(mut self, name: impl Into<String>) -> Self {
self.name = name.into();
self
}
pub fn with_type(mut self, r#type: TypeId) -> Self {
self.r#type = r#type;
self
}
pub fn with_ignore_name(mut self, ignore_name: bool) -> Self {
self.ignore_name = ignore_name;
self
}
pub fn with_ignore_alias(mut self, ignore_alias: bool) -> Self {
self.ignore_alias = ignore_alias;
self
}
pub fn with_ignore_index(mut self, ignore_index: bool) -> Self {
self.ignore_index = ignore_index;
self
}
pub fn with_hint(mut self, hint: impl Into<String>) -> Self {
self.help.set_hint(hint);
self
}
pub fn with_help(mut self, help: impl Into<String>) -> Self {
self.help.set_help(help);
self
}
pub fn with_action(mut self, action: Action) -> Self {
self.action = action;
self
}
pub fn with_opt_help(mut self, help: Help) -> Self {
self.help = help;
self
}
pub fn with_style(mut self, styles: Vec<Style>) -> Self {
self.styles = styles;
self
}
pub fn with_idx(mut self, index: Option<Index>) -> Self {
self.index = index;
self
}
pub fn with_force(mut self, force: bool) -> Self {
self.force = force;
self
}
pub fn with_alias(mut self, alias: Option<Vec<String>>) -> Self {
self.alias = alias;
self
}
pub fn with_accessor(mut self, value: ValAccessor) -> Self {
self.accessor = value;
self
}
}
impl AOpt {
pub fn set_name(&mut self, name: impl Into<String>) -> &mut Self {
self.name = name.into();
self
}
pub fn set_type(&mut self, r#type: TypeId) -> &mut Self {
self.r#type = r#type;
self
}
pub fn set_value(&mut self, value: ValAccessor) -> &mut Self {
self.accessor = value;
self
}
pub fn set_hint(&mut self, hint: impl Into<String>) -> &mut Self {
self.help.set_hint(hint);
self
}
pub fn set_help(&mut self, help: impl Into<String>) -> &mut Self {
self.help.set_help(help);
self
}
pub fn set_action(&mut self, action: Action) -> &mut Self {
self.action = action;
self
}
pub fn set_style(&mut self, styles: Vec<Style>) -> &mut Self {
self.styles = styles;
self
}
pub fn set_index(&mut self, index: Option<Index>) -> &mut Self {
self.index = index;
self
}
pub fn set_force(&mut self, force: bool) -> &mut Self {
self.force = force;
self
}
pub fn add_alias(&mut self, name: impl Into<String>) -> &mut Self {
if let Some(alias) = &mut self.alias {
alias.push(name.into());
}
self
}
pub fn rem_alias(&mut self, name: &str) -> &mut Self {
if let Some(alias) = &mut self.alias {
if let Some((i, _)) = alias.iter().enumerate().find(|(_, v)| v == &name) {
alias.remove(i);
}
}
self
}
pub fn set_ignore_name(&mut self, ignore_name: bool) -> &mut Self {
self.ignore_name = ignore_name;
self
}
pub fn set_ignore_alias(&mut self, ignore_alias: bool) -> &mut Self {
self.ignore_alias = ignore_alias;
self
}
pub fn set_ignore_index(&mut self, ignore_index: bool) -> &mut Self {
self.ignore_index = ignore_index;
self
}
}
impl Opt for AOpt {
fn reset(&mut self) {
self.set_matched(false);
}
fn uid(&self) -> Uid {
self.uid
}
fn name(&self) -> &str {
&self.name
}
fn r#type(&self) -> &TypeId {
&self.r#type
}
fn hint(&self) -> &str {
self.help.hint()
}
fn help(&self) -> &str {
self.help.help()
}
fn valid(&self) -> bool {
!self.force() || self.matched()
}
fn matched(&self) -> bool {
self.matched
}
fn force(&self) -> bool {
self.force
}
fn action(&self) -> &Action {
&self.action
}
fn index(&self) -> Option<&Index> {
self.index.as_ref()
}
fn alias(&self) -> Option<&Vec<String>> {
self.alias.as_ref()
}
fn accessor(&self) -> &ValAccessor {
&self.accessor
}
fn accessor_mut(&mut self) -> &mut ValAccessor {
&mut self.accessor
}
fn ignore_alias(&self) -> bool {
self.ignore_alias
}
fn ignore_name(&self) -> bool {
self.ignore_name
}
fn ignore_index(&self) -> bool {
self.ignore_index
}
fn set_uid(&mut self, uid: Uid) {
self.uid = uid;
}
fn set_matched(&mut self, matched: bool) {
self.matched = matched;
}
fn mat_style(&self, style: Style) -> bool {
self.styles.iter().any(|v| v == &style)
}
fn mat_force(&self, force: bool) -> bool {
self.force() == force
}
fn mat_name(&self, name: Option<&str>) -> bool {
name == Some(self.name())
}
fn mat_alias(&self, name: &str) -> bool {
if let Some(alias) = &self.alias {
alias.iter().any(|v| v == name)
} else {
false
}
}
fn mat_index(&self, index: Option<(usize, usize)>) -> bool {
if let Some((index, total)) = index {
if let Some(realindex) = self.index() {
if let Some(realindex) = realindex.calc_index(index, total) {
return realindex == index;
}
}
}
false
}
fn init(&mut self) -> Result<(), Error> {
self.accessor.initialize()
}
fn set_name(&mut self, name: impl Into<String>) -> &mut Self {
self.name = name.into();
self
}
fn set_type(&mut self, r#type: TypeId) -> &mut Self {
self.r#type = r#type;
self
}
fn set_value(&mut self, value: ValAccessor) -> &mut Self {
self.accessor = value;
self
}
fn set_hint(&mut self, hint: impl Into<String>) -> &mut Self {
self.help.set_hint(hint);
self
}
fn set_help(&mut self, help: impl Into<String>) -> &mut Self {
self.help.set_help(help);
self
}
fn set_action(&mut self, action: Action) -> &mut Self {
self.action = action;
self
}
fn set_style(&mut self, styles: Vec<Style>) -> &mut Self {
self.styles = styles;
self
}
fn set_index(&mut self, index: Option<Index>) -> &mut Self {
self.index = index;
self
}
fn set_force(&mut self, force: bool) -> &mut Self {
self.force = force;
self
}
fn add_alias(&mut self, name: impl Into<String>) -> &mut Self {
if let Some(alias) = &mut self.alias {
alias.push(name.into());
}
self
}
fn rem_alias(&mut self, name: &str) -> &mut Self {
if let Some(alias) = &mut self.alias {
if let Some((i, _)) = alias.iter().enumerate().find(|(_, v)| v == &name) {
alias.remove(i);
}
}
self
}
fn set_ignore_name(&mut self, ignore_name: bool) -> &mut Self {
self.ignore_name = ignore_name;
self
}
fn set_ignore_alias(&mut self, ignore_alias: bool) -> &mut Self {
self.ignore_alias = ignore_alias;
self
}
fn set_ignore_index(&mut self, ignore_index: bool) -> &mut Self {
self.ignore_index = ignore_index;
self
}
}
fn gen_hint(
hint: Option<impl Into<String>>,
n: &str,
idx: Option<&Index>,
alias: Option<&Vec<String>>,
) -> String {
let hint_generator = || {
let mut names = Vec::with_capacity(1 + alias.map(|v| v.len()).unwrap_or_default());
names.push(n);
if let Some(alias_vec) = alias {
for alias in alias_vec {
names.push(alias.as_str());
}
}
names.sort_by_key(|v| v.len());
if let Some(index) = idx {
let index_string = index.to_help();
if index_string.is_empty() {
names.join(", ")
} else {
format!("{}@{}", names.join(", "), index_string)
}
} else {
names.join(", ")
}
};
hint.map(|v| v.into()).unwrap_or_else(hint_generator)
}
impl TryFrom<OptConfig> for AOpt {
type Error = Error;
fn try_from(mut value: OptConfig) -> Result<Self, Self::Error> {
let r#type = value.take_type();
let name = value.take_name();
let force = value.take_force();
let index = value.take_index();
let alias = value.take_alias();
let hint = value.take_hint();
let help = value.take_help();
let action = value.take_action();
let storer = value.take_storer();
let styles = value.take_style();
let initializer = value.take_initializer();
let ignore_name = value.ignore_name();
let ignore_alias = value.ignore_alias();
let ignore_index = value.ignore_index();
let force = force.unwrap_or(false);
let action = action.unwrap_or(Action::App);
let storer = storer.ok_or_else(|| error!("incomplete configuration: missing ValStorer"))?;
let initializer = initializer
.ok_or_else(|| error!("incomplete configuration: missing ValInitializer"))?;
let styles = styles.ok_or_else(|| error!("incomplete configuration: missing Style"))?;
let name = name.ok_or_else(|| error!("incomplete configuration: missing option name"))?;
let hint = gen_hint(hint.as_ref(), &name, index.as_ref(), alias.as_ref());
let help = help.unwrap_or_default();
let r#type =
r#type.ok_or_else(|| error!("incomplete configuration: missing option value type"))?;
let help = Help::default().with_help(help).with_hint(hint);
if ignore_alias {
if let Some(alias) = &alias {
debug_assert!(
!alias.is_empty(),
"option {} not support alias: {:?}",
name,
alias
);
}
}
if ignore_index {
if let Some(index) = &index {
debug_assert!(
!index.is_null(),
"please remove the index, option `{}` not support positional parameters: {:?}",
name,
index
);
}
} else {
debug_assert!(
index.is_some(),
"please provide an index, indicate the position you want to capture for option `{}`.",
name
);
}
Ok(
AOpt::new(name, r#type, ValAccessor::new(storer, initializer))
.with_force(force)
.with_idx(index)
.with_action(action)
.with_alias(alias)
.with_style(styles)
.with_opt_help(help)
.with_ignore_name(ignore_name)
.with_ignore_alias(ignore_alias)
.with_ignore_index(ignore_index),
)
}
}