diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-07-17 11:08:07 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-07-17 11:11:28 +0800 |
| commit | 79ec6878877f0fd9246d67d3cd4f8cc2d1200150 (patch) | |
| tree | e3cd8cfc7ef5cd2a6a7ceb93d9a4b1764fa21b61 /arg_picker/src/picker/parse.rs | |
| parent | e6136f22cff446b16dbebf3b26a6fdea6dbc0e83 (diff) | |
refactor: rename `mingling_picker` to `arg_picker`
Diffstat (limited to 'arg_picker/src/picker/parse.rs')
| -rw-r--r-- | arg_picker/src/picker/parse.rs | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/arg_picker/src/picker/parse.rs b/arg_picker/src/picker/parse.rs new file mode 100644 index 0000000..366028b --- /dev/null +++ b/arg_picker/src/picker/parse.rs @@ -0,0 +1,177 @@ +// -------------------------------------------------------------------------------------------- +// I have to say, the code generated by this `internal_repeat!` macro is really UGLY. +// +// But I have to admit, this is a **trade-off**. To achieve the syntax of `pick().pick().pick()` +// while ensuring type safety, this is the best approach I could think of. +// +// P.S. If there's a better way, please let me know. Thanks! +// -------------------------------------------------------------------------------------------- +// +// Then, I must disable `clippy::type_complexity` — this guy is way too noisy. +#![allow(clippy::type_complexity)] + +use crate::{Pickable, PickerArgAttr, PickerArgInfo, PickerArgResult, PickerArgs, TagPhaseContext}; +use arg_picker_macros::internal_repeat; + +internal_repeat!(1..=32 => { + use crate::PickerPattern$; + use crate::PickerResult$; +}); + +internal_repeat!(1..=32 => { + impl<'a, (T$,+), Route> PickerPattern$<'a, (T$,+), Route> + where (T$: Pickable<'a>,+) { + /// Unwraps the result, panicking if a route was selected. + /// + /// # Panics + /// + /// Panics if a route was selected. + pub fn unwrap(self) -> ((T$,+)) { + let p = self.parse(); + ((p.v$.unwrap(),+)) + } + + /// Returns the individual option values without checking the route. + pub fn unpack(self) -> ((Option<T$>,+)) { + let p = self.parse(); + ((p.v$,+)) + } + + /// Converts to a `Result`, returning `Err(route)` if a route was selected, + /// or `Ok(values)` otherwise. + pub fn to_result(self) -> Result<((T$,+)), Route> { + let p = self.parse(); + if let Some(r) = p.route { + return Err(r); + } + Ok(p.unwrap()) + } + + /// Converts to an `Option`, returning `None` if a route was selected, + /// or `Some(values)` otherwise. + pub fn to_option(self) -> Option<((T$,+))> { + let p = self.parse(); + if p.route.is_some() { + return None; + } + Some(p.unwrap()) + } + } +}); + +internal_repeat!(1..=32 => { + impl<'a, (T$,+), Route> PickerPattern$<'a, (T$,+), Route> + where (T$: Pickable<'a>,+) + { + pub fn parse(mut self) -> PickerResult$<(T$,+), Route> { + // ArgInfos + let arg_infos: [PickerArgInfo; $] = [ + ( + PickerArgInfo::from(self.arg_$), + +) + ]; + + let mut bundle: [ + ( + // Arg Attr + PickerArgAttr, + + // Tag Func + Box<dyn FnOnce(&PickerArgs<'a>, &[u8]) -> Vec<usize>>, + + // Pick Func + Box<dyn FnOnce(&[&str], &mut Option<Route>)>, + + // Index + usize + ) + ; $] = [ + ( + ( + // Arg Attr + T$::get_attr(self.arg_$), + + // Tag Func + Box::new(|args, mask| { + let ctx = TagPhaseContext { + arg_info: &arg_infos[$-], + args, + mask + }; + T$::tag(ctx) + }), + + // Pick Func + Box::new(|args, error_route| { + self.result_$ = match T$::pick(args) { + PickerArgResult::Parsed(mut value) => { + // Postprocess + if let Some(post) = self.post_$ { + value = post(value); + } + PickerArgResult::Parsed(value) + }, + other => { + if let Some(get_default) = self.default_$ { + let mut value = get_default(); + + // Postprocess + if let Some(post) = self.post_$ { + value = post(value); + } + + PickerArgResult::Parsed(value) + } else { + if error_route.is_none() { + if let Some(get_route) = self.route_$ { + *error_route = Some(get_route().into()); + } + } + other + } + }, + + } + }), + + // Index + $ + ), + +) + ]; + + // Sort by Bundle Ord (descending) + bundle.sort_by(|a, b| b.0.cmp(&a.0)); + + // Mask — size = number of args (not args), so use args length + let mut mask: Vec<u8> = vec![0u8; self.args.len()]; + + // Parsing + for (_, tag_func, pick_func, _idx) in bundle { + + // Tag phase + let tagged = tag_func(&self.args, mask.as_slice()); + let mut args_to_pick: Vec<&str> = vec![]; + + for i in tagged { + mask[i] = 1; + + // Update args to pick + args_to_pick.push(self.args.get(i).unwrap_or_default()); + } + + // Pick phase + pick_func(args_to_pick.as_slice(), &mut self.error_route); + } + + // Combine Result + let result: PickerResult$<(T$,+), Route> = PickerResult$ { + route: self.error_route, + ( + v$: self.result_$.to_option(), + +) + }; + result + } + } +}); |
