Skip to content

Commit 55fcb30

Browse files
committed
Use indices for fields and variants when that option is enabled.
1 parent e461da4 commit 55fcb30

File tree

3 files changed

+49
-20
lines changed

3 files changed

+49
-20
lines changed

serde-diff-derive/src/serde_diff/mod.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ fn generate_fields_diff(
7777
let right = format_ident!("r{}", field_idx);
7878

7979
let push = if let Some(_) = ident {
80-
quote!{ctx.push_field(#ident_as_str);}
80+
quote!{ctx.push_field(#field_idx, #ident_as_str);}
8181
} else {
8282
quote!{ctx.push_field_index(#field_idx);}
8383
};
@@ -170,7 +170,7 @@ fn ok_fields(fields : &syn::Fields) -> Result<Vec<ParsedField>, proc_macro::Toke
170170
}
171171
}
172172

173-
fn generate_arms(name: &syn::Ident, variant: Option<&syn::Ident>, fields: &syn::Fields, matching: bool)
173+
fn generate_arms(name: &syn::Ident, variant: Option<(u16, &syn::Ident)>, fields: &syn::Fields, matching: bool)
174174
-> Result<(Vec<proc_macro2::TokenStream>, Vec<proc_macro2::TokenStream>),
175175
proc_macro2::TokenStream>
176176
{
@@ -182,14 +182,15 @@ fn generate_arms(name: &syn::Ident, variant: Option<&syn::Ident>, fields: &syn::
182182
matching,
183183
);
184184
let (left, right) = enum_fields(&fields, false);
185-
let variant_specifier = if let Some(id) = variant {
185+
let variant_specifier = if let Some((_, id)) = variant {
186186
quote!{ :: #id}
187187
} else {
188188
quote!{}
189189
};
190190

191-
let variant_as_str = variant.map(|i| i.to_string());
192-
let push_variant = variant.map(|_| quote!{ctx.push_variant(#variant_as_str);});
191+
let variant_idx = variant.map(|(i, _)| i);
192+
let variant_as_str = variant.map(|(_, i)| i.to_string());
193+
let push_variant = variant.map(|_| quote!{ctx.push_variant(#variant_idx, #variant_as_str);});
193194
let pop_variant = variant.map(|_| quote!{ctx.pop_path_element()?;});
194195

195196
let left = if matching {
@@ -259,6 +260,16 @@ fn generate_arms(name: &syn::Ident, variant: Option<&syn::Ident>, fields: &syn::
259260
}
260261

261262
if let Some(_) = variant {
263+
apply_match_arms.push(quote!{
264+
( &mut #name #variant_specifier #left, Some(serde_diff::DiffPathElementValue::EnumVariantIndex(#variant_idx))) => {
265+
while let Some(element) = ctx.next_path_element(seq)? {
266+
match element {
267+
#(#apply_fn_field_handlers)*
268+
_ => ctx.skip_value(seq)?
269+
}
270+
}
271+
}
272+
});
262273
apply_match_arms.push(quote!{
263274
( &mut #name #variant_specifier #left, Some(serde_diff::DiffPathElementValue::EnumVariant(variant))) if variant == #variant_as_str => {
264275
while let Some(element) = ctx.next_path_element(seq)? {
@@ -299,8 +310,8 @@ fn generate(
299310
let has_variants = match &input.data {
300311
Data::Enum(e) => {
301312
for matching in &[true, false] {
302-
for v in &e.variants {
303-
let (diff, apply) = generate_arms(&struct_args.ident, Some(&v.ident), &v.fields, *matching)?;
313+
for (i, v) in e.variants.iter().enumerate() {
314+
let (diff, apply) = generate_arms(&struct_args.ident, Some((i as u16, &v.ident)), &v.fields, *matching)?;
304315
diff_match_arms.extend(diff);
305316
apply_match_arms.extend(apply);
306317
}

src/difference.rs

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,38 @@ impl<'a, S: SerializeSeq> DiffContext<'a, S> {
5858
/// Called when we visit a field. If the structure is recursive (i.e. struct within struct,
5959
/// elements within an array) this may be called more than once before a corresponding pop_path_element
6060
/// is called. See `pop_path_element`
61-
pub fn push_field(&mut self, field_name: &'static str) {
62-
self.element_stack
63-
.as_mut()
64-
.unwrap()
65-
.push(ElementStackEntry::PathElement(DiffPathElementValue::Field(
66-
Cow::Borrowed(field_name),
67-
)));
61+
pub fn push_field(&mut self, field_idx: u16, field_name: &'static str) {
62+
if matches!(self.field_path_mode, FieldPathMode::Index) {
63+
self.push_field_index(field_idx);
64+
} else {
65+
self.element_stack
66+
.as_mut()
67+
.unwrap()
68+
.push(ElementStackEntry::PathElement(DiffPathElementValue::Field(
69+
Cow::Borrowed(field_name),
70+
)));
71+
}
72+
}
73+
74+
pub fn push_variant(&mut self, variant_idx: u16, variant_name: &'static str) {
75+
if matches!(self.field_path_mode, FieldPathMode::Index) {
76+
self.push_variant_index(variant_idx);
77+
} else {
78+
self.element_stack
79+
.as_mut()
80+
.unwrap()
81+
.push(ElementStackEntry::PathElement(
82+
DiffPathElementValue::EnumVariant(Cow::Borrowed(variant_name)),
83+
));
84+
}
6885
}
6986

70-
pub fn push_variant(&mut self, variant_name: &'static str) {
87+
pub fn push_variant_index(&mut self, variant_idx: u16) {
7188
self.element_stack
7289
.as_mut()
7390
.unwrap()
7491
.push(ElementStackEntry::PathElement(
75-
DiffPathElementValue::EnumVariant(Cow::Borrowed(variant_name)),
92+
DiffPathElementValue::EnumVariantIndex(variant_idx),
7693
));
7794
}
7895

@@ -601,6 +618,7 @@ pub enum DiffPathElementValue<'a> {
601618
Field(Cow<'a, str>),
602619
FieldIndex(u16),
603620
EnumVariant(Cow<'a, str>),
621+
EnumVariantIndex(u16),
604622
FullEnumVariant,
605623
CollectionIndex(usize),
606624
AddToCollection,

src/implementation.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ macro_rules! tuple_impls {
9696
) -> Result<bool, S::Error> {
9797
let mut changed = false;
9898
$(
99-
ctx.push_field(stringify!($n));
99+
ctx.push_field_index($n);
100100
changed |= <$name as $crate::SerdeDiff>::diff(&self.$n, ctx, &other.$n)?;
101101
ctx.pop_path_element()?;
102102
)+
@@ -112,10 +112,10 @@ macro_rules! tuple_impls {
112112
A: serde::de::SeqAccess<'de>,
113113
{
114114
let mut changed = false;
115-
while let Some($crate::difference::DiffPathElementValue::Field(element)) = ctx.next_path_element(seq)? {
116-
match element.as_ref() {
115+
while let Some($crate::difference::DiffPathElementValue::FieldIndex(element)) = ctx.next_path_element(seq)? {
116+
match element {
117117
$(
118-
stringify!($n) => changed |= <$name as $crate::SerdeDiff>::apply(&mut self.$n, seq, ctx)?,
118+
$n => changed |= <$name as $crate::SerdeDiff>::apply(&mut self.$n, seq, ctx)?,
119119
)+
120120
_ => ctx.skip_value(seq)?,
121121
}

0 commit comments

Comments
 (0)