summaryrefslogtreecommitdiff
path: root/mingling_macros/src/lib.rs
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-03-29 00:52:16 +0800
committer魏曹先生 <1992414357@qq.com>2026-03-29 00:52:28 +0800
commitdb9afa0b06355028eafe3bc29fe0b2429ba8fd0a (patch)
tree60bf74d0853fcc0c1e9363813c26109a6ca38a4f /mingling_macros/src/lib.rs
parent7ce68cd11516bd7cf037ecea99a92aee7c31b2c3 (diff)
Completed the first preliminary usable version of the Mingling
framework.
Diffstat (limited to 'mingling_macros/src/lib.rs')
-rw-r--r--mingling_macros/src/lib.rs151
1 files changed, 120 insertions, 31 deletions
diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs
index 3fdd130..b32534b 100644
--- a/mingling_macros/src/lib.rs
+++ b/mingling_macros/src/lib.rs
@@ -4,14 +4,24 @@
//! Macros are implemented in separate modules and re-exported here.
use proc_macro::TokenStream;
+use proc_macro2::Ident;
+use quote::quote;
+use syn::parse_macro_input;
mod chain;
mod chain_struct;
-mod dispatcher;
+mod dispatcher_chain;
mod node;
mod render;
mod renderer;
+use once_cell::sync::Lazy;
+use std::sync::Mutex;
+
+// Global variable declarations for storing chain and renderer mappings
+pub(crate) static CHAINS: Lazy<Mutex<Vec<String>>> = Lazy::new(|| Mutex::new(Vec::new()));
+pub(crate) static RENDERERS: Lazy<Mutex<Vec<String>>> = Lazy::new(|| Mutex::new(Vec::new()));
+
/// Creates a command node from a dot-separated path string.
///
/// # Examples
@@ -26,31 +36,6 @@ pub fn node(input: TokenStream) -> TokenStream {
node::node(input)
}
-/// Derive macro for automatically implementing the `Dispatcher` trait.
-///
-/// This macro generates an implementation of `mingling::Dispatcher` for a struct.
-/// By default, it uses the struct name converted to snake_case as the command path.
-/// You can also specify a custom path using the `#[dispatcher("path")]` attribute.
-///
-/// # Examples
-///
-/// ```ignore
-/// use mingling_macros::Dispatcher;
-///
-/// // Uses default path: "remote.add"
-/// #[derive(Dispatcher)]
-/// pub struct RemoteAdd;
-///
-/// // Uses custom path: "remote.rm"
-/// #[derive(Dispatcher)]
-/// #[dispatcher("remote.rm")]
-/// pub struct MyCommand;
-/// ```
-#[proc_macro_derive(Dispatcher, attributes(dispatcher))]
-pub fn dispatcher_derive(input: TokenStream) -> TokenStream {
- dispatcher::dispatcher_derive(input)
-}
-
/// Macro for creating wrapper types with automatic trait implementations.
///
/// This macro creates a new struct that wraps an inner type and automatically
@@ -80,6 +65,16 @@ pub fn chain_struct(input: TokenStream) -> TokenStream {
chain_struct::chain_struct(input)
}
+#[proc_macro]
+pub fn dispatcher_chain(input: TokenStream) -> TokenStream {
+ dispatcher_chain::dispatcher_chain(input)
+}
+
+#[proc_macro]
+pub fn dispatcher_render(input: TokenStream) -> TokenStream {
+ dispatcher_chain::dispatcher_render(input)
+}
+
/// Macro for printing to a RenderResult without newline.
///
/// This macro expands to a call to `RenderResult::print` with formatted arguments.
@@ -127,8 +122,8 @@ pub fn r_println(input: TokenStream) -> TokenStream {
/// use mingling_macros::chain;
///
/// #[chain(InitEntry)]
-/// pub async fn proc(_: InitBegin) -> mingling::AnyOutput {
-/// AnyOutput::new::<InitResult>("初始化成功!".to_string().into())
+/// pub async fn proc(_: InitBegin) -> mingling::ChainProcess {
+/// AnyOutput::new::<InitResult>("Init!".to_string().into()).route_chain()
/// }
/// ```
///
@@ -137,8 +132,8 @@ pub fn r_println(input: TokenStream) -> TokenStream {
/// pub struct InitEntry;
/// impl Chain for InitEntry {
/// type Previous = InitBegin;
-/// async fn proc(_: Self::Previous) -> mingling::AnyOutput {
-/// AnyOutput::new::<InitResult>("初始化成功!".to_string().into())
+/// async fn proc(_: Self::Previous) -> mingling::ChainProcess {
+/// AnyOutput::new::<InitResult>("Init!".to_string().into()).route_chain()
/// }
/// }
/// ```
@@ -158,7 +153,7 @@ pub fn chain(attr: TokenStream, item: TokenStream) -> TokenStream {
/// use mingling_macros::renderer;
///
/// #[renderer(InitResultRenderer)]
-/// fn render(p: InitResult, r: &mut RenderResult) {
+/// fn render(p: InitResult) {
/// let str: String = p.into();
/// r_println!("{}", str);
/// }
@@ -180,3 +175,97 @@ pub fn chain(attr: TokenStream, item: TokenStream) -> TokenStream {
pub fn renderer(attr: TokenStream, item: TokenStream) -> TokenStream {
renderer::renderer_attr(attr, item)
}
+
+/// Macro for creating a program structure that collects all chains and renderers.
+///
+/// This macro creates a struct that implements the `ProgramCollect` trait,
+/// which collects all chains and renderers registered with `#[chain]` and `#[renderer]`
+/// attribute macros. The program can then be used to execute the command chain.
+///
+/// # Examples
+///
+/// ```ignore
+/// use mingling_macros::program;
+///
+/// program!(MyProgram);
+///
+/// // This generates:
+/// pub struct MyProgram;
+/// impl mingling::ProgramCollect for MyProgram {
+/// mingling::__dispatch_program_renderers!(...);
+/// mingling::__dispatch_program_chains!(...);
+/// }
+/// impl MyProgram {
+/// pub fn new() -> mingling::Program<MyProgram> {
+/// mingling::Program::new()
+/// }
+/// }
+/// ```
+#[proc_macro]
+pub fn program(input: TokenStream) -> TokenStream {
+ let name = parse_macro_input!(input as Ident);
+
+ let renderers = RENDERERS.lock().unwrap().clone();
+ let chains = CHAINS.lock().unwrap().clone();
+
+ let renderer_tokens: Vec<proc_macro2::TokenStream> = renderers
+ .iter()
+ .map(|s| syn::parse_str::<proc_macro2::TokenStream>(s).unwrap())
+ .collect();
+
+ let chain_tokens: Vec<proc_macro2::TokenStream> = chains
+ .iter()
+ .map(|s| syn::parse_str::<proc_macro2::TokenStream>(s).unwrap())
+ .collect();
+
+ let expanded = quote! {
+ pub struct #name;
+
+ impl ::mingling::ProgramCollect for #name {
+ ::mingling::__dispatch_program_renderers!(
+ #(#renderer_tokens)*
+ );
+ ::mingling::__dispatch_program_chains!(
+ #(#chain_tokens)*
+ );
+ }
+
+ impl #name {
+ pub fn new() -> ::mingling::Program<#name> {
+ ::mingling::Program::new()
+ }
+ }
+ };
+
+ TokenStream::from(expanded)
+}
+
+/// Internal macro for registering chains.
+///
+/// This macro is used internally by the `#[chain]` attribute macro
+/// and should not be used directly.
+#[doc(hidden)]
+#[proc_macro]
+pub fn __register_chain(input: TokenStream) -> TokenStream {
+ let chain_entry = parse_macro_input!(input as syn::LitStr);
+ let entry_str = chain_entry.value();
+
+ CHAINS.lock().unwrap().push(entry_str);
+
+ TokenStream::new()
+}
+
+/// Internal macro for registering renderers.
+///
+/// This macro is used internally by the `#[renderer]` attribute macro
+/// and should not be used directly.
+#[doc(hidden)]
+#[proc_macro]
+pub fn __register_renderer(input: TokenStream) -> TokenStream {
+ let renderer_entry = parse_macro_input!(input as syn::LitStr);
+ let entry_str = renderer_entry.value();
+
+ RENDERERS.lock().unwrap().push(entry_str);
+
+ TokenStream::new()
+}