mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-04 09:04:05 +02:00
rewrite derive macro
This commit is contained in:
parent
0701318120
commit
3852f09dd5
21 changed files with 1548 additions and 840 deletions
63
bitbuffer_derive/src/write/enum.rs
Normal file
63
bitbuffer_derive/src/write/enum.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
use crate::params::{EnumParam, VariantBody, VariantBodyType};
|
||||
use crate::write::field::write_enum_variant;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote_spanned;
|
||||
use syn::Path;
|
||||
|
||||
pub fn derive_encode_enum(params: &EnumParam) -> TokenStream {
|
||||
let discriminant_bits = params.discriminant_bits;
|
||||
let repr = params.discriminant_repr();
|
||||
let ident = params.ident.clone();
|
||||
let span = params.span();
|
||||
|
||||
let discriminant_value = params
|
||||
.variants
|
||||
.iter()
|
||||
.zip(params.write_discriminant_tokens())
|
||||
.map(|(variant, discriminant_token)| {
|
||||
let span = variant.span();
|
||||
let variant_name = &variant.variant_name;
|
||||
match variant.body.body_type() {
|
||||
VariantBodyType::Unit => quote_spanned! {span =>
|
||||
#ident::#variant_name => #discriminant_token
|
||||
},
|
||||
VariantBodyType::Unnamed => {
|
||||
quote_spanned! { span =>
|
||||
#ident::#variant_name(_) => #discriminant_token
|
||||
}
|
||||
}
|
||||
VariantBodyType::Named => {
|
||||
quote_spanned! { span =>
|
||||
#ident::#variant_name{..} => #discriminant_token
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let write_inner = params.variants.iter().map(|variant| {
|
||||
let span = variant.span();
|
||||
let mut path = Path::from(ident.clone());
|
||||
path.segments.push(variant.variant_name.clone().into());
|
||||
|
||||
match &variant.body {
|
||||
VariantBody::Unit => {
|
||||
quote_spanned! {span =>
|
||||
#path => {},
|
||||
}
|
||||
}
|
||||
VariantBody::Fields(fields) => write_enum_variant(path, &fields, span),
|
||||
}
|
||||
});
|
||||
|
||||
quote_spanned! {span=>
|
||||
let discriminant:#repr = match &self {
|
||||
#(#discriminant_value),*
|
||||
};
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
__stream.write_int(discriminant, #discriminant_bits as usize)?;
|
||||
match &self {
|
||||
#(#write_inner)*
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
81
bitbuffer_derive/src/write/field.rs
Normal file
81
bitbuffer_derive/src/write/field.rs
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
use crate::params::FieldParam;
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::quote_spanned;
|
||||
use syn::Path;
|
||||
|
||||
pub fn write_struct(fields: &[FieldParam], span: Span) -> TokenStream {
|
||||
let expand = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.zip(names(fields))
|
||||
.map(|((index, field), name)| {
|
||||
let member = field.member(index as u32);
|
||||
let size_field = match (field.is_int(), field.field_name.as_ref()) {
|
||||
(true, Some(name)) => Some(quote_spanned! { field.span() =>
|
||||
#[allow(unused_variables)]
|
||||
let #name = self.#member;
|
||||
}),
|
||||
_ => None,
|
||||
};
|
||||
quote_spanned! { field.span() =>
|
||||
#size_field
|
||||
#[allow(unused_variables)]
|
||||
let #name = &self.#member;
|
||||
}
|
||||
});
|
||||
let writes = writes(fields);
|
||||
|
||||
quote_spanned! {span=>
|
||||
#(#expand)*
|
||||
#(#writes)*
|
||||
}
|
||||
}
|
||||
|
||||
fn names(fields: &[FieldParam]) -> impl Iterator<Item = Ident> + '_ {
|
||||
fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, field)| Ident::new(&format!("__field_{}", index), field.span()))
|
||||
}
|
||||
|
||||
fn writes(fields: &[FieldParam]) -> impl Iterator<Item = TokenStream> + '_ {
|
||||
let names = names(fields);
|
||||
fields.iter().zip(names).map(|(field, name)| {
|
||||
let align = &field.align.write();
|
||||
let span = field.span();
|
||||
match &field.size {
|
||||
Some(size) => {
|
||||
quote_spanned! { span =>
|
||||
{
|
||||
#align
|
||||
let _size: usize = #size;
|
||||
__stream.write_sized(#name, _size)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
quote_spanned! { span =>
|
||||
{
|
||||
#align
|
||||
__stream.write(#name)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn write_enum_variant(variant: Path, fields: &[FieldParam], span: Span) -> TokenStream {
|
||||
let names = names(fields);
|
||||
let named = fields.iter().any(|f| f.field_name.is_some());
|
||||
let writes = writes(fields);
|
||||
if named {
|
||||
quote_spanned!(span => #variant{#(#names,)*} => {
|
||||
#(#writes;)*
|
||||
})
|
||||
} else {
|
||||
quote_spanned!(span => #variant(#(#names,)*) => {
|
||||
#(#writes;)*
|
||||
})
|
||||
}
|
||||
}
|
||||
68
bitbuffer_derive/src/write/mod.rs
Normal file
68
bitbuffer_derive/src/write/mod.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
pub mod r#enum;
|
||||
pub mod field;
|
||||
pub mod r#struct;
|
||||
|
||||
use self::r#enum::derive_encode_enum;
|
||||
use self::r#struct::derive_encode_struct;
|
||||
use crate::params::{InputInnerParams, InputParams};
|
||||
use crate::Derivable;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::Result;
|
||||
|
||||
fn encode_impl(params: &InputParams) -> Result<TokenStream> {
|
||||
Ok(match ¶ms.inner {
|
||||
InputInnerParams::Struct(inner) => derive_encode_struct(inner),
|
||||
InputInnerParams::Enum(inner) => derive_encode_enum(inner),
|
||||
})
|
||||
}
|
||||
|
||||
pub struct Write;
|
||||
|
||||
impl Derivable for Write {
|
||||
type Params = InputParams;
|
||||
|
||||
fn derive(params: Self::Params) -> Result<TokenStream> {
|
||||
let (impl_generics, ty_generics, where_clause) = params.generics_for_impl();
|
||||
|
||||
let encode = encode_impl(¶ms)?;
|
||||
let endianness = params.endianness();
|
||||
let name = params.ident.clone();
|
||||
let align = params.align.write();
|
||||
|
||||
Ok(quote! {
|
||||
impl #impl_generics ::bitbuffer::BitWrite<#endianness> for #name #ty_generics #where_clause {
|
||||
#[allow(unused_braces)]
|
||||
fn write(&self, __stream: &mut ::bitbuffer::BitWriteStream<#endianness>) -> ::bitbuffer::Result<()> {
|
||||
#align
|
||||
#encode
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WriteSized;
|
||||
|
||||
impl Derivable for WriteSized {
|
||||
type Params = InputParams;
|
||||
|
||||
fn derive(params: Self::Params) -> Result<TokenStream> {
|
||||
let (impl_generics, ty_generics, where_clause) = params.generics_for_impl();
|
||||
|
||||
let encode = encode_impl(¶ms)?;
|
||||
let endianness = params.endianness();
|
||||
let name = params.ident.clone();
|
||||
let align = params.align.write();
|
||||
|
||||
Ok(quote! {
|
||||
impl #impl_generics ::bitbuffer::BitWriteSized<#endianness> for #name #ty_generics #where_clause {
|
||||
#[allow(unused_braces)]
|
||||
fn write_sized(&self, __stream: &mut ::bitbuffer::BitWriteStream<#endianness>, input_size: usize) -> ::bitbuffer::Result<()> {
|
||||
#align
|
||||
#encode
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
13
bitbuffer_derive/src/write/struct.rs
Normal file
13
bitbuffer_derive/src/write/struct.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
use crate::params::StructParam;
|
||||
use crate::write::field::write_struct;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
pub fn derive_encode_struct(params: &StructParam) -> TokenStream {
|
||||
let body = write_struct(¶ms.fields, params.span());
|
||||
|
||||
quote!(
|
||||
#body
|
||||
Ok(())
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue