trigger-rs/crates/trigger-codegen/src/decodeable.rs
traffic95 23fcde33f5 Properties calc port for 1.7beta (#7)
Reviewed-on: ObolSquad/trigger-rs#7
Co-authored-by: traffic95 <traffic95@xeondev.com>
Co-committed-by: traffic95 <traffic95@xeondev.com>
2025-03-19 08:52:04 +00:00

76 lines
2.6 KiB
Rust

use proc_macro2::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput, Fields, Ident, parse_macro_input};
pub fn impl_decodeable(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(item as DeriveInput);
let input_name = &input.ident;
match &input.data {
Data::Struct(st) => {
let decode_calls = impl_decode_calls_for_fields(&st.fields);
quote! {
impl ::trigger_encoding::Decodeable for #input_name {
fn decode<R: ::std::io::Read>(r: &mut R) -> ::std::io::Result<Self> {
Ok(Self {
#decode_calls
})
}
}
}
.into()
}
Data::Enum(enumeration) => {
let repr = input
.attrs
.iter()
.find(|attr| attr.path().is_ident("repr"))
.expect("#[derive(Decodeable)] requires #[repr(ty)] attribute for enums")
.parse_args::<Ident>()
.unwrap();
let mut decode_match_arms = TokenStream::new();
for variant in enumeration.variants.iter() {
let variant_name = &variant.ident;
let (_, discriminant) = variant.discriminant.as_ref().expect(
"#[derive(Decodeable)] requires explicit enum discriminant declaration",
);
let decode_calls = impl_decode_calls_for_fields(&variant.fields);
decode_match_arms.extend(quote! {
#discriminant => Self::#variant_name {
#decode_calls
},
});
}
quote! {
impl ::trigger_encoding::Decodeable for #input_name {
fn decode<R: ::std::io::Read>(r: &mut R) -> ::std::io::Result<Self> {
Ok(match #repr::decode(r)? {
#decode_match_arms
unk => panic!("{}::decode: unknown discriminant encountered: {}", stringify!(#input_name), unk),
})
}
}
}.into()
}
Data::Union(_) => panic!("#[derive(Decodeable)] doesn't support unions"),
}
}
fn impl_decode_calls_for_fields(fields: &Fields) -> TokenStream {
let mut decode_calls = TokenStream::new();
fields.iter().for_each(|field| {
let name = field.ident.as_ref().unwrap();
decode_calls.extend(quote! {
#name: ::trigger_encoding::Decodeable::decode(r)?,
});
});
decode_calls
}