Skip to content

Commit 6e09ecf

Browse files
Don’t require explicit index for skipped fields
This patch allows for fields that are always skipped to not have an explicit index attribute so that users don’t have to assign bogus indices that are never used.
1 parent 07586db commit 6e09ecf

File tree

3 files changed

+28
-13
lines changed

3 files changed

+28
-13
lines changed

src/lib.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,10 @@ fn serialize_fields(
5353
) -> Vec<proc_macro2::TokenStream> {
5454
fields
5555
.iter()
56-
.filter_map(|field| {
57-
let index = field.index + offset;
56+
.filter(|field| !field.skip_serializing_if.is_always())
57+
.map(|field| {
58+
// index should only be none if the field is always skipped, so this should never panic
59+
let index = field.index.expect("index must be set for fields that are not skipped") + offset;
5860
let member = &field.member;
5961
let serialize_member = match &field.serialize_with {
6062
None => quote!(&self.#member),
@@ -85,15 +87,15 @@ fn serialize_fields(
8587

8688
// println!("field {:?} index {:?}", &field.label, field.index);
8789
match &field.skip_serializing_if {
88-
Skip::If(path) => Some(quote! {
90+
Skip::If(path) => quote! {
8991
if !#path(&self.#member) {
9092
map.serialize_entry(&#index, #serialize_member)?;
9193
}
92-
}),
93-
Skip::Always => None,
94-
Skip::Never => Some(quote! {
94+
},
95+
Skip::Always => unreachable!(),
96+
Skip::Never => quote! {
9597
map.serialize_entry(&#index, #serialize_member)?;
96-
}),
98+
},
9799
}
98100
})
99101
.collect()
@@ -222,7 +224,8 @@ fn match_fields(
222224
.map(|field| {
223225
let label = field.label.clone();
224226
let ident = format_ident!("{}", &field.label);
225-
let index = field.index + offset;
227+
// index should only be none if the field is always skipped, so this should never panic
228+
let index = field.index.expect("index must be set for fields that are not skipped") + offset;
226229
let span = field.original_span;
227230

228231
let next_value = match &field.deserialize_with {

src/parse.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl Skip {
3636
pub struct Field {
3737
pub label: String,
3838
pub member: syn::Member,
39-
pub index: usize,
39+
pub index: Option<usize>,
4040
pub skip_serializing_if: Skip,
4141
pub serialize_with: Option<syn::ExprPath>,
4242
pub deserialize_with: Option<syn::ExprPath>,
@@ -221,15 +221,24 @@ fn parse_field(
221221
}
222222
}
223223

224-
let index = if attrs.auto_index {
225-
auto_index
224+
if explicit_index.is_some() && skip_serializing_if.is_always() {
225+
return Err(Error::new_spanned(
226+
field,
227+
"`#[serde(index = ?]` and `#[serde(skip)]` cannot be combined",
228+
));
229+
}
230+
231+
let index = if skip_serializing_if.is_always() {
232+
None
233+
} else if attrs.auto_index {
234+
Some(auto_index)
226235
} else if let Some(index) = explicit_index {
227236
indices.push(index);
228-
index
237+
Some(index)
229238
} else {
230239
return Err(Error::new_spanned(
231240
field,
232-
"Field without index attribute and `#[serde(auto_index)]` is not enabled on the struct",
241+
"Field without index or skip attribute and `#[serde(auto_index)]` is not enabled on the struct",
233242
));
234243
};
235244
Ok(Field {

tests/basics.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,13 +629,16 @@ mod index {
629629
test2: usize,
630630
#[serde(index = 0x5A)]
631631
test3: usize,
632+
#[serde(skip)]
633+
test4: usize,
632634
}
633635

634636
fn indices_example() -> WithIndices {
635637
WithIndices {
636638
test1: 42,
637639
test2: 1,
638640
test3: 99,
641+
test4: 0,
639642
}
640643
}
641644

0 commit comments

Comments
 (0)