sp_runtime_interface_proc_macro/pass_by/
enum_.rs1use crate::utils::{generate_crate_access, generate_runtime_interface_include};
23
24use syn::{Data, DeriveInput, Error, Fields, Ident, Result};
25
26use quote::quote;
27
28use proc_macro2::{Span, TokenStream};
29
30pub fn derive_impl(input: DeriveInput) -> Result<TokenStream> {
32 let crate_include = generate_runtime_interface_include();
33 let crate_ = generate_crate_access();
34 let ident = input.ident;
35 let enum_fields = get_enum_field_idents(&input.data)?
36 .enumerate()
37 .map(|(i, v)| {
38 let i = i as u8;
39
40 v.map(|v| (quote!(#i => Ok(#ident::#v)), quote!(#ident::#v => #i)))
41 })
42 .collect::<Result<Vec<_>>>()?;
43 let try_from_variants = enum_fields.iter().map(|i| &i.0);
44 let into_variants = enum_fields.iter().map(|i| &i.1);
45
46 let res = quote! {
47 const _: () = {
48 #crate_include
49
50 impl #crate_::pass_by::PassBy for #ident {
51 type PassBy = #crate_::pass_by::Enum<#ident>;
52 }
53
54 impl TryFrom<u8> for #ident {
55 type Error = ();
56
57 fn try_from(inner: u8) -> core::result::Result<Self, ()> {
58 match inner {
59 #( #try_from_variants, )*
60 _ => Err(()),
61 }
62 }
63 }
64
65 impl From<#ident> for u8 {
66 fn from(var: #ident) -> u8 {
67 match var {
68 #( #into_variants ),*
69 }
70 }
71 }
72 };
73 };
74
75 Ok(res)
76}
77
78fn get_enum_field_idents(data: &Data) -> Result<impl Iterator<Item = Result<&Ident>>> {
83 match data {
84 Data::Enum(d) =>
85 if d.variants.len() <= 256 {
86 Ok(d.variants.iter().map(|v| {
87 if let Fields::Unit = v.fields {
88 Ok(&v.ident)
89 } else {
90 Err(Error::new(
91 Span::call_site(),
92 "`PassByEnum` only supports unit variants.",
93 ))
94 }
95 }))
96 } else {
97 Err(Error::new(Span::call_site(), "`PassByEnum` only supports `256` variants."))
98 },
99 _ => Err(Error::new(Span::call_site(), "`PassByEnum` only supports enums as input type.")),
100 }
101}