From f483d2df42867b757a52a507d79d6606c6d97bfb Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Sun, 5 Nov 2023 02:46:32 +0800 Subject: [PATCH] Lazily compile `GlobMatcher`s --- src/bin/bat/main.rs | 10 ++++++---- src/syntax_mapping.rs | 23 ++++++++++++++--------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/bin/bat/main.rs b/src/bin/bat/main.rs index 110b3741..f48abdc1 100644 --- a/src/bin/bat/main.rs +++ b/src/bin/bat/main.rs @@ -78,9 +78,11 @@ fn run_cache_subcommand( Ok(()) } -fn get_syntax_mapping_to_paths<'a>( - mappings: &[(&GlobMatcher, &MappingTarget<'a>)], -) -> HashMap<&'a str, Vec> { +fn get_syntax_mapping_to_paths<'r, 't, I>(mappings: I) -> HashMap<&'t str, Vec> +where + I: IntoIterator)>, + 't: 'r, // target text outlives rule +{ let mut map = HashMap::new(); for mapping in mappings { if let (matcher, MappingTarget::MapTo(s)) = mapping { @@ -123,7 +125,7 @@ pub fn get_languages(config: &Config, cache_dir: &Path) -> Result { languages.sort_by_key(|lang| lang.name.to_uppercase()); - let configured_languages = get_syntax_mapping_to_paths(&config.syntax_mapping.all_mappings()); + let configured_languages = get_syntax_mapping_to_paths(config.syntax_mapping.all_mappings()); for lang in &mut languages { if let Some(additional_paths) = configured_languages.get(lang.name.as_str()) { diff --git a/src/syntax_mapping.rs b/src/syntax_mapping.rs index 8c02883f..5b0e3c5f 100644 --- a/src/syntax_mapping.rs +++ b/src/syntax_mapping.rs @@ -56,30 +56,35 @@ impl<'a> SyntaxMapping<'a> { Ok(()) } - /// Returns all mappings. User-defined mappings are listed before builtin - /// mappings; mappings in front have higher precedence. + /// Returns an iterator over all mappings. User-defined mappings are listed + /// before builtin mappings; mappings in front have higher precedence. + /// + /// Builtin mappings' `GlobMatcher`s are lazily compiled. /// /// Note that this function ignores builtin mappings that are invalid under /// the current environment (i.e. their rules require an environment /// variable that is unset). - pub fn all_mappings(&self) -> Vec<(&GlobMatcher, &MappingTarget<'a>)> { + pub fn all_mappings(&self) -> impl Iterator)> { self.custom_mappings() .iter() .map(|(matcher, target)| (matcher, target)) // as_ref .chain(self.builtin_mappings()) - .collect() } - /// Returns all valid builtin mappings. Mappings in front have higher - /// precedence. + // IMPRV: ideally `Item` should be `(&'static GlobMatcher, &'static MappingTarget<'static>)` + // but `Iterator::chain` (used in `SyntaxMapping::all_mappings`) asserts `Item = Self::Item` + // so we need a lifetime downcast, which I'm not sure how to perform + /// Returns an iterator over all valid builtin mappings. Mappings in front + /// have higher precedence. + /// + /// The `GlabMatcher`s are lazily compiled. /// /// If a mapping rule requires an environment variable that is unset, it /// will be ignored. - pub fn builtin_mappings(&self) -> Vec<(&'static GlobMatcher, &'static MappingTarget<'static>)> { + pub fn builtin_mappings(&self) -> impl Iterator)> { BUILTIN_MAPPINGS .iter() .filter_map(|(matcher, target)| matcher.as_ref().map(|glob| (glob, target))) - .collect() } /// Returns all user-defined mappings. @@ -91,7 +96,7 @@ impl<'a> SyntaxMapping<'a> { // Try matching on the file name as-is. let candidate = Candidate::new(&path); let candidate_filename = path.as_ref().file_name().map(Candidate::new); - for (glob, syntax) in self.all_mappings().into_iter() { + for (glob, syntax) in self.all_mappings() { if glob.is_match_candidate(&candidate) || candidate_filename .as_ref()