1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{FnArg, ItemFn, ReturnType, Type, parse_macro_input};
4
5#[proc_macro_attribute]
6pub fn mate_object(_attr: TokenStream, item: TokenStream) -> TokenStream {
7 let input = parse_macro_input!(item as syn::DeriveInput);
8 let name = &input.ident;
9
10 let expanded = quote! {
11 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
12 #input
13
14 const _: () = {
15 fn assert_impl<T: serde::Serialize + serde::de::DeserializeOwned + Clone + std::fmt::Debug>() {}
16 fn assert_type() {
17 assert_impl::<#name>();
18 }
19 };
20 };
21
22 TokenStream::from(expanded)
23}
24
25#[proc_macro_attribute]
26pub fn mate_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
27 let input_fn = parse_macro_input!(item as ItemFn);
28 let fn_name = &input_fn.sig.ident;
29 let fn_vis = &input_fn.vis;
30 let fn_block = &input_fn.block;
31 let fn_attrs = &input_fn.attrs;
32 let fn_sig = &input_fn.sig;
33
34 let input_type = match fn_sig.inputs.first() {
36 Some(FnArg::Typed(pat_type)) => &pat_type.ty,
37 _ => {
38 return syn::Error::new_spanned(
39 &fn_sig.inputs,
40 "Handler function must have at least one parameter",
41 )
42 .to_compile_error()
43 .into();
44 }
45 };
46
47 let output_type = match &fn_sig.output {
49 ReturnType::Type(_, ty) => {
50 if let Type::Path(type_path) = ty.as_ref() {
52 if let Some(segment) = type_path.path.segments.last() {
53 if segment.ident == "Result" {
54 if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
56 if let Some(syn::GenericArgument::Type(ok_type)) = args.args.first() {
57 ok_type
58 } else {
59 ty.as_ref()
60 }
61 } else {
62 ty.as_ref()
63 }
64 } else {
65 ty.as_ref()
66 }
67 } else {
68 ty.as_ref()
69 }
70 } else {
71 ty.as_ref()
72 }
73 }
74 ReturnType::Default => {
75 return syn::Error::new_spanned(
76 &fn_sig.output,
77 "Handler function must return a Result type",
78 )
79 .to_compile_error()
80 .into();
81 }
82 };
83
84 let expanded = quote! {
85 use anyhow::Result;
86 use wit_bindgen;
87
88 mod bindings {
89 wit_bindgen::generate!({
90 async: true,
91 inline: r"
92 package mate:runtime@0.1.0;
93
94 world mate {
95 export handler: async func(data: string) -> result<string, string>;
96 }",
97 });
98 }
99
100 struct Mate;
101
102 impl bindings::Guest for Mate {
103 async fn handler(data: String) -> Result<String, String> {
104 let input: #input_type = serde_json::from_str(&data)
105 .map_err(|e| format!("Failed to deserialize input: {}", e))?;
106
107 let result: Result<#output_type> = #fn_name(input).await;
108
109 match result {
110 Ok(val) => serde_json::to_string(&val)
111 .map_err(|e| format!("Failed to serialize output: {}", e)),
112 Err(err) => Err(format!("Handler error: {}", err)),
113 }
114 }
115 }
116
117 bindings::export!(Mate with_types_in bindings);
118
119 #(#fn_attrs)*
120 #fn_vis #fn_sig {
121 #fn_block
122 }
123 };
124
125 TokenStream::from(expanded)
126}