templater: add property.into_dyn() helper

I'm going to move Box<dyn _> conversion to callers, so there will be more places
to use this helper.
This commit is contained in:
Yuya Nishihara 2025-04-30 10:59:41 +09:00
parent 533fb5e4bb
commit 96b633a091
4 changed files with 45 additions and 67 deletions

View File

@ -202,14 +202,8 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
let type_name = "Commit"; let type_name = "Commit";
let table = &self.build_fn_table.commit_methods; let table = &self.build_fn_table.commit_methods;
let build = template_parser::lookup_method(type_name, table, function)?; let build = template_parser::lookup_method(type_name, table, function)?;
let inner_property = property.try_unwrap(type_name); let inner_property = property.try_unwrap(type_name).into_dyn();
build( build(self, diagnostics, build_ctx, inner_property, function)
self,
diagnostics,
build_ctx,
Box::new(inner_property),
function,
)
} }
CommitTemplatePropertyKind::CommitList(property) => { CommitTemplatePropertyKind::CommitList(property) => {
// TODO: migrate to table? // TODO: migrate to table?
@ -232,14 +226,8 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
let type_name = "CommitRef"; let type_name = "CommitRef";
let table = &self.build_fn_table.commit_ref_methods; let table = &self.build_fn_table.commit_ref_methods;
let build = template_parser::lookup_method(type_name, table, function)?; let build = template_parser::lookup_method(type_name, table, function)?;
let inner_property = property.try_unwrap(type_name); let inner_property = property.try_unwrap(type_name).into_dyn();
build( build(self, diagnostics, build_ctx, inner_property, function)
self,
diagnostics,
build_ctx,
Box::new(inner_property),
function,
)
} }
CommitTemplatePropertyKind::CommitRefList(property) => { CommitTemplatePropertyKind::CommitRefList(property) => {
// TODO: migrate to table? // TODO: migrate to table?
@ -262,14 +250,8 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
let type_name = "RepoPath"; let type_name = "RepoPath";
let table = &self.build_fn_table.repo_path_methods; let table = &self.build_fn_table.repo_path_methods;
let build = template_parser::lookup_method(type_name, table, function)?; let build = template_parser::lookup_method(type_name, table, function)?;
let inner_property = property.try_unwrap(type_name); let inner_property = property.try_unwrap(type_name).into_dyn();
build( build(self, diagnostics, build_ctx, inner_property, function)
self,
diagnostics,
build_ctx,
Box::new(inner_property),
function,
)
} }
CommitTemplatePropertyKind::CommitOrChangeId(property) => { CommitTemplatePropertyKind::CommitOrChangeId(property) => {
let table = &self.build_fn_table.commit_or_change_id_methods; let table = &self.build_fn_table.commit_or_change_id_methods;
@ -313,21 +295,15 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
let build = template_parser::lookup_method(type_name, table, function)?; let build = template_parser::lookup_method(type_name, table, function)?;
// Strip off formatting parameters which are needed only for the // Strip off formatting parameters which are needed only for the
// default template output. // default template output.
let property = Box::new(property.map(|formatted| formatted.stats)); let property = property.map(|formatted| formatted.stats).into_dyn();
build(self, diagnostics, build_ctx, property, function) build(self, diagnostics, build_ctx, property, function)
} }
CommitTemplatePropertyKind::CryptographicSignatureOpt(property) => { CommitTemplatePropertyKind::CryptographicSignatureOpt(property) => {
let type_name = "CryptographicSignature"; let type_name = "CryptographicSignature";
let table = &self.build_fn_table.cryptographic_signature_methods; let table = &self.build_fn_table.cryptographic_signature_methods;
let build = template_parser::lookup_method(type_name, table, function)?; let build = template_parser::lookup_method(type_name, table, function)?;
let inner_property = property.try_unwrap(type_name); let inner_property = property.try_unwrap(type_name).into_dyn();
build( build(self, diagnostics, build_ctx, inner_property, function)
self,
diagnostics,
build_ctx,
Box::new(inner_property),
function,
)
} }
CommitTemplatePropertyKind::AnnotationLine(property) => { CommitTemplatePropertyKind::AnnotationLine(property) => {
let type_name = "AnnotationLine"; let type_name = "AnnotationLine";
@ -557,21 +533,21 @@ impl<'repo> IntoTemplateProperty<'repo> for CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::Core(property) => property.try_into_boolean(), CommitTemplatePropertyKind::Core(property) => property.try_into_boolean(),
CommitTemplatePropertyKind::Commit(_) => None, CommitTemplatePropertyKind::Commit(_) => None,
CommitTemplatePropertyKind::CommitOpt(property) => { CommitTemplatePropertyKind::CommitOpt(property) => {
Some(Box::new(property.map(|opt| opt.is_some()))) Some(property.map(|opt| opt.is_some()).into_dyn())
} }
CommitTemplatePropertyKind::CommitList(property) => { CommitTemplatePropertyKind::CommitList(property) => {
Some(Box::new(property.map(|l| !l.is_empty()))) Some(property.map(|l| !l.is_empty()).into_dyn())
} }
CommitTemplatePropertyKind::CommitRef(_) => None, CommitTemplatePropertyKind::CommitRef(_) => None,
CommitTemplatePropertyKind::CommitRefOpt(property) => { CommitTemplatePropertyKind::CommitRefOpt(property) => {
Some(Box::new(property.map(|opt| opt.is_some()))) Some(property.map(|opt| opt.is_some()).into_dyn())
} }
CommitTemplatePropertyKind::CommitRefList(property) => { CommitTemplatePropertyKind::CommitRefList(property) => {
Some(Box::new(property.map(|l| !l.is_empty()))) Some(property.map(|l| !l.is_empty()).into_dyn())
} }
CommitTemplatePropertyKind::RepoPath(_) => None, CommitTemplatePropertyKind::RepoPath(_) => None,
CommitTemplatePropertyKind::RepoPathOpt(property) => { CommitTemplatePropertyKind::RepoPathOpt(property) => {
Some(Box::new(property.map(|opt| opt.is_some()))) Some(property.map(|opt| opt.is_some()).into_dyn())
} }
CommitTemplatePropertyKind::CommitOrChangeId(_) => None, CommitTemplatePropertyKind::CommitOrChangeId(_) => None,
CommitTemplatePropertyKind::ShortestIdPrefix(_) => None, CommitTemplatePropertyKind::ShortestIdPrefix(_) => None,
@ -580,17 +556,17 @@ impl<'repo> IntoTemplateProperty<'repo> for CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::TreeDiff(_) => None, CommitTemplatePropertyKind::TreeDiff(_) => None,
CommitTemplatePropertyKind::TreeDiffEntry(_) => None, CommitTemplatePropertyKind::TreeDiffEntry(_) => None,
CommitTemplatePropertyKind::TreeDiffEntryList(property) => { CommitTemplatePropertyKind::TreeDiffEntryList(property) => {
Some(Box::new(property.map(|l| !l.is_empty()))) Some(property.map(|l| !l.is_empty()).into_dyn())
} }
CommitTemplatePropertyKind::TreeEntry(_) => None, CommitTemplatePropertyKind::TreeEntry(_) => None,
CommitTemplatePropertyKind::DiffStats(_) => None, CommitTemplatePropertyKind::DiffStats(_) => None,
CommitTemplatePropertyKind::CryptographicSignatureOpt(property) => { CommitTemplatePropertyKind::CryptographicSignatureOpt(property) => {
Some(Box::new(property.map(|sig| sig.is_some()))) Some(property.map(|sig| sig.is_some()).into_dyn())
} }
CommitTemplatePropertyKind::AnnotationLine(_) => None, CommitTemplatePropertyKind::AnnotationLine(_) => None,
CommitTemplatePropertyKind::Trailer(_) => None, CommitTemplatePropertyKind::Trailer(_) => None,
CommitTemplatePropertyKind::TrailerList(property) => { CommitTemplatePropertyKind::TrailerList(property) => {
Some(Box::new(property.map(|l| !l.is_empty()))) Some(property.map(|l| !l.is_empty()).into_dyn())
} }
} }
} }
@ -607,7 +583,7 @@ impl<'repo> IntoTemplateProperty<'repo> for CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::Core(property) => property.try_into_plain_text(), CommitTemplatePropertyKind::Core(property) => property.try_into_plain_text(),
_ => { _ => {
let template = self.try_into_template()?; let template = self.try_into_template()?;
Some(Box::new(PlainTextFormattedProperty::new(template))) Some(PlainTextFormattedProperty::new(template).into_dyn())
} }
} }
} }

View File

@ -184,7 +184,7 @@ impl IntoTemplateProperty<'static> for OperationTemplatePropertyKind {
OperationTemplatePropertyKind::Core(property) => property.try_into_plain_text(), OperationTemplatePropertyKind::Core(property) => property.try_into_plain_text(),
_ => { _ => {
let template = self.try_into_template()?; let template = self.try_into_template()?;
Some(Box::new(PlainTextFormattedProperty::new(template))) Some(PlainTextFormattedProperty::new(template).into_dyn())
} }
} }
} }

View File

@ -237,20 +237,20 @@ impl<'a> IntoTemplateProperty<'a> for CoreTemplatePropertyKind<'a> {
fn try_into_boolean(self) -> Option<Box<dyn TemplateProperty<Output = bool> + 'a>> { fn try_into_boolean(self) -> Option<Box<dyn TemplateProperty<Output = bool> + 'a>> {
match self { match self {
CoreTemplatePropertyKind::String(property) => { CoreTemplatePropertyKind::String(property) => {
Some(Box::new(property.map(|s| !s.is_empty()))) Some(property.map(|s| !s.is_empty()).into_dyn())
} }
CoreTemplatePropertyKind::StringList(property) => { CoreTemplatePropertyKind::StringList(property) => {
Some(Box::new(property.map(|l| !l.is_empty()))) Some(property.map(|l| !l.is_empty()).into_dyn())
} }
CoreTemplatePropertyKind::Boolean(property) => Some(property), CoreTemplatePropertyKind::Boolean(property) => Some(property),
CoreTemplatePropertyKind::Integer(_) => None, CoreTemplatePropertyKind::Integer(_) => None,
CoreTemplatePropertyKind::IntegerOpt(property) => { CoreTemplatePropertyKind::IntegerOpt(property) => {
Some(Box::new(property.map(|opt| opt.is_some()))) Some(property.map(|opt| opt.is_some()).into_dyn())
} }
CoreTemplatePropertyKind::ConfigValue(_) => None, CoreTemplatePropertyKind::ConfigValue(_) => None,
CoreTemplatePropertyKind::Signature(_) => None, CoreTemplatePropertyKind::Signature(_) => None,
CoreTemplatePropertyKind::Email(property) => { CoreTemplatePropertyKind::Email(property) => {
Some(Box::new(property.map(|e| !e.0.is_empty()))) Some(property.map(|e| !e.0.is_empty()).into_dyn())
} }
CoreTemplatePropertyKind::SizeHint(_) => None, CoreTemplatePropertyKind::SizeHint(_) => None,
CoreTemplatePropertyKind::Timestamp(_) => None, CoreTemplatePropertyKind::Timestamp(_) => None,
@ -267,7 +267,7 @@ impl<'a> IntoTemplateProperty<'a> for CoreTemplatePropertyKind<'a> {
match self { match self {
CoreTemplatePropertyKind::Integer(property) => Some(property), CoreTemplatePropertyKind::Integer(property) => Some(property),
CoreTemplatePropertyKind::IntegerOpt(property) => { CoreTemplatePropertyKind::IntegerOpt(property) => {
Some(Box::new(property.try_unwrap("Integer"))) Some(property.try_unwrap("Integer").into_dyn())
} }
_ => None, _ => None,
} }
@ -278,7 +278,7 @@ impl<'a> IntoTemplateProperty<'a> for CoreTemplatePropertyKind<'a> {
CoreTemplatePropertyKind::String(property) => Some(property), CoreTemplatePropertyKind::String(property) => Some(property),
_ => { _ => {
let template = self.try_into_template()?; let template = self.try_into_template()?;
Some(Box::new(PlainTextFormattedProperty::new(template))) Some(PlainTextFormattedProperty::new(template).into_dyn())
} }
} }
} }
@ -304,22 +304,22 @@ impl<'a> IntoTemplateProperty<'a> for CoreTemplatePropertyKind<'a> {
fn try_into_eq(self, other: Self) -> Option<Box<dyn TemplateProperty<Output = bool> + 'a>> { fn try_into_eq(self, other: Self) -> Option<Box<dyn TemplateProperty<Output = bool> + 'a>> {
match (self, other) { match (self, other) {
(CoreTemplatePropertyKind::String(lhs), CoreTemplatePropertyKind::String(rhs)) => { (CoreTemplatePropertyKind::String(lhs), CoreTemplatePropertyKind::String(rhs)) => {
Some(Box::new((lhs, rhs).map(|(l, r)| l == r))) Some((lhs, rhs).map(|(l, r)| l == r).into_dyn())
} }
(CoreTemplatePropertyKind::String(lhs), CoreTemplatePropertyKind::Email(rhs)) => { (CoreTemplatePropertyKind::String(lhs), CoreTemplatePropertyKind::Email(rhs)) => {
Some(Box::new((lhs, rhs).map(|(l, r)| l == r.0))) Some((lhs, rhs).map(|(l, r)| l == r.0).into_dyn())
} }
(CoreTemplatePropertyKind::Boolean(lhs), CoreTemplatePropertyKind::Boolean(rhs)) => { (CoreTemplatePropertyKind::Boolean(lhs), CoreTemplatePropertyKind::Boolean(rhs)) => {
Some(Box::new((lhs, rhs).map(|(l, r)| l == r))) Some((lhs, rhs).map(|(l, r)| l == r).into_dyn())
} }
(CoreTemplatePropertyKind::Integer(lhs), CoreTemplatePropertyKind::Integer(rhs)) => { (CoreTemplatePropertyKind::Integer(lhs), CoreTemplatePropertyKind::Integer(rhs)) => {
Some(Box::new((lhs, rhs).map(|(l, r)| l == r))) Some((lhs, rhs).map(|(l, r)| l == r).into_dyn())
} }
(CoreTemplatePropertyKind::Email(lhs), CoreTemplatePropertyKind::Email(rhs)) => { (CoreTemplatePropertyKind::Email(lhs), CoreTemplatePropertyKind::Email(rhs)) => {
Some(Box::new((lhs, rhs).map(|(l, r)| l == r))) Some((lhs, rhs).map(|(l, r)| l == r).into_dyn())
} }
(CoreTemplatePropertyKind::Email(lhs), CoreTemplatePropertyKind::String(rhs)) => { (CoreTemplatePropertyKind::Email(lhs), CoreTemplatePropertyKind::String(rhs)) => {
Some(Box::new((lhs, rhs).map(|(l, r)| l.0 == r))) Some((lhs, rhs).map(|(l, r)| l.0 == r).into_dyn())
} }
(CoreTemplatePropertyKind::String(_), _) => None, (CoreTemplatePropertyKind::String(_), _) => None,
(CoreTemplatePropertyKind::StringList(_), _) => None, (CoreTemplatePropertyKind::StringList(_), _) => None,
@ -343,7 +343,7 @@ impl<'a> IntoTemplateProperty<'a> for CoreTemplatePropertyKind<'a> {
) -> Option<Box<dyn TemplateProperty<Output = Ordering> + 'a>> { ) -> Option<Box<dyn TemplateProperty<Output = Ordering> + 'a>> {
match (self, other) { match (self, other) {
(CoreTemplatePropertyKind::Integer(lhs), CoreTemplatePropertyKind::Integer(rhs)) => { (CoreTemplatePropertyKind::Integer(lhs), CoreTemplatePropertyKind::Integer(rhs)) => {
Some(Box::new((lhs, rhs).map(|(l, r)| l.cmp(&r)))) Some((lhs, rhs).map(|(l, r)| l.cmp(&r)).into_dyn())
} }
(CoreTemplatePropertyKind::String(_), _) => None, (CoreTemplatePropertyKind::String(_), _) => None,
(CoreTemplatePropertyKind::StringList(_), _) => None, (CoreTemplatePropertyKind::StringList(_), _) => None,
@ -529,14 +529,8 @@ impl<'a, L: TemplateLanguage<'a> + ?Sized> CoreTemplateBuildFnTable<'a, L> {
let type_name = "Integer"; let type_name = "Integer";
let table = &self.integer_methods; let table = &self.integer_methods;
let build = template_parser::lookup_method(type_name, table, function)?; let build = template_parser::lookup_method(type_name, table, function)?;
let inner_property = property.try_unwrap(type_name); let inner_property = property.try_unwrap(type_name).into_dyn();
build( build(language, diagnostics, build_ctx, inner_property, function)
language,
diagnostics,
build_ctx,
Box::new(inner_property),
function,
)
} }
CoreTemplatePropertyKind::ConfigValue(property) => { CoreTemplatePropertyKind::ConfigValue(property) => {
let table = &self.config_value_methods; let table = &self.config_value_methods;
@ -1394,7 +1388,7 @@ where
}) })
.collect() .collect()
}); });
Ok(wrap_list(Box::new(out_property))) Ok(wrap_list(out_property.into_dyn()))
} }
/// Builds expression that extracts iterable property and applies template to /// Builds expression that extracts iterable property and applies template to
@ -1888,7 +1882,7 @@ pub fn expect_isize_expression<'a, L: TemplateLanguage<'a> + ?Sized>(
) -> TemplateParseResult<Box<dyn TemplateProperty<Output = isize> + 'a>> { ) -> TemplateParseResult<Box<dyn TemplateProperty<Output = isize> + 'a>> {
let i64_property = expect_integer_expression(language, diagnostics, build_ctx, node)?; let i64_property = expect_integer_expression(language, diagnostics, build_ctx, node)?;
let isize_property = i64_property.and_then(|v| Ok(isize::try_from(v)?)); let isize_property = i64_property.and_then(|v| Ok(isize::try_from(v)?));
Ok(Box::new(isize_property)) Ok(isize_property.into_dyn())
} }
/// If the given expression `node` is of `Integer` type, converts it to `usize`. /// If the given expression `node` is of `Integer` type, converts it to `usize`.
@ -1900,7 +1894,7 @@ pub fn expect_usize_expression<'a, L: TemplateLanguage<'a> + ?Sized>(
) -> TemplateParseResult<Box<dyn TemplateProperty<Output = usize> + 'a>> { ) -> TemplateParseResult<Box<dyn TemplateProperty<Output = usize> + 'a>> {
let i64_property = expect_integer_expression(language, diagnostics, build_ctx, node)?; let i64_property = expect_integer_expression(language, diagnostics, build_ctx, node)?;
let usize_property = i64_property.and_then(|v| Ok(usize::try_from(v)?)); let usize_property = i64_property.and_then(|v| Ok(usize::try_from(v)?));
Ok(Box::new(usize_property)) Ok(usize_property.into_dyn())
} }
pub fn expect_plain_text_expression<'a, L: TemplateLanguage<'a> + ?Sized>( pub fn expect_plain_text_expression<'a, L: TemplateLanguage<'a> + ?Sized>(

View File

@ -435,6 +435,14 @@ pub trait TemplatePropertyExt: TemplateProperty {
{ {
Box::new(FormattablePropertyTemplate::new(self)) Box::new(FormattablePropertyTemplate::new(self))
} }
/// Converts this property into boxed trait object.
fn into_dyn<'a>(self) -> Box<dyn TemplateProperty<Output = Self::Output> + 'a>
where
Self: Sized + 'a,
{
Box::new(self)
}
} }
impl<P: TemplateProperty + ?Sized> TemplatePropertyExt for P {} impl<P: TemplateProperty + ?Sized> TemplatePropertyExt for P {}