1use crate::arg::{ArgType, extract_subspan};
2use crate::deserialize::{
3 DeserError, DeserErrorKind, Expectation, Format, NextData, NextResult, Outcome, Raw, Scalar,
4 Span, Spanned,
5};
6use crate::fields::*;
7use crate::parse::parse_scalar;
8use crate::results::*;
9use alloc::borrow::Cow;
10use core::fmt;
11use facet_core::Facet;
12
13pub struct Cli;
15
16impl fmt::Display for Cli {
17 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18 write!(f, "Cli")
19 }
20}
21
22pub fn from_slice<'input, 'facet, T: Facet<'facet>>(
24 args: &'input [&'input str],
25) -> Result<T, DeserError<'input>>
26where
27 'input: 'facet,
28{
29 crate::deserialize::deserialize(args, Cli)
30}
31
32pub fn from_std_args<'input, 'facet, T: Facet<'facet>>() -> Result<T, DeserError<'input>>
34where
35 'input: 'facet,
36{
37 let args = std::env::args().skip(1).collect::<Vec<String>>();
38 let args_str: Vec<&'static str> = args
39 .into_iter()
40 .map(|s| Box::leak(s.into_boxed_str()) as &str)
41 .collect();
42
43 from_slice(Box::leak(args_str.into_boxed_slice()))
44}
45
46impl Format for Cli {
47 type Input<'input> = [&'input str];
48 type SpanType = Raw;
49
50 fn next<'input, 'facet>(
51 &mut self,
52 nd: NextData<'input, 'facet, Self::SpanType, Self::Input<'input>>,
53 expectation: Expectation,
54 ) -> NextResult<
55 'input,
56 'facet,
57 Spanned<Outcome<'input>, Self::SpanType>,
58 Spanned<DeserErrorKind, Self::SpanType>,
59 Self::SpanType,
60 Self::Input<'input>,
61 > {
62 let arg_idx = nd.start();
63 let shape = nd.wip.shape();
64 let args = nd.input();
65 let subspans = nd.substack().get();
66 let has_subspans = !subspans.is_empty();
67
68 let stay_put = Span::new(arg_idx, 0);
69 let step_forth = Span::new(arg_idx, 1);
70
71 let span = match expectation {
72 Expectation::Value => stay_put,
73 Expectation::ObjectKeyOrObjectClose
74 | Expectation::ObjectVal
75 | Expectation::ListItemOrListClose => step_forth,
76 };
77
78 let result = match expectation {
79 Expectation::Value => {
81 wrap_outcome_result(validate_struct_type(shape), Outcome::ObjectStarted, span)
83 }
84
85 Expectation::ObjectKeyOrObjectClose => {
87 if arg_idx < args.len() {
89 let arg = args[arg_idx];
90
91 if arg.starts_with("-") && arg.contains('=') && !has_subspans {
93 if let Some(key_value_subspans) = create_key_value_subspans(arg) {
95 return (nd, wrap_resegmented_result(key_value_subspans, stay_put));
96 }
97 }
98
99 let effective_arg = if has_subspans {
101 extract_subspan(&subspans[0], arg)
102 } else {
103 arg
104 };
105
106 match ArgType::parse(effective_arg) {
108 ArgType::LongFlag(key) => {
109 wrap_string_result(
111 validate_field(&key, shape, &nd.wip).map(|_| key),
112 if has_subspans { stay_put } else { span },
113 )
114 }
115 ArgType::ShortFlag(key) => {
116 wrap_field_result(
118 find_field_by_short_flag(key, shape),
119 if has_subspans { stay_put } else { span },
120 )
121 }
122 ArgType::Positional => {
123 wrap_field_result(find_positional_field(shape, &nd.wip), stay_put)
125 }
126 ArgType::None => {
127 let err = create_unknown_field_error("empty argument", shape);
129 Err(Spanned { node: err, span })
130 }
131 }
132 } else {
133 handle_unset_bool_field_error(find_unset_bool_field(shape, &nd.wip), span)
135 }
136 }
137
138 Expectation::ObjectVal => {
140 if shape.is_type::<bool>() {
142 let has_arg = arg_idx < args.len();
144 wrap_result(handle_bool_value(has_arg), Outcome::Scalar, stay_put)
145 } else {
146 let result = if has_subspans && arg_idx < args.len() {
148 let arg = args[arg_idx];
149 let subspan = &subspans[1];
150 let arg_type: ArgType = (subspan, arg).into();
151
152 match arg_type {
154 ArgType::ShortFlag(_) | ArgType::LongFlag(_) => {
155 None
157 }
158 _ => {
159 let part = extract_subspan(subspan, arg);
161 Some(Ok(parse_scalar(part, span)))
162 }
163 }
164 } else {
165 None
166 };
167
168 result.unwrap_or_else(|| {
170 match validate_value_available(arg_idx, args) {
172 Ok(arg) => Ok(parse_scalar(arg, span)),
173 Err(err) => Err(Spanned {
174 node: err,
175 span: Span::new(arg_idx.saturating_sub(1), 0),
176 }),
177 }
178 })
179 }
180 }
181
182 Expectation::ListItemOrListClose => {
184 if is_list_ended(arg_idx, args) {
186 Ok(Spanned {
188 node: Outcome::ListEnded,
189 span,
190 })
191 } else {
192 Ok(Spanned {
194 node: Outcome::Scalar(Scalar::String(Cow::Borrowed(args[arg_idx]))),
195 span: step_forth,
196 })
197 }
198 }
199 };
200
201 (nd, result)
202 }
203
204 fn skip<'input, 'facet>(
205 &mut self,
206 nd: NextData<'input, 'facet, Self::SpanType, Self::Input<'input>>,
207 ) -> NextResult<
208 'input,
209 'facet,
210 Span<Self::SpanType>,
211 Spanned<DeserErrorKind, Self::SpanType>,
212 Self::SpanType,
213 Self::Input<'input>,
214 > {
215 let arg_idx = nd.start();
216 let args = nd.input();
217 let span = Span::new(arg_idx, 1);
218
219 let result = if arg_idx < args.len() {
220 Ok(span)
222 } else {
223 Err(Spanned {
225 node: DeserErrorKind::UnexpectedEof {
226 wanted: "argument to skip",
227 },
228 span,
229 })
230 };
231
232 (nd, result)
233 }
234}