aboutsummaryrefslogtreecommitdiff
path: root/mingling_macros/src
diff options
context:
space:
mode:
Diffstat (limited to 'mingling_macros/src')
-rw-r--r--mingling_macros/src/attr/chain.rs22
-rw-r--r--mingling_macros/src/derive/grouped.rs12
-rw-r--r--mingling_macros/src/extensions.rs4
-rw-r--r--mingling_macros/src/extensions/renderify.rs48
-rw-r--r--mingling_macros/src/func/gen_program.rs22
-rw-r--r--mingling_macros/src/func/group.rs6
-rw-r--r--mingling_macros/src/func/pack.rs6
-rw-r--r--mingling_macros/src/func/pack_err.rs4
-rw-r--r--mingling_macros/src/func/r_print.rs65
-rw-r--r--mingling_macros/src/lib.rs191
-rw-r--r--mingling_macros/src/systems/structural_data.rs24
11 files changed, 366 insertions, 38 deletions
diff --git a/mingling_macros/src/attr/chain.rs b/mingling_macros/src/attr/chain.rs
index dbd87dd..dc28a39 100644
--- a/mingling_macros/src/attr/chain.rs
+++ b/mingling_macros/src/attr/chain.rs
@@ -44,7 +44,6 @@ fn generate_proc_fn(
previous_type: &TypePath,
is_async_fn: bool,
is_unit_return: bool,
- origin_return_type: &proc_macro2::TokenStream,
) -> proc_macro2::TokenStream {
let immut_resource_stmts = generate_immut_resource_bindings(resources.iter(), program_type);
let mut_resources: Vec<_> = resources.iter().filter(|r| r.is_mut).collect();
@@ -82,8 +81,14 @@ fn generate_proc_fn(
}
};
- // Convert the function call to a syn::Stmt so existing wrapping functions can use it
- let fn_call_expr: syn::Expr = syn::parse_quote! { #fn_call };
+ // Convert the function call to a syn::Stmt so existing wrapping functions can use it.
+ // For non-unit returns, wrap in `to_chain()` so mutable-resource closures
+ // return `ChainProcess<C>` (as required by `__modify_res_and_return_route`).
+ let fn_call_expr: syn::Expr = if is_unit_return {
+ syn::parse_quote! { #fn_call }
+ } else {
+ syn::parse_quote! { ::mingling::Routable::<#program_type>::to_chain(#fn_call) }
+ };
let fn_call_stmt = syn::Stmt::Expr(fn_call_expr, None);
let wrapped_body = if is_async_fn && !mut_resources.is_empty() {
@@ -124,9 +129,7 @@ fn generate_proc_fn(
};
quote! {
let __chain_result = { #body };
- <#origin_return_type as ::std::convert::Into<
- ::mingling::ChainProcess<#program_type>
- >>::into(__chain_result)
+ ::mingling::Routable::<#program_type>::to_chain(__chain_result)
}
};
@@ -249,12 +252,6 @@ pub(crate) fn chain_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
// Always use the default crate-defined program path
let program_type = crate::default_program_path();
- // Extract the user's return type for the explicit Into turbofish
- let origin_return_type = match &input_fn.sig.output {
- ReturnType::Type(_, ty) => quote! { #ty },
- ReturnType::Default => quote! { () },
- };
-
// Generate the `proc` function for the Chain impl
let proc_fn = generate_proc_fn(
fn_name,
@@ -267,7 +264,6 @@ pub(crate) fn chain_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
#[cfg(not(feature = "async"))]
false,
is_unit_return,
- &origin_return_type,
);
// Preserve the original function untouched
diff --git a/mingling_macros/src/derive/grouped.rs b/mingling_macros/src/derive/grouped.rs
index 307aab6..a00eea1 100644
--- a/mingling_macros/src/derive/grouped.rs
+++ b/mingling_macros/src/derive/grouped.rs
@@ -16,7 +16,11 @@ pub(crate) fn derive_grouped(input: TokenStream) -> TokenStream {
let expanded = quote! {
::mingling::macros::register_type!(#struct_name);
- impl ::mingling::Grouped<#group_ident> for #struct_name {
+ /// SAFETY: This is an internal implementation of the `Grouped` derive macro,
+ /// guaranteeing that the enum value registered by the `register_type!` macro
+ /// is exactly the same as the actual return value,
+ /// which can be confirmed via the `Ident` in the `quote!` block.
+ unsafe impl ::mingling::Grouped<#group_ident> for #struct_name {
fn member_id() -> #group_ident {
#group_ident::#struct_name
}
@@ -46,7 +50,11 @@ pub fn derive_grouped_serialize(input: TokenStream) -> TokenStream {
::mingling::macros::register_type!(#struct_name);
- impl ::mingling::Grouped<#group_ident> for #struct_name {
+ /// SAFETY: This is an internal implementation of the `Grouped` derive macro,
+ /// guaranteeing that the enum value registered by the `register_type!` macro
+ /// is exactly the same as the actual return value,
+ /// which can be confirmed via the `Ident` in the `quote!` block.
+ unsafe impl ::mingling::Grouped<#group_ident> for #struct_name {
fn member_id() -> #group_ident {
#group_ident::#struct_name
}
diff --git a/mingling_macros/src/extensions.rs b/mingling_macros/src/extensions.rs
index 022761b..c2fdb30 100644
--- a/mingling_macros/src/extensions.rs
+++ b/mingling_macros/src/extensions.rs
@@ -13,6 +13,10 @@ use syn::{Ident, Token};
#[cfg(feature = "extra_macros")]
pub(crate) mod routeify;
+/// Extension: `#[renderify]` — transforms `expr?` into `render_route!(expr)`.
+#[cfg(feature = "extra_macros")]
+pub(crate) mod renderify;
+
/// Extension: `#[buffer]` — wraps a unit-returning function to return `RenderResult`.
pub(crate) mod buffer;
diff --git a/mingling_macros/src/extensions/renderify.rs b/mingling_macros/src/extensions/renderify.rs
new file mode 100644
index 0000000..9be8acc
--- /dev/null
+++ b/mingling_macros/src/extensions/renderify.rs
@@ -0,0 +1,48 @@
+//! The `#[renderify]` extension — transforms `expr?` into `render_route!(expr)`.
+//!
+//! Designed as an extension for the Mingling attribute macro system, intended
+//! to be used with `#[renderer(renderify)]`, `#[help(renderify)]`,
+//! or standalone as `#[renderify]`.
+//!
+//! # How it works
+//!
+//! The macro parses the function AST and replaces every `Expr::Try` node with an
+//! equivalent `render_route!(expr)` invocation, which routes errors to the
+//! rendering pipeline via `crate::ThisProgram::render(AnyOutput::new(e))`.
+
+use proc_macro::TokenStream;
+use quote::ToTokens;
+use syn::spanned::Spanned;
+use syn::visit_mut::VisitMut;
+use syn::{Expr, ItemFn, parse_macro_input};
+
+struct RenderifyTransform;
+
+impl VisitMut for RenderifyTransform {
+ fn visit_expr_mut(&mut self, expr: &mut Expr) {
+ syn::visit_mut::visit_expr_mut(self, expr);
+
+ if let Expr::Try(try_expr) = expr {
+ let inner = &*try_expr.expr;
+ let inner_tokens = inner.to_token_stream();
+
+ // Set the span of the generated `render_route` ident to the `?` token's span,
+ // so that rust-analyzer resolves the `?` position to the `render_route!` macro
+ // instead of the standard Try trait, showing the render_route macro's docs on hover.
+ let q_span = try_expr.question_token.span();
+ let route_ident = proc_macro2::Ident::new("render_route", q_span);
+
+ if let Ok(macro_expr) = syn::parse2::<Expr>(quote::quote! {
+ ::mingling::macros::#route_ident!(#inner_tokens)
+ }) {
+ *expr = macro_expr;
+ }
+ }
+ }
+}
+
+pub(crate) fn renderify_impl(_attr: TokenStream, item: TokenStream) -> TokenStream {
+ let mut input_fn = parse_macro_input!(item as ItemFn);
+ RenderifyTransform.visit_item_fn_mut(&mut input_fn);
+ input_fn.to_token_stream().into()
+}
diff --git a/mingling_macros/src/func/gen_program.rs b/mingling_macros/src/func/gen_program.rs
index de4da06..db82504 100644
--- a/mingling_macros/src/func/gen_program.rs
+++ b/mingling_macros/src/func/gen_program.rs
@@ -342,7 +342,7 @@ fn main() {
) -> Result<::mingling::RenderResult, ::mingling::error::StructuralRendererSerializeError> {
#[allow(unused_imports)]
#(#pathf_uses)*
- match any.member_id {
+ match any.member_id() {
#(#structural_renderer_tokens)*
_ => {
// Non-structural types: render ResultEmpty (which implements
@@ -408,7 +408,7 @@ fn main() {
fn do_comp(any: &::mingling::AnyOutput<Self::Enum>, ctx: &::mingling::ShellContext) -> ::mingling::Suggest {
#[allow(unused_imports)]
#(#pathf_uses)*
- match any.member_id {
+ match any.member_id() {
#(#completion_tokens)*
_ => ::mingling::Suggest::FileCompletion,
}
@@ -442,7 +442,7 @@ fn main() {
}).collect();
quote! {
fn render(any: ::mingling::AnyOutput<Self::Enum>) -> ::mingling::RenderResult {
- match any.member_id {
+ match any.member_id() {
#(#render_arms)*
_ => ::mingling::RenderResult::default(),
}
@@ -494,9 +494,9 @@ fn main() {
fn do_chain(
any: ::mingling::AnyOutput<Self::Enum>,
) -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = ::mingling::ChainProcess<Self::Enum>> + ::std::marker::Send>> {
- match any.member_id {
+ match any.member_id() {
#(#chain_arms_async)*
- _ => ::core::panic!("No chain found for type id: {:?}", any.type_id),
+ _ => ::core::panic!("No chain found for type id: {:?}", any.type_id()),
}
}
}
@@ -505,9 +505,9 @@ fn main() {
fn do_chain(
any: ::mingling::AnyOutput<Self::Enum>,
) -> ::mingling::ChainProcess<Self::Enum> {
- match any.member_id {
+ match any.member_id() {
#(#chain_arms_sync)*
- _ => ::core::panic!("No chain found for type id: {:?}", any.type_id),
+ _ => ::core::panic!("No chain found for type id: {:?}", any.type_id()),
}
}
}
@@ -535,7 +535,7 @@ fn main() {
let expanded = quote! {
#pathf_hint
- #[derive(Debug, PartialEq, Eq, Clone)]
+ #[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(#repr_type)]
#[allow(nonstandard_style)]
pub enum #name {
@@ -569,19 +569,19 @@ fn main() {
fn render_help(any: ::mingling::AnyOutput<Self::Enum>) -> ::mingling::RenderResult {
#[allow(unused_imports)]
#(#pathf_uses)*
- match any.member_id {
+ match any.member_id() {
#(#help_tokens)*
_ => ::mingling::RenderResult::default(),
}
}
fn has_renderer(any: &::mingling::AnyOutput<Self::Enum>) -> bool {
- match any.member_id {
+ match any.member_id() {
#(#renderer_exist_tokens)*
_ => false
}
}
fn has_chain(any: &::mingling::AnyOutput<Self::Enum>) -> bool {
- match any.member_id {
+ match any.member_id() {
#(#chain_exist_tokens)*
_ => false
}
diff --git a/mingling_macros/src/func/group.rs b/mingling_macros/src/func/group.rs
index b865913..edb1fe1 100644
--- a/mingling_macros/src/func/group.rs
+++ b/mingling_macros/src/func/group.rs
@@ -133,7 +133,11 @@ pub(crate) fn group_macro(input: TokenStream) -> TokenStream {
#type_use
#alias_use
- impl ::mingling::Grouped<__MinglingProgram> for #type_name {
+ /// SAFETY: This is an internal implementation of the `group!` macro,
+ /// guaranteeing that the enum value registered by the `register_type!` macro
+ /// is exactly the same as the actual return value,
+ /// which can be confirmed via the `Ident` in the `quote!` block.
+ unsafe impl ::mingling::Grouped<__MinglingProgram> for #type_name {
fn member_id() -> __MinglingProgram {
__MinglingProgram::#type_name
}
diff --git a/mingling_macros/src/func/pack.rs b/mingling_macros/src/func/pack.rs
index a1a7e6b..7206b8e 100644
--- a/mingling_macros/src/func/pack.rs
+++ b/mingling_macros/src/func/pack.rs
@@ -138,7 +138,11 @@ pub(crate) fn pack(input: TokenStream) -> TokenStream {
}
}
- impl ::mingling::Grouped<#group_name> for #type_name {
+ /// SAFETY: This is an internal implementation of the `pack!` macro,
+ /// guaranteeing that the enum value registered by the `register_type!` macro
+ /// is exactly the same as the actual return value,
+ /// which can be confirmed via the `Ident` in the `quote!` block.
+ unsafe impl ::mingling::Grouped<#group_name> for #type_name {
fn member_id() -> #group_name {
#group_name::#type_name
}
diff --git a/mingling_macros/src/func/pack_err.rs b/mingling_macros/src/func/pack_err.rs
index 36e550a..2a318bc 100644
--- a/mingling_macros/src/func/pack_err.rs
+++ b/mingling_macros/src/func/pack_err.rs
@@ -139,8 +139,8 @@ pub(crate) fn pack_err_structural(input: TokenStream) -> TokenStream {
.insert(type_name_str);
let structural_data = quote! {
- impl ::mingling::__private::StructuralDataSealed for #type_name {}
- impl ::mingling::__private::StructuralData for #type_name {}
+ impl ::mingling::__private::StructuralDataSealed<crate::ThisProgram> for #type_name {}
+ impl ::mingling::__private::StructuralData<crate::ThisProgram> for #type_name {}
};
// Generate the struct + impls (same as pack_err! but with Serialize derive + sealed)
diff --git a/mingling_macros/src/func/r_print.rs b/mingling_macros/src/func/r_print.rs
index e81b544..86ea52f 100644
--- a/mingling_macros/src/func/r_print.rs
+++ b/mingling_macros/src/func/r_print.rs
@@ -60,3 +60,68 @@ pub(crate) fn r_println(input: TokenStream) -> TokenStream {
pub(crate) fn r_print(input: TokenStream) -> TokenStream {
expand_print(input, "print")
}
+
+pub(crate) fn r_eprintln(input: TokenStream) -> TokenStream {
+ expand_print(input, "eprintln")
+}
+
+pub(crate) fn r_eprint(input: TokenStream) -> TokenStream {
+ expand_print(input, "eprint")
+}
+
+/// Parsed input for `r_append!`.
+///
+/// Two forms:
+/// - `(dst, src)` — explicit buffer and source
+/// - `(src)` — implicit `__render_result_buffer`
+struct AppendInput {
+ dst: Option<Ident>,
+ src: proc_macro2::TokenStream,
+}
+
+impl Parse for AppendInput {
+ fn parse(input: ParseStream) -> syn::Result<Self> {
+ if input.peek(Ident) && input.peek2(Token![,]) {
+ let dst: Ident = input.parse()?;
+ let _comma: Token![,] = input.parse()?;
+ let src: TokenStream2 = input.parse()?;
+ Ok(AppendInput {
+ dst: Some(dst),
+ src,
+ })
+ } else {
+ let src: TokenStream2 = input.parse()?;
+ Ok(AppendInput { dst: None, src })
+ }
+ }
+}
+
+/// `r_append!` macro: appends the contents of another `RenderResult` to this one.
+///
+/// Two forms:
+/// - `r_append!(dst, src)` — appends `src` into `dst`
+/// - `r_append!(src)` — appends `src` into `__render_result_buffer`
+pub(crate) fn r_append(input: TokenStream) -> TokenStream {
+ let parsed: AppendInput = match syn::parse(input) {
+ Ok(p) => p,
+ Err(e) => return e.to_compile_error().into(),
+ };
+
+ let dst_ident = parsed.dst.clone();
+ let src_tokens = parsed.src;
+
+ let expanded = match dst_ident {
+ Some(dst) => {
+ quote! {
+ #dst.append_other(#src_tokens);
+ }
+ }
+ None => {
+ quote! {
+ __render_result_buffer.append_other(#src_tokens);
+ }
+ }
+ };
+
+ expanded.into()
+}
diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs
index 56ed999..ca3261e 100644
--- a/mingling_macros/src/lib.rs
+++ b/mingling_macros/src/lib.rs
@@ -590,6 +590,56 @@ pub fn route(input: TokenStream) -> TokenStream {
TokenStream::from(expanded)
}
+/// Routes errors to the rendering pipeline instead of the chain pipeline.
+///
+/// This macro is similar to [`route!`] but instead of routing errors through
+/// `Routable::to_chain()` (which returns `ChainProcess`), it routes them
+/// directly to the renderer via `crate::ThisProgram::render(AnyOutput::new(e))`
+/// (which returns `RenderResult`).
+///
+/// This is useful in `#[renderer]` and `#[help]` functions where the return
+/// type is `RenderResult` rather than `ChainProcess`.
+///
+/// # Syntax
+///
+/// ```rust,ignore
+/// render_route!(expr)
+/// ```
+///
+/// Where `expr` is an expression of type `Result<T, E>`.
+///
+/// # Interaction with `#[routeify]`
+///
+/// When `#[routeify]` is used on a `#[renderer]` or `#[help]` function (e.g.
+/// `#[renderer(routeify)]` or `#[help(routeify)]`), every `expr?` is automatically
+/// replaced with `render_route!(expr)` instead of `route!(expr)`.
+///
+/// # Example
+///
+/// ```rust,ignore
+/// use mingling::macros::{renderer, render_route};
+/// use std::io::Write;
+///
+/// #[renderer]
+/// fn render_something(prev: SomeType) -> RenderResult {
+/// let data = render_route!(fetch_data().map_err(|e| ErrorEntry::new(e.to_string())))?;
+/// // ... render data
+/// Ok(RenderResult::new())
+/// }
+/// ```
+#[cfg(feature = "extra_macros")]
+#[proc_macro]
+pub fn render_route(input: TokenStream) -> TokenStream {
+ let expr = parse_macro_input!(input as syn::Expr);
+ let expanded = quote! {
+ match #expr {
+ Ok(r) => r,
+ Err(e) => return <crate::ThisProgram as ::mingling::ProgramCollect>::render(::mingling::AnyOutput::new(e)),
+ }
+ };
+ TokenStream::from(expanded)
+}
+
/// Creates an empty result value wrapped in `ChainProcess` for early return
/// from a chain function.
///
@@ -1293,6 +1343,25 @@ pub fn help(attr: TokenStream, item: TokenStream) -> TokenStream {
help::help_attr(item)
}
+/// Marker attribute for the Mingling lint system.
+///
+/// The content of this attribute is ignored by rustc and reserved for
+/// the mlint tool to interpret. All it does is pass the item through
+/// unchanged.
+///
+/// # Examples
+///
+/// ```rust,ignore
+/// #[mlint(allow(MLINT_SOME_LINT))]
+/// #[mlint(warn(MLINT_SOME_LINT))]
+/// #[mlint(deny(MLINT_SOME_LINT))]
+/// fn some_item() {}
+/// ```
+#[proc_macro_attribute]
+pub fn mlint(_attr: TokenStream, item: TokenStream) -> TokenStream {
+ item
+}
+
/// Extension attribute macro that transforms `expr?` into `route!(expr)`.
///
/// Designed for use with `#[chain(routeify, ...)]` to enable concise error
@@ -1314,6 +1383,32 @@ pub fn routeify(attr: TokenStream, item: TokenStream) -> TokenStream {
extensions::routeify::routeify_impl(attr, item)
}
+/// Extension attribute macro that transforms `expr?` into `render_route!(expr)`.
+///
+/// Designed for use with `#[renderer(renderify, ...)]` or `#[help(renderify, ...)]`
+/// to enable concise error routing in renderer and help functions using the `?`
+/// operator syntax.
+///
+/// Unlike `#[routeify]` which routes errors to the chain pipeline via `route!`,
+/// `#[renderify]` routes errors to the rendering pipeline via `render_route!`,
+/// which matches the `RenderResult` return type of renderer and help functions.
+///
+/// # Example
+///
+/// ```rust,ignore
+/// #[renderer(renderify)]
+/// fn render_greeting(prev: Greeting) -> RenderResult {
+/// let data = load_data()?; // expands to render_route!(load_data())
+/// r_println!("{data}");
+/// Ok(RenderResult::new())
+/// }
+/// ```
+#[cfg(feature = "extra_macros")]
+#[proc_macro_attribute]
+pub fn renderify(attr: TokenStream, item: TokenStream) -> TokenStream {
+ extensions::renderify::renderify_impl(attr, item)
+}
+
/// Wraps a unit-returning function to produce a `RenderResult`.
///
/// The `#[buffer]` attribute macro injects a local `__render_result_buffer`
@@ -1412,6 +1507,102 @@ pub fn r_print(input: TokenStream) -> TokenStream {
func::r_print::r_print(input)
}
+/// Prints text to a `RenderResult` buffer (standard error style), with a trailing newline.
+///
+/// This macro works identically to `r_println!` but conceptually targets
+/// "error output" — it writes into a `RenderResult` buffer with a trailing newline.
+///
+/// # Implicit buffer (inside `#[buffer]` functions)
+///
+/// ```rust,ignore
+/// use mingling::macros::{buffer, r_eprintln};
+///
+/// #[buffer]
+/// fn render() {
+/// r_eprintln!("Error: {}", err_msg);
+/// }
+/// ```
+///
+/// # Explicit buffer
+///
+/// Pass a `RenderResult` variable as the first argument:
+///
+/// ```rust,ignore
+/// use mingling::macros::r_eprintln;
+/// use mingling::RenderResult;
+///
+/// let mut r = RenderResult::new();
+/// r_eprintln!(r, "error: {}", 42);
+/// assert_eq!(&*r, "error: 42\n");
+/// ```
+#[proc_macro]
+pub fn r_eprintln(input: TokenStream) -> TokenStream {
+ func::r_print::r_eprintln(input)
+}
+
+/// Prints text to a `RenderResult` buffer (standard error style), without a trailing newline.
+///
+/// This macro works identically to `r_print!` but conceptually targets
+/// "error output" — it writes into a `RenderResult` buffer without a trailing newline.
+///
+/// # Implicit buffer (inside `#[buffer]` functions)
+///
+/// ```rust,ignore
+/// use mingling::macros::{buffer, r_eprint};
+///
+/// #[buffer]
+/// fn render() {
+/// r_eprint!("Error: ");
+/// r_eprintln!("something went wrong");
+/// }
+/// ```
+///
+/// # Explicit buffer
+///
+/// ```rust,ignore
+/// use mingling::macros::r_eprint;
+/// use mingling::RenderResult;
+///
+/// let mut r = RenderResult::new();
+/// r_eprint!(r, "error: ");
+/// r_eprintln!(r, "42");
+/// assert_eq!(&*r, "error: 42\n");
+/// ```
+#[proc_macro]
+pub fn r_eprint(input: TokenStream) -> TokenStream {
+ func::r_print::r_eprint(input)
+}
+
+/// Appends the contents of one `RenderResult` to another.
+///
+/// # Implicit buffer (inside `#[buffer]` functions)
+///
+/// ```rust,ignore
+/// use mingling::macros::{buffer, r_append};
+///
+/// #[buffer]
+/// fn render() {
+/// let other = make_other_result();
+/// r_append!(other);
+/// }
+/// ```
+///
+/// # Explicit buffer
+///
+/// ```rust,ignore
+/// use mingling::macros::r_append;
+/// use mingling::RenderResult;
+///
+/// let mut dst = RenderResult::new();
+/// let src = RenderResult::from("hello");
+/// r_append!(dst, src);
+/// assert!(!dst.is_empty());
+/// ```
+#[proc_macro]
+pub fn r_append(input: TokenStream) -> TokenStream {
+ func::r_print::r_append(input)
+}
+
/// Derive macro for automatically implementing the `Grouped` trait on a struct.
///
/// The `#[derive(Grouped)]` macro:
diff --git a/mingling_macros/src/systems/structural_data.rs b/mingling_macros/src/systems/structural_data.rs
index 74bcf09..46d7cf8 100644
--- a/mingling_macros/src/systems/structural_data.rs
+++ b/mingling_macros/src/systems/structural_data.rs
@@ -29,8 +29,8 @@ pub(crate) fn derive_structural_data(input: TokenStream) -> TokenStream {
// Users cannot implement StructuralDataSealed manually (it's #[doc(hidden)]),
// so the only way to get StructuralData is through this derive macro.
let expanded = quote! {
- impl ::mingling::__private::StructuralDataSealed for #type_name {}
- impl ::mingling::__private::StructuralData for #type_name {}
+ impl ::mingling::__private::StructuralDataSealed<crate::ThisProgram> for #type_name {}
+ impl ::mingling::__private::StructuralData<crate::ThisProgram> for #type_name {}
};
expanded.into()
@@ -149,8 +149,8 @@ pub(crate) fn pack_structural(input: TokenStream) -> TokenStream {
// StructuralData impl + sealed + registration
let structural_impl = quote! {
- impl ::mingling::__private::StructuralDataSealed for #type_name {}
- impl ::mingling::__private::StructuralData for #type_name {}
+ impl ::mingling::__private::StructuralDataSealed<crate::ThisProgram> for #type_name {}
+ impl ::mingling::__private::StructuralData<crate::ThisProgram> for #type_name {}
};
let expanded = quote! {
@@ -176,7 +176,11 @@ pub(crate) fn pack_structural(input: TokenStream) -> TokenStream {
}
}
- impl ::mingling::Grouped<#program_path> for #type_name {
+ /// SAFETY: This is an internal implementation of the `pack_structural!` macro,
+ /// guaranteeing that the enum value registered by the `register_type!` macro
+ /// is exactly the same as the actual return value,
+ /// which can be confirmed via the `Ident` in the `quote!` block.
+ unsafe impl ::mingling::Grouped<#program_path> for #type_name {
fn member_id() -> #program_path {
#program_path::#type_name
}
@@ -297,14 +301,18 @@ pub(crate) fn group_structural(input: TokenStream) -> TokenStream {
#type_use
#alias_use
- impl ::mingling::Grouped<__MinglingProgram> for #type_name {
+ /// SAFETY: This is an internal implementation of the `pack_structural!` macro,
+ /// guaranteeing that the enum value registered by the `register_type!` macro
+ /// is exactly the same as the actual return value,
+ /// which can be confirmed via the `Ident` in the `quote!` block.
+ unsafe impl ::mingling::Grouped<__MinglingProgram> for #type_name {
fn member_id() -> __MinglingProgram {
__MinglingProgram::#type_name
}
}
- impl ::mingling::__private::StructuralDataSealed for #type_name {}
- impl ::mingling::__private::StructuralData for #type_name {}
+ impl ::mingling::__private::StructuralDataSealed<crate::ThisProgram> for #type_name {}
+ impl ::mingling::__private::StructuralData<crate::ThisProgram> for #type_name {}
::mingling::macros::register_type!(#type_name);
}