1#![feature(coverage_attribute)]
16#![feature(iterator_try_collect)]
17
18use proc_macro::TokenStream;
19use proc_macro2::{Span, TokenStream as TokenStream2};
20use quote::{format_ident, quote};
21use syn::{Data, DataStruct, DeriveInput, Result, parse_macro_input};
22
23mod generate;
24
25#[proc_macro_derive(AnyPB)]
28pub fn any_pb(input: TokenStream) -> TokenStream {
29 let ast = parse_macro_input!(input as DeriveInput);
31
32 match produce(&ast) {
33 Ok(tokens) => tokens.into(),
34 Err(e) => e.to_compile_error().into(),
35 }
36}
37
38fn produce(ast: &DeriveInput) -> Result<TokenStream2> {
40 let name = &ast.ident;
41
42 let struct_get = if let syn::Data::Struct(DataStruct { ref fields, .. }) = ast.data {
44 let generated: Vec<_> = fields.iter().map(generate::implement).try_collect()?;
45 quote! {
46 impl #name {
47 #(#generated)*
48 }
49 }
50 } else {
51 quote! {}
53 };
54
55 let pb_alias = {
58 let pb_name = format_ident!("Pb{name}");
59 quote! {
60 pub type #pb_name = #name;
61 }
62 };
63
64 Ok(quote! {
65 #pb_alias
66 #struct_get
67 })
68}
69
70#[proc_macro_derive(Version)]
71pub fn version(input: TokenStream) -> TokenStream {
72 fn version_inner(ast: &DeriveInput) -> syn::Result<TokenStream2> {
73 let last_variant = match &ast.data {
74 Data::Enum(v) => v.variants.iter().next_back().ok_or_else(|| {
75 syn::Error::new(
76 Span::call_site(),
77 "This macro requires at least one variant in the enum.",
78 )
79 })?,
80 _ => {
81 return Err(syn::Error::new(
82 Span::call_site(),
83 "This macro only supports enums.",
84 ));
85 }
86 };
87
88 let enum_name = &ast.ident;
89 let last_variant_name = &last_variant.ident;
90
91 Ok(quote! {
92 impl #enum_name {
93 pub const LATEST: Self = Self::#last_variant_name;
94 }
95 })
96 }
97
98 let ast = parse_macro_input!(input as DeriveInput);
99
100 match version_inner(&ast) {
101 Ok(tokens) => tokens.into(),
102 Err(e) => e.to_compile_error().into(),
103 }
104}