use convert_case::{Case, Casing};
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{Data, DeriveInput, Fields};
#[proc_macro_attribute]
pub fn buffered(args: TokenStream, mut input: TokenStream) -> TokenStream {
let item = syn::parse::<DeriveInput>(input.clone()).expect("Failed to parse");
let ty = match item.data {
Data::Struct(x) => x,
_ => panic!("Buffed only works for structs"),
};
let (fields, types): (Vec<_>, Vec<_>) = match ty.fields {
Fields::Named(x) => x.named,
_ => panic!("Buffed only supports named field structs"),
}
.into_iter()
.map(|f| (format_ident!("{}", f.ident.unwrap()), f.ty))
.unzip();
let buffered_name = format_ident!("{}Buffered", item.ident);
let buffered_fields_name = format_ident!("{}Fields", item.ident);
let buffered_fields_selector_name = format_ident!("{}FieldSelectors", item.ident);
let uppercase_fields: Vec<_> = fields
.iter()
.map(|f| format!("{}", f).to_case(Case::UpperCamel))
.map(|f| format_ident!("{}", f))
.collect();
let output: TokenStream = quote! {
#[derive(Debug)]
struct #buffered_name {
#(#fields : Vec<#types>),*
}
#[derive(Debug)]
enum #buffered_fields_name {
#(#uppercase_fields(#types)),*
}
#[derive(Debug)]
enum #buffered_fields_selector_name {
#(#uppercase_fields),*
}
impl Buffered for #buffered_name {
type Fields = #buffered_fields_name;
fn push_field(&mut self, field: Self::Fields) -> Result<(), Self::Fields> {
match field {
#(Self::Fields::#uppercase_fields(x) => self.#fields.push(x)),*
}
Ok(())
}
}
impl #buffered_name {
fn new() -> Self {
Self {
#(#fields : Vec::new()),*
}
}
}
}
.into();
input.extend(output);
input
}