@@ -111,7 +111,7 @@ impl Assets {
111111 AssetOrigin :: Copy ( src_path) => syntax:: AssetOrigin :: Copy ( src_path) ,
112112 AssetOrigin :: FontCss => syntax:: AssetOrigin :: FontCss ( css_data. clone ( ) ) ,
113113 } ;
114- assets. insert ( dest_path, info) ;
114+ assets. 0 . insert ( dest_path, info) ;
115115 }
116116
117117 assets
@@ -247,8 +247,8 @@ impl AssetSpecification {
247247
248248 use syntax:: AssetOrigin as AO ;
249249
250- for ( path, new_origin) in & new {
251- if let Some ( cur_origin) = self . 0 . get_mut ( path) {
250+ for ( path, new_origin) in & new. 0 {
251+ if let Some ( cur_origin) = self . 0 . 0 . get_mut ( path) {
252252 match ( new_origin, cur_origin) {
253253 ( AO :: Copy ( new_src) , AO :: Copy ( cur_src) ) => {
254254 if cur_src != new_src {
@@ -288,7 +288,7 @@ impl AssetSpecification {
288288
289289 ( AO :: FontCss ( new_fe) , AO :: FontCss ( cur_fe) ) => {
290290 // We have two font ensembles. Try merging.
291- syntax:: merge_font_ensembles ( cur_fe, new_fe) ?;
291+ syntax:: merge_font_ensembles ( & mut cur_fe. 0 , & new_fe. 0 ) ?;
292292 }
293293
294294 ( new2, cur2) => {
@@ -302,7 +302,7 @@ impl AssetSpecification {
302302 }
303303 } else {
304304 // This path is undefined in the current object. Just add it!
305- self . 0 . insert ( path. clone ( ) , new_origin. clone ( ) ) ;
305+ self . 0 . 0 . insert ( path. clone ( ) , new_origin. clone ( ) ) ;
306306 }
307307 }
308308
@@ -324,7 +324,7 @@ impl AssetSpecification {
324324 /// specification.
325325 pub fn output_paths < ' a > ( & ' a self ) -> impl Iterator < Item = Cow < ' a , str > > {
326326 AssetOutputsIterator {
327- iter : self . 0 . iter ( ) ,
327+ iter : self . 0 . 0 . iter ( ) ,
328328 cur_vg_path : None ,
329329 next_vg_index : 0 ,
330330 }
@@ -355,7 +355,7 @@ impl AssetSpecification {
355355 /// the ones this particular session knows about.
356356 pub ( crate ) fn check_runtime_assets ( & self , assets : & mut Assets ) -> Result < ( ) > {
357357 for ( path, run_origin) in & assets. paths {
358- if let Some ( pre_origin) = self . 0 . get ( path) {
358+ if let Some ( pre_origin) = self . 0 . 0 . get ( path) {
359359 match ( run_origin, pre_origin) {
360360 ( AssetOrigin :: Copy ( run_path) , syntax:: AssetOrigin :: Copy ( pre_path) ) => {
361361 ensure ! (
@@ -387,7 +387,7 @@ impl AssetSpecification {
387387
388388 // Now update the runtime assets to include all precomputed ones.
389389
390- for ( path, pre_origin) in & self . 0 {
390+ for ( path, pre_origin) in & self . 0 . 0 {
391391 let mapped = match pre_origin {
392392 syntax:: AssetOrigin :: Copy ( pre_path) => AssetOrigin :: Copy ( pre_path. to_owned ( ) ) ,
393393 syntax:: AssetOrigin :: FontCss ( _) => AssetOrigin :: FontCss ,
@@ -449,11 +449,26 @@ impl<'a> Iterator for AssetOutputsIterator<'a> {
449449///
450450/// The top-level type is Assets.
451451pub ( crate ) mod syntax {
452- use serde:: { Deserialize , Serialize } ;
453- use std:: collections:: HashMap ;
452+ use serde:: { Deserialize , Serialize , Serializer } ;
453+ use std:: collections:: { BTreeMap , HashMap } ;
454454 use tectonic_errors:: prelude:: * ;
455455
456- pub type Assets = HashMap < String , AssetOrigin > ;
456+ /// Annoyingly we need to wrap this hashmap in a struct because we need to
457+ /// customize the serializer to sort the keys for reproducible outputs.
458+ /// Likewise for all other hashmaps in this module.
459+ #[ derive( Clone , Debug , Default , Serialize , Deserialize ) ]
460+ pub struct Assets ( #[ serde( serialize_with = "ordered_map" ) ] pub HashMap < String , AssetOrigin > ) ;
461+
462+ fn ordered_map < K : Ord + Serialize , V : Serialize , S > (
463+ value : & HashMap < K , V > ,
464+ serializer : S ,
465+ ) -> Result < S :: Ok , S :: Error >
466+ where
467+ S : Serializer ,
468+ {
469+ let ordered: BTreeMap < _ , _ > = value. iter ( ) . collect ( ) ;
470+ ordered. serialize ( serializer)
471+ }
457472
458473 #[ derive( Clone , Debug , Deserialize , Serialize ) ]
459474 #[ serde( tag = "kind" ) ]
@@ -480,7 +495,7 @@ pub(crate) mod syntax {
480495
481496 write ! ( f, "CSS for font faces" ) ?;
482497
483- for facename in fe. keys ( ) {
498+ for facename in fe. 0 . keys ( ) {
484499 if first {
485500 write ! ( f, " " ) ?;
486501 first = false ;
@@ -515,6 +530,7 @@ pub(crate) mod syntax {
515530 /// Due to limitations of (serde's) JSON serialization, the keys of this
516531 /// dictionary have to be strings, even though we would like them to be
517532 /// GlyphIds.
533+ #[ serde( serialize_with = "ordered_map" ) ]
518534 pub vglyphs : HashMap < String , GlyphVariantMapping > ,
519535 }
520536
@@ -568,7 +584,10 @@ pub(crate) mod syntax {
568584 }
569585
570586 /// Map from symbolic family name to info about the fonts defining it.
571- pub type FontEnsembleAssetData = HashMap < String , FontFamilyAssetData > ;
587+ #[ derive( Clone , Debug , Default , Deserialize , Serialize ) ]
588+ pub struct FontEnsembleAssetData (
589+ #[ serde( serialize_with = "ordered_map" ) ] pub HashMap < String , FontFamilyAssetData > ,
590+ ) ;
572591
573592 /// Merge one font ensemble (table of font-family definitions) into another.
574593 /// This can fail if the tables are not self-consistent.
@@ -608,10 +627,11 @@ pub(crate) mod syntax {
608627 #[ derive( Clone , Debug , Default , Deserialize , Eq , PartialEq , Serialize ) ]
609628 pub struct FontFamilyAssetData {
610629 /// Map from face type to the output path of the font file providing it.
630+ #[ serde( serialize_with = "ordered_map" ) ]
611631 pub faces : HashMap < FaceType , String > ,
612632 }
613633
614- #[ derive( Clone , Copy , Debug , Deserialize , Eq , Hash , PartialEq , Serialize ) ]
634+ #[ derive( Clone , Copy , Debug , Deserialize , Eq , Hash , Ord , PartialEq , PartialOrd , Serialize ) ]
615635 pub enum FaceType {
616636 /// The regular (upright) font of a font family.
617637 Regular ,
0 commit comments