use proc_macro::TokenStream;
use quote::quote;
use crate::util::*;
pub fn dep_decode_snippet(_index: usize, field: &syn::Field) -> proc_macro2::TokenStream {
let ty = &field.ty;
if let Some(ident) = &field.ident {
quote! {
#ident: <#ty as numbat_codec::NestedDecode>::dep_decode(input)?
}
} else {
quote! {
<#ty as numbat_codec::NestedDecode>::dep_decode(input)?
}
}
}
pub fn dep_decode_or_exit_snippet(_index: usize, field: &syn::Field) -> proc_macro2::TokenStream {
let ty = &field.ty;
if let Some(ident) = &field.ident {
quote! {
#ident: <#ty as numbat_codec::NestedDecode>::dep_decode_or_exit(input, c.clone(), exit)
}
} else {
quote! {
<#ty as numbat_codec::NestedDecode>::dep_decode_or_exit(input, c.clone(), exit)
}
}
}
pub fn variant_dep_decode_snippets(
name: &syn::Ident,
data_enum: &syn::DataEnum,
) -> Vec<proc_macro2::TokenStream> {
data_enum
.variants
.iter()
.enumerate()
.map(|(variant_index, variant)| {
let variant_index_u8 = variant_index as u8;
let variant_ident = &variant.ident;
let variant_field_snippets = fields_decl_syntax(&variant.fields, |index, field| {
dep_decode_snippet(index, field)
});
quote! {
#variant_index_u8 => core::result::Result::Ok( #name::#variant_ident #variant_field_snippets ),
}
})
.collect()
}
pub fn variant_dep_decode_or_exit_snippets(
name: &syn::Ident,
data_enum: &syn::DataEnum,
) -> Vec<proc_macro2::TokenStream> {
data_enum
.variants
.iter()
.enumerate()
.map(|(variant_index, variant)| {
let variant_index_u8 = variant_index as u8;
let variant_ident = &variant.ident;
let variant_field_snippets = fields_decl_syntax(&variant.fields, |index, field| {
dep_decode_or_exit_snippet(index, field)
});
quote! {
#variant_index_u8 => #name::#variant_ident #variant_field_snippets ,
}
})
.collect()
}
pub fn nested_decode_impl(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
let (impl_generics, ty_generics, where_clause) = &ast.generics.split_for_impl();
let gen = match &ast.data {
syn::Data::Struct(data_struct) => {
let field_dep_decode_snippets =
fields_decl_syntax(&data_struct.fields, |index, field| {
dep_decode_snippet(index, field)
});
let field_dep_encode_or_exit_snippets =
fields_decl_syntax(&data_struct.fields, |index, field| {
dep_decode_or_exit_snippet(index, field)
});
quote! {
impl #impl_generics numbat_codec::NestedDecode for #name #ty_generics #where_clause {
fn dep_decode<I: numbat_codec::NestedDecodeInput>(input: &mut I) -> core::result::Result<Self, numbat_codec::DecodeError> {
core::result::Result::Ok(
#name #field_dep_decode_snippets
)
}
fn dep_decode_or_exit<I: numbat_codec::NestedDecodeInput, ExitCtx: Clone>(
input: &mut I,
c: ExitCtx,
exit: fn(ExitCtx, numbat_codec::DecodeError) -> !,
) -> Self {
#name #field_dep_encode_or_exit_snippets
}
}
}
},
syn::Data::Enum(data_enum) => {
assert!(
data_enum.variants.len() < 256,
"enums with more than 256 variants not supported"
);
let variant_dep_decode_snippets = variant_dep_decode_snippets(name, data_enum);
let variant_dep_decode_or_exit_snippets =
variant_dep_decode_or_exit_snippets(name, data_enum);
quote! {
impl #impl_generics numbat_codec::NestedDecode for #name #ty_generics #where_clause {
fn dep_decode<I: numbat_codec::NestedDecodeInput>(input: &mut I) -> core::result::Result<Self, numbat_codec::DecodeError> {
match <u8 as numbat_codec::NestedDecode>::dep_decode(input)? {
#(#variant_dep_decode_snippets)*
_ => core::result::Result::Err(numbat_codec::DecodeError::INVALID_VALUE),
}
}
fn dep_decode_or_exit<I: numbat_codec::NestedDecodeInput, ExitCtx: Clone>(
input: &mut I,
c: ExitCtx,
exit: fn(ExitCtx, numbat_codec::DecodeError) -> !,
) -> Self {
match <u8 as numbat_codec::NestedDecode>::dep_decode_or_exit(input, c.clone(), exit) {
#(#variant_dep_decode_or_exit_snippets)*
_ => exit(c, numbat_codec::DecodeError::INVALID_VALUE),
}
}
}
}
},
syn::Data::Union(_) => panic!("Union not supported"),
};
gen.into()
}