aboutsummaryrefslogtreecommitdiff
path: root/mingling_core/src
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-06-20 01:11:25 +0800
committer魏曹先生 <1992414357@qq.com>2026-06-20 01:11:25 +0800
commit9d491352d161ee629cc47459537344ba0ea4bb35 (patch)
tree40d847da5cfafce48c3ca99c78bcc077da4c4fb2 /mingling_core/src
parent8749087c5035fbe4c0dce0893a39e0e2265fa130 (diff)
Add shared `MockProgramCollect` and conditional `Groupped` bounds
Extract duplicate `MockCollect` implementations into a reusable `MockProgramCollect` type. Conditionally require `Serialize` on the `Groupped` trait when the `general_renderer` feature is enabled.
Diffstat (limited to 'mingling_core/src')
-rw-r--r--mingling_core/src/any/group.rs87
-rw-r--r--mingling_core/src/comp/comp_ctx.rs65
-rw-r--r--mingling_core/src/program/collection.rs3
-rw-r--r--mingling_core/src/program/collection/mock.rs105
-rw-r--r--mingling_core/src/program/setup.rs63
5 files changed, 188 insertions, 135 deletions
diff --git a/mingling_core/src/any/group.rs b/mingling_core/src/any/group.rs
index c251286..e9fce5e 100644
--- a/mingling_core/src/any/group.rs
+++ b/mingling_core/src/any/group.rs
@@ -1,21 +1,74 @@
-use crate::{AnyOutput, ChainProcess};
-
-/// Used to mark a type with a unique enum ID, assisting dynamic dispatch
-pub trait Groupped<Group> {
- /// 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> {
- AnyOutput::new(self).route_chain()
+#[cfg(feature = "general_renderer")]
+pub use general_renderer_groupped::*;
+
+#[cfg(not(feature = "general_renderer"))]
+pub use groupped::*;
+
+#[cfg(feature = "general_renderer")]
+mod general_renderer_groupped {
+ use serde::Serialize;
+
+ use crate::{AnyOutput, ChainProcess};
+ /// Used to mark a type with a unique enum ID, assisting dynamic dispatch
+ pub trait Groupped<Group>
+ where
+ Self: Sized + Serialize + '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 + Serialize,
+ {
+ 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 + Serialize,
+ {
+ AnyOutput::new(self).route_renderer()
+ }
}
+}
+
+#[cfg(not(feature = "general_renderer"))]
+mod groupped {
+ use crate::{AnyOutput, ChainProcess};
+
+ /// Used to mark a type with a unique enum ID, assisting dynamic dispatch
+ pub trait Groupped<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,
+ {
+ 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> {
- AnyOutput::new(self).route_renderer()
+ /// 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,
+ {
+ AnyOutput::new(self).route_renderer()
+ }
}
}
diff --git a/mingling_core/src/comp/comp_ctx.rs b/mingling_core/src/comp/comp_ctx.rs
index b9f9020..8d7fa5c 100644
--- a/mingling_core/src/comp/comp_ctx.rs
+++ b/mingling_core/src/comp/comp_ctx.rs
@@ -20,80 +20,27 @@ where
#[cfg(test)]
mod tests {
- use super::*;
- use crate::{AnyOutput, ChainProcess, Groupped, RenderResult};
-
- /// Minimal mock collector that satisfies `C: ProgramCollect<Enum = C>`
- /// by setting `Enum = Self`.
- #[derive(Debug, Clone, PartialEq)]
- struct MockCollect;
-
- impl Groupped<MockCollect> for MockCollect {
- fn member_id() -> MockCollect {
- MockCollect
- }
- }
+ use crate::MockProgramCollect;
- impl ProgramCollect for MockCollect {
- type Enum = MockCollect;
- type ErrorDispatcherNotFound = MockCollect;
- type ErrorRendererNotFound = MockCollect;
- type ResultEmpty = MockCollect;
-
- fn build_renderer_not_found(_member_id: MockCollect) -> AnyOutput<MockCollect> {
- unimplemented!()
- }
- fn build_dispatcher_not_found(_args: Vec<String>) -> AnyOutput<MockCollect> {
- unimplemented!()
- }
- fn build_empty_result() -> AnyOutput<MockCollect> {
- unimplemented!()
- }
- fn render(_any: AnyOutput<MockCollect>, _r: &mut RenderResult) {
- unimplemented!()
- }
- fn render_help(_any: AnyOutput<MockCollect>, _r: &mut RenderResult) {
- unimplemented!()
- }
- fn do_chain(_any: AnyOutput<MockCollect>) -> ChainProcess<MockCollect> {
- unimplemented!()
- }
- #[cfg(feature = "comp")]
- fn do_comp(_any: &AnyOutput<MockCollect>, _ctx: &crate::ShellContext) -> crate::Suggest {
- unimplemented!()
- }
- fn has_renderer(_any: &AnyOutput<MockCollect>) -> bool {
- unimplemented!()
- }
- fn has_chain(_any: &AnyOutput<MockCollect>) -> bool {
- unimplemented!()
- }
-
- #[cfg(feature = "general_renderer")]
- fn general_render(
- _any: AnyOutput<MockCollect>,
- _setting: &crate::GeneralRendererSetting,
- ) -> Result<RenderResult, crate::error::GeneralRendererSerializeError> {
- unimplemented!()
- }
- }
+ use super::*;
#[test]
fn test_is_completing_with_comp_subcommand() {
- let program: Program<MockCollect> =
+ let program: Program<MockProgramCollect> =
Program::new_with_args(["program", "__comp", "some", "args"]);
assert!(program.is_completing());
}
#[test]
fn test_is_completing_with_normal_subcommand() {
- let program: Program<MockCollect> = Program::new_with_args(["program", "normal", "cmd"]);
+ let program: Program<MockProgramCollect> =
+ Program::new_with_args(["program", "normal", "cmd"]);
assert!(!program.is_completing());
}
#[test]
fn test_is_completing_with_no_args() {
- let program: Program<MockCollect> = Program::new_with_args(["program"]);
+ let program: Program<MockProgramCollect> = Program::new_with_args(["program"]);
assert!(!program.is_completing());
}
}
diff --git a/mingling_core/src/program/collection.rs b/mingling_core/src/program/collection.rs
index d3d18d6..078f736 100644
--- a/mingling_core/src/program/collection.rs
+++ b/mingling_core/src/program/collection.rs
@@ -12,6 +12,9 @@ use crate::{GeneralRendererSetting, error::GeneralRendererSerializeError};
#[cfg(feature = "comp")]
use crate::{ShellContext, Suggest};
+mod mock;
+pub use mock::*;
+
/// 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
diff --git a/mingling_core/src/program/collection/mock.rs b/mingling_core/src/program/collection/mock.rs
new file mode 100644
index 0000000..e1b3aa4
--- /dev/null
+++ b/mingling_core/src/program/collection/mock.rs
@@ -0,0 +1,105 @@
+pub use mock::*;
+
+mod mock {
+ #[cfg(feature = "async")]
+ use std::pin::Pin;
+
+ #[cfg(feature = "dispatch_tree")]
+ use crate::Dispatcher;
+
+ use crate::{AnyOutput, ChainProcess, Groupped, ProgramCollect, RenderResult};
+
+ #[cfg(feature = "general_renderer")]
+ use crate::{GeneralRendererSetting, error::GeneralRendererSerializeError};
+
+ #[cfg(feature = "comp")]
+ use crate::{ShellContext, Suggest};
+
+ #[cfg(feature = "general_renderer")]
+ use serde::Serialize;
+
+ #[cfg_attr(feature = "general_renderer", derive(Serialize))]
+ #[allow(unused)]
+ pub enum MockProgramCollect {
+ Foo,
+ Bar,
+ }
+
+ impl Groupped<MockProgramCollect> for MockProgramCollect {
+ fn member_id() -> MockProgramCollect {
+ MockProgramCollect::Foo
+ }
+ }
+
+ impl ProgramCollect for MockProgramCollect {
+ type Enum = MockProgramCollect;
+ type ErrorDispatcherNotFound = MockProgramCollect;
+ type ErrorRendererNotFound = MockProgramCollect;
+ type ResultEmpty = MockProgramCollect;
+
+ #[cfg(feature = "dispatch_tree")]
+ fn dispatch_args_trie(
+ _raw: &[String],
+ ) -> Result<AnyOutput<Self::Enum>, crate::error::ProgramInternalExecuteError> {
+ unreachable!()
+ }
+
+ #[cfg(feature = "dispatch_tree")]
+ fn get_nodes() -> Vec<(String, &'static (dyn Dispatcher<Self::Enum> + Send + Sync))> {
+ unreachable!()
+ }
+
+ fn build_renderer_not_found(_member_id: Self::Enum) -> AnyOutput<Self::Enum> {
+ unreachable!()
+ }
+
+ fn build_dispatcher_not_found(_args: Vec<String>) -> AnyOutput<Self::Enum> {
+ unreachable!()
+ }
+
+ fn build_empty_result() -> AnyOutput<Self::Enum> {
+ unreachable!()
+ }
+
+ fn render(_any: AnyOutput<Self::Enum>, _r: &mut RenderResult) {
+ unreachable!()
+ }
+
+ fn render_help(_any: AnyOutput<Self::Enum>, _r: &mut RenderResult) {
+ unreachable!()
+ }
+
+ #[cfg(feature = "async")]
+ fn do_chain(
+ _any: AnyOutput<Self::Enum>,
+ ) -> Pin<Box<dyn Future<Output = ChainProcess<Self::Enum>> + Send>> {
+ unreachable!()
+ }
+
+ #[cfg(not(feature = "async"))]
+ fn do_chain(_any: AnyOutput<Self::Enum>) -> ChainProcess<Self::Enum> {
+ unreachable!()
+ }
+
+ #[cfg(feature = "comp")]
+ fn do_comp(_any: &AnyOutput<Self::Enum>, _ctx: &ShellContext) -> Suggest {
+ unreachable!()
+ }
+
+ fn has_renderer(_any: &AnyOutput<Self::Enum>) -> bool {
+ unreachable!()
+ }
+
+ fn has_chain(_any: &AnyOutput<Self::Enum>) -> bool {
+ unreachable!()
+ }
+
+ #[cfg(feature = "general_renderer")]
+ fn general_render(
+ _any: AnyOutput<Self::Enum>,
+ _setting: &GeneralRendererSetting,
+ ) -> Result<RenderResult, GeneralRendererSerializeError> {
+ unreachable!()
+ }
+ }
+}
diff --git a/mingling_core/src/program/setup.rs b/mingling_core/src/program/setup.rs
index 2bfced1..f248fb6 100644
--- a/mingling_core/src/program/setup.rs
+++ b/mingling_core/src/program/setup.rs
@@ -20,69 +20,14 @@ where
#[cfg(test)]
mod tests {
use super::*;
- use crate::{AnyOutput, ChainProcess, Groupped, RenderResult};
-
- /// Minimal mock collector that satisfies `C: ProgramCollect<Enum = C>`
- /// by setting `Enum = Self`.
- #[derive(Debug, Clone, PartialEq)]
- struct MockCollect;
-
- impl Groupped<MockCollect> for MockCollect {
- fn member_id() -> MockCollect {
- MockCollect
- }
- }
-
- impl ProgramCollect for MockCollect {
- type Enum = MockCollect;
- type ErrorDispatcherNotFound = MockCollect;
- type ErrorRendererNotFound = MockCollect;
- type ResultEmpty = MockCollect;
-
- fn build_renderer_not_found(_member_id: MockCollect) -> AnyOutput<MockCollect> {
- unimplemented!()
- }
- fn build_dispatcher_not_found(_args: Vec<String>) -> AnyOutput<MockCollect> {
- unimplemented!()
- }
- fn build_empty_result() -> AnyOutput<MockCollect> {
- unimplemented!()
- }
- fn render(_any: AnyOutput<MockCollect>, _r: &mut RenderResult) {
- unimplemented!()
- }
- fn render_help(_any: AnyOutput<MockCollect>, _r: &mut RenderResult) {
- unimplemented!()
- }
- fn do_chain(_any: AnyOutput<MockCollect>) -> ChainProcess<MockCollect> {
- unimplemented!()
- }
- #[cfg(feature = "comp")]
- fn do_comp(_any: &AnyOutput<MockCollect>, _ctx: &crate::ShellContext) -> crate::Suggest {
- unimplemented!()
- }
- fn has_renderer(_any: &AnyOutput<MockCollect>) -> bool {
- unimplemented!()
- }
- fn has_chain(_any: &AnyOutput<MockCollect>) -> bool {
- unimplemented!()
- }
-
- #[cfg(feature = "general_renderer")]
- fn general_render(
- _any: AnyOutput<MockCollect>,
- _setting: &crate::GeneralRendererSetting,
- ) -> Result<RenderResult, crate::error::GeneralRendererSerializeError> {
- unimplemented!()
- }
- }
+ use crate::MockProgramCollect;
struct TestSetup {
called: std::rc::Rc<std::cell::Cell<bool>>,
}
- impl ProgramSetup<MockCollect> for TestSetup {
- fn setup(self, _program: &mut Program<MockCollect>) {
+ impl ProgramSetup<MockProgramCollect> for TestSetup {
+ fn setup(self, _program: &mut Program<MockProgramCollect>) {
self.called.set(true);
}
}
@@ -93,7 +38,7 @@ mod tests {
let setup = TestSetup {
called: std::rc::Rc::clone(&called),
};
- let mut program: Program<MockCollect> = Program::new_with_args(["test"]);
+ let mut program: Program<MockProgramCollect> = Program::new_with_args(["test"]);
program.with_setup(setup);
assert!(called.get());
}