aboutsummaryrefslogtreecommitdiff
path: root/mingling_picker/src/picker
diff options
context:
space:
mode:
Diffstat (limited to 'mingling_picker/src/picker')
-rw-r--r--mingling_picker/src/picker/parse.rs177
-rw-r--r--mingling_picker/src/picker/patterns.rs205
-rw-r--r--mingling_picker/src/picker/result.rs56
3 files changed, 0 insertions, 438 deletions
diff --git a/mingling_picker/src/picker/parse.rs b/mingling_picker/src/picker/parse.rs
deleted file mode 100644
index 698baac..0000000
--- a/mingling_picker/src/picker/parse.rs
+++ /dev/null
@@ -1,177 +0,0 @@
-// --------------------------------------------------------------------------------------------
-// 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 mingling_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
- }
- }
-});
diff --git a/mingling_picker/src/picker/patterns.rs b/mingling_picker/src/picker/patterns.rs
deleted file mode 100644
index 78ae2b0..0000000
--- a/mingling_picker/src/picker/patterns.rs
+++ /dev/null
@@ -1,205 +0,0 @@
-use mingling_picker_macros::internal_repeat;
-
-use crate::{Pickable, PickerArg, PickerArgResult, PickerArgs};
-
-internal_repeat!(1..=32 => {
- #[doc(hidden)]
- pub struct PickerPattern$<'a, (T$,+), Route>
- where (T$: Pickable<'a>,+)
- {
- pub args: PickerArgs<'a>,
- pub error_route: Option<Route>,
- (
- pub(crate) arg_$: &'a PickerArg<'a, T$>,
- pub(crate) result_$: PickerArgResult<T$>,
- pub(crate) default_$: Option<Box<dyn FnOnce() -> T$>>,
- pub(crate) route_$: Option<Box<dyn FnOnce() -> Route>>,
- pub(crate) post_$: Option<Box<dyn FnOnce(T$) -> T$>>,
- +)
- }
-});
-
-internal_repeat!(1..=32 => {
- impl<'a, (T$,+), Route> PickerPattern$<'a, (T$,+), Route>
- where (T$: Pickable<'a>,+)
- {
- /// Sets a default value provider for this arg.
- ///
- /// If the arg is not provided by the user at runtime, the given closure will be
- /// called to produce a default value. The closure is expected to return `T$`.
- ///
- /// # Example
- ///
- #[allow(clippy::type_complexity)]
- pub fn or<F>(mut self, func: F) -> Self
- where
- F: FnMut() -> T$,
- F: 'static,
- {
- self.default_$ = Some(Box::new(func));
- self
- }
-
- /// Uses the default value for this arg's type if the arg is not provided.
- ///
- /// If the arg is not provided by the user at runtime, the default value for `T$`
- /// (as defined by the `Default` trait) will be used.
- ///
- /// # Example
- ///
- #[allow(clippy::type_complexity)]
- pub fn or_default(mut self) -> Self
- where
- T$: Default,
- {
- self.default_$ = Some(Box::new(|| T$::default()));
- self
- }
-
- /// Sets a route for when the arg is not provided.
- ///
- /// If the arg is not provided by the user at runtime, the given closure will be
- /// called to produce a route value that will be returned early.
- ///
- /// # Example
- ///
- pub fn or_route<F>(mut self, func: F) -> Self
- where
- F: FnMut() -> Route,
- F: 'static,
- {
- self.route_$ = Some(Box::new(func));
- self
- }
-
-
- /// Resets the route for this picker pattern, allowing a different route type.
- ///
- /// This method converts the current `PickerPattern` into a new one with a different
- /// route type `NewRoute`. All existing arg configurations, defaults, and post-
- /// processing functions are preserved, but the `error_route` and individual
- /// `route_$` fields are cleared (set to `None`).
- ///
- /// This is useful when you want to change the error/redirect route type mid-chain,
- /// for example when composing patterns from different contexts that use different
- /// route enums.
- #[allow(clippy::type_complexity)]
- pub fn with_route<NewRoute>(self) -> PickerPattern$<'a, (T$,+), NewRoute>
- {
- PickerPattern$ {
- args: self.args,
- error_route: None,
- (
- arg_$: self.arg_$,
- result_$: self.result_$,
- default_$: self.default_$,
- route_$: None,
- post_$: self.post_$,
- +)
- }
- }
-
- /// Attaches a post-processing function to this arg.
- ///
- /// After the arg's value is parsed (or defaulted), the given closure will be
- /// invoked with the parsed value and its return value will be used as the final
- /// result. This allows transforming or validating the parsed value.
- ///
- /// # Example
- ///
- #[allow(clippy::type_complexity)]
- pub fn post<F>(mut self, func: F) -> Self
- where
- F: FnMut(T$) -> T$,
- F: 'static,
- {
- self.post_$ = Some(Box::new(func));
- self
- }
- }
-});
-
-internal_repeat!(1..32 => {
- impl<'a, (T$,+), Route> PickerPattern$<'a, (T$,+), Route>
- where (T$: Pickable<'a>,+)
- {
- #[allow(clippy::type_complexity)]
- /// Adds a new arg to the picking chain, returning a new `PickerPattern` with one more type parameter.
- ///
- /// This method extends the current picking pattern by appending an additional arg.
- /// The previous args and their results are preserved as part of the new pattern.
- /// The new arg's result is initially `Unparsed`.
- pub fn pick<N>(self, arg: impl Into<&'a PickerArg<'a, N>>) -> PickerPattern$+<'a, (T$,+), N, Route>
- where
- N: Pickable<'a>,
- {
- PickerPattern$+ {
- // Args
- args: self.args,
- error_route: self.error_route,
-
- // Current
- arg_$+: arg.into(),
- result_$+: PickerArgResult::Unparsed,
- default_$+: None,
- route_$+: None,
- post_$+: None,
-
- // Prev
- (
- arg_$: self.arg_$,
- result_$: self.result_$,
- default_$: self.default_$,
- route_$: self.route_$,
- post_$: self.post_$,
- +)
- }
- }
-
- /// Picks a new arg with a default value provider in a single call.
- ///
- /// This is a shorthand for calling `.pick(arg).or(func)`.
- ///
- /// # Example
- ///
- #[allow(clippy::type_complexity)]
- pub fn pick_or<N, F>(self, arg: impl Into<&'a PickerArg<'a, N>>, func: F) -> PickerPattern$+<'a, (T$,+), N, Route>
- where
- N: Pickable<'a>,
- F: FnMut() -> N + 'static,
- F: 'static,
- {
- self.pick(arg).or(func)
- }
-
- /// Picks a new arg with a default value in a single call.
- ///
- /// This is a shorthand for calling `.pick(arg).or_default()`.
- ///
- /// # Example
- ///
- #[allow(clippy::type_complexity)]
- pub fn pick_or_default<N>(self, arg: impl Into<&'a PickerArg<'a, N>>) -> PickerPattern$+<'a, (T$,+), N, Route>
- where
- N: Pickable<'a> + Default,
- {
- self.pick(arg).or_default()
- }
-
- /// Picks a new arg with a route in a single call.
- ///
- /// This is a shorthand for calling `.pick(arg).or_route(func)`.
- ///
- /// # Example
- ///
- #[allow(clippy::type_complexity)]
- pub fn pick_or_route<N, F>(self, arg: impl Into<&'a PickerArg<'a, N>>, func: F) -> PickerPattern$+<'a, (T$,+), N, Route>
- where
- N: Pickable<'a>,
- F: FnMut() -> Route + 'static,
- F: 'static,
- {
- self.pick(arg).or_route(func)
- }
- }
-});
diff --git a/mingling_picker/src/picker/result.rs b/mingling_picker/src/picker/result.rs
deleted file mode 100644
index 9cd78ae..0000000
--- a/mingling_picker/src/picker/result.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-#![allow(clippy::type_complexity)] // Aha, Type Gymnastics!
-
-use mingling_picker_macros::internal_repeat;
-
-internal_repeat!(1..=32 => {
- #[doc(hidden)]
- pub struct PickerResult$<(T$,+), Route> {
- /// The route selected by the picker, if any.
- /// If this is `Some`, the picker chose to follow a route instead of selecting values,
- /// and all value fields (`v1`, `v2`, ...) will be `None`.
- ///
- /// Note: "route" here refers to an alternative path/choice, not a network route.
- pub route: Option<Route>,
-
- (
- #[doc = concat!("The optional value for the ", $, "th type parameter.")]
- pub v$: Option<T$>,
- +)
- }
-});
-
-internal_repeat!(1..=32 => {
- impl<(T$,+), Route> PickerResult$<(T$,+), Route> {
- /// Unwraps the result, panicking if a route was selected.
- ///
- /// # Panics
- ///
- /// Panics if `self.route` is `Some(...)`.
- pub fn unwrap(self) -> ((T$,+)) {
- ((self.v$.unwrap(),+))
- }
-
- /// Returns the individual option values without checking the route.
- pub fn unpack(self) -> ((Option<T$>,+)) {
- ((self.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> {
- if let Some(r) = self.route {
- return Err(r);
- }
- Ok(self.unwrap())
- }
-
- /// Converts to an `Option`, returning `None` if a route was selected,
- /// or `Some(values)` otherwise.
- pub fn to_option(self) -> Option<((T$,+))> {
- if let Some(_) = self.route {
- return None;
- }
- Some(self.unwrap())
- }
- }
-});