From f1ed18e668a830646fe507ee33c4b010a1690342 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Wed, 1 Apr 2026 20:14:56 +0800 Subject: Add documentation for mingling_core --- mingling_core/src/any.rs | 31 +++++++++++++++++++++ mingling_core/src/any/group.rs | 2 ++ mingling_core/src/asset.rs | 4 +++ mingling_core/src/asset/chain.rs | 5 ++++ mingling_core/src/asset/dispatcher.rs | 20 ++++++++++++++ mingling_core/src/asset/node.rs | 5 ++++ mingling_core/src/asset/renderer.rs | 4 +++ mingling_core/src/lib.rs | 43 +++++++++++++++++++---------- mingling_core/src/markers.rs | 1 + mingling_core/src/program.rs | 19 +++++++++++++ mingling_core/src/program/config.rs | 2 ++ mingling_core/src/program/exec.rs | 1 + mingling_core/src/program/flag.rs | 41 +++++++++++++++++++++++++++ mingling_core/src/renderer/render_result.rs | 41 +++++++++++++++++++++++++++ 14 files changed, 205 insertions(+), 14 deletions(-) (limited to 'mingling_core') diff --git a/mingling_core/src/any.rs b/mingling_core/src/any.rs index dac0d44..d550ec7 100644 --- a/mingling_core/src/any.rs +++ b/mingling_core/src/any.rs @@ -6,8 +6,18 @@ use serde::Serialize; use crate::Groupped; use crate::error::ChainProcessError; +#[doc(hidden)] pub mod group; +/// Any type output +/// +/// Accepts any type that implements `Send + Groupped` +/// After being passed into AnyOutput, it will be converted to `Box` +/// +/// Note: +/// - If an enum value that does not belong to this type is incorrectly specified, it will be **unsafely** unwrapped by the scheduler +/// - Under the `general_renderer` feature, the passed value must ensure it implements `serde::Serialize` +/// - It is recommended to use the `pack!` macro from [mingling_macros](https://crates.io/crates/mingling_macros) to create types that can be converted to `AnyOutput`, which guarantees runtime safety #[derive(Debug)] pub struct AnyOutput where @@ -22,6 +32,7 @@ impl AnyOutput where G: Display, { + /// Create an AnyOutput from a `Send + Groupped + Serialize` type #[cfg(feature = "general_renderer")] pub fn new(value: T) -> Self where @@ -34,6 +45,7 @@ where } } + /// Create an AnyOutput from a `Send + Groupped` type #[cfg(not(feature = "general_renderer"))] pub fn new(value: T) -> Self where @@ -46,6 +58,7 @@ where } } + /// Downcast the AnyOutput to a concrete type T pub fn downcast(self) -> Result { if self.type_id == std::any::TypeId::of::() { Ok(*self.inner.downcast::().unwrap()) @@ -54,6 +67,7 @@ where } } + /// Check if the inner value is of type T pub fn is(&self) -> bool { self.type_id == std::any::TypeId::of::() } @@ -89,6 +103,12 @@ where } } +/// Chain exec result type +/// +/// Stores `Ok` and `Err` types of execution results, used to notify the scheduler what to execute next +/// - Returns `Ok((`[`AnyOutput`](./struct.AnyOutput.html)`, `[`Next::Chain`](./enum.Next.html)`))` to continue execution with this type next +/// - Returns `Ok((`[`AnyOutput`](./struct.AnyOutput.html)`, `[`Next::Renderer`](./enum.Next.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 where G: Display, @@ -97,6 +117,10 @@ where Err(ChainProcessError), } +/// Indicates the next step after processing +/// +/// - `Chain`: Continue execution to the next chain +/// - `Renderer`: Send output to renderer and end execution pub enum Next { Chain, Renderer, @@ -106,14 +130,17 @@ impl ChainProcess where G: Display, { + /// Returns true if the result is Ok (has a next step) pub fn is_next(&self) -> bool { matches!(self, Self::Ok(_)) } + /// Returns true if the result is an error pub fn is_err(&self) -> bool { matches!(self, Self::Err(_)) } + /// Returns the next step if the result is Ok pub fn next(&self) -> Option<&Next> { match self { Self::Ok((_, next)) => Some(next), @@ -121,6 +148,7 @@ where } } + /// Returns the error if the result is Err pub fn err(&self) -> Option<&ChainProcessError> { match self { Self::Ok(_) => None, @@ -128,6 +156,7 @@ where } } + /// Unwraps the result, panics if it's an error pub fn unwrap(self) -> (AnyOutput, Next) { match self { Self::Ok(tuple) => tuple, @@ -135,6 +164,7 @@ where } } + /// Returns the Ok value or a provided default pub fn unwrap_or(self, default: (AnyOutput, Next)) -> (AnyOutput, Next) { match self { Self::Ok(tuple) => tuple, @@ -142,6 +172,7 @@ where } } + /// Returns the Ok value or computes it from the error pub fn unwrap_or_else(self, f: F) -> (AnyOutput, Next) where F: FnOnce(ChainProcessError) -> (AnyOutput, Next), diff --git a/mingling_core/src/any/group.rs b/mingling_core/src/any/group.rs index 29d6a48..04701f2 100644 --- a/mingling_core/src/any/group.rs +++ b/mingling_core/src/any/group.rs @@ -1,3 +1,5 @@ +/// Used to mark a type with a unique enum ID, assisting dynamic dispatch pub trait Groupped { + /// Returns the specific enum value representing its ID within that enum fn member_id() -> Group; } diff --git a/mingling_core/src/asset.rs b/mingling_core/src/asset.rs index c2adf4e..81aa3a6 100644 --- a/mingling_core/src/asset.rs +++ b/mingling_core/src/asset.rs @@ -1,4 +1,8 @@ +#[doc(hidden)] pub mod chain; +#[doc(hidden)] pub mod dispatcher; +#[doc(hidden)] pub mod node; +#[doc(hidden)] pub mod renderer; diff --git a/mingling_core/src/asset/chain.rs b/mingling_core/src/asset/chain.rs index 9f62228..70eda8c 100644 --- a/mingling_core/src/asset/chain.rs +++ b/mingling_core/src/asset/chain.rs @@ -2,12 +2,17 @@ use std::fmt::Display; use crate::ChainProcess; +#[doc(hidden)] pub mod error; +/// Takes over a type (G: Previous) and converts it to another [AnyOutput](./struct.AnyOutput.html) pub trait Chain where G: Display, { + /// The previous type in the chain type Previous; + + /// Process the previous value and return a future that resolves to a [`ChainProcess`](./enum.ChainProcess.html) fn proc(p: Self::Previous) -> impl Future> + Send; } diff --git a/mingling_core/src/asset/dispatcher.rs b/mingling_core/src/asset/dispatcher.rs index 0863f16..86dfe7c 100644 --- a/mingling_core/src/asset/dispatcher.rs +++ b/mingling_core/src/asset/dispatcher.rs @@ -2,12 +2,22 @@ use std::fmt::Display; use crate::{ChainProcess, Program, asset::node::Node}; +/// Dispatches user input commands to specific [ChainProcess](./enum.ChainProcess.html) +/// +/// Note: If you are using [mingling_macros](https://crates.io/crates/mingling_macros), +/// you can use the `dispatcher!("node.subnode", CommandType => Entry)` macro to declare a `Dispatcher` pub trait Dispatcher where G: Display, { + /// Returns a command node for matching user input fn node(&self) -> Node; + + /// Returns a [ChainProcess](./enum.ChainProcess.html) based on user input arguments, + /// to be sent to the specific invocation fn begin(&self, args: Vec) -> ChainProcess; + + /// Clones the current dispatcher for implementing the `Clone` trait fn clone_dispatcher(&self) -> Box>; } @@ -39,6 +49,16 @@ impl Program { } } +/// A collection of dispatchers. +/// +/// This struct holds a vector of boxed `Dispatcher` trait objects, +/// allowing multiple dispatchers to be grouped together and passed +/// to the program via `Program::with_dispatchers`. +/// A collection of dispatchers. +/// +/// This struct holds a vector of boxed `Dispatcher` trait objects, +/// allowing multiple dispatchers to be grouped together and passed +/// to the program via `Program::with_dispatchers`. pub struct Dispatchers { dispatcher: Vec + 'static>>, } diff --git a/mingling_core/src/asset/node.rs b/mingling_core/src/asset/node.rs index c8b7600..035d227 100644 --- a/mingling_core/src/asset/node.rs +++ b/mingling_core/src/asset/node.rs @@ -1,11 +1,16 @@ use just_fmt::kebab_case; +/// Represents a command node, used to match user-input command paths. +/// +/// The node consists of multiple parts, each separated by a dot (`.`), and automatically converted to kebab-case. +/// For example, the input string `"node.subnode"` will be converted to a node representation of `["node", "subnode"]`. #[derive(Debug, Default)] pub struct Node { node: Vec, } impl Node { + /// Append a new part to the node path. pub fn join(self, node: impl Into) -> Node { let mut new_node = self.node; new_node.push(node.into()); diff --git a/mingling_core/src/asset/renderer.rs b/mingling_core/src/asset/renderer.rs index 3852b55..de417a2 100644 --- a/mingling_core/src/asset/renderer.rs +++ b/mingling_core/src/asset/renderer.rs @@ -1,6 +1,10 @@ use crate::RenderResult; +/// Takes over a type (Self::Previous) and converts it to a [`RenderResult`](./struct.RenderResult.html) pub trait Renderer { + /// The previous type in the chain type Previous; + + /// Process the previous value and write the result into the provided [`RenderResult`](./struct.RenderResult.html) fn render(p: Self::Previous, r: &mut RenderResult); } diff --git a/mingling_core/src/lib.rs b/mingling_core/src/lib.rs index 3d2be11..bcad91d 100644 --- a/mingling_core/src/lib.rs +++ b/mingling_core/src/lib.rs @@ -1,28 +1,43 @@ +//! Mingling Core +//! +//! # Intro +//! This crate is the core implementation of `mingling`, containing the complete logic for command dispatching, execution, and rendering. +//! +//! # Note +//! It is not recommended to use [mingling_core](https://crates.io/crates/mingling_core) directly, as this will lose the code generation functionality of [mingling_macros](https://crates.io/crates/mingling_macros). +//! +//! Recommended to import [mingling](https://crates.io/crates/mingling) to use its features. + mod any; +mod asset; +mod markers; +mod program; +mod renderer; + pub use crate::any::group::*; pub use crate::any::*; -mod markers; -pub mod marker { - pub use crate::markers::group_process::*; -} +pub use crate::asset::chain::*; +pub use crate::asset::dispatcher::*; +pub use crate::asset::node::*; +pub use crate::asset::renderer::*; +/// All error types of `Mingling` pub mod error { pub use crate::asset::chain::error::*; pub use crate::exec::error::*; } -mod program; pub use crate::program::*; + +pub use crate::renderer::render_result::*; + +/// All marker types of `Mingling` that serve no practical purpose +pub mod marker { + pub use crate::markers::group_process::*; +} + +/// `Mingling`'s Program initialization system pub mod setup { pub use crate::program::setup::*; } - -mod renderer; - -mod asset; -pub use crate::asset::chain::*; -pub use crate::asset::dispatcher::*; -pub use crate::asset::node::*; -pub use crate::asset::renderer::*; -pub use crate::renderer::render_result::*; diff --git a/mingling_core/src/markers.rs b/mingling_core/src/markers.rs index e95fb8a..151a0d4 100644 --- a/mingling_core/src/markers.rs +++ b/mingling_core/src/markers.rs @@ -1 +1,2 @@ +#[doc(hidden)] pub mod group_process; diff --git a/mingling_core/src/program.rs b/mingling_core/src/program.rs index ffba17e..5d81234 100644 --- a/mingling_core/src/program.rs +++ b/mingling_core/src/program.rs @@ -4,7 +4,9 @@ use crate::{ }; use std::{env, fmt::Display, pin::Pin}; +#[doc(hidden)] pub mod exec; +#[doc(hidden)] pub mod setup; mod config; @@ -14,6 +16,7 @@ mod flag; pub use flag::*; use tokio::io::AsyncWriteExt; +/// Program, used to define the behavior of the entire command-line program #[derive(Default)] pub struct Program where @@ -86,15 +89,31 @@ where } } +/// Collected program context +/// +/// Note: It is recommended to use the `gen_program!()` macro from [mingling_macros](https://crates.io/crates/mingling_macros) to automatically create this type pub trait ProgramCollect { + /// Enum type representing internal IDs for the program type Enum: Display; + + /// Build an [AnyOutput](./struct.AnyOutput.html) to indicate that a renderer was not found fn build_renderer_not_found(member_id: Self::Enum) -> AnyOutput; + + /// Build an [AnyOutput](./struct.AnyOutput.html) to indicate that a dispatcher was not found fn build_dispatcher_not_found(args: Vec) -> AnyOutput; + + /// Render the input [AnyOutput](./struct.AnyOutput.html) fn render(any: AnyOutput, r: &mut RenderResult); + + /// Find a matching chain to continue execution based on the input [AnyOutput](./struct.AnyOutput.html), returning a new [AnyOutput](./struct.AnyOutput.html) fn do_chain( any: AnyOutput, ) -> Pin> + Send>>; + + /// Whether the program has a renderer that can handle the current [AnyOutput](./struct.AnyOutput.html) fn has_renderer(any: &AnyOutput) -> bool; + + /// Whether the program has a chain that can handle the current [AnyOutput](./struct.AnyOutput.html) fn has_chain(any: &AnyOutput) -> bool; } diff --git a/mingling_core/src/program/config.rs b/mingling_core/src/program/config.rs index 386b112..6ad0a38 100644 --- a/mingling_core/src/program/config.rs +++ b/mingling_core/src/program/config.rs @@ -1,3 +1,4 @@ +/// Program stdout settings #[derive(Debug, Clone)] pub struct ProgramStdoutSetting { /// Output error messages @@ -16,6 +17,7 @@ impl Default for ProgramStdoutSetting { } } +/// Program stdout settings #[derive(Debug, Clone, Default)] pub struct ProgramUserContext { /// View help information instead of running the command diff --git a/mingling_core/src/program/exec.rs b/mingling_core/src/program/exec.rs index 7de3723..9c80c4a 100644 --- a/mingling_core/src/program/exec.rs +++ b/mingling_core/src/program/exec.rs @@ -7,6 +7,7 @@ use crate::{ error::ProgramInternalExecuteError, }; +#[doc(hidden)] pub mod error; pub async fn exec(program: Program) -> Result diff --git a/mingling_core/src/program/flag.rs b/mingling_core/src/program/flag.rs index 84fae01..a520495 100644 --- a/mingling_core/src/program/flag.rs +++ b/mingling_core/src/program/flag.rs @@ -2,6 +2,45 @@ use std::fmt::Display; use crate::{Program, ProgramCollect}; +/// A wrapper for a collection of static string slices representing command-line flags or arguments. +/// +/// `Flag` is used to store one or more static string slices (e.g., `["-h", "--help"]`) that +/// represent command-line flags or arguments. It provides conversions from various input types +/// (like a single `&'static str`, a slice, or an array) and dereferences to a slice of strings +/// for easy iteration and access. +/// +/// # Examples +/// +/// ``` +/// use mingling_core::Flag; +/// +/// // Create a Flag from a single string slice +/// let flag1 = Flag::from("-h"); +/// assert_eq!(flag1.as_ref(), &["-h"]); +/// +/// // Create a Flag from a slice of string slices +/// let flag2 = Flag::from(&["-h", "--help"][..]); +/// assert_eq!(flag2.as_ref(), &["-h", "--help"]); +/// +/// // Create a Flag from an array +/// let flag3 = Flag::from(["-v", "--verbose"]); +/// assert_eq!(flag3.as_ref(), &["-v", "--verbose"]); +/// +/// // Create a Flag from a reference to an array +/// let arr = &["-f", "--file"]; +/// let flag4 = Flag::from(arr); +/// assert_eq!(flag4.as_ref(), &["-f", "--file"]); +/// +/// // Create an empty Flag from unit type +/// let flag5 = Flag::from(()); +/// assert_eq!(flag5.as_ref(), &[] as &[&str]); +/// +/// // Dereference to slice for iteration +/// let flag = Flag::from(["-a", "-b"]); +/// for arg in flag.iter() { +/// println!("Flag: {}", arg); +/// } +/// ``` pub struct Flag { vec: Vec<&'static str>, } @@ -57,6 +96,7 @@ impl std::ops::Deref for Flag { } #[macro_export] +#[doc(hidden)] macro_rules! special_flag { ($args:expr, $flag:expr) => {{ let flag = $flag; @@ -67,6 +107,7 @@ macro_rules! special_flag { } #[macro_export] +#[doc(hidden)] macro_rules! special_argument { ($args:expr, $flag:expr) => {{ let flag = $flag; diff --git a/mingling_core/src/renderer/render_result.rs b/mingling_core/src/renderer/render_result.rs index 73c38e7..d9da7b7 100644 --- a/mingling_core/src/renderer/render_result.rs +++ b/mingling_core/src/renderer/render_result.rs @@ -3,6 +3,7 @@ use std::{ ops::Deref, }; +/// Render result, containing the rendered text content. #[derive(Default, Debug, PartialEq)] pub struct RenderResult { render_text: String, @@ -23,15 +24,55 @@ impl Deref for RenderResult { } impl RenderResult { + /// Appends the given text to the rendered content. + /// + /// # Examples + /// + /// ``` + /// use mingling_core::RenderResult; + /// use std::ops::Deref; + /// + /// let mut result = RenderResult::default(); + /// result.print("Hello"); + /// result.print(", world!"); + /// assert_eq!(result.deref(), "Hello, world!"); + /// ``` pub fn print(&mut self, text: &str) { self.render_text.push_str(text); } + /// Appends the given text followed by a newline to the rendered content. + /// + /// # Examples + /// + /// ``` + /// use mingling_core::RenderResult; + /// use std::ops::Deref; + /// + /// let mut result = RenderResult::default(); + /// result.println("First line"); + /// 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); self.render_text.push('\n'); } + /// Clears all rendered content. + /// + /// # Examples + /// + /// ``` + /// use mingling_core::RenderResult; + /// use std::ops::Deref; + /// + /// let mut result = RenderResult::default(); + /// result.print("Some content"); + /// assert!(!result.is_empty()); + /// result.clear(); + /// assert!(result.is_empty()); + /// ``` pub fn clear(&mut self) { self.render_text.clear(); } -- cgit