From db172aa7c95c506c9be25d3aea5e0f1d6c82f445 Mon Sep 17 00:00:00 2001 From: Yuya Nishihara Date: Fri, 3 Feb 2023 20:28:44 +0900 Subject: [PATCH] templater: process property composition by parse__method() This prepares for adding method arguments support. Since a method argument should be evaluated in the surrounding scope, its type will be 'TemplateProperty', not 'TemplateProperty' for the receiver type 'J'. Then, the receiver of type 'TemplateProperty', and arguments of type 'TemplateProperty' will be composed to an input of type 'TemplateProperty'. wrap_fn() is removed since it's only useful for nullary methods, and we no longer need Box to abstract the return value. --- src/template_parser.rs | 137 ++++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 76 deletions(-) diff --git a/src/template_parser.rs b/src/template_parser.rs index c13ecf049..4d5eb0a10 100644 --- a/src/template_parser.rs +++ b/src/template_parser.rs @@ -187,29 +187,6 @@ enum Property<'a, I> { } impl<'a, I: 'a> Property<'a, I> { - fn after(self, first: Box + 'a>) -> Property<'a, C> { - fn chain<'a, C: 'a, I: 'a, O: 'a>( - first: Box + 'a>, - second: Box + 'a>, - ) -> Box + 'a> { - Box::new(TemplateFunction::new(first, move |value| { - second.extract(&value) - })) - } - match self { - Property::String(property) => Property::String(chain(first, property)), - Property::Boolean(property) => Property::Boolean(chain(first, property)), - Property::CommitOrChangeId(property) => { - Property::CommitOrChangeId(chain(first, property)) - } - Property::IdWithHighlightedPrefix(property) => { - Property::IdWithHighlightedPrefix(chain(first, property)) - } - Property::Signature(property) => Property::Signature(chain(first, property)), - Property::Timestamp(property) => Property::Timestamp(chain(first, property)), - } - } - fn try_into_boolean(self) -> Option + 'a>> { match self { Property::String(property) => { @@ -306,10 +283,10 @@ fn parse_method_chain<'a, I: 'a>( }; labels.push(name.as_str().to_owned()); property = match property { - Property::String(property) => parse_string_method(name, args_pair)?.after(property), - Property::Boolean(property) => parse_boolean_method(name, args_pair)?.after(property), + Property::String(property) => parse_string_method(property, name, args_pair)?, + Property::Boolean(property) => parse_boolean_method(property, name, args_pair)?, Property::CommitOrChangeId(property) => { - parse_commit_or_change_id_method(name, args_pair)?.after(property) + parse_commit_or_change_id_method(property, name, args_pair)? } Property::IdWithHighlightedPrefix(_property) => { return Err(TemplateParseError::no_such_method( @@ -317,61 +294,65 @@ fn parse_method_chain<'a, I: 'a>( &name, )); } - Property::Signature(property) => { - parse_signature_method(name, args_pair)?.after(property) - } - Property::Timestamp(property) => { - parse_timestamp_method(name, args_pair)?.after(property) - } + Property::Signature(property) => parse_signature_method(property, name, args_pair)?, + Property::Timestamp(property) => parse_timestamp_method(property, name, args_pair)?, }; } Ok(PropertyAndLabels(property, labels)) } -fn parse_string_method<'a>( +fn chain_properties<'a, I: 'a, J: 'a, O: 'a>( + first: impl TemplateProperty + 'a, + second: impl TemplateProperty + 'a, +) -> Box + 'a> { + Box::new(TemplateFunction::new(first, move |value| { + second.extract(&value) + })) +} + +fn parse_string_method<'a, I: 'a>( + self_property: impl TemplateProperty + 'a, name: Pair, _args_pair: Pair, -) -> TemplateParseResult> { - fn wrap_fn<'a, O>( - f: impl Fn(&String) -> O + 'a, - ) -> Box + 'a> { - Box::new(TemplatePropertyFn(f)) - } +) -> TemplateParseResult> { // TODO: validate arguments let property = match name.as_str() { - "first_line" => Property::String(wrap_fn(|s| { - s.lines().next().unwrap_or_default().to_string() - })), + "first_line" => Property::String(chain_properties( + self_property, + TemplatePropertyFn(|s: &String| s.lines().next().unwrap_or_default().to_string()), + )), _ => return Err(TemplateParseError::no_such_method("String", &name)), }; Ok(property) } -fn parse_boolean_method<'a>( +fn parse_boolean_method<'a, I: 'a>( + _self_property: impl TemplateProperty + 'a, name: Pair, _args_pair: Pair, -) -> TemplateParseResult> { +) -> TemplateParseResult> { Err(TemplateParseError::no_such_method("Boolean", &name)) } -fn parse_commit_or_change_id_method<'a>( +fn parse_commit_or_change_id_method<'a, I: 'a>( + self_property: impl TemplateProperty> + 'a, name: Pair, _args_pair: Pair, -) -> TemplateParseResult>> { - fn wrap_fn<'a, O>( - f: impl Fn(&CommitOrChangeId<'a>) -> O + 'a, - ) -> Box, Output = O> + 'a> { - Box::new(TemplatePropertyFn(f)) - } +) -> TemplateParseResult> { // TODO: validate arguments let property = match name.as_str() { - "short" => Property::String(wrap_fn(|id| id.short())), - "shortest_prefix_and_brackets" => { - Property::String(wrap_fn(|id| id.shortest_prefix_and_brackets())) - } - "shortest_styled_prefix" => { - Property::IdWithHighlightedPrefix(wrap_fn(|id| id.shortest_styled_prefix())) - } + "short" => Property::String(chain_properties( + self_property, + TemplatePropertyFn(|id: &CommitOrChangeId| id.short()), + )), + "shortest_prefix_and_brackets" => Property::String(chain_properties( + self_property, + TemplatePropertyFn(|id: &CommitOrChangeId| id.shortest_prefix_and_brackets()), + )), + "shortest_styled_prefix" => Property::IdWithHighlightedPrefix(chain_properties( + self_property, + TemplatePropertyFn(|id: &CommitOrChangeId| id.shortest_styled_prefix()), + )), _ => { return Err(TemplateParseError::no_such_method( "CommitOrChangeId", @@ -382,37 +363,41 @@ fn parse_commit_or_change_id_method<'a>( Ok(property) } -fn parse_signature_method<'a>( +fn parse_signature_method<'a, I: 'a>( + self_property: impl TemplateProperty + 'a, name: Pair, _args_pair: Pair, -) -> TemplateParseResult> { - fn wrap_fn<'a, O>( - f: impl Fn(&Signature) -> O + 'a, - ) -> Box + 'a> { - Box::new(TemplatePropertyFn(f)) - } +) -> TemplateParseResult> { // TODO: validate arguments let property = match name.as_str() { - "name" => Property::String(wrap_fn(|signature| signature.name.clone())), - "email" => Property::String(wrap_fn(|signature| signature.email.clone())), - "timestamp" => Property::Timestamp(wrap_fn(|signature| signature.timestamp.clone())), + "name" => Property::String(chain_properties( + self_property, + TemplatePropertyFn(|signature: &Signature| signature.name.clone()), + )), + "email" => Property::String(chain_properties( + self_property, + TemplatePropertyFn(|signature: &Signature| signature.email.clone()), + )), + "timestamp" => Property::Timestamp(chain_properties( + self_property, + TemplatePropertyFn(|signature: &Signature| signature.timestamp.clone()), + )), _ => return Err(TemplateParseError::no_such_method("Signature", &name)), }; Ok(property) } -fn parse_timestamp_method<'a>( +fn parse_timestamp_method<'a, I: 'a>( + self_property: impl TemplateProperty + 'a, name: Pair, _args_pair: Pair, -) -> TemplateParseResult> { - fn wrap_fn<'a, O>( - f: impl Fn(&Timestamp) -> O + 'a, - ) -> Box + 'a> { - Box::new(TemplatePropertyFn(f)) - } +) -> TemplateParseResult> { // TODO: validate arguments let property = match name.as_str() { - "ago" => Property::String(wrap_fn(time_util::format_timestamp_relative_to_now)), + "ago" => Property::String(chain_properties( + self_property, + TemplatePropertyFn(time_util::format_timestamp_relative_to_now), + )), _ => return Err(TemplateParseError::no_such_method("Timestamp", &name)), }; Ok(property)