mirror of
https://github.com/trussed-dev/serde-indexed.git
synced 2026-06-20 04:16:32 -07:00
Add support for serde(skip) in skip_serializing_if
This commit is contained in:
+13
-13
@@ -30,6 +30,7 @@ extern crate proc_macro;
|
||||
|
||||
mod parse;
|
||||
|
||||
use parse::Skip;
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::{Ident, Span};
|
||||
use quote::{format_ident, quote};
|
||||
@@ -40,23 +41,20 @@ use crate::parse::Input;
|
||||
fn serialize_fields(fields: &[parse::Field], offset: usize) -> Vec<proc_macro2::TokenStream> {
|
||||
fields
|
||||
.iter()
|
||||
.map(|field| {
|
||||
.filter_map(|field| {
|
||||
let index = field.index + offset;
|
||||
let member = &field.member;
|
||||
// println!("field {:?} index {:?}", &field.label, field.index);
|
||||
match &field.skip_serializing_if {
|
||||
Some(path) => {
|
||||
quote! {
|
||||
if !#path(&self.#member) {
|
||||
map.serialize_entry(&#index, &self.#member)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
quote! {
|
||||
Skip::If(path) => Some(quote! {
|
||||
if !#path(&self.#member) {
|
||||
map.serialize_entry(&#index, &self.#member)?;
|
||||
}
|
||||
}
|
||||
}),
|
||||
Skip::Always => None,
|
||||
Skip::None => Some(quote! {
|
||||
map.serialize_entry(&#index, &self.#member)?;
|
||||
}),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
@@ -69,10 +67,12 @@ fn count_serialized_fields(fields: &[parse::Field]) -> Vec<proc_macro2::TokenStr
|
||||
// let index = field.index + offset;
|
||||
let member = &field.member;
|
||||
match &field.skip_serializing_if {
|
||||
Some(path) => {
|
||||
Skip::If(path) => {
|
||||
quote! { if #path(&self.#member) { 0 } else { 1 } }
|
||||
}
|
||||
None => {
|
||||
Skip::Always => quote! { 0 },
|
||||
|
||||
Skip::None => {
|
||||
quote! { 1 }
|
||||
}
|
||||
}
|
||||
|
||||
+30
-6
@@ -16,11 +16,23 @@ pub struct StructAttrs {
|
||||
// pub skip_nones: bool,
|
||||
}
|
||||
|
||||
pub enum Skip {
|
||||
None,
|
||||
If(syn::ExprPath),
|
||||
Always,
|
||||
}
|
||||
|
||||
impl Skip {
|
||||
pub fn is_none(&self) -> bool {
|
||||
matches!(self, Self::None)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Field {
|
||||
pub label: String,
|
||||
pub member: syn::Member,
|
||||
pub index: usize,
|
||||
pub skip_serializing_if: Option<syn::ExprPath>,
|
||||
pub skip_serializing_if: Skip,
|
||||
}
|
||||
|
||||
fn parse_meta(attrs: &mut StructAttrs, meta: ParseNestedMeta) -> Result<()> {
|
||||
@@ -113,18 +125,30 @@ fn fields_from_ast(
|
||||
index: i,
|
||||
// TODO: make this... more concise? handle errors? the thing with the spans?
|
||||
skip_serializing_if: {
|
||||
let mut skip_serializing_if = None;
|
||||
let mut skip_serializing_if = Skip::None;
|
||||
for attr in &field.attrs {
|
||||
if attr.path().is_ident("serde") {
|
||||
attr.parse_nested_meta(|meta| {
|
||||
if meta.path.is_ident("skip_serializing_if") {
|
||||
let litstr: LitStr = meta.value()?.parse()?;
|
||||
let tokens = syn::parse_str(&litstr.value())?;
|
||||
if skip_serializing_if.is_some() {
|
||||
return Err(meta
|
||||
.error("Multiple attributes for skip_serializing_if"));
|
||||
if !skip_serializing_if.is_none() {
|
||||
return Err(meta.error(
|
||||
"Multiple attributes for skip_serializing_if or skip",
|
||||
));
|
||||
}
|
||||
skip_serializing_if = Some(syn::parse2(tokens)?);
|
||||
skip_serializing_if = Skip::If(syn::parse2(tokens)?);
|
||||
Ok(())
|
||||
} else if meta.path.is_ident("skip") {
|
||||
if meta.value().is_ok() {
|
||||
return Err(meta.error("`skip` does not expect any value"));
|
||||
}
|
||||
if !skip_serializing_if.is_none() {
|
||||
return Err(meta.error(
|
||||
"Multiple attributes for skip_serializing_if or skip",
|
||||
));
|
||||
}
|
||||
skip_serializing_if = Skip::Always;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(meta.error("Unkown field attribute"))
|
||||
|
||||
Reference in New Issue
Block a user