Skip to main content

appcore_args/
spec.rs

1use std::fmt;
2
3#[derive(Clone, Debug, PartialEq, Eq)]
4pub struct CliSpec {
5    name: String,
6    about: String,
7    version: Option<String>,
8    commands: Vec<CommandSpec>,
9    options: Vec<OptionSpec>,
10    arguments: Vec<ArgumentSpec>,
11    command_required: bool,
12}
13
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct CommandSpec {
16    name: String,
17    aliases: Vec<String>,
18    about: String,
19    commands: Vec<CommandSpec>,
20    options: Vec<OptionSpec>,
21    arguments: Vec<ArgumentSpec>,
22    command_required: bool,
23    hidden: bool,
24}
25
26#[derive(Clone, Debug, PartialEq, Eq)]
27pub struct OptionSpec {
28    long: String,
29    short: Option<char>,
30    value: ValueMode,
31    value_name: String,
32    value_type: ValueType,
33    possible_values: Vec<String>,
34    about: String,
35    required: bool,
36    repeatable: bool,
37    terminal: bool,
38    hidden: bool,
39    conflicts_with: Vec<String>,
40    requires: Vec<String>,
41}
42
43#[derive(Clone, Debug, PartialEq, Eq)]
44pub struct ArgumentSpec {
45    name: String,
46    about: String,
47    value_type: ValueType,
48    possible_values: Vec<String>,
49    required: bool,
50    multiple: bool,
51}
52
53#[derive(Clone, Copy, Debug, PartialEq, Eq)]
54pub enum ValueMode {
55    Forbidden,
56    Required,
57    Optional,
58}
59
60#[derive(Clone, Copy, Debug, PartialEq, Eq)]
61pub enum ValueType {
62    String,
63    Bool,
64    I64,
65    U64,
66}
67
68#[derive(Clone, Debug, PartialEq, Eq)]
69pub struct SpecError {
70    message: String,
71}
72
73impl CliSpec {
74    pub fn new(name: impl Into<String>) -> Self {
75        Self {
76            name: name.into(),
77            about: String::new(),
78            version: None,
79            commands: Vec::new(),
80            options: Vec::new(),
81            arguments: Vec::new(),
82            command_required: false,
83        }
84    }
85    pub fn about(mut self, about: impl Into<String>) -> Self {
86        self.about = about.into();
87        self
88    }
89    pub fn version(mut self, version: impl Into<String>) -> Self {
90        self.version = Some(version.into());
91        self
92    }
93    pub fn command(mut self, command: CommandSpec) -> Self {
94        self.commands.push(command);
95        self
96    }
97    pub fn option(mut self, option: OptionSpec) -> Self {
98        self.options.push(option);
99        self
100    }
101    pub fn argument(mut self, argument: ArgumentSpec) -> Self {
102        self.arguments.push(argument);
103        self
104    }
105    pub fn command_required(mut self, required: bool) -> Self {
106        self.command_required = required;
107        self
108    }
109    pub fn validate(&self) -> Result<(), SpecError> {
110        crate::spec_validation::validate_spec(self)
111    }
112    pub fn name(&self) -> &str {
113        &self.name
114    }
115    pub fn about_text(&self) -> &str {
116        &self.about
117    }
118    pub fn version_text(&self) -> Option<&str> {
119        self.version.as_deref()
120    }
121    pub fn commands(&self) -> &[CommandSpec] {
122        &self.commands
123    }
124    pub fn options(&self) -> &[OptionSpec] {
125        &self.options
126    }
127    pub fn arguments(&self) -> &[ArgumentSpec] {
128        &self.arguments
129    }
130    pub fn is_command_required(&self) -> bool {
131        self.command_required
132    }
133}
134
135impl CommandSpec {
136    pub fn new(name: impl Into<String>) -> Self {
137        Self {
138            name: name.into(),
139            aliases: Vec::new(),
140            about: String::new(),
141            commands: Vec::new(),
142            options: Vec::new(),
143            arguments: Vec::new(),
144            command_required: false,
145            hidden: false,
146        }
147    }
148    pub fn alias(mut self, alias: impl Into<String>) -> Self {
149        self.aliases.push(alias.into());
150        self
151    }
152    pub fn about(mut self, about: impl Into<String>) -> Self {
153        self.about = about.into();
154        self
155    }
156    pub fn command(mut self, command: CommandSpec) -> Self {
157        self.commands.push(command);
158        self
159    }
160    pub fn option(mut self, option: OptionSpec) -> Self {
161        self.options.push(option);
162        self
163    }
164    pub fn argument(mut self, argument: ArgumentSpec) -> Self {
165        self.arguments.push(argument);
166        self
167    }
168    pub fn command_required(mut self, required: bool) -> Self {
169        self.command_required = required;
170        self
171    }
172    pub fn hidden(mut self, hidden: bool) -> Self {
173        self.hidden = hidden;
174        self
175    }
176    pub fn name(&self) -> &str {
177        &self.name
178    }
179    pub fn aliases(&self) -> &[String] {
180        &self.aliases
181    }
182    pub fn matches(&self, value: &str) -> bool {
183        self.name == value || self.aliases.iter().any(|alias| alias == value)
184    }
185    pub fn about_text(&self) -> &str {
186        &self.about
187    }
188    pub fn commands(&self) -> &[CommandSpec] {
189        &self.commands
190    }
191    pub fn options(&self) -> &[OptionSpec] {
192        &self.options
193    }
194    pub fn arguments(&self) -> &[ArgumentSpec] {
195        &self.arguments
196    }
197    pub fn is_command_required(&self) -> bool {
198        self.command_required
199    }
200    pub fn is_hidden(&self) -> bool {
201        self.hidden
202    }
203}
204
205impl OptionSpec {
206    pub fn flag(long: impl Into<String>) -> Self {
207        Self::new(long, ValueMode::Forbidden)
208    }
209    pub fn value(long: impl Into<String>) -> Self {
210        Self::new(long, ValueMode::Required)
211    }
212    fn new(long: impl Into<String>, value: ValueMode) -> Self {
213        Self {
214            long: long.into(),
215            short: None,
216            value,
217            value_name: "VALUE".into(),
218            value_type: ValueType::String,
219            possible_values: Vec::new(),
220            about: String::new(),
221            required: false,
222            repeatable: false,
223            terminal: false,
224            hidden: false,
225            conflicts_with: Vec::new(),
226            requires: Vec::new(),
227        }
228    }
229    pub fn short(mut self, short: char) -> Self {
230        self.short = Some(short);
231        self
232    }
233    pub fn optional_value(mut self) -> Self {
234        self.value = ValueMode::Optional;
235        self
236    }
237    pub fn value_name(mut self, name: impl Into<String>) -> Self {
238        self.value_name = name.into();
239        self
240    }
241    pub fn value_type(mut self, value_type: ValueType) -> Self {
242        self.value_type = value_type;
243        self
244    }
245    pub fn possible_value(mut self, value: impl Into<String>) -> Self {
246        self.possible_values.push(value.into());
247        self
248    }
249    pub fn about(mut self, about: impl Into<String>) -> Self {
250        self.about = about.into();
251        self
252    }
253    pub fn required(mut self, required: bool) -> Self {
254        self.required = required;
255        self
256    }
257    pub fn repeatable(mut self, repeatable: bool) -> Self {
258        self.repeatable = repeatable;
259        self
260    }
261    pub fn terminal(mut self, terminal: bool) -> Self {
262        self.terminal = terminal;
263        self
264    }
265    pub fn hidden(mut self, hidden: bool) -> Self {
266        self.hidden = hidden;
267        self
268    }
269    pub fn conflicts_with(mut self, long: impl Into<String>) -> Self {
270        self.conflicts_with.push(long.into());
271        self
272    }
273    pub fn requires(mut self, long: impl Into<String>) -> Self {
274        self.requires.push(long.into());
275        self
276    }
277    pub fn long(&self) -> &str {
278        &self.long
279    }
280    pub fn short_name(&self) -> Option<char> {
281        self.short
282    }
283    pub fn value_mode(&self) -> ValueMode {
284        self.value
285    }
286    pub fn value_name_text(&self) -> &str {
287        &self.value_name
288    }
289    pub fn value_type_kind(&self) -> ValueType {
290        self.value_type
291    }
292    pub fn possible_values(&self) -> &[String] {
293        &self.possible_values
294    }
295    pub fn about_text(&self) -> &str {
296        &self.about
297    }
298    pub fn is_required(&self) -> bool {
299        self.required
300    }
301    pub fn is_repeatable(&self) -> bool {
302        self.repeatable
303    }
304    pub fn is_terminal(&self) -> bool {
305        self.terminal
306    }
307    pub fn is_hidden(&self) -> bool {
308        self.hidden
309    }
310    pub fn conflicts(&self) -> &[String] {
311        &self.conflicts_with
312    }
313    pub fn requirements(&self) -> &[String] {
314        &self.requires
315    }
316}
317
318impl ArgumentSpec {
319    pub fn new(name: impl Into<String>) -> Self {
320        Self {
321            name: name.into(),
322            about: String::new(),
323            value_type: ValueType::String,
324            possible_values: Vec::new(),
325            required: false,
326            multiple: false,
327        }
328    }
329    pub fn about(mut self, about: impl Into<String>) -> Self {
330        self.about = about.into();
331        self
332    }
333    pub fn value_type(mut self, value_type: ValueType) -> Self {
334        self.value_type = value_type;
335        self
336    }
337    pub fn possible_value(mut self, value: impl Into<String>) -> Self {
338        self.possible_values.push(value.into());
339        self
340    }
341    pub fn required(mut self, required: bool) -> Self {
342        self.required = required;
343        self
344    }
345    pub fn multiple(mut self, multiple: bool) -> Self {
346        self.multiple = multiple;
347        self
348    }
349    pub fn name(&self) -> &str {
350        &self.name
351    }
352    pub fn about_text(&self) -> &str {
353        &self.about
354    }
355    pub fn value_type_kind(&self) -> ValueType {
356        self.value_type
357    }
358    pub fn possible_values(&self) -> &[String] {
359        &self.possible_values
360    }
361    pub fn is_required(&self) -> bool {
362        self.required
363    }
364    pub fn is_multiple(&self) -> bool {
365        self.multiple
366    }
367}
368
369impl SpecError {
370    fn new(message: impl Into<String>) -> Self {
371        Self {
372            message: message.into(),
373        }
374    }
375    pub(crate) fn new_internal(message: impl Into<String>) -> Self {
376        Self::new(message)
377    }
378}
379impl fmt::Display for SpecError {
380    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
381        f.write_str(&self.message)
382    }
383}
384impl std::error::Error for SpecError {}