@@ -7,7 +7,7 @@ use crate::{
77use serde:: { de, ser:: SerializeSeq , Deserialize , Serialize } ;
88
99use std:: {
10- collections:: { BTreeMap , HashMap } ,
10+ collections:: { BTreeMap , BTreeSet , HashMap , HashSet } ,
1111 hash:: Hash ,
1212} ;
1313
@@ -237,6 +237,78 @@ macro_rules! map_serde_diff {
237237map_serde_diff ! ( HashMap <K , V >, Hash , Eq ) ;
238238map_serde_diff ! ( BTreeMap <K , V >, Ord ) ;
239239
240+ /// Implement SerdeDiff on a "set-like" type such as HashSet.
241+ macro_rules! set_serde_diff {
242+ ( $t: ty, $( $extra_traits: path) ,* ) => {
243+ impl <K > SerdeDiff for $t
244+ where
245+ K : SerdeDiff + Serialize + for <' a> Deserialize <' a> $( + $extra_traits) * , // + Hash + Eq,
246+ {
247+ fn diff<' a, S : SerializeSeq >(
248+ & self ,
249+ ctx: & mut $crate:: difference:: DiffContext <' a, S >,
250+ other: & Self ,
251+ ) -> Result <bool , S :: Error > {
252+ use $crate:: difference:: DiffCommandRef ;
253+
254+ let mut changed = false ;
255+
256+ // TODO: detect renames
257+ for key in self . iter( ) {
258+ if !other. contains( key) {
259+ ctx. save_command( & DiffCommandRef :: RemoveKey ( key) , true , true ) ?;
260+ changed = true ;
261+ }
262+ }
263+
264+ for key in other. iter( ) {
265+ if !self . contains( key) {
266+ ctx. save_command( & DiffCommandRef :: AddKey ( key) , true , true ) ?;
267+ changed = true ;
268+ }
269+ }
270+
271+ if changed {
272+ ctx. save_command:: <( ) >( & DiffCommandRef :: Exit , true , false ) ?;
273+ }
274+ Ok ( changed)
275+ }
276+
277+ fn apply<' de, A >(
278+ & mut self ,
279+ seq: & mut A ,
280+ ctx: & mut ApplyContext ,
281+ ) -> Result <bool , <A as de:: SeqAccess <' de>>:: Error >
282+ where
283+ A : de:: SeqAccess <' de>,
284+ {
285+ let mut changed = false ;
286+ while let Some ( cmd) = ctx. read_next_command:: <A , K >( seq) ? {
287+ use $crate:: difference:: DiffCommandValue :: * ;
288+ use $crate:: difference:: DiffPathElementValue :: * ;
289+ match cmd {
290+ // we should not be getting fields when reading collection commands
291+ Enter ( Field ( _) ) | EnterKey ( _) => {
292+ ctx. skip_value( seq) ?;
293+ break ;
294+ }
295+ AddKey ( key) => {
296+ self . insert( key) ;
297+ changed = true ;
298+ }
299+ RemoveKey ( key) => changed |= self . remove( & key) ,
300+ _ => break ,
301+ }
302+ }
303+ Ok ( changed)
304+ }
305+ }
306+ } ;
307+ }
308+
309+ set_serde_diff ! ( HashSet <K >, Hash , Eq ) ;
310+ set_serde_diff ! ( BTreeSet <K >, Ord ) ;
311+
240312/// Implements SerdeDiff on a type given that it impls Serialize + Deserialize + PartialEq.
241313/// This makes the type a "terminal" type in the SerdeDiff hierarchy, meaning deeper inspection
242314/// will not be possible. Use the SerdeDiff derive macro for recursive field inspection.
0 commit comments