diff options
Diffstat (limited to 'mingling_core/src')
| -rw-r--r-- | mingling_core/src/any.rs | 37 | ||||
| -rw-r--r-- | mingling_core/src/any/group.rs | 28 | ||||
| -rw-r--r-- | mingling_core/src/asset.rs | 3 | ||||
| -rw-r--r-- | mingling_core/src/asset/dispatcher.rs | 34 | ||||
| -rw-r--r-- | mingling_core/src/asset/routable.rs | 22 | ||||
| -rw-r--r-- | mingling_core/src/comp.rs | 2 | ||||
| -rw-r--r-- | mingling_core/src/comp/shell_ctx.rs | 34 | ||||
| -rw-r--r-- | mingling_core/src/comp/suggest.rs | 8 | ||||
| -rw-r--r-- | mingling_core/src/lib.rs | 7 | ||||
| -rw-r--r-- | mingling_core/src/program.rs | 20 | ||||
| -rw-r--r-- | mingling_core/src/program/collection.rs | 16 | ||||
| -rw-r--r-- | mingling_core/src/program/collection/mock.rs | 4 | ||||
| -rw-r--r-- | mingling_core/src/program/hook.rs | 4 | ||||
| -rw-r--r-- | mingling_core/src/renderer/render_result.rs | 13 | ||||
| -rw-r--r-- | mingling_core/src/renderer/structural/error.rs | 1 |
15 files changed, 187 insertions, 46 deletions
diff --git a/mingling_core/src/any.rs b/mingling_core/src/any.rs index 2680f43..ec29a1b 100644 --- a/mingling_core/src/any.rs +++ b/mingling_core/src/any.rs @@ -1,12 +1,12 @@ use crate::error::ChainProcessError; -use crate::{Groupped, ProgramCollect}; +use crate::{Grouped, ProgramCollect}; #[doc(hidden)] pub mod group; /// Any type output /// -/// Accepts any type that implements `Send + Groupped<G>` +/// Accepts any type that implements `Send + Grouped<G>` /// After being passed into `AnyOutput`, it will be converted to `Box<dyn Any + Send + 'static>` /// /// Note: @@ -17,15 +17,26 @@ pub mod group; #[derive(Debug)] pub struct AnyOutput<G> { pub(crate) inner: Box<dyn std::any::Any + Send + 'static>, + + /// The [`TypeId`] of the concrete type stored in `inner`. + /// + /// This is set during construction and used for type-checking + /// in downcast, restore, and is methods. pub type_id: std::any::TypeId, + + /// The variant identifier returned by [`Grouped::member_id`] for the + /// concrete type stored in `inner`. + /// + /// This is used by the scheduler to dispatch on the correct enum + /// variant when routing the output. pub member_id: G, } impl<G> AnyOutput<G> { - /// Create an `AnyOutput` from a `Send + Groupped<G>` type + /// Create an `AnyOutput` from a `Send + Grouped<G>` type pub fn new<T>(value: T) -> Self where - T: Send + Groupped<G> + 'static, + T: Send + Grouped<G> + 'static, { Self { inner: Box::new(value), @@ -106,7 +117,9 @@ impl<G> std::ops::DerefMut for AnyOutput<G> { /// - Returns `Ok((`[`AnyOutput`](./struct.AnyOutput.html)`, `[`NextProcess::Renderer`](./enum.NextProcess.html)`))` to render this type next and output to the terminal /// - Returns `Err(`[`ChainProcessError`](./error/enum.ChainProcessError.html)`]` to terminate the program directly pub enum ChainProcess<G> { + /// Indicates success, containing the output value and the next step to execute. Ok((AnyOutput<G>, NextProcess)), + /// Indicates a processing failure, containing the error that occurred. Err(ChainProcessError), } @@ -117,7 +130,9 @@ pub enum ChainProcess<G> { #[derive(Debug, PartialEq, Eq)] #[repr(u8)] pub enum NextProcess { + /// Continue execution to the next chain Chain, + /// Send output to renderer and end execution Renderer, } @@ -148,7 +163,7 @@ where #[cfg(test)] mod tests { use super::*; - use crate::Groupped; + use crate::Grouped; /// Mock enum for testing AnyOutput #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -175,7 +190,7 @@ mod tests { value: i32, } - impl Groupped<MockGroup> for AlphaData { + impl Grouped<MockGroup> for AlphaData { fn member_id() -> MockGroup { MockGroup::Alpha } @@ -187,7 +202,7 @@ mod tests { name: String, } - impl Groupped<MockGroup> for BetaData { + impl Grouped<MockGroup> for BetaData { fn member_id() -> MockGroup { MockGroup::Beta } @@ -198,7 +213,7 @@ mod tests { #[cfg_attr(feature = "structural_renderer", derive(serde::Serialize))] struct GammaData; - impl Groupped<MockGroup> for GammaData { + impl Grouped<MockGroup> for GammaData { fn member_id() -> MockGroup { MockGroup::Gamma } @@ -354,7 +369,7 @@ mod tests { x: i32, } - impl Groupped<MockGroup> for SerData { + impl Grouped<MockGroup> for SerData { fn member_id() -> MockGroup { MockGroup::Gamma } @@ -381,13 +396,13 @@ mod tests { b: String, } - impl Groupped<MockGroup> for SerA { + impl Grouped<MockGroup> for SerA { fn member_id() -> MockGroup { MockGroup::Alpha } } - impl Groupped<MockGroup> for SerB { + impl Grouped<MockGroup> for SerB { fn member_id() -> MockGroup { MockGroup::Beta } diff --git a/mingling_core/src/any/group.rs b/mingling_core/src/any/group.rs index cb847d9..2813ad5 100644 --- a/mingling_core/src/any/group.rs +++ b/mingling_core/src/any/group.rs @@ -1,34 +1,28 @@ -use crate::{AnyOutput, ChainProcess}; +use crate::{AnyOutput, ChainProcess, ProgramCollect, Routable}; /// Used to mark a type with a unique enum ID, assisting dynamic dispatch /// -/// **Note:** Unlike earlier versions, `Groupped` no longer requires `Serialize` +/// **Note:** Unlike earlier versions, `Grouped` no longer requires `Serialize` /// even when the `structural_renderer` feature is enabled. Structured output is /// controlled separately via the \[`StructuralData`\] trait. -pub trait Groupped<Group> +pub trait Grouped<Group> where Self: Sized + 'static, { /// Returns the specific enum value representing its ID within that enum fn member_id() -> Group; +} - /// Converts the grouped item into a `ChainProcess` directed to the chain route. - /// - /// This wraps the item into an `AnyOutput` and routes it to the chain processing pipeline. - fn to_chain(self) -> ChainProcess<Group> - where - Self: Send, - { +impl<T, C> Routable<C> for T +where + C: ProgramCollect<Enum = C>, + T: Grouped<C> + Send, +{ + fn to_chain(self) -> ChainProcess<C> { AnyOutput::new(self).route_chain() } - /// Converts the grouped item into a `ChainProcess` directed to the render route. - /// - /// This wraps the item into an `AnyOutput` and routes it to the render processing pipeline. - fn to_render(self) -> ChainProcess<Group> - where - Self: Send, - { + fn to_render(self) -> ChainProcess<C> { AnyOutput::new(self).route_renderer() } } diff --git a/mingling_core/src/asset.rs b/mingling_core/src/asset.rs index b1fd617..9b9a5d4 100644 --- a/mingling_core/src/asset.rs +++ b/mingling_core/src/asset.rs @@ -21,3 +21,6 @@ pub mod node; #[doc(hidden)] pub mod renderer; + +#[doc(hidden)] +pub mod routable; diff --git a/mingling_core/src/asset/dispatcher.rs b/mingling_core/src/asset/dispatcher.rs index 8f04955..01c9ccf 100644 --- a/mingling_core/src/asset/dispatcher.rs +++ b/mingling_core/src/asset/dispatcher.rs @@ -32,22 +32,46 @@ where C: ProgramCollect<Enum = C>, { /// Adds a dispatcher to the program. - #[cfg(not(feature = "dispatch_tree"))] + #[cfg_attr( + feature = "dispatch_tree", + deprecated( + note = "When the `dispatch_tree` feature is enabled, the `dispatcher` field no longer exists inside Program. All types are collected at compile time by the `gen_program!()` macro, so the `with_dispatcher` function is no longer needed" + ) + )] pub fn with_dispatcher<Disp>(&mut self, dispatcher: Disp) where Disp: Dispatcher<C> + Send + Sync + 'static, { - self.dispatcher.push(Box::new(dispatcher)); + #[cfg(not(feature = "dispatch_tree"))] + { + self.dispatcher.push(Box::new(dispatcher)); + } + #[cfg(feature = "dispatch_tree")] + { + let _ = dispatcher; + } } /// Add some dispatchers to the program. - #[cfg(not(feature = "dispatch_tree"))] + #[cfg_attr( + feature = "dispatch_tree", + deprecated( + note = "When the `dispatch_tree` feature is enabled, the `dispatcher` field no longer exists inside Program. All types are collected at compile time by the `gen_program!()` macro, so the `with_dispatcher` function is no longer needed" + ) + )] pub fn with_dispatchers<D>(&mut self, dispatchers: D) where D: Into<Dispatchers<C>>, { - let dispatchers = dispatchers.into(); - self.dispatcher.extend(dispatchers.dispatcher); + #[cfg(not(feature = "dispatch_tree"))] + { + let dispatchers = dispatchers.into(); + self.dispatcher.extend(dispatchers.dispatcher); + } + #[cfg(feature = "dispatch_tree")] + { + let _ = dispatchers; + } } } diff --git a/mingling_core/src/asset/routable.rs b/mingling_core/src/asset/routable.rs new file mode 100644 index 0000000..24b7bb1 --- /dev/null +++ b/mingling_core/src/asset/routable.rs @@ -0,0 +1,22 @@ +use crate::ChainProcess; + +/// Provides routing capabilities for converting an item into a `ChainProcess` +/// directed to either the chain or render processing pipeline. +/// +/// This trait enables items to be dispatched to different processing routes +/// (chain or render) by wrapping them into an `AnyOutput` and routing them +/// through the appropriate pipeline. +pub trait Routable<Group> +where + Self: Sized + 'static, +{ + /// Converts the routable item into a `ChainProcess` directed to the chain route. + /// + /// This wraps the item into an `AnyOutput` and routes it to the chain processing pipeline. + fn to_chain(self) -> ChainProcess<Group>; + + /// Converts the routable item into a `ChainProcess` directed to the render route. + /// + /// This wraps the item into an `AnyOutput` and routes it to the render processing pipeline. + fn to_render(self) -> ChainProcess<Group>; +} diff --git a/mingling_core/src/comp.rs b/mingling_core/src/comp.rs index f6fecd1..55e9952 100644 --- a/mingling_core/src/comp.rs +++ b/mingling_core/src/comp.rs @@ -96,7 +96,7 @@ impl CompletionHelper { trace!("entry type: {}", any.member_id); let dispatcher_not_found = - <P::ErrorDispatcherNotFound as crate::Groupped<P>>::member_id(); + <P::ErrorDispatcherNotFound as crate::Grouped<P>>::member_id(); if dispatcher_not_found == any.member_id { debug!("dispatcher_not_found matched"); diff --git a/mingling_core/src/comp/shell_ctx.rs b/mingling_core/src/comp/shell_ctx.rs index cfa4700..1fca325 100644 --- a/mingling_core/src/comp/shell_ctx.rs +++ b/mingling_core/src/comp/shell_ctx.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] + use std::collections::HashSet; use crate::{Flag, ShellFlag, Suggest}; @@ -115,6 +117,13 @@ impl ShellContext { /// // } /// } /// ``` + #[must_use] + #[cfg_attr( + feature = "picker", + deprecated( + note = "When using the `picker` feature, this method does not work under all ParserStyle settings" + ) + )] pub fn filling_argument_first(&self, flag: impl Into<Flag>) -> bool { let flag = flag.into(); if self.filling_argument(&flag) { @@ -153,6 +162,13 @@ impl ShellContext { /// // } /// } /// ``` + #[must_use] + #[cfg_attr( + feature = "picker", + deprecated( + note = "When using the `picker` feature, this method does not work under all ParserStyle settings" + ) + )] pub fn filling_argument(&self, flag: impl Into<Flag>) -> bool { for f in flag.into().iter() { if self.previous_word == **f { @@ -190,6 +206,12 @@ impl ShellContext { /// } /// ``` #[must_use] + #[cfg_attr( + feature = "picker", + deprecated( + note = "When using the `picker` feature, this method does not work under all ParserStyle settings" + ) + )] pub fn typing_argument(&self) -> bool { #[cfg(target_os = "windows")] { @@ -208,6 +230,12 @@ impl ShellContext { /// when the user has already typed certain flags. The method processes both /// regular suggestion sets and file completion suggestions differently. #[must_use] + #[cfg_attr( + feature = "picker", + deprecated( + note = "When using the `picker` feature, this method does not work under all ParserStyle settings" + ) + )] pub fn strip_typed_argument(&self, suggest: Suggest) -> Suggest { let typed = Self::get_typed_arguments(self); match suggest { @@ -225,6 +253,12 @@ impl ShellContext { /// which typically represent command-line flags or options. It returns a vector /// containing these flag strings, converted to owned `String` values. #[must_use] + #[cfg_attr( + feature = "picker", + deprecated( + note = "When using the `picker` feature, this method does not work under all ParserStyle settings" + ) + )] pub fn get_typed_arguments(&self) -> HashSet<String> { self.all_words .iter() diff --git a/mingling_core/src/comp/suggest.rs b/mingling_core/src/comp/suggest.rs index a81de64..99afc54 100644 --- a/mingling_core/src/comp/suggest.rs +++ b/mingling_core/src/comp/suggest.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] + use std::collections::BTreeSet; use crate::ShellContext; @@ -30,6 +32,12 @@ impl Suggest { /// Filters out already typed flag arguments from suggestion results. #[must_use] + #[cfg_attr( + feature = "picker", + deprecated( + note = "When using the `picker` feature, this method does not work under all ParserStyle settings" + ) + )] pub fn strip_typed_argument(self, ctx: &ShellContext) -> Self { ctx.strip_typed_argument(self) } diff --git a/mingling_core/src/lib.rs b/mingling_core/src/lib.rs index 3c2cf9b..2cb24b9 100644 --- a/mingling_core/src/lib.rs +++ b/mingling_core/src/lib.rs @@ -8,6 +8,8 @@ //! //! Recommended to import [mingling](https://crates.io/crates/mingling) to use its features. +#![deny(missing_docs)] + mod any; mod asset; mod program; @@ -36,6 +38,7 @@ pub use crate::asset::help::*; pub use crate::asset::lazy_resource::*; pub use crate::asset::node::*; pub use crate::asset::renderer::*; +pub use crate::asset::routable::*; /// All error types of `Mingling` pub mod error { @@ -76,6 +79,10 @@ pub mod comp; #[cfg(feature = "comp")] pub use crate::comp::*; +/// Module for setting up a `Mingling` program. +/// +/// This module provides the [`ProgramSetup`] type, which allows users to configure +/// and initialize the program's execution environment. pub mod setup { pub use crate::program::setup::ProgramSetup; } diff --git a/mingling_core/src/program.rs b/mingling_core/src/program.rs index 0d409b7..11e1bbf 100644 --- a/mingling_core/src/program.rs +++ b/mingling_core/src/program.rs @@ -53,10 +53,30 @@ where #[cfg(not(feature = "dispatch_tree"))] pub(crate) dispatcher: Vec<Box<dyn Dispatcher<C> + Send + Sync>>, + /// Program stdout settings. + /// + /// This struct controls the program's output behavior, including whether + /// to output errors, render results, suppress panic messages, enable + /// verbose/quiet/debug modes, colored output, and progress indicators. + /// + /// # Convention-only fields + /// + /// Fields marked with convention only are not enforced by the framework; + /// they serve as a shared convention for applications to follow consistently. pub stdout_setting: ProgramStdoutSetting, + + /// User-defined context that can be accessed throughout the program. + /// + /// This field holds a user-defined context value that can be + /// accessed and modified at any point during program execution. It is + /// useful for passing shared state or configuration across different + /// parts of the program. pub user_context: ProgramUserContext, #[cfg(feature = "structural_renderer")] + /// Setting for the structural renderer. + /// + /// This field is only available when the `structural_renderer` feature is enabled. pub structural_renderer_name: StructuralRendererSetting, pub(crate) hooks: Vec<ProgramHook<C>>, diff --git a/mingling_core/src/program/collection.rs b/mingling_core/src/program/collection.rs index d5aab4b..14705ac 100644 --- a/mingling_core/src/program/collection.rs +++ b/mingling_core/src/program/collection.rs @@ -4,7 +4,7 @@ use std::pin::Pin; #[cfg(feature = "dispatch_tree")] use crate::Dispatcher; -use crate::{AnyOutput, ChainProcess, Groupped, RenderResult}; +use crate::{AnyOutput, ChainProcess, Grouped, RenderResult}; #[cfg(feature = "structural_renderer")] use crate::{StructuralRendererSetting, error::StructuralRendererSerializeError}; @@ -21,9 +21,17 @@ pub use mock::*; pub trait ProgramCollect { /// Enum type representing internal IDs for the program type Enum; - type ErrorDispatcherNotFound: Groupped<Self::Enum>; - type ErrorRendererNotFound: Groupped<Self::Enum>; - type ResultEmpty: Groupped<Self::Enum>; + /// Error type when a dispatcher is not found for the given member + type ErrorDispatcherNotFound: Grouped<Self::Enum>; + + /// Error type when a renderer is not found for the given member + type ErrorRendererNotFound: Grouped<Self::Enum>; + + /// Result type for an empty chain result + /// + /// When the `extra_macros` feature is enabled, + /// you can use the `empty_result!()` macro to create this + type ResultEmpty: Grouped<Self::Enum>; /// Use a prefix tree to quickly match arguments and dispatch to an Entry #[cfg(feature = "dispatch_tree")] diff --git a/mingling_core/src/program/collection/mock.rs b/mingling_core/src/program/collection/mock.rs index 9b2e7af..5847f10 100644 --- a/mingling_core/src/program/collection/mock.rs +++ b/mingling_core/src/program/collection/mock.rs @@ -4,7 +4,7 @@ use std::pin::Pin; #[cfg(feature = "dispatch_tree")] use crate::Dispatcher; -use crate::{AnyOutput, ChainProcess, Groupped, ProgramCollect, RenderResult}; +use crate::{AnyOutput, ChainProcess, Grouped, ProgramCollect, RenderResult}; #[cfg(feature = "structural_renderer")] use crate::{StructuralRendererSetting, error::StructuralRendererSerializeError}; @@ -23,7 +23,7 @@ pub enum MockProgramCollect { Bar, } -impl Groupped<MockProgramCollect> for MockProgramCollect { +impl Grouped<MockProgramCollect> for MockProgramCollect { fn member_id() -> MockProgramCollect { MockProgramCollect::Foo } diff --git a/mingling_core/src/program/hook.rs b/mingling_core/src/program/hook.rs index 56d8e0e..db1691b 100644 --- a/mingling_core/src/program/hook.rs +++ b/mingling_core/src/program/hook.rs @@ -678,7 +678,7 @@ where #[cfg(test)] mod tests { use super::*; - use crate::Groupped; + use crate::Grouped; use std::sync::atomic::{AtomicBool, Ordering}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -694,7 +694,7 @@ mod tests { } } - impl Groupped<MockHookEnum> for MockHookEnum { + impl Grouped<MockHookEnum> for MockHookEnum { fn member_id() -> MockHookEnum { MockHookEnum::A } diff --git a/mingling_core/src/renderer/render_result.rs b/mingling_core/src/renderer/render_result.rs index e57a5b9..2c60fa4 100644 --- a/mingling_core/src/renderer/render_result.rs +++ b/mingling_core/src/renderer/render_result.rs @@ -8,6 +8,11 @@ use std::{ #[derive(Default, Debug, PartialEq)] pub struct RenderResult { render_text: String, + + /// The exit code to return from the rendering process. + /// + /// A value of `0` indicates success, while non-zero values indicate + /// various error conditions. pub exit_code: i32, } @@ -132,8 +137,8 @@ impl RenderResult { /// result.print(", world!"); /// assert_eq!(result.deref(), "Hello, world!"); /// ``` - pub fn print(&mut self, text: &str) { - self.render_text.push_str(text); + pub fn print(&mut self, text: impl AsRef<str>) { + self.render_text.push_str(text.as_ref()); } /// Appends the given text followed by a newline to the rendered content. @@ -149,8 +154,8 @@ impl RenderResult { /// result.println("Second line"); /// assert_eq!(result.deref(), "First line\nSecond line\n"); /// ``` - pub fn println(&mut self, text: &str) { - self.render_text.push_str(text); + pub fn println(&mut self, text: impl AsRef<str>) { + self.render_text.push_str(text.as_ref()); self.render_text.push('\n'); } diff --git a/mingling_core/src/renderer/structural/error.rs b/mingling_core/src/renderer/structural/error.rs index a7fbc75..63ded81 100644 --- a/mingling_core/src/renderer/structural/error.rs +++ b/mingling_core/src/renderer/structural/error.rs @@ -9,6 +9,7 @@ pub struct StructuralRendererSerializeError { } impl StructuralRendererSerializeError { + /// Creates a new `StructuralRendererSerializeError` with the given error message. #[must_use] pub fn new(error: String) -> Self { Self { error } |
