1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
use proc_macro::TokenStream;
use quote::quote;
use syn::{ItemFn, Type, parse_macro_input, spanned::Spanned};
/// Macro for simplifying renderer definitions
///
/// Expands the `#[result_renderer(Renderer)]` macro into the corresponding struct and trait implementation
///
/// # Example
/// ```ignore
/// #[result_renderer(MyRenderer)]
/// async fn render(data: &Output) -> Result<JVRenderResult, CmdRenderError> {
/// // Rendering logic
/// }
/// ```
///
/// Expands to:
/// ```ignore
/// pub struct MyRenderer;
///
/// impl JVResultRenderer<Output> for MyRenderer {
/// async fn render(data: &Output) -> Result<JVRenderResult, CmdRenderError> {
/// // Rendering logic
/// }
/// }
///
/// impl JVResultAutoRenderer<Output> for MyRenderer {
/// fn get_type_id(&self) -> std::any::TypeId {
/// std::any::TypeId::of::<Self>()
/// }
///
/// fn get_data_type_id(&self) -> std::any::TypeId {
/// std::any::TypeId::of::<Output>()
/// }
/// }
/// ```
#[proc_macro_attribute]
pub fn result_renderer(args: TokenStream, input: TokenStream) -> TokenStream {
// Parse macro arguments (renderer struct name)
let renderer_name = parse_macro_input!(args as syn::Ident);
// Parse the input function
let input_fn = parse_macro_input!(input as ItemFn);
// Check if the function is async
if input_fn.sig.asyncness.is_none() {
return syn::Error::new(input_fn.sig.ident.span(), "renderer function must be async")
.to_compile_error()
.into();
}
// Get the function name
let fn_name = &input_fn.sig.ident;
// Get function parameters
let fn_inputs = &input_fn.sig.inputs;
// Check the number of function parameters
if fn_inputs.len() != 1 {
return syn::Error::new(
input_fn.sig.paren_token.span.join(),
"renderer function must have exactly one parameter",
)
.to_compile_error()
.into();
}
// Extract the type of the first parameter
let param_type = match &fn_inputs[0] {
syn::FnArg::Typed(pat_type) => &pat_type.ty,
syn::FnArg::Receiver(_) => {
return syn::Error::new(
fn_inputs[0].span(),
"renderer function cannot have self parameter",
)
.to_compile_error()
.into();
}
};
// Check if the parameter type is a reference type, and extract the inner type
let inner_type = match &**param_type {
Type::Reference(type_ref) => {
// Ensure it's a reference type
&type_ref.elem
}
_ => {
return syn::Error::new(
param_type.span(),
"renderer function parameter must be a reference type (&Data)",
)
.to_compile_error()
.into();
}
};
// Extract the parameter pattern (for function calls)
let param_pattern = match &fn_inputs[0] {
syn::FnArg::Typed(pat_type) => &pat_type.pat,
_ => unreachable!(),
};
// Extract the function's visibility modifier
let visibility = &input_fn.vis;
// Extract generic parameters (if any)
let generics = &input_fn.sig.generics;
// Extract where clause (if any)
let where_clause = &generics.where_clause;
// Build the output
let expanded = quote! {
#input_fn
#visibility struct #renderer_name;
impl #generics crate::systems::render::renderer::JVResultRenderer<#inner_type> for #renderer_name
#where_clause
{
fn render(
#fn_inputs
) -> impl ::std::future::Future<Output = ::std::result::Result<
crate::systems::render::renderer::JVRenderResult,
crate::systems::cmd::errors::CmdRenderError
>> + ::std::marker::Send + ::std::marker::Sync {
async move {
#fn_name(#param_pattern).await
}
}
fn get_type_id(&self) -> std::any::TypeId {
std::any::TypeId::of::<Self>()
}
fn get_data_type_id(&self) -> std::any::TypeId {
std::any::TypeId::of::<#inner_type>()
}
}
};
expanded.into()
}
|