cw_orch_from_interface_derive/
lib.rs1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{parse_macro_input, ItemEnum};
6const INTERFACE_POSTFIX: &str = "Interface";
7
8#[proc_macro_derive(FromInterface)]
9pub fn from_derive(input: TokenStream) -> TokenStream {
10 let ast = parse_macro_input!(input as ItemEnum);
11 let (impl_generics, ty_generics, where_clause) = &ast.generics.split_for_impl();
12
13 let interface_name = &ast.ident;
14 let original_name = {
15 let counter_name = interface_name.to_string();
16 let (counter_name, _) = counter_name
18 .split_once(INTERFACE_POSTFIX)
19 .expect(r#"Interface message type supposed to have "Interface" postfix"#);
20 proc_macro2::Ident::new(counter_name, proc_macro2::Span::call_site())
21 };
22 let froms = ast.variants.into_iter().map(|variant| {
23 let variant_name = variant.ident.clone();
24 let fields = match variant.fields {
25 syn::Fields::Unnamed(variant_fields) => {
26 let variant_fields = (0..variant_fields.unnamed.len()).map(|i| {
27 proc_macro2::Ident::new(&format!("arg{i}"), proc_macro2::Span::call_site())
28 });
29 quote!( ( #(#variant_fields,)* ) )
30 }
31 syn::Fields::Named(variant_fields) => {
32 let idents = variant_fields
33 .named
34 .into_iter()
35 .map(|field| field.ident.unwrap());
36 quote!( { #(#idents,)* } )
37 }
38 syn::Fields::Unit => quote!(),
39 };
40 quote! ( #interface_name::#variant_name #fields => #original_name::#variant_name #fields )
41 });
42 quote!(
43 impl #impl_generics From<#interface_name #ty_generics> for #original_name #ty_generics
44 #where_clause
45 {
46 fn from(value: #interface_name #ty_generics) -> #original_name #ty_generics {
47 match value {
48 #(#froms,)*
49 }
50 }
51 }
52 )
53 .into()
54}