mirror of
https://github.com/azalea-rs/simdnbt.git
synced 2025-08-02 07:26:04 +00:00
add flatten, deny_unknown_fields, generics, and support more types of HashMap keys
This commit is contained in:
parent
331d135910
commit
57dfc2c1a9
5 changed files with 88 additions and 15 deletions
3
simdnbt-derive/README.md
Normal file
3
simdnbt-derive/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
Add support for `#[derive(Serialize, Deserialize)]` to sidmnbt.
|
||||
|
||||
You can use `#[simdnbt(rename = "Value")]` to have fields be serialized with a name other than the field name.
|
|
@ -3,6 +3,12 @@ use syn::parse::{Parse, ParseStream};
|
|||
#[derive(Default, Debug)]
|
||||
pub struct FieldAttrs {
|
||||
pub rename: Option<String>,
|
||||
pub flatten: bool,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct StructAttrs {
|
||||
pub deny_unknown_fields: bool,
|
||||
}
|
||||
|
||||
impl Parse for FieldAttrs {
|
||||
|
@ -18,6 +24,27 @@ impl Parse for FieldAttrs {
|
|||
|
||||
attrs.rename = Some(rename.value());
|
||||
}
|
||||
"flatten" => {
|
||||
attrs.flatten = true;
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(attrs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for StructAttrs {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let mut attrs = Self::default();
|
||||
|
||||
while !input.is_empty() {
|
||||
let attr = input.parse::<proc_macro2::Ident>()?;
|
||||
match attr.to_string().as_str() {
|
||||
"deny_unknown_fields" => {
|
||||
attrs.deny_unknown_fields = true;
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
@ -40,3 +67,18 @@ pub fn parse_field_attrs(attrs: &[syn::Attribute]) -> FieldAttrs {
|
|||
|
||||
field_attrs
|
||||
}
|
||||
|
||||
pub fn parse_struct_attrs(attrs: &[syn::Attribute]) -> StructAttrs {
|
||||
let mut struct_attrs = StructAttrs::default();
|
||||
|
||||
for attr in attrs.iter().filter(|attr| attr.path().is_ident("simdnbt")) {
|
||||
let new_attr = attr
|
||||
.parse_args::<StructAttrs>()
|
||||
.expect("invalid simdnbt attr");
|
||||
if new_attr.deny_unknown_fields {
|
||||
struct_attrs.deny_unknown_fields = true;
|
||||
}
|
||||
}
|
||||
|
||||
struct_attrs
|
||||
}
|
||||
|
|
|
@ -25,11 +25,17 @@ pub fn deserialize_derive(input: proc_macro::TokenStream) -> proc_macro::TokenSt
|
|||
.take()
|
||||
.unwrap_or_else(|| struct_field_name.to_string());
|
||||
|
||||
field_deserializers.push(quote! {
|
||||
#struct_field_name: simdnbt::FromNbtTag::from_optional_nbt_tag(
|
||||
nbt.take(#field_name)
|
||||
)?.ok_or(simdnbt::DeserializeError::MismatchedFieldType)?
|
||||
});
|
||||
if field_attrs.flatten {
|
||||
field_deserializers.push(quote! {
|
||||
#struct_field_name: simdnbt::Deserialize::from_compound(nbt)?,
|
||||
})
|
||||
} else {
|
||||
field_deserializers.push(quote! {
|
||||
#struct_field_name: simdnbt::FromNbtTag::from_optional_nbt_tag(
|
||||
nbt.take(#field_name)
|
||||
)?.ok_or(simdnbt::DeserializeError::MismatchedFieldType)?
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
syn::Fields::Unnamed(_) => todo!(),
|
||||
|
@ -39,12 +45,27 @@ pub fn deserialize_derive(input: proc_macro::TokenStream) -> proc_macro::TokenSt
|
|||
syn::Data::Union(_) => todo!(),
|
||||
}
|
||||
|
||||
let generics = input.generics;
|
||||
let struct_attrs = attrs::parse_struct_attrs(&input.attrs);
|
||||
|
||||
let extra_checks = if struct_attrs.deny_unknown_fields {
|
||||
quote! {
|
||||
if !nbt.is_empty() {
|
||||
return Err(simdnbt::DeserializeError::UnknownField(nbt.keys().next().unwrap().clone()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
|
||||
let output = quote! {
|
||||
impl simdnbt::Deserialize for #ident {
|
||||
impl #generics simdnbt::Deserialize for #ident #generics {
|
||||
fn from_compound(mut nbt: simdnbt::owned::NbtCompound) -> Result<Self, simdnbt::DeserializeError> {
|
||||
Ok(Self {
|
||||
let value = Self {
|
||||
#(#field_deserializers),*
|
||||
})
|
||||
};
|
||||
#extra_checks
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -87,8 +108,11 @@ pub fn serialize_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStre
|
|||
syn::Data::Union(_) => todo!(),
|
||||
}
|
||||
|
||||
let generics = input.generics;
|
||||
let struct_attrs = attrs::parse_struct_attrs(&input.attrs);
|
||||
|
||||
let output = quote! {
|
||||
impl simdnbt::Serialize for #ident {
|
||||
impl #generics simdnbt::Serialize for #ident #generics {
|
||||
fn to_compound(self) -> simdnbt::owned::NbtCompound {
|
||||
let mut nbt = simdnbt::owned::NbtCompound::new();
|
||||
#(#field_serializers)*
|
||||
|
|
|
@ -20,4 +20,6 @@ pub enum DeserializeError {
|
|||
MissingField,
|
||||
#[error("Mismatched type")]
|
||||
MismatchedFieldType,
|
||||
#[error("Unknown fields {0:?}")]
|
||||
UnknownField(Vec<String>),
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, fmt::Display, hash::Hash, hash::Hasher, str::FromStr};
|
||||
|
||||
use crate::DeserializeError;
|
||||
|
||||
|
@ -37,26 +37,28 @@ pub trait ToNbtTag: Sized {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: FromNbtTag> Deserialize for HashMap<String, T> {
|
||||
impl<K: Display + FromStr + Eq + Hash, V: FromNbtTag> Deserialize for HashMap<K, V> {
|
||||
fn from_compound(compound: crate::owned::NbtCompound) -> Result<Self, DeserializeError> {
|
||||
let mut hashmap = HashMap::with_capacity(compound.values.len());
|
||||
|
||||
for (k, v) in compound.values {
|
||||
hashmap.insert(
|
||||
k.to_string(),
|
||||
T::from_nbt_tag(v).ok_or(DeserializeError::MismatchedFieldType)?,
|
||||
k.to_str()
|
||||
.parse()
|
||||
.map_err(|_| DeserializeError::MismatchedFieldType)?,
|
||||
V::from_nbt_tag(v).ok_or(DeserializeError::MismatchedFieldType)?,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(hashmap)
|
||||
}
|
||||
}
|
||||
impl<T: ToNbtTag> Serialize for HashMap<String, T> {
|
||||
impl<K: Display + FromStr + Eq + Hash, V: ToNbtTag> Serialize for HashMap<K, V> {
|
||||
fn to_compound(self) -> crate::owned::NbtCompound {
|
||||
let mut compound = crate::owned::NbtCompound::new();
|
||||
|
||||
for (k, v) in self {
|
||||
compound.insert(k, v.to_nbt_tag());
|
||||
compound.insert(k.to_string(), v.to_nbt_tag());
|
||||
}
|
||||
|
||||
compound
|
||||
|
|
Loading…
Add table
Reference in a new issue