use proc_macro2::{Ident, TokenStream};
use quote::{quote, TokenStreamExt};
use syn::{spanned::Spanned, Fields};
use crate::{
array_len_write,
attribute::{parse_attributes, AttrLocation, Attribute},
DeriveKind, RESERVED_NAMES,
};
pub mod enums;
pub mod structs;
pub struct PackFields {
pub pack_fields: TokenStream,
pub write_pack_fields: TokenStream,
pub match_fields: TokenStream,
pub unit: bool,
}
pub fn pack_fields(fields: &Fields, location: AttrLocation) -> syn::Result<PackFields> {
let unit;
let mut pack_fields = quote! {};
let mut write_pack_fields = quote! {};
let mut match_fields = quote! {};
match fields {
Fields::Named(fields) => {
let mut fields_len = 0usize;
for field in fields.named.iter() {
let attributes = parse_attributes(&field.attrs, location, DeriveKind::MsgPack)?;
if !attributes.contains(&Attribute::Skip) {
fields_len += 1;
}
}
pack_fields.append_all(quote! {
.chain(::msgpck::helpers::pack_array_header(#fields_len))
});
write_pack_fields.append_all(array_len_write(fields_len));
unit = fields_len == 0;
for field in &fields.named {
let field_attributes =
parse_attributes(&field.attrs, location, DeriveKind::MsgPack)?;
if field_attributes.contains(&Attribute::Skip) {
continue;
}
let field_name = field.ident.as_ref().expect("fields are named");
if RESERVED_NAMES.contains(&field_name.to_string().as_str()) {
return Err(syn::Error::new(
field.ident.span(),
"MsgPack: reserved identifier",
));
}
match_fields.append_all(quote! {#field_name, });
pack_fields.append_all(quote! {
.chain(::msgpck::MsgPack::pack(#field_name))
});
write_pack_fields.append_all(quote! {
__msgpck_n += ::msgpck::MsgPack::pack_with_writer(#field_name, __msgpck_w)?;
});
}
match_fields = quote! { { #match_fields .. } };
}
syn::Fields::Unnamed(fields) => {
let mut fields_len = 0usize;
for field in fields.unnamed.iter() {
let attributes = parse_attributes(&field.attrs, location, DeriveKind::MsgPack)?;
if !attributes.contains(&Attribute::Skip) {
fields_len += 1;
}
}
if fields_len != 1 {
pack_fields.append_all(quote! {
.chain(::msgpck::helpers::pack_array_header(#fields_len))
});
write_pack_fields.append_all(array_len_write(fields_len));
}
unit = fields_len == 0;
for (i, field) in fields.unnamed.iter().enumerate() {
let field_attributes =
parse_attributes(&field.attrs, location, DeriveKind::MsgPack)?;
if field_attributes.contains(&Attribute::Skip) {
continue;
}
let field_name = Ident::new(&format!("_{i}"), field.span());
match_fields.append_all(quote! {#field_name, });
pack_fields.append_all(quote! {
.chain(#field_name.pack())
});
write_pack_fields.append_all(quote! {
__msgpck_n += ::msgpck::MsgPack::pack_with_writer(#field_name, __msgpck_w)?;
});
}
match_fields = quote! { (#match_fields ..) };
}
syn::Fields::Unit => {
pack_fields.append_all(quote! {
.chain(::msgpck::helpers::pack_array_header(0))
});
write_pack_fields.append_all(array_len_write(0));
unit = true;
}
}
Ok(PackFields {
pack_fields,
write_pack_fields,
match_fields,
unit,
})
}