aboutsummaryrefslogtreecommitdiff
path: root/mingling_macros/src/func
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-07-20 08:42:16 +0800
committer魏曹先生 <1992414357@qq.com>2026-07-20 08:42:16 +0800
commit7b3a1d7fd9f60b91a7f9602374c081882d46facc (patch)
treedc0c8a9bf095308e6d29091db4b5037c29ed5742 /mingling_macros/src/func
parent9dc737acec1eab40ef65bef8e6c729a4e5e06401 (diff)
feat(macros): add `#[buffer]` attribute and re-export `r_print!(ln)`
macros Reintroduce `r_print!` and `r_println!` macros as public exports, now supporting both explicit buffer argument and implicit `#[buffer]` attr. Add `#[buffer]` attribute macro that wraps unit-returning functions to produce a `RenderResult` with an automatically injected buffer variable. Relax `RenderResult::print()` and `println()` to accept `impl AsRef<str>`.
Diffstat (limited to 'mingling_macros/src/func')
-rw-r--r--mingling_macros/src/func/r_print.rs62
1 files changed, 62 insertions, 0 deletions
diff --git a/mingling_macros/src/func/r_print.rs b/mingling_macros/src/func/r_print.rs
new file mode 100644
index 0000000..e81b544
--- /dev/null
+++ b/mingling_macros/src/func/r_print.rs
@@ -0,0 +1,62 @@
+use proc_macro::TokenStream;
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+use syn::parse::{Parse, ParseStream};
+use syn::{Ident, Token};
+
+/// Parsed input for `r_println!` and `r_print!`.
+///
+/// Two forms:
+/// - `(ident, format_args...)` — explicit buffer
+/// - `(format_args...)` — implicit `__render_result_buffer`
+enum PrintInput {
+ Explicit { dst: Ident, args: TokenStream2 },
+ Implicit { args: TokenStream2 },
+}
+
+impl Parse for PrintInput {
+ fn parse(input: ParseStream) -> syn::Result<Self> {
+ // Peek: if the next token is an ident followed by a comma, it's the explicit form
+ if input.peek(Ident) && input.peek2(Token![,]) {
+ let dst: Ident = input.parse()?;
+ let _comma: Token![,] = input.parse()?;
+ let args: TokenStream2 = input.parse()?;
+ Ok(PrintInput::Explicit { dst, args })
+ } else {
+ let args: TokenStream2 = input.parse()?;
+ Ok(PrintInput::Implicit { args })
+ }
+ }
+}
+
+fn expand_print(input: TokenStream, method: &str) -> TokenStream {
+ let parsed: PrintInput = match syn::parse(input) {
+ Ok(p) => p,
+ Err(e) => return e.to_compile_error().into(),
+ };
+
+ let method_ident = Ident::new(method, proc_macro2::Span::call_site());
+
+ let expanded = match parsed {
+ PrintInput::Explicit { dst, args } => {
+ quote! {
+ #dst.#method_ident(format!(#args))
+ }
+ }
+ PrintInput::Implicit { args } => {
+ quote! {
+ __render_result_buffer.#method_ident(format!(#args))
+ }
+ }
+ };
+
+ expanded.into()
+}
+
+pub(crate) fn r_println(input: TokenStream) -> TokenStream {
+ expand_print(input, "println")
+}
+
+pub(crate) fn r_print(input: TokenStream) -> TokenStream {
+ expand_print(input, "print")
+}