diff --git a/cli/examples/custom-commit-templater/main.rs b/cli/examples/custom-commit-templater/main.rs index 0452a1b70..ce20d7a64 100644 --- a/cli/examples/custom-commit-templater/main.rs +++ b/cli/examples/custom-commit-templater/main.rs @@ -18,7 +18,7 @@ use jj_cli::commit_templater::{ }; use jj_cli::template_builder::TemplateLanguage; use jj_cli::template_parser::{self, TemplateParseError}; -use jj_cli::templater::{TemplateFunction, TemplatePropertyError}; +use jj_cli::templater::TemplatePropertyExt as _; use jj_lib::backend::CommitId; use jj_lib::commit::Commit; use jj_lib::extensions_map::ExtensionsMap; @@ -39,14 +39,14 @@ fn num_digits_in_id(id: &CommitId) -> i64 { count } -fn num_char_in_id(commit: Commit, ch_match: char) -> Result { +fn num_char_in_id(commit: Commit, ch_match: char) -> i64 { let mut count = 0; for ch in commit.id().hex().chars() { if ch == ch_match { count += 1; } } - Ok(count) + count } struct MostDigitsInId { @@ -85,19 +85,18 @@ impl CommitTemplateLanguageExtension for HexCounter { .cache_extension::() .unwrap() .count(language.repo()); - Ok(L::wrap_boolean(TemplateFunction::new( - property, - move |commit| Ok(num_digits_in_id(commit.id()) == most_digits), - ))) + Ok(L::wrap_boolean(property.map(move |commit| { + num_digits_in_id(commit.id()) == most_digits + }))) }, ); table.commit_methods.insert( "num_digits_in_id", |_language, _build_context, property, call| { template_parser::expect_no_arguments(call)?; - Ok(L::wrap_integer(TemplateFunction::new(property, |commit| { - Ok(num_digits_in_id(commit.id())) - }))) + Ok(L::wrap_integer( + property.map(|commit| num_digits_in_id(commit.id())), + )) }, ); table.commit_methods.insert( @@ -116,10 +115,9 @@ impl CommitTemplateLanguageExtension for HexCounter { } })?; - Ok(L::wrap_integer(TemplateFunction::new( - property, - move |commit| num_char_in_id(commit, char_arg), - ))) + Ok(L::wrap_integer( + property.map(move |commit| num_char_in_id(commit, char_arg)), + )) }, ); diff --git a/cli/examples/custom-operation-templater/main.rs b/cli/examples/custom-operation-templater/main.rs index dcfb57567..562f1efb4 100644 --- a/cli/examples/custom-operation-templater/main.rs +++ b/cli/examples/custom-operation-templater/main.rs @@ -18,7 +18,7 @@ use jj_cli::operation_templater::{ }; use jj_cli::template_builder::TemplateLanguage; use jj_cli::template_parser::{self, TemplateParseError}; -use jj_cli::templater::{TemplateFunction, TemplatePropertyError}; +use jj_cli::templater::TemplatePropertyExt as _; use jj_lib::extensions_map::ExtensionsMap; use jj_lib::object_id::ObjectId; use jj_lib::op_store::OperationId; @@ -36,14 +36,14 @@ fn num_digits_in_id(id: &OperationId) -> i64 { count } -fn num_char_in_id(operation: Operation, ch_match: char) -> Result { +fn num_char_in_id(operation: Operation, ch_match: char) -> i64 { let mut count = 0; for ch in operation.id().hex().chars() { if ch == ch_match { count += 1; } } - Ok(count) + count } impl OperationTemplateLanguageExtension for HexCounter { @@ -54,10 +54,9 @@ impl OperationTemplateLanguageExtension for HexCounter { "num_digits_in_id", |_language, _build_context, property, call| { template_parser::expect_no_arguments(call)?; - Ok(L::wrap_integer(TemplateFunction::new( - property, - |operation| Ok(num_digits_in_id(operation.id())), - ))) + Ok(L::wrap_integer( + property.map(|operation| num_digits_in_id(operation.id())), + )) }, ); table.operation_methods.insert( @@ -76,10 +75,9 @@ impl OperationTemplateLanguageExtension for HexCounter { } })?; - Ok(L::wrap_integer(TemplateFunction::new( - property, - move |operation| num_char_in_id(operation, char_arg), - ))) + Ok(L::wrap_integer( + property.map(move |operation| num_char_in_id(operation, char_arg)), + )) }, ); diff --git a/cli/src/commands/config.rs b/cli/src/commands/config.rs index b7ec77033..b3a0b8145 100644 --- a/cli/src/commands/config.rs +++ b/cli/src/commands/config.rs @@ -26,7 +26,7 @@ use crate::command_error::{user_error, CommandError}; use crate::config::{AnnotatedValue, ConfigSource}; use crate::generic_templater::GenericTemplateLanguage; use crate::template_builder::TemplateLanguage as _; -use crate::templater::{Template as _, TemplateFunction}; +use crate::templater::{Template as _, TemplatePropertyExt as _}; use crate::ui::Ui; #[derive(clap::Args, Clone, Debug)] @@ -191,20 +191,16 @@ fn config_template_language() -> GenericTemplateLanguage<'static, AnnotatedValue let mut language = L::new(); // "name" instead of "path" to avoid confusion with the source file path language.add_keyword("name", |self_property| { - let out_property = - TemplateFunction::new(self_property, |annotated| Ok(annotated.path.join("."))); + let out_property = self_property.map(|annotated| annotated.path.join(".")); Ok(L::wrap_string(out_property)) }); language.add_keyword("value", |self_property| { // TODO: would be nice if we can provide raw dynamically-typed value - let out_property = TemplateFunction::new(self_property, |annotated| { - Ok(serialize_config_value(&annotated.value)) - }); + let out_property = self_property.map(|annotated| serialize_config_value(&annotated.value)); Ok(L::wrap_string(out_property)) }); language.add_keyword("overridden", |self_property| { - let out_property = - TemplateFunction::new(self_property, |annotated| Ok(annotated.is_overridden)); + let out_property = self_property.map(|annotated| annotated.is_overridden); Ok(L::wrap_boolean(out_property)) }); language diff --git a/cli/src/commit_templater.rs b/cli/src/commit_templater.rs index 0a2a69c37..6b5d33b01 100644 --- a/cli/src/commit_templater.rs +++ b/cli/src/commit_templater.rs @@ -38,7 +38,8 @@ use crate::template_builder::{ }; use crate::template_parser::{self, FunctionCallNode, TemplateParseError, TemplateParseResult}; use crate::templater::{ - self, IntoTemplate, PlainTextFormattedProperty, Template, TemplateFunction, TemplateProperty, + self, IntoTemplate, PlainTextFormattedProperty, Template, TemplateProperty, + TemplatePropertyExt as _, }; use crate::{revset_util, text_util}; @@ -236,15 +237,11 @@ impl<'repo> IntoTemplateProperty<'repo> for CommitTemplatePropertyKind<'repo> { CommitTemplatePropertyKind::Core(property) => property.try_into_boolean(), CommitTemplatePropertyKind::Commit(_) => None, CommitTemplatePropertyKind::CommitList(property) => { - Some(Box::new(TemplateFunction::new(property, |l| { - Ok(!l.is_empty()) - }))) + Some(Box::new(property.map(|l| !l.is_empty()))) } CommitTemplatePropertyKind::RefName(_) => None, CommitTemplatePropertyKind::RefNameList(property) => { - Some(Box::new(TemplateFunction::new(property, |l| { - Ok(!l.is_empty()) - }))) + Some(Box::new(property.map(|l| !l.is_empty()))) } CommitTemplatePropertyKind::CommitOrChangeId(_) => None, CommitTemplatePropertyKind::ShortestIdPrefix(_) => None, @@ -377,9 +374,8 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm "description", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |commit| { - Ok(text_util::complete_newline(commit.description())) - }); + let out_property = + self_property.map(|commit| text_util::complete_newline(commit.description())); Ok(L::wrap_string(out_property)) }, ); @@ -387,9 +383,8 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm "change_id", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |commit| { - Ok(CommitOrChangeId::Change(commit.change_id().to_owned())) - }); + let out_property = + self_property.map(|commit| CommitOrChangeId::Change(commit.change_id().to_owned())); Ok(L::wrap_commit_or_change_id(out_property)) }, ); @@ -397,9 +392,8 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm "commit_id", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |commit| { - Ok(CommitOrChangeId::Commit(commit.id().to_owned())) - }); + let out_property = + self_property.map(|commit| CommitOrChangeId::Commit(commit.id().to_owned())); Ok(L::wrap_commit_or_change_id(out_property)) }, ); @@ -407,7 +401,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm "parents", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |commit| Ok(commit.parents())); + let out_property = self_property.map(|commit| commit.parents()); Ok(L::wrap_commit_list(out_property)) }, ); @@ -415,8 +409,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm "author", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = - TemplateFunction::new(self_property, |commit| Ok(commit.author().clone())); + let out_property = self_property.map(|commit| commit.author().clone()); Ok(L::wrap_signature(out_property)) }, ); @@ -424,8 +417,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm "committer", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = - TemplateFunction::new(self_property, |commit| Ok(commit.committer().clone())); + let out_property = self_property.map(|commit| commit.committer().clone()); Ok(L::wrap_signature(out_property)) }, ); @@ -434,9 +426,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm |language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; let repo = language.repo; - let out_property = TemplateFunction::new(self_property, |commit| { - Ok(extract_working_copies(repo, &commit)) - }); + let out_property = self_property.map(|commit| extract_working_copies(repo, &commit)); Ok(L::wrap_string(out_property)) }, ); @@ -446,8 +436,8 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm template_parser::expect_no_arguments(function)?; let repo = language.repo; let workspace_id = language.workspace_id.clone(); - let out_property = TemplateFunction::new(self_property, move |commit| { - Ok(Some(commit.id()) == repo.view().get_wc_commit_id(&workspace_id)) + let out_property = self_property.map(move |commit| { + Some(commit.id()) == repo.view().get_wc_commit_id(&workspace_id) }); Ok(L::wrap_boolean(out_property)) }, @@ -457,13 +447,13 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm |language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; let index = language.keyword_cache.branches_index(language.repo).clone(); - let out_property = TemplateFunction::new(self_property, move |commit| { - Ok(index + let out_property = self_property.map(move |commit| { + index .get(commit.id()) .iter() .filter(|ref_name| ref_name.is_local() || !ref_name.synced) .cloned() - .collect()) + .collect() }); Ok(L::wrap_ref_name_list(out_property)) }, @@ -473,13 +463,13 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm |language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; let index = language.keyword_cache.branches_index(language.repo).clone(); - let out_property = TemplateFunction::new(self_property, move |commit| { - Ok(index + let out_property = self_property.map(move |commit| { + index .get(commit.id()) .iter() .filter(|ref_name| ref_name.is_local()) .cloned() - .collect()) + .collect() }); Ok(L::wrap_ref_name_list(out_property)) }, @@ -489,13 +479,13 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm |language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; let index = language.keyword_cache.branches_index(language.repo).clone(); - let out_property = TemplateFunction::new(self_property, move |commit| { - Ok(index + let out_property = self_property.map(move |commit| { + index .get(commit.id()) .iter() .filter(|ref_name| ref_name.is_remote()) .cloned() - .collect()) + .collect() }); Ok(L::wrap_ref_name_list(out_property)) }, @@ -503,9 +493,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm map.insert("tags", |language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; let index = language.keyword_cache.tags_index(language.repo).clone(); - let out_property = TemplateFunction::new(self_property, move |commit| { - Ok(index.get(commit.id()).to_vec()) - }); + let out_property = self_property.map(move |commit| index.get(commit.id()).to_vec()); Ok(L::wrap_ref_name_list(out_property)) }); map.insert( @@ -513,9 +501,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm |language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; let index = language.keyword_cache.git_refs_index(language.repo).clone(); - let out_property = TemplateFunction::new(self_property, move |commit| { - Ok(index.get(commit.id()).to_vec()) - }); + let out_property = self_property.map(move |commit| index.get(commit.id()).to_vec()); Ok(L::wrap_ref_name_list(out_property)) }, ); @@ -524,8 +510,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm |language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; let repo = language.repo; - let out_property = - TemplateFunction::new(self_property, |commit| Ok(extract_git_head(repo, &commit))); + let out_property = self_property.map(|commit| extract_git_head(repo, &commit)); Ok(L::wrap_ref_name_list(out_property)) }, ); @@ -534,10 +519,10 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm |language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; let repo = language.repo; - let out_property = TemplateFunction::new(self_property, |commit| { + let out_property = self_property.map(|commit| { // The given commit could be hidden in e.g. obslog. let maybe_entries = repo.resolve_change_id(commit.change_id()); - Ok(maybe_entries.map_or(0, |entries| entries.len()) > 1) + maybe_entries.map_or(0, |entries| entries.len()) > 1 }); Ok(L::wrap_boolean(out_property)) }, @@ -545,9 +530,9 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm map.insert("hidden", |language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; let repo = language.repo; - let out_property = TemplateFunction::new(self_property, |commit| { + let out_property = self_property.map(|commit| { let maybe_entries = repo.resolve_change_id(commit.change_id()); - Ok(maybe_entries.map_or(true, |entries| !entries.contains(commit.id()))) + maybe_entries.map_or(true, |entries| !entries.contains(commit.id())) }); Ok(L::wrap_boolean(out_property)) }); @@ -557,8 +542,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm template_parser::expect_no_arguments(function)?; let revset = evaluate_immutable_revset(language, function.name_span)?; let is_immutable = revset.containing_fn(); - let out_property = - TemplateFunction::new(self_property, move |commit| Ok(is_immutable(commit.id()))); + let out_property = self_property.map(move |commit| is_immutable(commit.id())); Ok(L::wrap_boolean(out_property)) }, ); @@ -566,15 +550,14 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm "conflict", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = - TemplateFunction::new(self_property, |commit| Ok(commit.has_conflict()?)); + let out_property = self_property.and_then(|commit| Ok(commit.has_conflict()?)); Ok(L::wrap_boolean(out_property)) }, ); map.insert("empty", |language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; let repo = language.repo; - let out_property = TemplateFunction::new(self_property, |commit| { + let out_property = self_property.and_then(|commit| { if let [parent] = &commit.parents()[..] { return Ok(parent.tree_id() == commit.tree_id()); } @@ -586,9 +569,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm map.insert("root", |language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; let repo = language.repo; - let out_property = TemplateFunction::new(self_property, |commit| { - Ok(commit.id() == repo.store().root_commit_id()) - }); + let out_property = self_property.map(|commit| commit.id() == repo.store().root_commit_id()); Ok(L::wrap_boolean(out_property)) }); map @@ -682,16 +663,14 @@ fn builtin_ref_name_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Re let mut map = CommitTemplateBuildMethodFnMap::::new(); map.insert("name", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |ref_name| Ok(ref_name.name)); + let out_property = self_property.map(|ref_name| ref_name.name); Ok(L::wrap_string(out_property)) }); map.insert( "remote", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |ref_name| { - Ok(ref_name.remote.unwrap_or_default()) - }); + let out_property = self_property.map(|ref_name| ref_name.remote.unwrap_or_default()); Ok(L::wrap_string(out_property)) }, ); @@ -842,9 +821,8 @@ fn builtin_commit_or_change_id_methods<'repo>( let len_property = len_node .map(|node| template_builder::expect_usize_expression(language, build_ctx, node)) .transpose()?; - let out_property = TemplateFunction::new((self_property, len_property), |(id, len)| { - Ok(id.short(len.unwrap_or(12))) - }); + let out_property = + (self_property, len_property).map(|(id, len)| id.short(len.unwrap_or(12))); Ok(L::wrap_string(out_property)) }); map.insert( @@ -855,9 +833,8 @@ fn builtin_commit_or_change_id_methods<'repo>( let len_property = len_node .map(|node| template_builder::expect_usize_expression(language, build_ctx, node)) .transpose()?; - let out_property = TemplateFunction::new((self_property, len_property), |(id, len)| { - Ok(id.shortest(language.repo, id_prefix_context, len.unwrap_or(0))) - }); + let out_property = (self_property, len_property) + .map(|(id, len)| id.shortest(language.repo, id_prefix_context, len.unwrap_or(0))); Ok(L::wrap_shortest_id_prefix(out_property)) }, ); @@ -902,23 +879,23 @@ fn builtin_shortest_id_prefix_methods<'repo>( "prefix", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |id| Ok(id.prefix)); + let out_property = self_property.map(|id| id.prefix); Ok(L::wrap_string(out_property)) }, ); map.insert("rest", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |id| Ok(id.rest)); + let out_property = self_property.map(|id| id.rest); Ok(L::wrap_string(out_property)) }); map.insert("upper", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |id| Ok(id.to_upper())); + let out_property = self_property.map(|id| id.to_upper()); Ok(L::wrap_shortest_id_prefix(out_property)) }); map.insert("lower", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |id| Ok(id.to_lower())); + let out_property = self_property.map(|id| id.to_lower()); Ok(L::wrap_shortest_id_prefix(out_property)) }); map diff --git a/cli/src/generic_templater.rs b/cli/src/generic_templater.rs index 4dae4970c..00026a087 100644 --- a/cli/src/generic_templater.rs +++ b/cli/src/generic_templater.rs @@ -59,7 +59,7 @@ impl<'a, C> GenericTemplateLanguage<'a, C> { /// /// ```ignore /// language.add_keyword("name", |self_property| { - /// let out_property = TemplateFunction::new(self_property, |v| Ok(v.to_string())); + /// let out_property = self_property.map(|v| v.to_string()); /// Ok(GenericTemplateLanguage::wrap_string(out_property)) /// }); /// ``` diff --git a/cli/src/operation_templater.rs b/cli/src/operation_templater.rs index 3ece72880..8bd06b6f6 100644 --- a/cli/src/operation_templater.rs +++ b/cli/src/operation_templater.rs @@ -29,7 +29,7 @@ use crate::template_builder::{ }; use crate::template_parser::{self, FunctionCallNode, TemplateParseResult}; use crate::templater::{ - IntoTemplate, PlainTextFormattedProperty, Template, TemplateFunction, TemplateProperty, + IntoTemplate, PlainTextFormattedProperty, Template, TemplateProperty, TemplatePropertyExt as _, TimestampRange, }; @@ -221,9 +221,7 @@ fn builtin_operation_methods() -> OperationTemplateBuildMethodFnMap { |language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; let current_op_id = language.current_op_id.clone(); - let out_property = TemplateFunction::new(self_property, move |op| { - Ok(Some(op.id()) == current_op_id.as_ref()) - }); + let out_property = self_property.map(move |op| Some(op.id()) == current_op_id.as_ref()); Ok(L::wrap_boolean(out_property)) }, ); @@ -231,56 +229,47 @@ fn builtin_operation_methods() -> OperationTemplateBuildMethodFnMap { "description", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = - TemplateFunction::new(self_property, |op| Ok(op.metadata().description.clone())); + let out_property = self_property.map(|op| op.metadata().description.clone()); Ok(L::wrap_string(out_property)) }, ); map.insert("id", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |op| Ok(op.id().clone())); + let out_property = self_property.map(|op| op.id().clone()); Ok(L::wrap_operation_id(out_property)) }); map.insert("tags", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |op| { + let out_property = self_property.map(|op| { // TODO: introduce map type - Ok(op - .metadata() + op.metadata() .tags .iter() .map(|(key, value)| format!("{key}: {value}")) - .join("\n")) + .join("\n") }); Ok(L::wrap_string(out_property)) }); map.insert("time", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |op| { - Ok(TimestampRange { - start: op.metadata().start_time.clone(), - end: op.metadata().end_time.clone(), - }) + let out_property = self_property.map(|op| TimestampRange { + start: op.metadata().start_time.clone(), + end: op.metadata().end_time.clone(), }); Ok(L::wrap_timestamp_range(out_property)) }); map.insert("user", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |op| { + let out_property = self_property.map(|op| { // TODO: introduce dedicated type and provide accessors? - Ok(format!( - "{}@{}", - op.metadata().username, - op.metadata().hostname - )) + format!("{}@{}", op.metadata().username, op.metadata().hostname) }); Ok(L::wrap_string(out_property)) }); map.insert("root", |language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; let root_op_id = language.root_op_id.clone(); - let out_property = - TemplateFunction::new(self_property, move |op| Ok(op.id() == &root_op_id)); + let out_property = self_property.map(move |op| op.id() == &root_op_id); Ok(L::wrap_boolean(out_property)) }); map @@ -302,10 +291,10 @@ fn builtin_operation_id_methods() -> OperationTemplateBuildMethodFnMap IntoTemplateProperty<'a> for CoreTemplatePropertyKind<'a> { fn try_into_boolean(self) -> Option + 'a>> { match self { CoreTemplatePropertyKind::String(property) => { - Some(Box::new(TemplateFunction::new(property, |s| { - Ok(!s.is_empty()) - }))) + Some(Box::new(property.map(|s| !s.is_empty()))) } CoreTemplatePropertyKind::StringList(property) => { - Some(Box::new(TemplateFunction::new(property, |l| { - Ok(!l.is_empty()) - }))) + Some(Box::new(property.map(|l| !l.is_empty()))) } CoreTemplatePropertyKind::Boolean(property) => Some(property), CoreTemplatePropertyKind::Integer(_) => None, @@ -473,11 +469,11 @@ fn build_unary_operation<'a, L: TemplateLanguage<'a> + ?Sized>( match op { UnaryOp::LogicalNot => { let arg = expect_boolean_expression(language, build_ctx, arg_node)?; - Ok(L::wrap_boolean(TemplateFunction::new(arg, |v| Ok(!v)))) + Ok(L::wrap_boolean(arg.map(|v| !v))) } UnaryOp::Negate => { let arg = expect_integer_expression(language, build_ctx, arg_node)?; - Ok(L::wrap_integer(TemplateFunction::new(arg, |v| { + Ok(L::wrap_integer(arg.and_then(|v| { v.checked_neg() .ok_or_else(|| TemplatePropertyError("Attempt to negate with overflow".into())) }))) @@ -497,19 +493,13 @@ fn build_binary_operation<'a, L: TemplateLanguage<'a> + ?Sized>( // No short-circuiting supported let lhs = expect_boolean_expression(language, build_ctx, lhs_node)?; let rhs = expect_boolean_expression(language, build_ctx, rhs_node)?; - Ok(L::wrap_boolean(TemplateFunction::new( - (lhs, rhs), - |(l, r)| Ok(l | r), - ))) + Ok(L::wrap_boolean((lhs, rhs).map(|(l, r)| l | r))) } BinaryOp::LogicalAnd => { // No short-circuiting supported let lhs = expect_boolean_expression(language, build_ctx, lhs_node)?; let rhs = expect_boolean_expression(language, build_ctx, rhs_node)?; - Ok(L::wrap_boolean(TemplateFunction::new( - (lhs, rhs), - |(l, r)| Ok(l & r), - ))) + Ok(L::wrap_boolean((lhs, rhs).map(|(l, r)| l & r))) } } } @@ -521,7 +511,7 @@ fn builtin_string_methods<'a, L: TemplateLanguage<'a> + ?Sized>( let mut map = TemplateBuildMethodFnMap::::new(); map.insert("len", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |s| Ok(s.len().try_into()?)); + let out_property = self_property.and_then(|s| Ok(s.len().try_into()?)); Ok(L::wrap_integer(out_property)) }); map.insert( @@ -530,10 +520,8 @@ fn builtin_string_methods<'a, L: TemplateLanguage<'a> + ?Sized>( let [needle_node] = template_parser::expect_exact_arguments(function)?; // TODO: or .try_into_string() to disable implicit type cast? let needle_property = expect_plain_text_expression(language, build_ctx, needle_node)?; - let out_property = - TemplateFunction::new((self_property, needle_property), |(haystack, needle)| { - Ok(haystack.contains(&needle)) - }); + let out_property = (self_property, needle_property) + .map(|(haystack, needle)| haystack.contains(&needle)); Ok(L::wrap_boolean(out_property)) }, ); @@ -542,10 +530,8 @@ fn builtin_string_methods<'a, L: TemplateLanguage<'a> + ?Sized>( |language, build_ctx, self_property, function| { let [needle_node] = template_parser::expect_exact_arguments(function)?; let needle_property = expect_plain_text_expression(language, build_ctx, needle_node)?; - let out_property = - TemplateFunction::new((self_property, needle_property), |(haystack, needle)| { - Ok(haystack.starts_with(&needle)) - }); + let out_property = (self_property, needle_property) + .map(|(haystack, needle)| haystack.starts_with(&needle)); Ok(L::wrap_boolean(out_property)) }, ); @@ -554,10 +540,8 @@ fn builtin_string_methods<'a, L: TemplateLanguage<'a> + ?Sized>( |language, build_ctx, self_property, function| { let [needle_node] = template_parser::expect_exact_arguments(function)?; let needle_property = expect_plain_text_expression(language, build_ctx, needle_node)?; - let out_property = - TemplateFunction::new((self_property, needle_property), |(haystack, needle)| { - Ok(haystack.ends_with(&needle)) - }); + let out_property = (self_property, needle_property) + .map(|(haystack, needle)| haystack.ends_with(&needle)); Ok(L::wrap_boolean(out_property)) }, ); @@ -566,13 +550,12 @@ fn builtin_string_methods<'a, L: TemplateLanguage<'a> + ?Sized>( |language, build_ctx, self_property, function| { let [needle_node] = template_parser::expect_exact_arguments(function)?; let needle_property = expect_plain_text_expression(language, build_ctx, needle_node)?; - let out_property = - TemplateFunction::new((self_property, needle_property), |(haystack, needle)| { - Ok(haystack - .strip_prefix(&needle) - .map(ToOwned::to_owned) - .unwrap_or(haystack)) - }); + let out_property = (self_property, needle_property).map(|(haystack, needle)| { + haystack + .strip_prefix(&needle) + .map(ToOwned::to_owned) + .unwrap_or(haystack) + }); Ok(L::wrap_string(out_property)) }, ); @@ -581,13 +564,12 @@ fn builtin_string_methods<'a, L: TemplateLanguage<'a> + ?Sized>( |language, build_ctx, self_property, function| { let [needle_node] = template_parser::expect_exact_arguments(function)?; let needle_property = expect_plain_text_expression(language, build_ctx, needle_node)?; - let out_property = - TemplateFunction::new((self_property, needle_property), |(haystack, needle)| { - Ok(haystack - .strip_suffix(&needle) - .map(ToOwned::to_owned) - .unwrap_or(haystack)) - }); + let out_property = (self_property, needle_property).map(|(haystack, needle)| { + haystack + .strip_suffix(&needle) + .map(ToOwned::to_owned) + .unwrap_or(haystack) + }); Ok(L::wrap_string(out_property)) }, ); @@ -595,41 +577,36 @@ fn builtin_string_methods<'a, L: TemplateLanguage<'a> + ?Sized>( let [start_idx, end_idx] = template_parser::expect_exact_arguments(function)?; let start_idx_property = expect_isize_expression(language, build_ctx, start_idx)?; let end_idx_property = expect_isize_expression(language, build_ctx, end_idx)?; - let out_property = TemplateFunction::new( - (self_property, start_idx_property, end_idx_property), - |(s, start_idx, end_idx)| { + let out_property = + (self_property, start_idx_property, end_idx_property).map(|(s, start_idx, end_idx)| { let start_idx = string_index_to_char_boundary(&s, start_idx); let end_idx = string_index_to_char_boundary(&s, end_idx); - Ok(s.get(start_idx..end_idx).unwrap_or_default().to_owned()) - }, - ); + s.get(start_idx..end_idx).unwrap_or_default().to_owned() + }); Ok(L::wrap_string(out_property)) }); map.insert( "first_line", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |s| { - Ok(s.lines().next().unwrap_or_default().to_string()) - }); + let out_property = + self_property.map(|s| s.lines().next().unwrap_or_default().to_string()); Ok(L::wrap_string(out_property)) }, ); map.insert("lines", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |s| { - Ok(s.lines().map(|l| l.to_owned()).collect()) - }); + let out_property = self_property.map(|s| s.lines().map(|l| l.to_owned()).collect()); Ok(L::wrap_string_list(out_property)) }); map.insert("upper", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |s| Ok(s.to_uppercase())); + let out_property = self_property.map(|s| s.to_uppercase()); Ok(L::wrap_string(out_property)) }); map.insert("lower", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |s| Ok(s.to_lowercase())); + let out_property = self_property.map(|s| s.to_lowercase()); Ok(L::wrap_string(out_property)) }); map @@ -658,21 +635,21 @@ fn builtin_signature_methods<'a, L: TemplateLanguage<'a> + ?Sized>( let mut map = TemplateBuildMethodFnMap::::new(); map.insert("name", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |signature| Ok(signature.name)); + let out_property = self_property.map(|signature| signature.name); Ok(L::wrap_string(out_property)) }); map.insert("email", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |signature| Ok(signature.email)); + let out_property = self_property.map(|signature| signature.email); Ok(L::wrap_string(out_property)) }); map.insert( "username", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |signature| { + let out_property = self_property.map(|signature| { let (username, _) = text_util::split_email(&signature.email); - Ok(username.to_owned()) + username.to_owned() }); Ok(L::wrap_string(out_property)) }, @@ -681,8 +658,7 @@ fn builtin_signature_methods<'a, L: TemplateLanguage<'a> + ?Sized>( "timestamp", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = - TemplateFunction::new(self_property, |signature| Ok(signature.timestamp)); + let out_property = self_property.map(|signature| signature.timestamp); Ok(L::wrap_timestamp(out_property)) }, ); @@ -698,9 +674,8 @@ fn builtin_timestamp_methods<'a, L: TemplateLanguage<'a> + ?Sized>( template_parser::expect_no_arguments(function)?; let now = Timestamp::now(); let format = timeago::Formatter::new(); - let out_property = TemplateFunction::new(self_property, move |timestamp| { - Ok(time_util::format_duration(×tamp, &now, &format)?) - }); + let out_property = self_property + .and_then(move |timestamp| Ok(time_util::format_duration(×tamp, &now, &format)?)); Ok(L::wrap_string(out_property)) }); map.insert( @@ -715,7 +690,7 @@ fn builtin_timestamp_methods<'a, L: TemplateLanguage<'a> + ?Sized>( }) })? .into_owned(); - let out_property = TemplateFunction::new(self_property, move |timestamp| { + let out_property = self_property.and_then(move |timestamp| { Ok(time_util::format_absolute_timestamp_with( ×tamp, &format, )?) @@ -725,9 +700,9 @@ fn builtin_timestamp_methods<'a, L: TemplateLanguage<'a> + ?Sized>( ); map.insert("utc", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |mut timestamp| { + let out_property = self_property.map(|mut timestamp| { timestamp.tz_offset = 0; - Ok(timestamp) + timestamp }); Ok(L::wrap_timestamp(out_property)) }); @@ -737,9 +712,9 @@ fn builtin_timestamp_methods<'a, L: TemplateLanguage<'a> + ?Sized>( .ok() .and_then(|tz_string| tz_string.parse::().ok()) .unwrap_or_else(|| chrono::Local::now().offset().local_minus_utc() / 60); - let out_property = TemplateFunction::new(self_property, move |mut timestamp| { + let out_property = self_property.map(move |mut timestamp| { timestamp.tz_offset = tz_offset; - Ok(timestamp) + timestamp }); Ok(L::wrap_timestamp(out_property)) }); @@ -753,20 +728,19 @@ fn builtin_timestamp_range_methods<'a, L: TemplateLanguage<'a> + ?Sized>( let mut map = TemplateBuildMethodFnMap::::new(); map.insert("start", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |time_range| Ok(time_range.start)); + let out_property = self_property.map(|time_range| time_range.start); Ok(L::wrap_timestamp(out_property)) }); map.insert("end", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = TemplateFunction::new(self_property, |time_range| Ok(time_range.end)); + let out_property = self_property.map(|time_range| time_range.end); Ok(L::wrap_timestamp(out_property)) }); map.insert( "duration", |_language, _build_ctx, self_property, function| { template_parser::expect_no_arguments(function)?; - let out_property = - TemplateFunction::new(self_property, |time_range| Ok(time_range.duration()?)); + let out_property = self_property.and_then(|time_range| Ok(time_range.duration()?)); Ok(L::wrap_string(out_property)) }, ); @@ -807,8 +781,7 @@ where let property = match function.name { "len" => { template_parser::expect_no_arguments(function)?; - let out_property = - TemplateFunction::new(self_property, |items| Ok(items.len().try_into()?)); + let out_property = self_property.and_then(|items| Ok(items.len().try_into()?)); L::wrap_integer(out_property) } "join" => { @@ -840,8 +813,7 @@ where let property = match function.name { "len" => { template_parser::expect_no_arguments(function)?; - let out_property = - TemplateFunction::new(self_property, |items| Ok(items.len().try_into()?)); + let out_property = self_property.and_then(|items| Ok(items.len().try_into()?)); L::wrap_integer(out_property) } // No "join" @@ -930,9 +902,8 @@ fn builtin_functions<'a, L: TemplateLanguage<'a> + ?Sized>() -> TemplateBuildFun let [label_node, content_node] = template_parser::expect_exact_arguments(function)?; let label_property = expect_plain_text_expression(language, build_ctx, label_node)?; let content = expect_template_expression(language, build_ctx, content_node)?; - let labels = TemplateFunction::new(label_property, |s| { - Ok(s.split_whitespace().map(ToString::to_string).collect()) - }); + let labels = + label_property.map(|s| s.split_whitespace().map(ToString::to_string).collect()); Ok(L::wrap_template(Box::new(LabelTemplate::new( content, labels, )))) @@ -1123,7 +1094,7 @@ pub fn expect_isize_expression<'a, L: TemplateLanguage<'a> + ?Sized>( node: &ExpressionNode, ) -> TemplateParseResult + 'a>> { let i64_property = expect_integer_expression(language, build_ctx, node)?; - let isize_property = TemplateFunction::new(i64_property, |v| Ok(isize::try_from(v)?)); + let isize_property = i64_property.and_then(|v| Ok(isize::try_from(v)?)); Ok(Box::new(isize_property)) } @@ -1134,7 +1105,7 @@ pub fn expect_usize_expression<'a, L: TemplateLanguage<'a> + ?Sized>( node: &ExpressionNode, ) -> TemplateParseResult + 'a>> { let i64_property = expect_integer_expression(language, build_ctx, node)?; - let usize_property = TemplateFunction::new(i64_property, |v| Ok(usize::try_from(v)?)); + let usize_property = i64_property.and_then(|v| Ok(usize::try_from(v)?)); Ok(Box::new(usize_property)) }