aopt_core/
ctx.rs

1use std::borrow::Cow;
2use std::ffi::OsStr;
3use std::fmt::Display;
4
5use crate::args::Args;
6use crate::opt::Style;
7use crate::parser::Action;
8use crate::str::display_of_osstr;
9use crate::str::display_of_str;
10use crate::value::RawValParser;
11use crate::Error;
12use crate::Uid;
13
14#[derive(Debug, Clone, Default)]
15pub struct InnerCtx<'a> {
16    uid: Uid,
17
18    name: Option<Cow<'a, str>>,
19
20    style: Style,
21
22    arg: Option<Cow<'a, OsStr>>,
23
24    index: usize,
25
26    total: usize,
27}
28
29impl<'a> InnerCtx<'a> {
30    pub fn with_uid(mut self, uid: Uid) -> Self {
31        self.uid = uid;
32        self
33    }
34
35    pub fn with_idx(mut self, index: usize) -> Self {
36        self.index = index;
37        self
38    }
39
40    pub fn with_total(mut self, total: usize) -> Self {
41        self.total = total;
42        self
43    }
44
45    pub fn with_name(mut self, name: Option<Cow<'a, str>>) -> Self {
46        self.name = name;
47        self
48    }
49
50    pub fn with_style(mut self, style: Style) -> Self {
51        self.style = style;
52        self
53    }
54
55    pub fn with_arg(mut self, arg: Option<Cow<'a, OsStr>>) -> Self {
56        self.arg = arg;
57        self
58    }
59
60    /// The uid of matched option.
61    pub fn uid(&self) -> Uid {
62        self.uid
63    }
64
65    /// The index of matched option.
66    pub fn idx(&self) -> usize {
67        self.index
68    }
69
70    /// The total number of arguments.
71    pub fn total(&self) -> usize {
72        self.total
73    }
74
75    /// The name of matched option.
76    /// For option it is the option name, for NOA it is the argument,
77    /// which set in [`invoke`](https://docs.rs/aopt/latest/aopt/guess/struct.InvokeGuess.html#method.invoke).
78    pub fn name(&self) -> Option<&Cow<'a, str>> {
79        self.name.as_ref()
80    }
81
82    /// The style of matched option.
83    pub fn style(&self) -> Style {
84        self.style
85    }
86
87    /// The argument which set in [`invoke`](https://docs.rs/aopt/latest/aopt/guess/struct.InvokeGuess.html#method.invoke).
88    pub fn arg(&self) -> Option<&Cow<'a, OsStr>> {
89        self.arg.as_ref()
90    }
91
92    pub fn set_uid(&mut self, uid: Uid) -> &mut Self {
93        self.uid = uid;
94        self
95    }
96
97    /// The index of matching context.
98    pub fn set_index(&mut self, index: usize) -> &mut Self {
99        self.index = index;
100        self
101    }
102
103    /// The total of matching context.
104    pub fn set_total(&mut self, total: usize) -> &mut Self {
105        self.total = total;
106        self
107    }
108
109    pub fn set_name(&mut self, name: Option<Cow<'a, str>>) -> &mut Self {
110        self.name = name;
111        self
112    }
113
114    pub fn set_style(&mut self, style: Style) -> &mut Self {
115        self.style = style;
116        self
117    }
118
119    pub fn set_arg(&mut self, arg: Option<Cow<'a, OsStr>>) -> &mut Self {
120        self.arg = arg;
121        self
122    }
123}
124
125impl Display for InnerCtx<'_> {
126    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127        write!(
128            f,
129            "InnerCtx {{ uid: {}, name: {}, style: {}, arg: {}, index: {}, total: {} }}",
130            self.uid,
131            display_of_str(self.name.as_deref()),
132            self.style,
133            display_of_osstr(self.arg.as_deref()),
134            self.index,
135            self.total,
136        )
137    }
138}
139
140/// The invoke context of option handler.
141/// It saved the option information and matched arguments.
142#[derive(Debug, Default)]
143pub struct Ctx<'a> {
144    pub orig: Args,
145
146    pub args: Vec<&'a OsStr>,
147
148    pub inner_ctx: Option<InnerCtx<'a>>,
149
150    #[cfg(not(feature = "sync"))]
151    action: std::cell::RefCell<Action>,
152
153    #[cfg(feature = "sync")]
154    action: std::sync::Mutex<Action>,
155}
156
157impl Clone for Ctx<'_> {
158    fn clone(&self) -> Self {
159        Self {
160            orig: self.orig.clone(),
161            args: self.args.clone(),
162            inner_ctx: self.inner_ctx.clone(),
163            #[cfg(not(feature = "sync"))]
164            action: self.action.clone(),
165            #[cfg(feature = "sync")]
166            action: std::sync::Mutex::new(*self.action.lock().unwrap()),
167        }
168    }
169}
170
171impl<'a> Ctx<'a> {
172    pub fn with_args(mut self, args: Vec<&'a OsStr>) -> Self {
173        self.args = args;
174        self
175    }
176
177    pub fn with_orig(mut self, orig_args: Args) -> Self {
178        self.orig = orig_args;
179        self
180    }
181
182    pub fn with_inner_ctx(mut self, inner_ctx: InnerCtx<'a>) -> Self {
183        self.inner_ctx = Some(inner_ctx);
184        self
185    }
186}
187
188impl<'a> Ctx<'a> {
189    /// The uid of matched option.
190    pub fn uid(&self) -> Result<Uid, Error> {
191        Ok(self.inner_ctx()?.uid())
192    }
193
194    /// The index of matched option.
195    pub fn idx(&self) -> Result<usize, Error> {
196        Ok(self.inner_ctx()?.idx())
197    }
198
199    /// The total number of arguments.
200    pub fn total(&self) -> Result<usize, Error> {
201        Ok(self.inner_ctx()?.total())
202    }
203
204    /// The name of matched option.
205    /// For option it is the option name, for NOA it is the argument,
206    /// which set in [`invoke`](https://docs.rs/aopt/latest/aopt/guess/struct.InvokeGuess.html#method.invoke).
207    pub fn name(&self) -> Result<Option<&Cow<'a, str>>, Error> {
208        Ok(self.inner_ctx()?.name())
209    }
210
211    /// The style of matched option.
212    pub fn style(&self) -> Result<Style, Error> {
213        Ok(self.inner_ctx()?.style())
214    }
215
216    /// The copy of [`Args`] when the option matched.
217    /// It may be changing during parsing process.
218    pub fn args(&self) -> &[&'a OsStr] {
219        &self.args
220    }
221
222    /// The argument which set in [`invoke`](https://docs.rs/aopt/latest/aopt/guess/struct.InvokeGuess.html#method.invoke).
223    pub fn arg(&self) -> Result<Option<&Cow<'a, OsStr>>, Error> {
224        Ok(self.inner_ctx()?.arg())
225    }
226
227    pub fn inner_ctx(&self) -> Result<&InnerCtx<'a>, Error> {
228        self.inner_ctx
229            .as_ref()
230            .ok_or_else(|| crate::error!("InnerCtx not exist, try create a new one"))
231    }
232
233    pub fn inner_ctx_mut(&mut self) -> Result<&mut InnerCtx<'a>, Error> {
234        self.inner_ctx
235            .as_mut()
236            .ok_or_else(|| crate::error!("InnerCtx(mutable) not exist, try create a new one"))
237    }
238
239    /// The original arguments passed by user.
240    pub fn orig(&self) -> &Args {
241        &self.orig
242    }
243
244    /// The current argument indexed by `self.idx()`.
245    pub fn arg_at(&self, idx: usize) -> Result<Option<&'a OsStr>, Error> {
246        Ok(self.args.get(idx).copied())
247    }
248
249    pub fn take_args(&mut self) -> Vec<&OsStr> {
250        std::mem::take(&mut self.args)
251    }
252
253    pub fn take_orig_args(&mut self) -> Args {
254        std::mem::take(&mut self.orig)
255    }
256}
257
258impl<'a> Ctx<'a> {
259    pub fn set_uid(&mut self, uid: Uid) -> Result<&mut Self, Error> {
260        self.inner_ctx_mut()?.set_uid(uid);
261        Ok(self)
262    }
263
264    /// The index of matching context.
265    pub fn set_index(&mut self, index: usize) -> Result<&mut Self, Error> {
266        self.inner_ctx_mut()?.set_index(index);
267        Ok(self)
268    }
269
270    /// The total of matching context.
271    pub fn set_total(&mut self, total: usize) -> Result<&mut Self, Error> {
272        self.inner_ctx_mut()?.set_total(total);
273        Ok(self)
274    }
275
276    pub fn set_args(&mut self, args: Vec<&'a OsStr>) -> &mut Self {
277        self.args = args;
278        self
279    }
280
281    pub fn set_name(&mut self, name: Option<Cow<'a, str>>) -> Result<&mut Self, Error> {
282        self.inner_ctx_mut()?.set_name(name);
283        Ok(self)
284    }
285
286    pub fn set_style(&mut self, style: Style) -> Result<&mut Self, Error> {
287        self.inner_ctx_mut()?.set_style(style);
288        Ok(self)
289    }
290
291    pub fn set_arg(&mut self, arg: Option<Cow<'a, OsStr>>) -> Result<&mut Self, Error> {
292        self.inner_ctx_mut()?.set_arg(arg);
293        Ok(self)
294    }
295
296    pub fn set_orig_args(&mut self, orig_args: Args) -> &mut Self {
297        self.orig = orig_args;
298        self
299    }
300
301    pub fn set_inner_ctx(&mut self, inner_ctx: Option<InnerCtx<'a>>) -> &mut Self {
302        crate::trace!("switching InnerCtx to {:?}", inner_ctx);
303        self.inner_ctx = inner_ctx;
304        self
305    }
306}
307
308impl Ctx<'_> {
309    #[cfg(not(feature = "sync"))]
310    pub fn policy_act(&self) -> Action {
311        *self.action.borrow()
312    }
313
314    #[cfg(feature = "sync")]
315    pub fn policy_act(&self) -> Action {
316        *self.action.lock().unwrap()
317    }
318
319    #[cfg(not(feature = "sync"))]
320    pub fn set_policy_act(&self, act: Action) {
321        *self.action.borrow_mut() = act;
322    }
323
324    #[cfg(feature = "sync")]
325    pub fn set_policy_act(&self, act: Action) {
326        *self.action.lock().unwrap() = act;
327    }
328
329    #[cfg(not(feature = "sync"))]
330    pub fn reset_policy_act(&self) {
331        *self.action.borrow_mut() = Action::Null;
332    }
333
334    #[cfg(feature = "sync")]
335    pub fn reset_policy_act(&self) {
336        *self.action.lock().unwrap() = Action::Null;
337    }
338}
339
340impl Ctx<'_> {
341    pub fn value<T: RawValParser>(&self) -> Result<T, Error> {
342        let arg = self.arg()?.map(|v| v.as_ref());
343        let uid = self.uid()?;
344
345        T::parse(arg, self).map_err(|e| e.into().with_uid(uid))
346    }
347}