diff options
Diffstat (limited to 'CHANGELOG.md')
| -rw-r--r-- | CHANGELOG.md | 116 |
1 files changed, 110 insertions, 6 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c70d3d..b90536e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,7 +58,36 @@ None #### Optimizations: -None +1. **[`macros`]** Updated `route!` macro to use `Routable` trait instead of `Grouped` trait for error conversion, making the semantics clearer. The `route!` macro now calls `::mingling::Routable::to_chain(e)` on the error branch instead of `::mingling::Grouped::to_chain(e)`. + + Additionally, `ChainProcess<ThisProgram>` now implements `Routable<ThisProgram>`, allowing `route!` to work with `Result<Ok, ChainProcess<ThisProgram>>` patterns — where the error side is already a `ChainProcess` value that should be routed directly: + + When `ChainProcess` implements `Routable`, `to_chain()` re-routes the inner `AnyOutput` to the chain pipeline (preserving the existing `NextProcess::Chain`/`Renderer` flag), while `to_render()` re-routes it to the render pipeline. This enables seamless propagation of already-routed chain process values through the `route!` macro without double-wrapping. + + The `Routable` trait is defined in `mingling_core::asset::routable` and provides unified routing capabilities (`to_chain` / `to_render`) for any type that can be dispatched into the program's pipeline. A blanket implementation is provided for all `T: Grouped<C> + Send`, ensuring backward compatibility — existing types that implement `Grouped` automatically implement `Routable`. + +2. **[`macros`]** Restructured the `mingling_macros` crate's internal module hierarchy. The previously flat module structure has been reorganized into a logical directory-based layout: + + - **`attr/`** — Attribute macro implementations (e.g., `#[chain]`, `#[renderer]`, `#[help]`, `#[completion]`, `#[dispatcher_clap]`, `#[program_setup]`) + - **`derive/`** — Derive macro implementations (e.g., `#[derive(Grouped)]`, `#[derive(EnumTag)]`) + - **`func/`** — Function-like macro implementations (e.g., `pack!`, `group!`, `dispatcher!`, `suggest!`, `entry!`, `node!`, `gen_program!` and its sub-macros) + - **`systems/`** — Cross-cutting systems (e.g., resource injection, dispatch tree generation, structural data derive support) + - **`extensions/`** — Extension point mechanism for attribute macros (unchanged) + - **`utils.rs`** — Shared utility module for future common helpers + + All public API items (`#[proc_macro]`, `#[proc_macro_derive]`, `#[proc_macro_attribute]`) remain at the crate root (`lib.rs`) with identical signatures. Internal function visibility has been tightened from `pub fn` to `pub(crate) fn` for all module-internal functions that were previously publicly accessible only within the crate. + + _No migration is required for downstream code — all macros are re-exported with the same names and signatures as before._ + +3. **[`macros`]** Refactored the code generation strategy for `#[chain]`, `#[renderer]`, `#[help]`, and `#[completion]` attribute macros. Instead of inlining the user's function body directly into the generated trait implementation, these macros now **preserve the original user function as a standalone item** and generate trait method implementations that **call the original function by name**, injecting resources from the application context. + + This approach provides several benefits: + + - **Better debugging and error messages** — The user's function exists as a named, callable item. Stack traces, profiler output, and error messages reference the user's function name (e.g., `handle_greet`) rather than an anonymous closure or inlined block, making debugging more intuitive. + + - **Clearer macro expansion** — The generated code maintains a clear separation between the original user function and the trait glue code, reducing the cognitive load when inspecting macro-expanded output. + + _No migration is required for downstream code — the behavior of all four macros is unchanged. This is purely an internal code generation refactoring._ #### Features: @@ -206,29 +235,74 @@ None The generated `proc` function now wraps the body result in `<UserReturnType as Into<ChainProcess<ThisProgram>>>::into(...)`, which: - Works for `Next` / `ChainProcess` via the identity `From<T> for T` implementation. - - Works for any pack type (`ResultGreeting`, etc.) via the `.into()` conversion generated by `pack!` / `#[derive(Groupped)]`. + - Works for any pack type (`ResultGreeting`, etc.) via the `.into()` conversion generated by `pack!` / `#[derive(Grouped)]`. - Works for `()` via the `From<()>` implementation on `ChainProcess`. The return type validation has been removed entirely — any valid Rust return type is accepted. If the type does not implement `Into<ChainProcess<ThisProgram>>`, a standard Rust compilation error will be produced at the call site. +10. **[`macros`]** **[`extensions`]** Added the `extensions` module to `mingling_macros`, providing an extension point mechanism for attribute macros (`#[chain]`, `#[renderer]`, `#[help]`, `#[completion]`). The extension system allows identifiers in the attribute argument to be extracted and processed before the main macro logic runs. + + Each attribute macro now attempts to redispatch through `extensions::try_redispatch_simple()` (or `try_redispatch_completion` for `#[completion]`) before executing its standard logic. If extension identifiers are detected, the call is re-routed so that extensions are applied via additional `#[...]` attributes stacked on top of the inner core attribute. New extensions can be added without modifying the attribute macros themselves — only the `extensions` module needs to be updated to register new identifiers. + + This system is designed for future extensibility: as new cross-cutting concerns (e.g., logging, metrics, validation) are identified, they can be added as simple extension identifiers without touching the core macro logic. + +11. **[`extensions`]** **[`macros`]** Added the `#[routeify]` extension attribute macro that transforms `expr?` into `route!(expr)`, enabling concise error routing in chain functions using the `?` operator syntax. + + The `#[routeify]` macro can be used: + - **Standalone** — as a direct attribute: `#[routeify] fn handle(...) { ... }` + - **As an extension** — via the extension point system: `#[chain(routeify)] fn handle(...) { ... }` + + When used as a `#[chain]` extension, the `routeify` identifier is detected by the extension point mechanism, stripped from the `#[chain]` attribute arguments, and `#[routeify]` is applied as an outer attribute on top of `#[chain]`. The re-dispatch token stream now correctly generates `#[#exts]*` (i.e., `#[routeify] #[chain]`) instead of the previous bare `#exts` — fixing a bug where extension identifiers were emitted without the `#[...]` attribute delimiter, producing invalid token streams. + + ```rust + use mingling::macros::routeify; + + #[chain(routeify)] + fn handle_calc(args: EntryCalculate) -> Next { + let a = args.pick(&arg![f32]).to_result()?; + let op = args.pick(&arg![Operator]).to_result()?; + StateCalculate { number_a: a, operator: op, ... }.to_chain() + } + ``` + + The `#[routeify]` macro is feature-gated behind `extra_macros` and re-exported as `mingling::macros::routeify`. + + Internal changes: + - Added `mingling_macros/src/extensions/routeify.rs` with `routeify_impl` implementation. + - Updated `try_redispatch_simple` and `try_redispatch_completion` to emit `#[#exts]` instead of bare `#exts`, ensuring proper attribute syntax in the re-dispatched token stream. + - Registered `#[proc_macro_attribute] pub fn routeify` in `mingling_macros/src/lib.rs`. + #### **BREAKING CHANGES** (API CHANGES): -1. **[`macros:renderer`]** **[`macros:help`]** Removed `r_println!` and `r_print!` macros. The `#[renderer]` and `#[help]` macros no longer implicitly inject an internal `RenderResult` variable or provide `r_println!` / `r_print!` macros. +1. **[`macros:renderer`]** **[`macros:help`]** Removed `r_println!` and `r_print!` macros from being implicitly injected by `#[renderer]` and `#[help]` macros. These macros still exist, but must now be used **explicitly** — either with an explicit buffer argument, or via the `#[buffer]` extension attribute that re-enables implicit buffer injection. - Renderers and help functions must now explicitly create and return a `RenderResult`: + **Option A — Explicit buffer:** Pass a `RenderResult` variable as the first argument: ```rust + use mingling::macros::r_println; use mingling::prelude::*; #[renderer] fn render_greeting(greeting: ResultGreeting) -> RenderResult { let mut result = RenderResult::new(); - writeln!(result, "Hello, {}!", *greeting).ok(); + r_println!(result, "Hello, {}!", *greeting); result } ``` - All examples, docs, and test cases across the repository have been updated to use the new pattern: creating a `RenderResult` with `RenderResult::new()` or `RenderResult::default()`, writing with `write!`/`writeln!` from `std::io::Write`, and returning the result. + **Option B — Implicit buffer via `#[buffer]` extension:** Use `#[renderer(buffer)]` to re-enable the old implicit injection behavior, where a `RenderResult` buffer is automatically created and `r_println!`/`r_print!` write to it without an explicit argument. This requires the function to return `()` (unit); the expanded function will return `RenderResult`: + + ```rust + use mingling::macros::r_println; + + #[renderer(buffer)] + fn render_greeting(greeting: ResultGreeting) { + r_println!("Hello, {}!", *greeting); + // Returns RenderResult implicitly + } + ``` + + The `#[buffer]` extension is also available standalone as `#[buffer]` for use outside of `#[renderer]`/`#[help]` functions. 2. **[`macros:chain`]** The `#[chain]` macro's return type requirement has been relaxed. Previously, chain functions were required to return `Next` or `()` (with `()` auto-converting to `ResultEmpty`). Now, chain functions can also return `ChainProcess<ThisProgram>` directly, or omit the return type entirely (which defaults to `()` → `ResultEmpty`). @@ -263,6 +337,36 @@ None 3. **[`core`]** **[`ExitCodeSetup`]** Updated `ExitCodeSetup` to only override the exit code when `ResExitCode` has been modified (i.e., `exit_code != 0`). Previously, it unconditionally overrode the exit code, which could interfere with exit codes set by other hooks or the program's default exit flow. The `on_finish` hook now returns `ProgramControlUnit::OverrideExitCode(...)` only when the exit code is non-zero, and `ProgramControls::Empty` otherwise. The import of `ProgramControls` has been added accordingly. +4. **[`core`]** **[`macros`]** Renamed `Groupped` (typo) to `Grouped`. All references to the trait, derive macro, module files, and related types have been corrected throughout the codebase: + + - Trait: `Groupped<Group>` → `Grouped<Group>` + - Derive macro: `#[derive(Groupped)]` → `#[derive(Grouped)]` + - Serialize variant: `GrouppedSerialize` → `GroupedSerialize` + - Source files: `groupped.rs` → `grouped.rs` + - Pattern matcher: `GrouppedDerivePattern` → `GroupedDerivePattern` + - All `use` imports, type annotations, and trait bound references updated accordingly. + + This is a pure rename — no behavioral changes. All functionality remains identical. Downstream code using the old `Groupped` name must migrate to `Grouped`. + +5. **[`core`]** **[`macros`]** Removed `to_chain()` and `to_render()` default methods from the `Grouped` trait. These methods are now exclusively provided by the `Routable` trait. All code that previously called `to_chain()` or `to_render()` via `Grouped` must now call them via `Routable`: + + ```rust + // Before (via Grouped — removed) + use mingling::Grouped; + my_value.to_chain(); + + // After (via Routable) + use mingling::Routable; + my_value.to_chain(); + ``` + + - The `Routable` trait is re-exported in `mingling::prelude` alongside `Grouped`. + - The blanket implementation `impl<T: Grouped<C> + Send> Routable<C> for T` remains, so all types that implement `Grouped` still have `to_chain()` and `to_render()` — they just need to import `Routable` instead of relying on `Grouped` for those methods. + - Internal macro-generated code (in `#[chain]`, `#[renderer]`, `#[dispatcher_clap]`, `gen_program!`, `empty_result!`, etc.) has been updated to reference `::mingling::Routable::<C>::to_chain(...)` / `::mingling::Routable::<C>::to_render(...)` instead of `::mingling::Grouped::<C>::to_chain(...)` / `::mingling::Grouped::<C>::to_render(...)`. + - Downstream crates using `mingling` macros are automatically migrated — the macro output now references `Routable`. Only manual `.to_chain()` / `.to_render()` calls in user code need updating (add `use mingling::Routable;`). + + _No behavioral changes — this is a pure API migration from `Grouped` to `Routable` for routing methods._ + --- ## Release 0.2.2 (2026-07-10) |
