@@ -77,12 +77,12 @@ fn convert_bad_chars(name: &str) -> String {
7777// The timezone file contains impls of `Timespans` for all timezones in the 
7878// database. The `Wrap` wrapper in the `timezone_impl` module then implements 
7979// TimeZone for any contained struct that implements `Timespans`. 
80- fn  write_timezone_file ( timezone_file :   & mut   File ,   table :   & Table ,   uncased :   bool )  -> io :: Result < ( ) >   { 
81-     let  zones = table 
82-          . zonesets 
83-          . keys ( ) 
84-          . chain ( table . links . keys ( ) ) 
85-          . collect :: < BTreeSet < _ > > ( ) ; 
80+ fn  write_timezone_file ( 
81+     timezone_file :   & mut   File , 
82+     table :   & Table , 
83+     zones :   & BTreeSet < & str > , 
84+     uncased :   bool , 
85+ )  -> io :: Result < ( ) >   { 
8686    writeln ! ( 
8787        timezone_file, 
8888        "use core::fmt::{{self, Debug, Display, Formatter}};" , 
@@ -106,14 +106,14 @@ fn write_timezone_file(timezone_file: &mut File, table: &Table, uncased: bool) -
106106        r#"#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]"# 
107107    ) ?; 
108108    writeln ! ( timezone_file,  "pub enum Tz {{" ) ?; 
109-     for  zone in  & zones { 
109+     for  & zone in  zones { 
110110        let  zone_name = convert_bad_chars ( zone) ; 
111111        writeln ! ( timezone_file,  "    /// {zone}\n     {zone_name}," ) ?; 
112112    } 
113113    writeln ! ( timezone_file,  "}}" ) ?; 
114114
115115    let  mut  map = phf_codegen:: Map :: new ( ) ; 
116-     for  zone in  & zones { 
116+     for  & zone in  zones { 
117117        map. entry ( zone,  format ! ( "Tz::{}" ,  convert_bad_chars( zone) ) ) ; 
118118    } 
119119    writeln ! ( 
@@ -126,7 +126,7 @@ fn write_timezone_file(timezone_file: &mut File, table: &Table, uncased: bool) -
126126    if  uncased { 
127127        writeln ! ( timezone_file,  "use uncased::UncasedStr;\n " , ) ?; 
128128        let  mut  map = phf_codegen:: Map :: new ( ) ; 
129-         for  zone in  & zones { 
129+         for  & zone in  zones { 
130130            map. entry ( 
131131                uncased:: UncasedStr :: new ( zone) , 
132132                format ! ( "Tz::{}" ,  convert_bad_chars( zone) ) , 
@@ -168,7 +168,7 @@ impl FromStr for Tz {{
168168    pub fn name(self) -> &'static str {{ 
169169        match self {{" 
170170    ) ?; 
171-     for  zone in  & zones { 
171+     for  & zone in  zones { 
172172        let  zone_name = convert_bad_chars ( zone) ; 
173173        writeln ! ( timezone_file,  "            Tz::{zone_name} => \" {zone}\" ," ) ?; 
174174    } 
@@ -213,10 +213,11 @@ impl FromStr for Tz {{
213213        "impl TimeSpans for Tz {{ 
214214    fn timespans(&self) -> FixedTimespanSet {{" 
215215    ) ?; 
216-     for  zone in  & zones { 
217-         if  table. links . get ( zone. as_str ( ) ) . is_some ( )  { 
218-             continue ; 
219-         } 
216+     for  zone in  zones
217+         . iter ( ) 
218+         . map ( |& z| table. links . get ( z) . map ( String :: as_str) . unwrap_or ( z) ) 
219+         . collect :: < BTreeSet < _ > > ( ) 
220+     { 
220221        let  zone_name = convert_bad_chars ( zone) ; 
221222        let  timespans = table. timespans ( zone) . unwrap ( ) ; 
222223        writeln ! ( 
@@ -240,9 +241,9 @@ impl FromStr for Tz {{
240241" 
241242    ) ?; 
242243
243-     for  zone in  & zones { 
244+     for  & zone in  zones { 
244245        let  zone_name = convert_bad_chars ( zone) ; 
245-         let  target_name = if  let  Some ( target)  = table. links . get ( zone. as_str ( ) )  { 
246+         let  target_name = if  let  Some ( target)  = table. links . get ( zone)  { 
246247            convert_bad_chars ( target) 
247248        }  else  { 
248249            zone_name. clone ( ) 
@@ -273,7 +274,7 @@ pub static TZ_VARIANTS: [Tz; {num}] = [
273274" , 
274275        num = zones. len( ) 
275276    ) ?; 
276-     for  zone in  & zones { 
277+     for  & zone in  zones { 
277278        writeln ! ( 
278279            timezone_file, 
279280            "    Tz::{zone}," , 
@@ -286,29 +287,30 @@ pub static TZ_VARIANTS: [Tz; {num}] = [
286287
287288// Create a file containing nice-looking re-exports such as Europe::London 
288289// instead of having to use chrono_tz::timezones::Europe__London 
289- fn  write_directory_file ( directory_file :  & mut  File ,  table :  & Table ,  version :  & str )  -> io:: Result < ( ) >  { 
290+ fn  write_directory_file ( 
291+     directory_file :  & mut  File , 
292+     table :  & Table , 
293+     zones :  & BTreeSet < & str > , 
294+     version :  & str , 
295+ )  -> io:: Result < ( ) >  { 
296+     writeln ! ( directory_file,  "use crate::timezones::Tz;\n " ) ?; 
297+ 
290298    // expose the underlying IANA TZDB version 
291299    writeln ! ( 
292300        directory_file, 
293301        "pub const IANA_TZDB_VERSION: &str = \" {version}\" ;\n " 
294302    ) ?; 
303+ 
295304    // add the `loose' zone definitions first 
296-     writeln ! ( directory_file,  "use crate::timezones::Tz;\n " ) ?; 
297-     let  zones = table
298-         . zonesets 
299-         . keys ( ) 
300-         . chain ( table. links . keys ( ) ) 
301-         . filter ( |zone| !zone. contains ( '/' ) ) 
302-         . collect :: < BTreeSet < _ > > ( ) ; 
303-     for  zone in  zones { 
305+     for  & zone in  zones. iter ( ) . filter ( |zone| !zone. contains ( '/' ) )  { 
304306        let  zone = convert_bad_chars ( zone) ; 
305307        writeln ! ( directory_file,  "pub const {zone}: Tz = Tz::{zone};" ) ?; 
306308    } 
307309    writeln ! ( directory_file) ?; 
308310
309311    // now add the `structured' zone names in submodules 
310312    let  mut  first = true ; 
311-     for  entry in  table . structure ( )  { 
313+     for  entry in  parse_zoneinfo :: structure:: build_tree ( zones . iter ( ) . copied ( ) )  { 
312314        if  entry. name . contains ( '/' )  { 
313315            continue ; 
314316        } 
@@ -320,7 +322,7 @@ fn write_directory_file(directory_file: &mut File, table: &Table, version: &str)
320322
321323        let  module_name = convert_bad_chars ( entry. name ) ; 
322324        writeln ! ( directory_file,  "pub mod {module_name} {{" ) ?; 
323-         writeln ! ( directory_file,  "    use crate::timezones::Tz ;\n " , ) ?; 
325+         writeln ! ( directory_file,  "    use super::* ;\n " , ) ?; 
324326        for  child in  entry. children  { 
325327            let  name = match  child { 
326328                Child :: Submodule ( name)  => name, 
@@ -365,112 +367,28 @@ fn write_directory_file(directory_file: &mut File, table: &Table, version: &str)
365367    Ok ( ( ) ) 
366368} 
367369
368- /// Module containing code supporting filter-by-regex feature  
369- /// 
370- /// The "GMT" and "UTC" time zones are always included . 
370+ /// Checks the `CHRONO_TZ_TIMEZONE_FILTER` environment variable.  
371+ /// Converts it to a regex if set. Panics if the regex is not valid, as we want  
372+ /// to fail the build if that happens . 
371373#[ cfg( feature = "filter-by-regex" ) ]  
372- mod  filter { 
373-     use  std:: collections:: HashSet ; 
374-     use  std:: env; 
375- 
376-     use  regex:: Regex ; 
377- 
378-     use  crate :: { Table ,  FILTER_ENV_VAR_NAME } ; 
379- 
380-     /// Filter `table` by applying [`FILTER_ENV_VAR_NAME`]. 
381- pub ( crate )  fn  maybe_filter_timezone_table ( table :  & mut  Table )  { 
382-         if  let  Some ( filter_regex)  = get_filter_regex ( )  { 
383-             filter_timezone_table ( table,  filter_regex) ; 
384-         } 
385-     } 
386- 
387-     /// Checks the `CHRONO_TZ_TIMEZONE_FILTER` environment variable. 
388- /// Converts it to a regex if set. Panics if the regex is not valid, as we want 
389- /// to fail the build if that happens. 
390- fn  get_filter_regex ( )  -> Option < Regex >  { 
391-         match  env:: var ( FILTER_ENV_VAR_NAME )  { 
392-             Ok ( val)  => { 
393-                 let  val = val. trim ( ) ; 
394-                 if  val. is_empty ( )  { 
395-                     return  None ; 
396-                 } 
397-                 match  Regex :: new ( val)  { 
374+ fn  get_filter_regex ( )  -> Option < regex:: Regex >  { 
375+     match  std:: env:: var ( FILTER_ENV_VAR_NAME )  { 
376+         Ok ( val)  => { 
377+             let  val = val. trim ( ) ; 
378+             if  val. is_empty ( )  { 
379+                 return  None ; 
380+             } 
381+             match  regex:: Regex :: new ( val)  { 
398382                    Ok ( regex)  => Some ( regex) , 
399383                    Err ( err)  => panic ! ( 
400384                        "The value '{val:?}' for environment variable {FILTER_ENV_VAR_NAME} is not a valid regex, err={err}" 
401385                    ) , 
402386                } 
403-             } 
404-             Err ( env:: VarError :: NotPresent )  => None , 
405-             Err ( env:: VarError :: NotUnicode ( s) )  => panic ! ( 
406-                 "The value '{s:?}' for environment variable {FILTER_ENV_VAR_NAME} is not valid Unicode" 
407-             ) , 
408-         } 
409-     } 
410- 
411-     /// Insert a new name in the list of names to keep. If the name has 3 
412- /// parts, then also insert the 2-part prefix. If we don't do this we will lose 
413- /// half of Indiana in `directory.rs`. But we *don't* want to keep one-part names, 
414- /// otherwise we will inevitably end up with 'America' and include too much as 
415- /// a consequence. 
416- fn  insert_keep_entry ( keep :  & mut  HashSet < String > ,  new_value :  & str )  { 
417-         let  mut  parts = new_value. split ( '/' ) ; 
418-         if  let  ( Some ( p1) ,  Some ( p2) ,  Some ( _) ,  None )  =
419-             ( parts. next ( ) ,  parts. next ( ) ,  parts. next ( ) ,  parts. next ( ) ) 
420-         { 
421-             keep. insert ( format ! ( "{p1}/{p2}" ) ) ; 
422-         } 
423- 
424-         keep. insert ( new_value. to_string ( ) ) ; 
425-     } 
426- 
427-     /// Filter `table` by applying `filter_regex`. 
428- fn  filter_timezone_table ( table :  & mut  Table ,  filter_regex :  Regex )  { 
429-         // Compute the transitive closure of things to keep. 
430-         // Doing this, instead of just filtering `zonesets` and `links` by the 
431-         // regex, helps to keep the `structure()` intact. 
432-         let  mut  keep = HashSet :: new ( ) ; 
433-         for  ( k,  v)  in  & table. links  { 
434-             if  filter_regex. is_match ( k)  || k == "GMT"  || k == "UTC"  { 
435-                 insert_keep_entry ( & mut  keep,  k) ; 
436-             } 
437-             if  filter_regex. is_match ( v)  || k == "GMT"  || k == "UTC"  { 
438-                 insert_keep_entry ( & mut  keep,  v) ; 
439-             } 
440-         } 
441- 
442-         let  mut  n = 0 ; 
443-         loop  { 
444-             let  len = keep. len ( ) ; 
445- 
446-             for  ( k,  v)  in  & table. links  { 
447-                 if  keep. contains ( k)  && !keep. contains ( v)  { 
448-                     insert_keep_entry ( & mut  keep,  v) ; 
449-                 } 
450-                 if  keep. contains ( v)  && !keep. contains ( k)  { 
451-                     insert_keep_entry ( & mut  keep,  k) ; 
452-                 } 
453-             } 
454- 
455-             if  keep. len ( )  == len { 
456-                 break ; 
457-             } 
458- 
459-             n += 1 ; 
460-             if  n == 50  { 
461-                 println ! ( "cargo:warning=Recursion limit reached while building filter list" ) ; 
462-                 break ; 
463-             } 
464387        } 
465- 
466-         // Actually do the filtering. 
467-         table
468-             . links 
469-             . retain ( |k,  v| keep. contains ( k)  || keep. contains ( v) ) ; 
470- 
471-         table
472-             . zonesets 
473-             . retain ( |k,  _| filter_regex. is_match ( k)  || keep. iter ( ) . any ( |s| k. starts_with ( s) ) ) ; 
388+         Err ( env:: VarError :: NotPresent )  => None , 
389+         Err ( env:: VarError :: NotUnicode ( s) )  => panic ! ( 
390+             "The value '{s:?}' for environment variable {FILTER_ENV_VAR_NAME} is not valid Unicode" 
391+         ) , 
474392    } 
475393} 
476394
@@ -495,7 +413,7 @@ fn detect_iana_db_version() -> String {
495413    unreachable ! ( "no version found" ) 
496414} 
497415
498- pub  fn  main ( dir :  & Path ,  _filter :  bool ,  _uncased :  bool )  { 
416+ pub  fn  main ( dir :  & Path ,  _filter :  bool ,  uncased :  bool )  { 
499417    let  mut  table = TableBuilder :: new ( ) ; 
500418
501419    let  root = PathBuf :: from ( env:: var ( "CARGO_MANIFEST_DIR" ) . unwrap_or_else ( |_| String :: new ( ) ) ) ; 
@@ -509,19 +427,29 @@ pub fn main(dir: &Path, _filter: bool, _uncased: bool) {
509427        } 
510428    } 
511429
512-     # [ allow ( unused_mut ) ] 
513-      let   mut  table = table . build ( ) ; 
430+     let  table = table . build ( ) ; 
431+ 
514432    #[ cfg( feature = "filter-by-regex" ) ]  
515-     if  _filter { 
516-         filter:: maybe_filter_timezone_table ( & mut  table) ; 
517-     } 
433+     let  regex = _filter. then ( get_filter_regex) . flatten ( ) ; 
434+     #[ cfg( feature = "filter-by-regex" ) ]  
435+     let  filter = |tz :  & str | regex. as_ref ( ) . is_none_or ( |r| r. is_match ( tz) ) ; 
436+     #[ cfg( not( feature = "filter-by-regex" ) ) ]  
437+     let  filter = |_:  & str | true ; 
438+ 
439+     let  zones = table
440+         . zonesets 
441+         . keys ( ) 
442+         . chain ( table. links . keys ( ) ) 
443+         . filter ( |s| filter ( s) ) 
444+         . map ( String :: as_str) 
445+         . collect :: < BTreeSet < _ > > ( ) ; 
518446
519447    let  timezone_path = dir. join ( "timezones.rs" ) ; 
520448    let  mut  timezone_file = File :: create ( timezone_path) . unwrap ( ) ; 
521-     write_timezone_file ( & mut  timezone_file,  & table,  _uncased ) . unwrap ( ) ; 
449+     write_timezone_file ( & mut  timezone_file,  & table,  & zones ,  uncased ) . unwrap ( ) ; 
522450
523451    let  directory_path = dir. join ( "directory.rs" ) ; 
524452    let  mut  directory_file = File :: create ( directory_path) . unwrap ( ) ; 
525453    let  version = detect_iana_db_version ( ) ; 
526-     write_directory_file ( & mut  directory_file,  & table,  & version) . unwrap ( ) ; 
454+     write_directory_file ( & mut  directory_file,  & table,  & zones ,   & version) . unwrap ( ) ; 
527455} 
0 commit comments