aboutsummaryrefslogtreecommitdiff
path: root/mingling_macros/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'mingling_macros/src/lib.rs')
-rw-r--r--mingling_macros/src/lib.rs124
1 files changed, 92 insertions, 32 deletions
diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs
index ae874af..ce3455e 100644
--- a/mingling_macros/src/lib.rs
+++ b/mingling_macros/src/lib.rs
@@ -36,7 +36,7 @@
//! │ V │
//! │ Reads all registries → generates ThisProgram with: │
//! │ • ProgramCollect impl (dispatch/render/chain dispatch tree) │
-//! │ • Fallback types (ErrorDispatcherNotFound, etc.) │
+//! │ • Fallback types (EntryFallback, etc.) │
//! │ • Completion logic (if `comp` feature enabled) │
//! └──────────────────────────────────────────────────────────────────┘
//! ```
@@ -100,10 +100,10 @@
//! |---------|---------------|
//! | `clap` | `dispatcher_clap!` |
//! | `comp` | [`#[completion]`](attr.completion.html), `suggest!`, `suggest_enum!` |
-//! | `extra_macros` | `entry!`, `empty_result!`, `route!`, [`#[program_setup]`](attr.program_setup.html), `group!` |
+//! | `extras` | `entry!`, `empty_result!`, `route!`, [`#[program_setup]`](attr.program_setup.html), `group!` |
//! | `dispatch_tree` | `register_dispatcher!` (enables trie-based command dispatch) |
//! | `structural_renderer` | `#[derive(StructuralData)]`, `pack_structural!`, `pack_err_structural!`, `group_structural!` |
-//! | `structural_renderer` + `extra_macros` | `group_structural!`, `pack_err_structural!` |
+//! | `structural_renderer` + `extras` | `group_structural!`, `pack_err_structural!` |
//! | `async` | Enables async `#[chain]` functions |
//! | `repl` | Enables REPL execution loop |
//!
@@ -120,8 +120,8 @@
//! ```rust,ignore
//! // Example of what gen_program! generates (simplified):
//! impl ProgramCollect for ThisProgram {
-//! fn build_dispatcher_not_found(args: Vec<String>) -> AnyOutput {
-//! AnyOutput::new(ErrorDispatcherNotFound::new(args))
+//! fn build_entry_fallback(args: Vec<String>) -> AnyOutput {
+//! AnyOutput::new(EntryFallback::new(args))
//! }
//! fn has_chain(any: &AnyOutput) -> bool {
//! match any.member_id() {
@@ -163,15 +163,15 @@ mod utils;
use attr::completion;
#[cfg(feature = "clap")]
use attr::dispatcher_clap;
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
use attr::program_setup;
-use attr::{chain, help, renderer};
+use attr::{chain, help, metadata, renderer};
use derive::{enum_tag, grouped};
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
use func::entry;
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
pub(crate) use func::group as group_impl;
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
use func::pack_err;
#[cfg(feature = "comp")]
use func::suggest;
@@ -209,6 +209,7 @@ pub(crate) static RENDERERS: Registry = OnceLock::new();
pub(crate) static CHAINS_EXIST: Registry = OnceLock::new();
pub(crate) static RENDERERS_EXIST: Registry = OnceLock::new();
pub(crate) static HELP_REQUESTS: Registry = OnceLock::new();
+pub(crate) static METADATA: Registry = OnceLock::new();
/// Checks if a variant name already exists in a registered set.
/// Returns a `compile_error` token stream if a duplicate is found.
@@ -293,7 +294,7 @@ fn entry_has_variant(entry: &str, variant_name: &str) -> bool {
///
/// - The type must be accessible at the call site (imported or fully qualified).
/// - The alias name (if provided) must not conflict with existing types.
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro]
pub fn group(input: TokenStream) -> TokenStream {
group_impl::group_macro(input)
@@ -309,8 +310,8 @@ pub fn group(input: TokenStream) -> TokenStream {
/// group_structural!(IoError = std::io::Error);
/// ```
///
-/// Requires the `structural_renderer` and `extra_macros` features.
-#[cfg(all(feature = "structural_renderer", feature = "extra_macros"))]
+/// Requires the `structural_renderer` and `extras` features.
+#[cfg(all(feature = "structural_renderer", feature = "extras"))]
#[proc_macro]
pub fn group_structural(input: TokenStream) -> TokenStream {
func::group_structural::group_structural(input)
@@ -490,8 +491,8 @@ pub fn pack_structural(input: TokenStream) -> TokenStream {
/// When the `structural_renderer` feature is enabled, the struct also gets
/// `#[derive(serde::Serialize)]`.
///
-/// This macro is only available with the `extra_macros` feature.
-#[cfg(feature = "extra_macros")]
+/// This macro is only available with the `extras` feature.
+#[cfg(feature = "extras")]
#[proc_macro]
pub fn pack_err(input: TokenStream) -> TokenStream {
pack_err::pack_err(input)
@@ -507,8 +508,8 @@ pub fn pack_err(input: TokenStream) -> TokenStream {
/// pack_err_structural!(ErrorNotDir = PathBuf);
/// ```
///
-/// Requires the `structural_renderer` and `extra_macros` features.
-#[cfg(all(feature = "structural_renderer", feature = "extra_macros"))]
+/// Requires the `structural_renderer` and `extras` features.
+#[cfg(all(feature = "structural_renderer", feature = "extras"))]
#[proc_macro]
pub fn pack_err_structural(input: TokenStream) -> TokenStream {
func::pack_err_structural::pack_err_structural(input)
@@ -568,7 +569,7 @@ pub fn pack_err_structural(input: TokenStream) -> TokenStream {
/// value.to_chain()
/// }
/// ```
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro]
pub fn route(input: TokenStream) -> TokenStream {
func::route::route(input)
@@ -611,7 +612,7 @@ pub fn route(input: TokenStream) -> TokenStream {
/// Ok(RenderResult::new())
/// }
/// ```
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro]
pub fn render_route(input: TokenStream) -> TokenStream {
func::render_route::render_route(input)
@@ -665,7 +666,7 @@ pub fn render_route(input: TokenStream) -> TokenStream {
///
/// [`ResultEmpty`]: https://docs.rs/mingling/latest/mingling/type.ResultEmpty.html
/// [`ChainProcess`]: https://docs.rs/mingling/latest/mingling/enum.ChainProcess.html
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro]
pub fn empty_result(input: TokenStream) -> TokenStream {
func::empty_result::empty_result(input)
@@ -692,9 +693,9 @@ pub fn empty_result(input: TokenStream) -> TokenStream {
/// dispatcher!(MyProgram, "command.path", CommandStruct => EntryStruct);
/// ```
///
-/// ## Abbreviated syntax (requires `extra_macros` feature)
+/// ## Abbreviated syntax (requires `extras` feature)
///
-/// When the `extra_macros` feature is enabled, the `CommandStruct => EntryStruct`
+/// When the `extras` feature is enabled, the `CommandStruct => EntryStruct`
/// portion can be omitted. Struct names are auto-derived from the command path
/// using `PascalCase` conversion:
///
@@ -721,7 +722,7 @@ pub fn empty_result(input: TokenStream) -> TokenStream {
/// // With explicit program:
/// dispatcher!(MyApp, "status", StatusCommand => StatusEntry);
///
-/// // Abbreviated form (extra_macros required):
+/// // Abbreviated form (extras required):
/// // dispatcher!("remote.add"); // → CMDRemoteAdd, EntryRemoteAdd
/// ```
///
@@ -978,11 +979,11 @@ pub fn chain(attr: TokenStream, item: TokenStream) -> TokenStream {
/// The macros `gen_program!` automatically generates two fallback types that
/// you can provide renderers for:
/// - `ErrorRendererNotFound` — triggered when no matching renderer is found
-/// - `ErrorDispatcherNotFound` — triggered when no matching dispatcher is found
+/// - `EntryFallback` — triggered when no matching dispatcher is found
///
/// ```rust,ignore
/// #[renderer]
-/// fn fallback_dispatcher_not_found(prev: ErrorDispatcherNotFound) -> RenderResult {
+/// fn fallback_dispatcher_not_found(prev: EntryFallback) -> RenderResult {
/// let mut result = RenderResult::new();
/// writeln!(result, "Unknown command: {}", prev.join(", "));
/// result
@@ -1094,7 +1095,7 @@ pub fn completion(attr: TokenStream, item: TokenStream) -> TokenStream {
/// - The function must have exactly one parameter of type `&mut Program<G>`.
/// - The function must return `()`.
/// - The function cannot be async.
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro_attribute]
pub fn program_setup(attr: TokenStream, item: TokenStream) -> TokenStream {
program_setup::setup_attr(attr, item)
@@ -1102,7 +1103,7 @@ pub fn program_setup(attr: TokenStream, item: TokenStream) -> TokenStream {
/// Declares a command from a plain function.
///
-/// **This macro is only available with the `extra_macros` feature.**
+/// **This macro is only available with the `extras` feature.**
///
/// The `#[command]` attribute converts a function taking `Vec<String>` into a
/// Mingling command by:
@@ -1181,7 +1182,7 @@ pub fn program_setup(attr: TokenStream, item: TokenStream) -> TokenStream {
/// - The function must have at least one parameter (the `Vec<String>` entry argument).
/// - The function must not have a `self` parameter.
/// - Visibility (`pub` etc.) and `async` are preserved on the original function.
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro_attribute]
pub fn command(attr: TokenStream, item: TokenStream) -> TokenStream {
attr::command::command_attr(attr, item)
@@ -1273,7 +1274,7 @@ pub fn dispatcher_clap(attr: TokenStream, item: TokenStream) -> TokenStream {
///
/// - `pack!` — For creating the wrapper types used with `entry!`.
/// - `dispatcher!` — Which implicitly creates entry types via `pack!`.
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro]
pub fn entry(input: TokenStream) -> TokenStream {
entry::entry(input)
@@ -1297,6 +1298,26 @@ pub fn register_help(input: TokenStream) -> TokenStream {
func::register_help::register_help(input)
}
+/// Registers metadata mapping between an enum variant and a metadata type.
+///
+/// This macro is used internally by the `#[metadata]` attribute and is also
+/// available for manual registration if needed.
+///
+/// # Syntax
+///
+/// ```rust,ignore
+/// register_metadata!(EntryVariant, MetadataType);
+/// ```
+///
+/// This adds an entry to the global `METADATA` registry, mapping the enum
+/// variant for `EntryVariant` to the metadata provider trait
+/// `::mingling::Metadata<MetadataType>`. The entry is consumed by
+/// `gen_program!` to generate the `get_metadata` method of `ProgramCollect`.
+#[proc_macro]
+pub fn register_metadata(input: TokenStream) -> TokenStream {
+ func::register_metadata::register_metadata_impl(input)
+}
+
/// Registers a dispatcher at compile time for the `dispatch_tree` feature.
///
/// This macro is called internally by `dispatcher!` when the `dispatch_tree`
@@ -1404,6 +1425,45 @@ pub fn help(attr: TokenStream, item: TokenStream) -> TokenStream {
help::help_attr(item)
}
+/// Declares compile-time metadata for an entry variant.
+///
+/// The `#[metadata]` attribute attaches an arbitrary, compile-time-typed value
+/// to an entry. The annotated function becomes the provider for the metadata:
+/// its return type is the metadata type, and the attribute argument names the
+/// entry enum variant the metadata belongs to.
+///
+/// The macro works by:
+/// 1. Generating `impl ::mingling::Metadata<ReturnType> for EntryVariant` whose
+/// `init_metadata()` calls the annotated function.
+/// 2. Registering the entry via `register_metadata!` in the global `METADATA`
+/// registry so that `gen_program!` emits the `get_metadata` method.
+/// 3. Keeping the original function unchanged for direct calls.
+///
+/// # Syntax
+///
+/// ```rust,ignore
+/// #[metadata(EntryGreet)]
+/// fn greet_desc() -> Description {
+/// Description { desc: "ok".into() }
+/// }
+/// ```
+///
+/// The metadata is later retrieved with `ProgramCollect::get_metadata`:
+///
+/// ```rust,ignore
+/// let desc = ThisProgram::get_metadata::<Description>(ThisProgram::EntryGreet);
+/// ```
+///
+/// # Requirements
+///
+/// - The attribute argument must be the enum variant to attach metadata to.
+/// - The function must take no parameters and return a concrete type.
+/// - The function cannot be async.
+#[proc_macro_attribute]
+pub fn metadata(attr: TokenStream, item: TokenStream) -> TokenStream {
+ metadata::metadata_attr(attr, item)
+}
+
/// Marker attribute for the Mingling lint system.
///
/// The content of this attribute is ignored by rustc and reserved for
@@ -1438,7 +1498,7 @@ pub fn mlint(attr: TokenStream, item: TokenStream) -> TokenStream {
/// StateCalculate { number_a: a, operator: op, ... }.to_chain()
/// }
/// ```
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro_attribute]
pub fn routeify(attr: TokenStream, item: TokenStream) -> TokenStream {
extensions::routeify::routeify_impl(attr, item)
@@ -1464,7 +1524,7 @@ pub fn routeify(attr: TokenStream, item: TokenStream) -> TokenStream {
/// Ok(RenderResult::new())
/// }
/// ```
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro_attribute]
pub fn renderify(attr: TokenStream, item: TokenStream) -> TokenStream {
extensions::renderify::renderify_impl(attr, item)
@@ -1819,7 +1879,7 @@ pub fn derive_grouped_serialize(input: TokenStream) -> TokenStream {
/// 1. **`pub type Next = ChainProcess<ProgramName>`** — A convenience type alias
/// for use in chain function return types.
/// 2. **`program_comp_gen!(...)`** (with `comp` feature) — Generates completion infrastructure.
-/// 3. **`program_fallback_gen!(...)`** — Generates `ErrorRendererNotFound` and `ErrorDispatcherNotFound` types.
+/// 3. **`program_fallback_gen!(...)`** — Generates `ErrorRendererNotFound` and `EntryFallback` types.
/// 4. **`program_final_gen!(...)`** — Generates the program enum with:
/// - An enum with all packed types as variants
/// - `Display` implementation for the enum