Skip to content

Commit 54832f1

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 4f46b7a commit 54832f1

File tree

3 files changed

+26
-13
lines changed

3 files changed

+26
-13
lines changed

src/lib.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,9 @@ fn serialize_fields(
7373
) -> Vec<proc_macro2::TokenStream> {
7474
fields
7575
.iter()
76-
.filter_map(|field| {
77-
let index = field.index + offset;
76+
.filter(|field| !field.skip_serializing_if.is_always())
77+
.map(|field| {
78+
let index = field.index.expect("index must be set for fields that are not skipped") + offset;
7879
let member = &field.member;
7980
let serialize_member = match &field.serialize_with {
8081
None => quote!(&self.#member),
@@ -105,15 +106,15 @@ fn serialize_fields(
105106

106107
// println!("field {:?} index {:?}", &field.label, field.index);
107108
match &field.skip_serializing_if {
108-
Skip::If(path) => Some(quote! {
109+
Skip::If(path) => quote! {
109110
if !#path(&self.#member) {
110111
map.serialize_entry(&#index, #serialize_member)?;
111112
}
112-
}),
113-
Skip::Always => None,
114-
Skip::Never => Some(quote! {
113+
},
114+
Skip::Always => unreachable!(),
115+
Skip::Never => quote! {
115116
map.serialize_entry(&#index, #serialize_member)?;
116-
}),
117+
},
117118
}
118119
})
119120
.collect()
@@ -242,7 +243,7 @@ fn match_fields(
242243
.map(|field| {
243244
let label = field.label.clone();
244245
let ident = format_ident!("{}", &field.label);
245-
let index = field.index + offset;
246+
let index = field.index.expect("index must be set for fields that are not skipped") + offset;
246247
let span = field.original_span;
247248

248249
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)