use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Fields};
pub fn derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let enum_name = &input.ident;
let variants = match &input.data {
Data::Enum(data) => &data.variants,
_ => panic!("#[derive(ClickEnum)] only supports enums"),
};
let mut variant_names = Vec::new();
for variant in variants {
match &variant.fields {
Fields::Unit => {
variant_names.push(&variant.ident);
}
_ => panic!("#[derive(ClickEnum)] only supports unit variants (variants without fields)"),
}
}
let discriminants: Vec<i8> = (0..variant_names.len() as i8).collect();
let expanded = quote! {
impl clicktype_core::traits::ClickHouseType for #enum_name {
fn type_name() -> std::borrow::Cow<'static, str> {
std::borrow::Cow::Borrowed("Int8")
}
fn write_binary<W: std::io::Write>(&self, writer: &mut W) -> Result<(), clicktype_core::error::WriteError> {
let value: i8 = match self {
#(
#enum_name::#variant_names => #discriminants,
)*
};
writer.write_all(&value.to_le_bytes())?;
Ok(())
}
fn read_binary<R: std::io::Read>(reader: &mut R) -> Result<Self, clicktype_core::error::ReadError> {
let mut buf = [0u8; 1];
reader.read_exact(&mut buf).map_err(|_| clicktype_core::error::ReadError::UnexpectedEof)?;
let value = i8::from_le_bytes(buf);
match value {
#(
#discriminants => Ok(#enum_name::#variant_names),
)*
_ => Err(clicktype_core::error::ReadError::InvalidVariant(value)),
}
}
fn fixed_size() -> Option<usize> {
Some(1)
}
}
};
TokenStream::from(expanded)
}