1use convert_case::{Case, Casing};
2use proc_macro::TokenStream;
3use quote::{format_ident, quote};
4use syn::{Data, DeriveInput, Fields};
5
6#[proc_macro_attribute]
7pub fn buffered(args: TokenStream, mut input: TokenStream) -> TokenStream {
8 let item = syn::parse::<DeriveInput>(input.clone()).expect("Failed to parse");
9 let ty = match item.data {
10 Data::Struct(x) => x,
11 _ => panic!("Buffed only works for structs"),
12 };
13
14 let (fields, types): (Vec<_>, Vec<_>) = match ty.fields {
15 Fields::Named(x) => x.named,
16 _ => panic!("Buffed only supports named field structs"),
17 }
18 .into_iter()
19 .map(|f| (format_ident!("{}", f.ident.unwrap()), f.ty))
20 .unzip();
21
22 let buffered_name = format_ident!("{}Buffered", item.ident);
23 let buffered_fields_name = format_ident!("{}Fields", item.ident);
24 let buffered_fields_selector_name = format_ident!("{}FieldSelectors", item.ident);
25 let uppercase_fields: Vec<_> = fields
26 .iter()
27 .map(|f| format!("{}", f).to_case(Case::UpperCamel))
28 .map(|f| format_ident!("{}", f))
29 .collect();
30
31 let output: TokenStream = quote! {
32 #[derive(Debug)]
33 struct #buffered_name {
34 #(#fields : Vec<#types>),*
35 }
36
37 #[derive(Debug)]
38 enum #buffered_fields_name {
39 #(#uppercase_fields(#types)),*
40 }
41
42 #[derive(Debug)]
43 enum #buffered_fields_selector_name {
44 #(#uppercase_fields),*
45 }
46
47 impl Buffered for #buffered_name {
48 type Fields = #buffered_fields_name;
49
50 fn push_field(&mut self, field: Self::Fields) -> Result<(), Self::Fields> {
51 match field {
52 #(Self::Fields::#uppercase_fields(x) => self.#fields.push(x)),*
53 }
54
55 Ok(())
56 }
57 }
58
59 impl #buffered_name {
60 fn new() -> Self {
61 Self {
62 #(#fields : Vec::new()),*
63 }
64 }
65 }
66
67 }
68 .into();
69
70 input.extend(output);
71 input
72}