MCPcopy Create free account
hub / github.com/dylan-sutton-chavez/edge-python / plugin_fn

Function plugin_fn

wasm-pdk/macros/src/lib.rs:12–158  ·  view source on GitHub ↗
(_attr: TokenStream, item: TokenStream)

Source from the content-addressed store, hash-verified

10
11#[proc_macro_attribute]
12pub fn plugin_fn(_attr: TokenStream, item: TokenStream) -> TokenStream {
13 let input = parse_macro_input!(item as ItemFn);
14 let user_vis = &input.vis;
15 let user_name = input.sig.ident.clone();
16 let user_inputs = input.sig.inputs.clone();
17 let user_output = input.sig.output.clone();
18 let user_block = input.block.clone();
19
20 // Wrapper claims the original name; user fn moves to `__edge_impl_<name>`.
21 let impl_name = syn::Ident::new(
22 &format!("__edge_impl_{}", user_name),
23 proc_macro2::Span::call_site(),
24 );
25
26 let mut bindings: Vec<(syn::Ident, syn::Type)> = Vec::new();
27 for (i, arg) in user_inputs.iter().enumerate() {
28 match arg {
29 FnArg::Typed(pat) => {
30 let name = match &*pat.pat {
31 Pat::Ident(id) => id.ident.clone(),
32 _ => syn::Ident::new(&format!("__arg{}", i), proc_macro2::Span::call_site()),
33 };
34 bindings.push((name, (*pat.ty).clone()));
35 }
36 FnArg::Receiver(_) => {
37 return TokenStream::from(quote! {
38 compile_error!("#[plugin_fn] does not support methods (`self` parameter)");
39 });
40 }
41 }
42 }
43
44 let return_ty: syn::Type = match &user_output {
45 ReturnType::Default => syn::parse_quote!(()),
46 ReturnType::Type(_, t) => (**t).clone(),
47 };
48 let is_result = matches!(&return_ty, syn::Type::Path(p) if p.path.segments.last().map(|s| s.ident == "Result").unwrap_or(false));
49
50 // Host always appends a trailing kwargs slot. Param order: fixed positionals, optional `Args`, optional `Kwargs`.
51 let type_named = |ty: &syn::Type, n: &str| matches!(ty, Type::Path(p) if p.path.segments.last().map(|s| s.ident == n).unwrap_or(false));
52 let last_is_kwargs = bindings.last().map(|(_, ty)| type_named(ty, "Kwargs")).unwrap_or(false);
53 let args_idx = bindings.iter().position(|(_, ty)| type_named(ty, "Args"));
54 let has_args = args_idx.is_some();
55 // Fixed positionals precede the optional variadic `Args` and the optional trailing `Kwargs`.
56 let num_fixed = bindings.len() - (has_args as usize) - (last_is_kwargs as usize);
57
58 if args_idx.is_some_and(|idx| idx != num_fixed) {
59 return TokenStream::from(quote! { compile_error!("#[plugin_fn] `Args` must follow the fixed params, before any `Kwargs`"); });
60 }
61 if bindings.iter().take(bindings.len().saturating_sub(1)).any(|(_, ty)| type_named(ty, "Kwargs")) {
62 return TokenStream::from(quote! { compile_error!("#[plugin_fn] `Kwargs` must be the final parameter"); });
63 }
64
65 let decodes: Vec<TokenStream2> = bindings.iter().enumerate().map(|(i, (name, ty))| {
66 if type_named(ty, "Kwargs") {
67 // The kwargs handle is always the final argv slot.
68 quote! {
69 let h = unsafe { *argv.add((argc as usize) - 1) };

Callers 1

plugin_constFunction · 0.85

Calls 5

pushMethod · 0.80
takeMethod · 0.80
collectMethod · 0.80
iterMethod · 0.45
lenMethod · 0.45

Tested by

no test coverage detected