11use super :: * ;
22use crate :: subpath:: BezierHandles ;
33use crate :: vector:: misc:: { HandleId , HandleType , point_to_dvec2} ;
4- use core_types:: uuid:: generate_uuid;
54use dyn_any:: DynAny ;
65use glam:: DVec2 ;
76use kurbo:: { BezPath , PathEl , Point } ;
8- use std:: collections:: { HashMap , HashSet } ;
9- use std:: hash:: BuildHasher ;
7+ use std:: collections:: { BTreeMap , BTreeSet , HashSet } ;
108
119/// Represents a procedural change to the [`PointDomain`] in [`Vector`].
12- #[ derive( Clone , Debug , Default , PartialEq , serde:: Serialize , serde:: Deserialize ) ]
10+ #[ derive( Clone , Debug , Default , PartialEq , graphene_hash :: CacheHash , serde:: Serialize , serde:: Deserialize ) ]
1311pub struct PointModification {
1412 add : Vec < PointId > ,
15- remove : HashSet < PointId > ,
16- #[ serde( serialize_with = "serialize_hashmap" , deserialize_with = "deserialize_hashmap" ) ]
17- delta : HashMap < PointId , DVec2 > ,
18- }
19-
20- impl Hash for PointModification {
21- fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
22- generate_uuid ( ) . hash ( state)
23- }
13+ remove : BTreeSet < PointId > ,
14+ #[ serde( deserialize_with = "deserialize_btreemap" ) ]
15+ delta : BTreeMap < PointId , DVec2 > ,
2416}
2517
2618impl PointModification {
@@ -62,7 +54,7 @@ impl PointModification {
6254 pub fn create_from_vector < Upstream > ( vector : & Vector < Upstream > ) -> Self {
6355 Self {
6456 add : vector. point_domain . ids ( ) . to_vec ( ) ,
65- remove : HashSet :: new ( ) ,
57+ remove : BTreeSet :: new ( ) ,
6658 delta : vector. point_domain . ids ( ) . iter ( ) . copied ( ) . zip ( vector. point_domain . positions ( ) . iter ( ) . cloned ( ) ) . collect ( ) ,
6759 }
6860 }
@@ -80,20 +72,20 @@ impl PointModification {
8072}
8173
8274/// Represents a procedural change to the [`SegmentDomain`] in [`Vector`].
83- #[ derive( Clone , Debug , Default , PartialEq , serde:: Serialize , serde:: Deserialize ) ]
75+ #[ derive( Clone , Debug , Default , PartialEq , graphene_hash :: CacheHash , serde:: Serialize , serde:: Deserialize ) ]
8476pub struct SegmentModification {
8577 add : Vec < SegmentId > ,
86- remove : HashSet < SegmentId > ,
87- #[ serde( serialize_with = "serialize_hashmap" , deserialize_with = "deserialize_hashmap " ) ]
88- start_point : HashMap < SegmentId , PointId > ,
89- #[ serde( serialize_with = "serialize_hashmap" , deserialize_with = "deserialize_hashmap " ) ]
90- end_point : HashMap < SegmentId , PointId > ,
91- #[ serde( serialize_with = "serialize_hashmap" , deserialize_with = "deserialize_hashmap " ) ]
92- handle_primary : HashMap < SegmentId , Option < DVec2 > > ,
93- #[ serde( serialize_with = "serialize_hashmap" , deserialize_with = "deserialize_hashmap " ) ]
94- handle_end : HashMap < SegmentId , Option < DVec2 > > ,
95- #[ serde( serialize_with = "serialize_hashmap" , deserialize_with = "deserialize_hashmap " ) ]
96- stroke : HashMap < SegmentId , StrokeId > ,
78+ remove : BTreeSet < SegmentId > ,
79+ #[ serde( deserialize_with = "deserialize_btreemap " ) ]
80+ start_point : BTreeMap < SegmentId , PointId > ,
81+ #[ serde( deserialize_with = "deserialize_btreemap " ) ]
82+ end_point : BTreeMap < SegmentId , PointId > ,
83+ #[ serde( deserialize_with = "deserialize_btreemap " ) ]
84+ handle_primary : BTreeMap < SegmentId , Option < DVec2 > > ,
85+ #[ serde( deserialize_with = "deserialize_btreemap " ) ]
86+ handle_end : BTreeMap < SegmentId , Option < DVec2 > > ,
87+ #[ serde( deserialize_with = "deserialize_btreemap " ) ]
88+ stroke : BTreeMap < SegmentId , StrokeId > ,
9789}
9890
9991impl SegmentModification {
@@ -219,7 +211,7 @@ impl SegmentModification {
219211 let point_id = |( & segment, & index) | ( segment, vector. point_domain . ids ( ) [ index] ) ;
220212 Self {
221213 add : vector. segment_domain . ids ( ) . to_vec ( ) ,
222- remove : HashSet :: new ( ) ,
214+ remove : BTreeSet :: new ( ) ,
223215 start_point : vector. segment_domain . ids ( ) . iter ( ) . zip ( vector. segment_domain . start_point ( ) ) . map ( point_id) . collect ( ) ,
224216 end_point : vector. segment_domain . ids ( ) . iter ( ) . zip ( vector. segment_domain . end_point ( ) ) . map ( point_id) . collect ( ) ,
225217 handle_primary : vector. segment_bezier_iter ( ) . map ( |( id, b, _, _) | ( id, b. handle_start ( ) . map ( |handle| handle - b. start ) ) ) . collect ( ) ,
@@ -250,14 +242,14 @@ impl SegmentModification {
250242}
251243
252244/// Represents a procedural change to the [`RegionDomain`] in [`Vector`].
253- #[ derive( Clone , Debug , Default , PartialEq , serde:: Serialize , serde:: Deserialize ) ]
245+ #[ derive( Clone , Debug , Default , PartialEq , graphene_hash :: CacheHash , serde:: Serialize , serde:: Deserialize ) ]
254246pub struct RegionModification {
255247 add : Vec < RegionId > ,
256- remove : HashSet < RegionId > ,
257- #[ serde( serialize_with = "serialize_hashmap" , deserialize_with = "deserialize_hashmap " ) ]
258- segment_range : HashMap < RegionId , std:: ops:: RangeInclusive < SegmentId > > ,
259- #[ serde( serialize_with = "serialize_hashmap" , deserialize_with = "deserialize_hashmap " ) ]
260- fill : HashMap < RegionId , FillId > ,
248+ remove : BTreeSet < RegionId > ,
249+ #[ serde( deserialize_with = "deserialize_btreemap " ) ]
250+ segment_range : BTreeMap < RegionId , std:: ops:: RangeInclusive < SegmentId > > ,
251+ #[ serde( deserialize_with = "deserialize_btreemap " ) ]
252+ fill : BTreeMap < RegionId , FillId > ,
261253}
262254
263255impl RegionModification {
@@ -286,21 +278,21 @@ impl RegionModification {
286278 pub fn create_from_vector < Upstream > ( vector : & Vector < Upstream > ) -> Self {
287279 Self {
288280 add : vector. region_domain . ids ( ) . to_vec ( ) ,
289- remove : HashSet :: new ( ) ,
281+ remove : BTreeSet :: new ( ) ,
290282 segment_range : vector. region_domain . ids ( ) . iter ( ) . copied ( ) . zip ( vector. region_domain . segment_range ( ) . iter ( ) . cloned ( ) ) . collect ( ) ,
291283 fill : vector. region_domain . ids ( ) . iter ( ) . copied ( ) . zip ( vector. region_domain . fill ( ) . iter ( ) . cloned ( ) ) . collect ( ) ,
292284 }
293285 }
294286}
295287
296288/// Represents a procedural change to the [`Vector`].
297- #[ derive( Clone , Debug , Default , PartialEq , DynAny , serde:: Serialize , serde:: Deserialize ) ]
289+ #[ derive( Clone , Debug , Default , PartialEq , graphene_hash :: CacheHash , DynAny , serde:: Serialize , serde:: Deserialize ) ]
298290pub struct VectorModification {
299291 points : PointModification ,
300292 segments : SegmentModification ,
301293 regions : RegionModification ,
302- add_g1_continuous : HashSet < [ HandleId ; 2 ] > ,
303- remove_g1_continuous : HashSet < [ HandleId ; 2 ] > ,
294+ add_g1_continuous : BTreeSet < [ HandleId ; 2 ] > ,
295+ remove_g1_continuous : BTreeSet < [ HandleId ; 2 ] > ,
304296}
305297
306298/// A modification type that can be added to a [`VectorModification`].
@@ -506,33 +498,70 @@ impl VectorModification {
506498 segments : SegmentModification :: create_from_vector ( vector) ,
507499 regions : RegionModification :: create_from_vector ( vector) ,
508500 add_g1_continuous : vector. colinear_manipulators . iter ( ) . copied ( ) . collect ( ) ,
509- remove_g1_continuous : HashSet :: new ( ) ,
501+ remove_g1_continuous : BTreeSet :: new ( ) ,
510502 }
511503 }
512504}
513505
514- impl Hash for VectorModification {
515- fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
516- generate_uuid ( ) . hash ( state)
506+ // Deserializes a BTreeMap from either a sequence of tuples (old document format) or a standard map.
507+ // TODO: Eventually remove this document upgrade code (the sequence-of-tuples path)
508+ use serde:: de:: { MapAccess , SeqAccess , Visitor } ;
509+ use serde:: ser:: SerializeSeq ;
510+ use serde:: { Deserialize , Deserializer , Serialize , Serializer } ;
511+ use std:: fmt;
512+ use std:: hash:: { BuildHasher , Hash } ;
513+ fn deserialize_btreemap < ' de , K , V , D > ( deserializer : D ) -> Result < BTreeMap < K , V > , D :: Error >
514+ where
515+ K : Deserialize < ' de > + Ord ,
516+ V : Deserialize < ' de > ,
517+ D : Deserializer < ' de > ,
518+ {
519+ struct BTreeMapVisitor < K , V > {
520+ marker : std:: marker:: PhantomData < fn ( ) -> BTreeMap < K , V > > ,
517521 }
518- }
519522
520- // Intentionally non-deterministic: fields contain HashMaps with non-deterministic iteration order,
521- // so we use a UUID to always bust the cache and force re-evaluation when any modification is present
522- impl graphene_hash:: CacheHash for VectorModification {
523- fn cache_hash < H : core:: hash:: Hasher > ( & self , state : & mut H ) {
524- core:: hash:: Hash :: hash ( & generate_uuid ( ) , state) ;
523+ impl < ' de , K , V > Visitor < ' de > for BTreeMapVisitor < K , V >
524+ where
525+ K : Deserialize < ' de > + Ord ,
526+ V : Deserialize < ' de > ,
527+ {
528+ type Value = BTreeMap < K , V > ;
529+
530+ fn expecting ( & self , formatter : & mut fmt:: Formatter ) -> fmt:: Result {
531+ formatter. write_str ( "a map or a sequence of key-value tuples" )
532+ }
533+
534+ // Old document format: serialized as a sequence of (key, value) tuples
535+ fn visit_seq < A > ( self , mut seq : A ) -> Result < Self :: Value , A :: Error >
536+ where
537+ A : SeqAccess < ' de > ,
538+ {
539+ let mut map = BTreeMap :: new ( ) ;
540+ while let Some ( ( key, value) ) = seq. next_element ( ) ? {
541+ map. insert ( key, value) ;
542+ }
543+ Ok ( map)
544+ }
545+
546+ // New format: standard map serialization from BTreeMap
547+ fn visit_map < A > ( self , mut map_access : A ) -> Result < Self :: Value , A :: Error >
548+ where
549+ A : MapAccess < ' de > ,
550+ {
551+ let mut map = BTreeMap :: new ( ) ;
552+ while let Some ( ( key, value) ) = map_access. next_entry ( ) ? {
553+ map. insert ( key, value) ;
554+ }
555+ Ok ( map)
556+ }
525557 }
558+
559+ deserializer. deserialize_any ( BTreeMapVisitor { marker : std:: marker:: PhantomData } )
526560}
527561
528- // Do we want to enforce that all serialized/deserialized hashmaps are a vec of tuples?
529- // TODO: Eventually remove this document upgrade code
530- use serde:: de:: { SeqAccess , Visitor } ;
531- use serde:: ser:: SerializeSeq ;
532- use serde:: { Deserialize , Deserializer , Serialize , Serializer } ;
533- use std:: fmt;
534- use std:: hash:: Hash ;
535- pub fn serialize_hashmap < K , V , S , H > ( hashmap : & HashMap < K , V , H > , serializer : S ) -> Result < S :: Ok , S :: Error >
562+ // Serializes a HashMap as a sequence of (key, value) tuples for stable document serialization.
563+ // Used externally by graph-craft and the editor for HashMap fields in serialized documents.
564+ pub fn serialize_hashmap < K , V , S , H > ( hashmap : & std:: collections:: HashMap < K , V , H > , serializer : S ) -> Result < S :: Ok , S :: Error >
536565where
537566 K : Serialize + Eq + Hash ,
538567 V : Serialize ,
@@ -546,7 +575,7 @@ where
546575 seq. end ( )
547576}
548577
549- pub fn deserialize_hashmap < ' de , K , V , D , H > ( deserializer : D ) -> Result < HashMap < K , V , H > , D :: Error >
578+ pub fn deserialize_hashmap < ' de , K , V , D , H > ( deserializer : D ) -> Result < std :: collections :: HashMap < K , V , H > , D :: Error >
550579where
551580 K : Deserialize < ' de > + Eq + Hash ,
552581 V : Deserialize < ' de > ,
@@ -555,7 +584,7 @@ where
555584{
556585 struct HashMapVisitor < K , V , H > {
557586 #[ allow( clippy:: type_complexity) ]
558- marker : std:: marker:: PhantomData < fn ( ) -> HashMap < K , V , H > > ,
587+ marker : std:: marker:: PhantomData < fn ( ) -> std :: collections :: HashMap < K , V , H > > ,
559588 }
560589
561590 impl < ' de , K , V , H > Visitor < ' de > for HashMapVisitor < K , V , H >
@@ -564,7 +593,7 @@ where
564593 V : Deserialize < ' de > ,
565594 H : BuildHasher + Default ,
566595 {
567- type Value = HashMap < K , V , H > ;
596+ type Value = std :: collections :: HashMap < K , V , H > ;
568597
569598 fn expecting ( & self , formatter : & mut fmt:: Formatter ) -> fmt:: Result {
570599 formatter. write_str ( "a sequence of tuples" )
@@ -574,7 +603,7 @@ where
574603 where
575604 A : SeqAccess < ' de > ,
576605 {
577- let mut hashmap = HashMap :: default ( ) ;
606+ let mut hashmap = std :: collections :: HashMap :: default ( ) ;
578607 while let Some ( ( key, value) ) = seq. next_element ( ) ? {
579608 hashmap. insert ( key, value) ;
580609 }
0 commit comments