combu 1.6.1

Combu is a yet another mini cli framework.
Documentation
use fmt::Debug;

use crate::{Command, Context};
use std::{error::Error, fmt};

/// `Action` is type for command action. It returns `Result<ActionResult, ActionError>`.
pub type Action = fn(Command, Context) -> Result<ActionResult, ActionError>;

/// `ActionResult` stores result of action.
/// `Command`のアクション結果を格納し、runの結果として返却するためのenum。
#[derive(Debug)]
pub enum ActionResult {
	///Done shows that action is done.
	Done,
	/// `ParentActionRequest` shows that action requested to show help.
	/// It is mainly used for help command.
	ParentActionRequest(Command, Context),
	/// Shows return `Context`, reached `Command` and `Action` as result for parse and run.
	/// By using this, it is possible to get parse result and run action without keeping command instances of tree in memory.
	Result(Command, Context),
	/// Custom result(can have Box including dyn Debug).
	Custom(Box<dyn Debug>),
}

impl ActionResult {
	/// Returns true if self is done.
	pub fn is_done(&self) -> bool {
		matches!(self, ActionResult::Done)
	}
}

/// `ActionError` stores error of action.
#[derive(Debug)]
pub struct ActionError {
	/// `ActionError`'s value
	pub value: String,
	/// `ActionError`'s Kind
	pub kind: ActionErrorKind,
	/// command is a field for storing command that error occured
	pub command: Box<Command>,
	/// context is a field for storing context that error occured
	pub context: Box<Context>,
	/// If there is an error which is not `ActionError`, this can stores it.
	pub related_error: Option<Box<dyn Error>>,
	/// printed flag. If this is true, this shows error is not printed yet.
	pub printed: bool,
}

/// `ErrorKind` of `ActionError`
#[derive(Debug)]
pub enum ActionErrorKind {
	/// Shows a custom(Normal) error
	Custom,
	/// Shows that no action is registered to specidied command.
	NoActionRegistered,
	/// Shows None.
	None,
}

impl ActionError {
	/// Creates new `ActionError`.
	pub fn new<T: Into<String>>(
		value: T,
		kind: ActionErrorKind,
		command: Command,
		context: Context,
		related_error: Option<Box<dyn Error>>,
	) -> Self {
		Self {
			value: value.into(),
			kind,
			command: Box::new(command),
			context: Box::new(context),
			related_error,
			printed: false,
		}
	}

	/// Creates new `ActionError` without (not action) error info.
	pub fn without_related_error(
		value: String,
		kind: ActionErrorKind,
		command: Command,
		context: Context,
	) -> Self {
		Self {
			value,
			kind,
			command: Box::new(command),
			context: Box::new(context),
			related_error: None,
			printed: false,
		}
	}
}

impl fmt::Display for ActionError {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
		match self.kind {
			ActionErrorKind::Custom => write!(f, "{}", self.value),
			ActionErrorKind::NoActionRegistered => {
				write!(f, "{} does not have its own action.", self.value)
			}
			ActionErrorKind::None => write!(f, "no action error"),
		}
	}
}

impl Error for ActionError {}

/// bundle is a helper for processing in action.
pub mod bundle {
	use std::collections::VecDeque;

	use crate::{Command, Context, FlagValue};

	/// New-type for help processing in action. Inner is simple tuple - `(Context,Command)`
	pub struct Bundle(pub Context, pub Command);

	impl From<(Context, Command)> for Bundle {
		fn from(val: (Context, Command)) -> Self {
			Bundle(val.0, val.1)
		}
	}

	impl From<Bundle> for (Context, Command) {
		fn from(val: Bundle) -> Self {
			val.unpack()
		}
	}

	impl Bundle {
		/// Creates new instance of bundle.
		pub fn new(ctx: Context, cmd: Command) -> Self {
			Bundle(ctx, cmd)
		}
		/// Returns inner tuple (Context,Command)
		pub fn unpack(self) -> (Context, Command) {
			let Bundle(ctx, cmd) = self;
			(ctx, cmd)
		}
		/// Returns ref of `Context`
		pub fn context(&self) -> &Context {
			&self.0
		}
		/// Returns ref of `Command`
		pub fn command(&self) -> &Command {
			&self.1
		}
		/// Returns mut ref of `Context`
		pub fn context_mut(&mut self) -> &mut Context {
			&mut self.0
		}
		/// Returns mut ref of `Command`
		pub fn command_mut(&mut self) -> &mut Command {
			&mut self.1
		}
		/// Get `exe_path` as `&str`
		pub fn exe_path(&self) -> &str {
			self.context().exe_path()
		}
		/// Takes flag value from context. Different from get, returns `FlagValue` instance own (not reference) that has context.
		/// contextからフラグ値を取得する。Getとは違い、参照ではなくcontextに格納されているもの(格納されていない場合はデフォルト値のコピー)そのものを返す
		pub fn take_flag_value_of(&mut self, flag_name: &str) -> Option<FlagValue> {
			self.0.take_flag_value_of(flag_name, &self.1)
		}
		/// Takes inputted flag value from context. Different from get, returns `FlagValue` instance own (not reference) that has context.
		/// contextからフラグ値を(ユーザによりargに指定(入力)されている場合)取得する。Getとは違い、参照ではなくcontextに格納されているもの(格納されていない場合はNoneを)そのものを返す
		pub fn take_inputted_flag_value_of(&mut self, flag_name: &str) -> Option<FlagValue> {
			self.0.take_inputted_flag_value_of(flag_name)
		}
		/// Takes flag value from context. Different from get, returns `FlagValue` instance own (not reference) that has context.
		/// contextからローカルフラグの値を取得する。Getとは違い、参照ではなくcontextに格納されているもの(格納されていない場合はデフォルト値のコピー)そのものを返す
		pub fn take_local_flag_value_of(&mut self, flag_name: &str) -> Option<FlagValue> {
			self.0.take_local_flag_value_of(flag_name, &self.1)
		}
		/// Takes inputted flag value from context. Different from get, returns `FlagValue` instance own (not reference) that has context.
		/// contextからコモンフラグの値を取得する。Getとは違い、参照ではなくcontextに格納されているもの(格納されていない場合はデフォルト値のコピー)そのものを返す
		pub fn take_common_flag_value_of(&mut self, flag_name: &str) -> Option<FlagValue> {
			self.0.take_common_flag_value_of(flag_name, &self.1)
		}

		/// Takes inputted local flag value from context. Different from get, returns `FlagValue` instance own (not reference) that has context.
		/// contextからローカルフラグ値を(ユーザによりargに指定(入力)されている場合)取得する。Getとは違い、参照ではなくcontextに格納されているものそのもの(格納されていない場合はNone)を返す
		pub fn take_inputted_local_flag_value_of(&mut self, flag_name: &str) -> Option<FlagValue> {
			self.0.take_inputted_local_flag_value_of(flag_name)
		}

		/// Takes inputted common flag value from context. Different from get, returns `FlagValue` instance own (not reference) that has context.
		/// contextからコモンフラグ値を(ユーザによりargに指定(入力)されている場合)取得する。Getとは違い、参照ではなくcontextに格納されているものそのもの(格納されていない場合はNone)を返す
		pub fn take_inputted_common_flag_value_of(&mut self, flag_name: &str) -> Option<FlagValue> {
			self.0.take_inputted_common_flag_value_of(flag_name)
		}

		/// Gets `FlagValue`'s clone of the flag matches `flag_name` from context.
		/// contextからフラグ値のcloneを取得する。フラグが設定されていない場合はNoneを返す
		/// なお明示的に値が指定されない場合、`Bool`型のフラグであれば`FlagValue::Bool(true)`とし、`String`型のフラグであれば`FlagValue::String(String::new())`、それ以外の型のフラグでは`FlagValue::None`をSomeで包んで返す
		pub fn get_flag_value_of(&self, flag_name: &str) -> Option<FlagValue> {
			self.0.get_local_flag_value_of(flag_name, &self.1)
		}

		/// Gets `FlagValue`'s clone of the inputted flag matches `flag_name` from context.
		/// contextからユーザから指定された場合のフラグ値のcloneを取得する。ユーザから入力されていない場合はNoneを返す。
		pub fn get_inputted_flag_value_of(&self, flag_name: &str) -> Option<FlagValue> {
			self.0.get_inputted_flag_value_of(flag_name)
		}

		/// Gets `FlagValue`'s clone of the common flag matches `flag_name` from context. If it is not defined, Returns None.
		/// contextからユーザから指定された場合のローカルフラグ値のcloneを取得する。ユーザから入力されていないが定義されている場合はデフォルト値のクローンを返す。定義もされていない場合はNoneを返す。
		/// なお明示的に値が指定されない場合、`Bool`型のフラグであれば`FlagValue::Bool(true)`とし、`String`型のフラグであれば`FlagValue::String(String::new())`、それ以外の型のフラグでは`FlagValue::None`をSomeで包んで返す
		pub fn get_local_flag_value_of(&self, flag_name: &str) -> Option<FlagValue> {
			self.0.get_local_flag_value_of(flag_name, &self.1)
		}

		/// Gets the flag value of the local flag matches `flag_name` if inputted. If it is not defined or not inputted, returns None.
		/// `flag_name`と`name`が一致するローカルフラグがあり、それがユーザからコマンド引数で指定されていた場合、その値のクローンをSomeで包んで返す。`flag_name`と一致する`name`をどのローカルフラグも持たないか、ユーザがコマンド引数で指定していない場合はNoneを返す。
		pub fn get_inputted_local_flag_value_of(&self, flag_name: &str) -> Option<FlagValue> {
			self.0.get_inputted_common_flag_value_of(flag_name)
		}

		/// Gets the flag value of the common flag whose name matches `flag_name`. If it is not defined or not inputted, returns None.
		/// `flag_name`と`name`が一致するコモンフラグがあり、それがユーザからコマンド引数で指定されていた場合、その値のクローンをSomeで包んで返す。`flag_name`と一致する`name`をどのコモンフラグも持たないか、ユーザがコマンド引数で指定していない場合はNoneを返す。
		pub fn get_inputted_common_flag_value_of(&self, flag_name: &str) -> Option<FlagValue> {
			self.0.get_inputted_common_flag_value_of(flag_name)
		}

		/// Returns true the value of the flag which has specified name is true.
		pub fn is_flag_true(&self, name: &str) -> bool {
			Some(FlagValue::Bool(true)) == self.0.get_flag_value_of(name, &self.1)
		}

		/// Returns depth of command - root:0
		pub fn depth(&self) -> usize {
			self.0.common_flags.len()
		}

		/// Returns reference of args
		pub fn args(&self) -> &VecDeque<String> {
			&self.0.args
		}

		/// Returns n'th arg
		pub fn arg(&self, index: usize) -> Option<&String> {
			self.0.args.get(index)
		}
	}
}