1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
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.
	ParentActionRequest(Command, Context),
	/// Shows return Context, reached Command and Action as result for parse and run.
	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: Command,
	/// context is a field for storing context that error occured
	pub context: Context,
	/// If there is an error which is not ActionError, related_error 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,
			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,
			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 flag_value 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 flag_value 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 flag_value 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 flag_value 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 flag_value 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 local flag value from context. Different from get, returns flag_value 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)
		}
	}
}