From 844c3c9029f75f37622413f3e3a92b93664852ed Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Tue, 21 Jul 2026 04:28:37 +0800 Subject: feat(core): add From impl for RenderResult with closure coercion --- CHANGELOG.md | 21 +++++++++++++++++++++ mingling_core/src/renderer/render_result.rs | 11 ++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bc0318..962d048 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -310,6 +310,27 @@ None The macro is re-exported as `mingling::macros::r_append` and included in `mingling::prelude::*`. +13. **[`core`]** **[`macros`]** Added `From` implementation for `RenderResult` where `F: FnOnce() -> RenderResult`. This enables `RenderResult` to be constructed from a closure or function pointer that returns a `RenderResult`, enabling ergonomic composition of render buffers. + + This is particularly useful with the `#[buffer]` extension attribute, which creates a separate buffer function that can be called from within a `#[renderer(buffer)]` function using `r_append!`: + + ```rust + use mingling::macros::{buffer, r_append, r_println}; + + // A standalone buffer function + #[buffer] + fn print_sth() { + r_println!("ok"); + } + + #[renderer(buffer)] + fn render_greet(_: ResultGreet) { + r_append!(print_sth); // appends `a`'s RenderResult content into `p`'s buffer + } + ``` + + Under the hood, `r_append!` (when used in implicit buffer mode inside a `#[buffer]` function) calls `append_other` on the current render buffer. The `From` implementation allows the buffer function's return value (a `RenderResult`) to be seamlessly converted into the parent's buffer via `append_other`. This enables clean separation of render logic into reusable buffer functions that can be composed together. + #### **BREAKING CHANGES** (API CHANGES): 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. diff --git a/mingling_core/src/renderer/render_result.rs b/mingling_core/src/renderer/render_result.rs index a495857..c38522a 100644 --- a/mingling_core/src/renderer/render_result.rs +++ b/mingling_core/src/renderer/render_result.rs @@ -47,6 +47,15 @@ pub enum RenderResultMode { Stderr = 1, } +impl From for RenderResult +where + F: FnOnce() -> RenderResult, +{ + fn from(value: F) -> Self { + value() + } +} + impl Write for RenderResult { fn write(&mut self, buf: &[u8]) -> std::io::Result { let s = std::str::from_utf8(buf).map_err(|_| { @@ -233,7 +242,7 @@ impl RenderResult { /// src.append_to_buffer("Hello", RenderResultMode::Stdout); /// src.append_to_buffer(" Error", RenderResultMode::Stderr); /// - /// dest.append_otehr(src); + /// dest.append_other(src); /// assert_eq!(dest.to_string(), "Hello Error"); /// ``` pub fn append_other(&mut self, other: impl Into) { -- cgit