1
1
use databake:: { quote, Bake } ;
2
+ use twox_hash:: XxHash64 ;
2
3
use std:: {
4
+ collections:: { BTreeMap , BTreeSet , HashMap } ,
3
5
fs:: { self , File } ,
6
+ hash:: { Hash , Hasher } ,
4
7
io:: { self , BufWriter , Write } ,
5
8
path:: Path ,
6
9
} ;
7
- use temporal_provider:: { tzif:: ZoneInfoProvider , IanaIdentifierNormalizer } ;
10
+ use temporal_provider:: {
11
+ tzif:: { ZeroTzifULE , ZoneInfoProvider } ,
12
+ IanaIdentifierNormalizer ,
13
+ } ;
8
14
9
15
trait BakedDataProvider {
10
16
fn write_data ( & self , data_path : & Path ) -> io:: Result < ( ) > ;
@@ -20,7 +26,7 @@ impl BakedDataProvider for ZoneInfoProvider<'_> {
20
26
21
27
let baked_macro = quote ! {
22
28
#[ macro_export]
23
- macro_rules! zone_info_provider {
29
+ macro_rules! zone_info_provider_baked {
24
30
( ) => {
25
31
pub const ZONE_INFO_PROVIDER : & ' static temporal_provider:: ZoneInfoProvider = & #baked;
26
32
}
@@ -41,26 +47,59 @@ impl BakedDataProvider for ZoneInfoProvider<'_> {
41
47
// Recreate directory.
42
48
fs:: create_dir_all ( zoneinfo_debug_path. clone ( ) ) ?;
43
49
50
+ let map_file = zoneinfo_debug_path. join ( "map.json" ) ;
51
+
52
+ // Create id sets for the tzifs
53
+ let mut tzif_ids: HashMap < usize , BTreeSet < String > > = HashMap :: new ( ) ;
44
54
for ( identifier, index) in self . ids . to_btreemap ( ) . iter ( ) {
45
- let ( directory, filename) = if identifier. contains ( '/' ) {
46
- let ( directory, filename) = identifier. rsplit_once ( '/' ) . expect ( "'/' must exist" ) ;
47
- let identifier_dir = zoneinfo_debug_path. join ( directory) ;
48
- fs:: create_dir_all ( identifier_dir. clone ( ) ) ?;
49
- ( identifier_dir, filename)
55
+ if let Some ( id_set) = tzif_ids. get_mut ( index) {
56
+ id_set. insert ( identifier. clone ( ) ) ;
50
57
} else {
51
- ( zoneinfo_debug_path. clone ( ) , identifier. as_str ( ) )
52
- } ;
53
- let mut filepath = directory. join ( filename) ;
54
- filepath. set_extension ( "json" ) ;
55
- let json = serde_json:: to_string_pretty ( & self . tzifs [ * index] ) ?;
56
- fs:: write ( filepath, json) ?;
58
+ tzif_ids. insert ( * index, BTreeSet :: from ( [ identifier. clone ( ) ] ) ) ;
59
+ }
60
+ }
61
+
62
+ let tzif_dir_path = zoneinfo_debug_path. join ( "tzifs" ) ;
63
+ fs:: create_dir_all ( tzif_dir_path. clone ( ) ) ?;
64
+
65
+ let mut id_map: BTreeMap < String , String > = BTreeMap :: new ( ) ;
66
+ for ( id, tzif) in self . tzifs . iter ( ) . enumerate ( ) {
67
+ let mut tzif_data = serde_json:: Map :: new ( ) ;
68
+ let id_set = tzif_ids. get ( & id) . unwrap ( ) ;
69
+ tzif_data. insert ( "ids" . into ( ) , serde_json:: to_value ( id_set) ?) ;
70
+ tzif_data. insert ( "tzif" . into ( ) , serde_json:: to_value ( & tzif) ?) ;
71
+ let filename = format ! ( "tzif-{}-{}.json" , hash_ids( id_set) , hash_tzif( & tzif) ) ;
72
+ let filepath = tzif_dir_path. join ( filename. clone ( ) ) ;
73
+ for id in id_set {
74
+ id_map. insert ( id. clone ( ) , filename. clone ( ) ) ;
75
+ }
76
+ fs:: write ( filepath, serde_json:: to_string_pretty ( & tzif_data) ?) ?;
57
77
}
58
78
79
+ fs:: write (
80
+ map_file,
81
+ format ! ( "{}\n " , serde_json:: to_string_pretty( & id_map) ?) ,
82
+ ) ?;
83
+
59
84
// TODO: Add version
60
85
Ok ( ( ) )
61
86
}
62
87
}
63
88
89
+ fn hash_ids ( set : & BTreeSet < String > ) -> String {
90
+ let mut hasher = XxHash64 :: default ( ) ;
91
+ set. hash ( & mut hasher) ;
92
+ format ! ( "{:x}" , hasher. finish( ) )
93
+ }
94
+
95
+ fn hash_tzif ( tzif : & ZeroTzifULE ) -> String {
96
+ let mut hasher = XxHash64 :: default ( ) ;
97
+ tzif. transitions ( ) . as_bytes ( ) . hash ( & mut hasher) ;
98
+ tzif. types ( ) . as_bytes ( ) . hash ( & mut hasher) ;
99
+ tzif. posix ( ) . as_bytes ( ) . hash ( & mut hasher) ;
100
+ format ! ( "{:x}" , hasher. finish( ) )
101
+ }
102
+
64
103
impl BakedDataProvider for IanaIdentifierNormalizer < ' _ > {
65
104
fn write_data ( & self , data_path : & Path ) -> io:: Result < ( ) > {
66
105
fs:: create_dir_all ( data_path) ?;
0 commit comments