templater: cache immutable revset fn globally

Since we have two separate "immutable" calls in the builtin node template, and
user might add a few more to their text template, it seems reasonable to cache
the containing_fn globally.
This commit is contained in:
Yuya Nishihara 2024-04-18 23:11:47 +09:00
parent 8bb92fa6fa
commit 556747ad8c

View File

@ -59,7 +59,7 @@ pub struct CommitTemplateLanguage<'repo> {
revset_parse_context: RevsetParseContext<'repo>, revset_parse_context: RevsetParseContext<'repo>,
id_prefix_context: &'repo IdPrefixContext, id_prefix_context: &'repo IdPrefixContext,
build_fn_table: CommitTemplateBuildFnTable<'repo>, build_fn_table: CommitTemplateBuildFnTable<'repo>,
keyword_cache: CommitKeywordCache, keyword_cache: CommitKeywordCache<'repo>,
cache_extensions: ExtensionsMap, cache_extensions: ExtensionsMap,
} }
@ -191,7 +191,7 @@ impl<'repo> CommitTemplateLanguage<'repo> {
&self.workspace_id &self.workspace_id
} }
pub fn keyword_cache(&self) -> &CommitKeywordCache { pub fn keyword_cache(&self) -> &CommitKeywordCache<'repo> {
&self.keyword_cache &self.keyword_cache
} }
@ -377,15 +377,16 @@ impl<'repo> CommitTemplateBuildFnTable<'repo> {
} }
} }
#[derive(Debug, Default)] #[derive(Default)]
pub struct CommitKeywordCache { pub struct CommitKeywordCache<'repo> {
// Build index lazily, and Rc to get away from &self lifetime. // Build index lazily, and Rc to get away from &self lifetime.
branches_index: OnceCell<Rc<RefNamesIndex>>, branches_index: OnceCell<Rc<RefNamesIndex>>,
tags_index: OnceCell<Rc<RefNamesIndex>>, tags_index: OnceCell<Rc<RefNamesIndex>>,
git_refs_index: OnceCell<Rc<RefNamesIndex>>, git_refs_index: OnceCell<Rc<RefNamesIndex>>,
is_immutable_fn: OnceCell<Rc<RevsetContainingFn<'repo>>>,
} }
impl CommitKeywordCache { impl<'repo> CommitKeywordCache<'repo> {
pub fn branches_index(&self, repo: &dyn Repo) -> &Rc<RefNamesIndex> { pub fn branches_index(&self, repo: &dyn Repo) -> &Rc<RefNamesIndex> {
self.branches_index self.branches_index
.get_or_init(|| Rc::new(build_branches_index(repo))) .get_or_init(|| Rc::new(build_branches_index(repo)))
@ -400,6 +401,17 @@ impl CommitKeywordCache {
self.git_refs_index self.git_refs_index
.get_or_init(|| Rc::new(build_ref_names_index(repo.view().git_refs()))) .get_or_init(|| Rc::new(build_ref_names_index(repo.view().git_refs())))
} }
pub fn is_immutable_fn(
&self,
language: &CommitTemplateLanguage<'repo>,
span: pest::Span<'_>,
) -> TemplateParseResult<&Rc<RevsetContainingFn<'repo>>> {
self.is_immutable_fn.get_or_try_init(|| {
let revset = evaluate_immutable_revset(language, span)?;
Ok(revset.containing_fn().into())
})
}
} }
fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Commit> { fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Commit> {
@ -583,8 +595,10 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
"immutable", "immutable",
|language, _build_ctx, self_property, function| { |language, _build_ctx, self_property, function| {
template_parser::expect_no_arguments(function)?; template_parser::expect_no_arguments(function)?;
let revset = evaluate_immutable_revset(language, function.name_span)?; let is_immutable = language
let is_immutable = revset.containing_fn(); .keyword_cache
.is_immutable_fn(language, function.name_span)?
.clone();
let out_property = self_property.map(move |commit| is_immutable(commit.id())); let out_property = self_property.map(move |commit| is_immutable(commit.id()));
Ok(L::wrap_boolean(out_property)) Ok(L::wrap_boolean(out_property))
}, },
@ -633,6 +647,8 @@ fn extract_working_copies(repo: &dyn Repo, commit: &Commit) -> String {
names.join(" ") names.join(" ")
} }
type RevsetContainingFn<'repo> = dyn Fn(&CommitId) -> bool + 'repo;
fn evaluate_immutable_revset<'repo>( fn evaluate_immutable_revset<'repo>(
language: &CommitTemplateLanguage<'repo>, language: &CommitTemplateLanguage<'repo>,
span: pest::Span<'_>, span: pest::Span<'_>,