forked from mirrors/jj
templater: remove Context type from TemplateLanguage/Property
Now a compiled template doesn't have a static Context type internally. A property is basically of "Fn() -> Result<O, _>" type, and a type-erased "self" variable will be injected as needed. Template<C> types will be refactored separately.
This commit is contained in:
parent
0fad9c9795
commit
911cf4b8f6
6 changed files with 139 additions and 176 deletions
|
@ -244,7 +244,7 @@ impl CommandHelper {
|
|||
/// This function also loads template aliases from the settings. Use
|
||||
/// `WorkspaceCommandHelper::parse_template()` if you've already
|
||||
/// instantiated the workspace helper.
|
||||
pub fn parse_template<'a, C: Clone + 'a, L: TemplateLanguage<'a, Context = ()> + ?Sized>(
|
||||
pub fn parse_template<'a, C: Clone + 'a, L: TemplateLanguage<'a> + ?Sized>(
|
||||
&self,
|
||||
ui: &Ui,
|
||||
language: &L,
|
||||
|
@ -899,7 +899,7 @@ Set which revision the branch points to with `jj branch set {branch_name} -r <RE
|
|||
///
|
||||
/// `wrap_self` specifies the type of the top-level property, which should
|
||||
/// be one of the `L::wrap_*()` functions.
|
||||
pub fn parse_template<'a, C: Clone + 'a, L: TemplateLanguage<'a, Context = ()> + ?Sized>(
|
||||
pub fn parse_template<'a, C: Clone + 'a, L: TemplateLanguage<'a> + ?Sized>(
|
||||
&self,
|
||||
language: &L,
|
||||
template_text: &str,
|
||||
|
|
|
@ -96,7 +96,6 @@ impl<'repo> CommitTemplateLanguage<'repo> {
|
|||
}
|
||||
|
||||
impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
|
||||
type Context = ();
|
||||
type Property = CommitTemplatePropertyKind<'repo>;
|
||||
|
||||
template_builder::impl_core_wrap_property_fns!('repo, CommitTemplatePropertyKind::Core);
|
||||
|
@ -185,54 +184,54 @@ impl<'repo> CommitTemplateLanguage<'repo> {
|
|||
}
|
||||
|
||||
pub fn wrap_commit(
|
||||
property: impl TemplateProperty<(), Output = Commit> + 'repo,
|
||||
property: impl TemplateProperty<Output = Commit> + 'repo,
|
||||
) -> CommitTemplatePropertyKind<'repo> {
|
||||
CommitTemplatePropertyKind::Commit(Box::new(property))
|
||||
}
|
||||
|
||||
pub fn wrap_commit_list(
|
||||
property: impl TemplateProperty<(), Output = Vec<Commit>> + 'repo,
|
||||
property: impl TemplateProperty<Output = Vec<Commit>> + 'repo,
|
||||
) -> CommitTemplatePropertyKind<'repo> {
|
||||
CommitTemplatePropertyKind::CommitList(Box::new(property))
|
||||
}
|
||||
|
||||
pub fn wrap_ref_name(
|
||||
property: impl TemplateProperty<(), Output = RefName> + 'repo,
|
||||
property: impl TemplateProperty<Output = RefName> + 'repo,
|
||||
) -> CommitTemplatePropertyKind<'repo> {
|
||||
CommitTemplatePropertyKind::RefName(Box::new(property))
|
||||
}
|
||||
|
||||
pub fn wrap_ref_name_list(
|
||||
property: impl TemplateProperty<(), Output = Vec<RefName>> + 'repo,
|
||||
property: impl TemplateProperty<Output = Vec<RefName>> + 'repo,
|
||||
) -> CommitTemplatePropertyKind<'repo> {
|
||||
CommitTemplatePropertyKind::RefNameList(Box::new(property))
|
||||
}
|
||||
|
||||
pub fn wrap_commit_or_change_id(
|
||||
property: impl TemplateProperty<(), Output = CommitOrChangeId> + 'repo,
|
||||
property: impl TemplateProperty<Output = CommitOrChangeId> + 'repo,
|
||||
) -> CommitTemplatePropertyKind<'repo> {
|
||||
CommitTemplatePropertyKind::CommitOrChangeId(Box::new(property))
|
||||
}
|
||||
|
||||
pub fn wrap_shortest_id_prefix(
|
||||
property: impl TemplateProperty<(), Output = ShortestIdPrefix> + 'repo,
|
||||
property: impl TemplateProperty<Output = ShortestIdPrefix> + 'repo,
|
||||
) -> CommitTemplatePropertyKind<'repo> {
|
||||
CommitTemplatePropertyKind::ShortestIdPrefix(Box::new(property))
|
||||
}
|
||||
}
|
||||
|
||||
pub enum CommitTemplatePropertyKind<'repo> {
|
||||
Core(CoreTemplatePropertyKind<'repo, ()>),
|
||||
Commit(Box<dyn TemplateProperty<(), Output = Commit> + 'repo>),
|
||||
CommitList(Box<dyn TemplateProperty<(), Output = Vec<Commit>> + 'repo>),
|
||||
RefName(Box<dyn TemplateProperty<(), Output = RefName> + 'repo>),
|
||||
RefNameList(Box<dyn TemplateProperty<(), Output = Vec<RefName>> + 'repo>),
|
||||
CommitOrChangeId(Box<dyn TemplateProperty<(), Output = CommitOrChangeId> + 'repo>),
|
||||
ShortestIdPrefix(Box<dyn TemplateProperty<(), Output = ShortestIdPrefix> + 'repo>),
|
||||
Core(CoreTemplatePropertyKind<'repo>),
|
||||
Commit(Box<dyn TemplateProperty<Output = Commit> + 'repo>),
|
||||
CommitList(Box<dyn TemplateProperty<Output = Vec<Commit>> + 'repo>),
|
||||
RefName(Box<dyn TemplateProperty<Output = RefName> + 'repo>),
|
||||
RefNameList(Box<dyn TemplateProperty<Output = Vec<RefName>> + 'repo>),
|
||||
CommitOrChangeId(Box<dyn TemplateProperty<Output = CommitOrChangeId> + 'repo>),
|
||||
ShortestIdPrefix(Box<dyn TemplateProperty<Output = ShortestIdPrefix> + 'repo>),
|
||||
}
|
||||
|
||||
impl<'repo> IntoTemplateProperty<'repo, ()> for CommitTemplatePropertyKind<'repo> {
|
||||
fn try_into_boolean(self) -> Option<Box<dyn TemplateProperty<(), Output = bool> + 'repo>> {
|
||||
impl<'repo> IntoTemplateProperty<'repo> for CommitTemplatePropertyKind<'repo> {
|
||||
fn try_into_boolean(self) -> Option<Box<dyn TemplateProperty<Output = bool> + 'repo>> {
|
||||
match self {
|
||||
CommitTemplatePropertyKind::Core(property) => property.try_into_boolean(),
|
||||
CommitTemplatePropertyKind::Commit(_) => None,
|
||||
|
@ -252,14 +251,14 @@ impl<'repo> IntoTemplateProperty<'repo, ()> for CommitTemplatePropertyKind<'repo
|
|||
}
|
||||
}
|
||||
|
||||
fn try_into_integer(self) -> Option<Box<dyn TemplateProperty<(), Output = i64> + 'repo>> {
|
||||
fn try_into_integer(self) -> Option<Box<dyn TemplateProperty<Output = i64> + 'repo>> {
|
||||
match self {
|
||||
CommitTemplatePropertyKind::Core(property) => property.try_into_integer(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_into_plain_text(self) -> Option<Box<dyn TemplateProperty<(), Output = String> + 'repo>> {
|
||||
fn try_into_plain_text(self) -> Option<Box<dyn TemplateProperty<Output = String> + 'repo>> {
|
||||
match self {
|
||||
CommitTemplatePropertyKind::Core(property) => property.try_into_plain_text(),
|
||||
_ => {
|
||||
|
|
|
@ -66,7 +66,7 @@ impl<'a, C> GenericTemplateLanguage<'a, C> {
|
|||
pub fn add_keyword<F>(&mut self, name: &'static str, build: F)
|
||||
where
|
||||
F: Fn(
|
||||
Box<dyn TemplateProperty<(), Output = C> + 'a>,
|
||||
Box<dyn TemplateProperty<Output = C> + 'a>,
|
||||
) -> TemplateParseResult<GenericTemplatePropertyKind<'a, C>>
|
||||
+ 'a,
|
||||
{
|
||||
|
@ -75,7 +75,6 @@ impl<'a, C> GenericTemplateLanguage<'a, C> {
|
|||
}
|
||||
|
||||
impl<'a, C: 'a> TemplateLanguage<'a> for GenericTemplateLanguage<'a, C> {
|
||||
type Context = ();
|
||||
type Property = GenericTemplatePropertyKind<'a, C>;
|
||||
|
||||
template_builder::impl_core_wrap_property_fns!('a, GenericTemplatePropertyKind::Core);
|
||||
|
@ -113,33 +112,33 @@ impl<'a, C: 'a> TemplateLanguage<'a> for GenericTemplateLanguage<'a, C> {
|
|||
|
||||
impl<'a, C> GenericTemplateLanguage<'a, C> {
|
||||
pub fn wrap_self(
|
||||
property: impl TemplateProperty<(), Output = C> + 'a,
|
||||
property: impl TemplateProperty<Output = C> + 'a,
|
||||
) -> GenericTemplatePropertyKind<'a, C> {
|
||||
GenericTemplatePropertyKind::Self_(Box::new(property))
|
||||
}
|
||||
}
|
||||
|
||||
pub enum GenericTemplatePropertyKind<'a, C> {
|
||||
Core(CoreTemplatePropertyKind<'a, ()>),
|
||||
Self_(Box<dyn TemplateProperty<(), Output = C> + 'a>),
|
||||
Core(CoreTemplatePropertyKind<'a>),
|
||||
Self_(Box<dyn TemplateProperty<Output = C> + 'a>),
|
||||
}
|
||||
|
||||
impl<'a, C: 'a> IntoTemplateProperty<'a, ()> for GenericTemplatePropertyKind<'a, C> {
|
||||
fn try_into_boolean(self) -> Option<Box<dyn TemplateProperty<(), Output = bool> + 'a>> {
|
||||
impl<'a, C: 'a> IntoTemplateProperty<'a> for GenericTemplatePropertyKind<'a, C> {
|
||||
fn try_into_boolean(self) -> Option<Box<dyn TemplateProperty<Output = bool> + 'a>> {
|
||||
match self {
|
||||
GenericTemplatePropertyKind::Core(property) => property.try_into_boolean(),
|
||||
GenericTemplatePropertyKind::Self_(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_into_integer(self) -> Option<Box<dyn TemplateProperty<(), Output = i64> + 'a>> {
|
||||
fn try_into_integer(self) -> Option<Box<dyn TemplateProperty<Output = i64> + 'a>> {
|
||||
match self {
|
||||
GenericTemplatePropertyKind::Core(property) => property.try_into_integer(),
|
||||
GenericTemplatePropertyKind::Self_(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_into_plain_text(self) -> Option<Box<dyn TemplateProperty<(), Output = String> + 'a>> {
|
||||
fn try_into_plain_text(self) -> Option<Box<dyn TemplateProperty<Output = String> + 'a>> {
|
||||
match self {
|
||||
GenericTemplatePropertyKind::Core(property) => property.try_into_plain_text(),
|
||||
GenericTemplatePropertyKind::Self_(_) => None,
|
||||
|
@ -161,7 +160,7 @@ impl<'a, C: 'a> IntoTemplateProperty<'a, ()> for GenericTemplatePropertyKind<'a,
|
|||
/// global resources, the keyword function is allowed to capture resources.
|
||||
pub type GenericTemplateBuildKeywordFn<'a, C> = Box<
|
||||
dyn Fn(
|
||||
Box<dyn TemplateProperty<(), Output = C> + 'a>,
|
||||
Box<dyn TemplateProperty<Output = C> + 'a>,
|
||||
) -> TemplateParseResult<GenericTemplatePropertyKind<'a, C>>
|
||||
+ 'a,
|
||||
>;
|
||||
|
|
|
@ -72,7 +72,6 @@ impl OperationTemplateLanguage {
|
|||
}
|
||||
|
||||
impl TemplateLanguage<'static> for OperationTemplateLanguage {
|
||||
type Context = ();
|
||||
type Property = OperationTemplatePropertyKind;
|
||||
|
||||
template_builder::impl_core_wrap_property_fns!('static, OperationTemplatePropertyKind::Core);
|
||||
|
@ -117,26 +116,26 @@ impl OperationTemplateLanguage {
|
|||
}
|
||||
|
||||
pub fn wrap_operation(
|
||||
property: impl TemplateProperty<(), Output = Operation> + 'static,
|
||||
property: impl TemplateProperty<Output = Operation> + 'static,
|
||||
) -> OperationTemplatePropertyKind {
|
||||
OperationTemplatePropertyKind::Operation(Box::new(property))
|
||||
}
|
||||
|
||||
pub fn wrap_operation_id(
|
||||
property: impl TemplateProperty<(), Output = OperationId> + 'static,
|
||||
property: impl TemplateProperty<Output = OperationId> + 'static,
|
||||
) -> OperationTemplatePropertyKind {
|
||||
OperationTemplatePropertyKind::OperationId(Box::new(property))
|
||||
}
|
||||
}
|
||||
|
||||
pub enum OperationTemplatePropertyKind {
|
||||
Core(CoreTemplatePropertyKind<'static, ()>),
|
||||
Operation(Box<dyn TemplateProperty<(), Output = Operation>>),
|
||||
OperationId(Box<dyn TemplateProperty<(), Output = OperationId>>),
|
||||
Core(CoreTemplatePropertyKind<'static>),
|
||||
Operation(Box<dyn TemplateProperty<Output = Operation>>),
|
||||
OperationId(Box<dyn TemplateProperty<Output = OperationId>>),
|
||||
}
|
||||
|
||||
impl IntoTemplateProperty<'static, ()> for OperationTemplatePropertyKind {
|
||||
fn try_into_boolean(self) -> Option<Box<dyn TemplateProperty<(), Output = bool>>> {
|
||||
impl IntoTemplateProperty<'static> for OperationTemplatePropertyKind {
|
||||
fn try_into_boolean(self) -> Option<Box<dyn TemplateProperty<Output = bool>>> {
|
||||
match self {
|
||||
OperationTemplatePropertyKind::Core(property) => property.try_into_boolean(),
|
||||
OperationTemplatePropertyKind::Operation(_) => None,
|
||||
|
@ -144,14 +143,14 @@ impl IntoTemplateProperty<'static, ()> for OperationTemplatePropertyKind {
|
|||
}
|
||||
}
|
||||
|
||||
fn try_into_integer(self) -> Option<Box<dyn TemplateProperty<(), Output = i64>>> {
|
||||
fn try_into_integer(self) -> Option<Box<dyn TemplateProperty<Output = i64>>> {
|
||||
match self {
|
||||
OperationTemplatePropertyKind::Core(property) => property.try_into_integer(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_into_plain_text(self) -> Option<Box<dyn TemplateProperty<(), Output = String>>> {
|
||||
fn try_into_plain_text(self) -> Option<Box<dyn TemplateProperty<Output = String>>> {
|
||||
match self {
|
||||
OperationTemplatePropertyKind::Core(property) => property.try_into_plain_text(),
|
||||
_ => {
|
||||
|
|
|
@ -31,33 +31,22 @@ use crate::{text_util, time_util};
|
|||
|
||||
/// Callbacks to build language-specific evaluation objects from AST nodes.
|
||||
pub trait TemplateLanguage<'a> {
|
||||
type Context: 'a;
|
||||
type Property: IntoTemplateProperty<'a, Self::Context>;
|
||||
type Property: IntoTemplateProperty<'a>;
|
||||
|
||||
fn wrap_string(
|
||||
property: impl TemplateProperty<Self::Context, Output = String> + 'a,
|
||||
) -> Self::Property;
|
||||
fn wrap_string(property: impl TemplateProperty<Output = String> + 'a) -> Self::Property;
|
||||
fn wrap_string_list(
|
||||
property: impl TemplateProperty<Self::Context, Output = Vec<String>> + 'a,
|
||||
) -> Self::Property;
|
||||
fn wrap_boolean(
|
||||
property: impl TemplateProperty<Self::Context, Output = bool> + 'a,
|
||||
) -> Self::Property;
|
||||
fn wrap_integer(
|
||||
property: impl TemplateProperty<Self::Context, Output = i64> + 'a,
|
||||
) -> Self::Property;
|
||||
fn wrap_signature(
|
||||
property: impl TemplateProperty<Self::Context, Output = Signature> + 'a,
|
||||
) -> Self::Property;
|
||||
fn wrap_timestamp(
|
||||
property: impl TemplateProperty<Self::Context, Output = Timestamp> + 'a,
|
||||
property: impl TemplateProperty<Output = Vec<String>> + 'a,
|
||||
) -> Self::Property;
|
||||
fn wrap_boolean(property: impl TemplateProperty<Output = bool> + 'a) -> Self::Property;
|
||||
fn wrap_integer(property: impl TemplateProperty<Output = i64> + 'a) -> Self::Property;
|
||||
fn wrap_signature(property: impl TemplateProperty<Output = Signature> + 'a) -> Self::Property;
|
||||
fn wrap_timestamp(property: impl TemplateProperty<Output = Timestamp> + 'a) -> Self::Property;
|
||||
fn wrap_timestamp_range(
|
||||
property: impl TemplateProperty<Self::Context, Output = TimestampRange> + 'a,
|
||||
property: impl TemplateProperty<Output = TimestampRange> + 'a,
|
||||
) -> Self::Property;
|
||||
|
||||
fn wrap_template(template: Box<dyn Template<Self::Context> + 'a>) -> Self::Property;
|
||||
fn wrap_list_template(template: Box<dyn ListTemplate<Self::Context> + 'a>) -> Self::Property;
|
||||
fn wrap_template(template: Box<dyn Template<()> + 'a>) -> Self::Property;
|
||||
fn wrap_list_template(template: Box<dyn ListTemplate<()> + 'a>) -> Self::Property;
|
||||
|
||||
/// Translates the given global `function` call to a property.
|
||||
///
|
||||
|
@ -98,13 +87,13 @@ macro_rules! impl_core_wrap_property_fns {
|
|||
}
|
||||
);
|
||||
fn wrap_template(
|
||||
template: Box<dyn $crate::templater::Template<Self::Context> + $a>,
|
||||
template: Box<dyn $crate::templater::Template<()> + $a>,
|
||||
) -> Self::Property {
|
||||
use $crate::template_builder::CoreTemplatePropertyKind as Kind;
|
||||
$outer(Kind::Template(template))
|
||||
}
|
||||
fn wrap_list_template(
|
||||
template: Box<dyn $crate::templater::ListTemplate<Self::Context> + $a>,
|
||||
template: Box<dyn $crate::templater::ListTemplate<()> + $a>,
|
||||
) -> Self::Property {
|
||||
use $crate::template_builder::CoreTemplatePropertyKind as Kind;
|
||||
$outer(Kind::ListTemplate(template))
|
||||
|
@ -116,8 +105,7 @@ macro_rules! impl_wrap_property_fns {
|
|||
($a:lifetime, $kind:path, $outer:path, { $( $func:ident($ty:ty) => $var:ident, )+ }) => {
|
||||
$(
|
||||
fn $func(
|
||||
property: impl $crate::templater::TemplateProperty<
|
||||
Self::Context, Output = $ty> + $a,
|
||||
property: impl $crate::templater::TemplateProperty<Output = $ty> + $a,
|
||||
) -> Self::Property {
|
||||
use $kind as Kind; // https://github.com/rust-lang/rust/issues/48067
|
||||
$outer(Kind::$var(Box::new(property)))
|
||||
|
@ -129,32 +117,34 @@ macro_rules! impl_wrap_property_fns {
|
|||
pub(crate) use {impl_core_wrap_property_fns, impl_wrap_property_fns};
|
||||
|
||||
/// Provides access to basic template property types.
|
||||
pub trait IntoTemplateProperty<'a, C> {
|
||||
fn try_into_boolean(self) -> Option<Box<dyn TemplateProperty<C, Output = bool> + 'a>>;
|
||||
fn try_into_integer(self) -> Option<Box<dyn TemplateProperty<C, Output = i64> + 'a>>;
|
||||
pub trait IntoTemplateProperty<'a> {
|
||||
fn try_into_boolean(self) -> Option<Box<dyn TemplateProperty<Output = bool> + 'a>>;
|
||||
fn try_into_integer(self) -> Option<Box<dyn TemplateProperty<Output = i64> + 'a>>;
|
||||
|
||||
fn try_into_plain_text(self) -> Option<Box<dyn TemplateProperty<C, Output = String> + 'a>>;
|
||||
fn try_into_template(self) -> Option<Box<dyn Template<C> + 'a>>;
|
||||
fn try_into_plain_text(self) -> Option<Box<dyn TemplateProperty<Output = String> + 'a>>;
|
||||
fn try_into_template(self) -> Option<Box<dyn Template<()> + 'a>>;
|
||||
}
|
||||
|
||||
pub enum CoreTemplatePropertyKind<'a, I> {
|
||||
String(Box<dyn TemplateProperty<I, Output = String> + 'a>),
|
||||
StringList(Box<dyn TemplateProperty<I, Output = Vec<String>> + 'a>),
|
||||
Boolean(Box<dyn TemplateProperty<I, Output = bool> + 'a>),
|
||||
Integer(Box<dyn TemplateProperty<I, Output = i64> + 'a>),
|
||||
Signature(Box<dyn TemplateProperty<I, Output = Signature> + 'a>),
|
||||
Timestamp(Box<dyn TemplateProperty<I, Output = Timestamp> + 'a>),
|
||||
TimestampRange(Box<dyn TemplateProperty<I, Output = TimestampRange> + 'a>),
|
||||
pub enum CoreTemplatePropertyKind<'a> {
|
||||
String(Box<dyn TemplateProperty<Output = String> + 'a>),
|
||||
StringList(Box<dyn TemplateProperty<Output = Vec<String>> + 'a>),
|
||||
Boolean(Box<dyn TemplateProperty<Output = bool> + 'a>),
|
||||
Integer(Box<dyn TemplateProperty<Output = i64> + 'a>),
|
||||
Signature(Box<dyn TemplateProperty<Output = Signature> + 'a>),
|
||||
Timestamp(Box<dyn TemplateProperty<Output = Timestamp> + 'a>),
|
||||
TimestampRange(Box<dyn TemplateProperty<Output = TimestampRange> + 'a>),
|
||||
|
||||
// TODO: This argument no longer makes sense. Maybe we can migrate these to
|
||||
// TemplateProperty<..>:
|
||||
// Similar to `TemplateProperty<I, Output = Box<dyn Template<()> + 'a>`, but doesn't
|
||||
// capture `I` to produce `Template<()>`. The context `I` would have to be cloned
|
||||
// to convert `Template<I>` to `Template<()>`.
|
||||
Template(Box<dyn Template<I> + 'a>),
|
||||
ListTemplate(Box<dyn ListTemplate<I> + 'a>),
|
||||
Template(Box<dyn Template<()> + 'a>),
|
||||
ListTemplate(Box<dyn ListTemplate<()> + 'a>),
|
||||
}
|
||||
|
||||
impl<'a, I: 'a> IntoTemplateProperty<'a, I> for CoreTemplatePropertyKind<'a, I> {
|
||||
fn try_into_boolean(self) -> Option<Box<dyn TemplateProperty<I, Output = bool> + 'a>> {
|
||||
impl<'a> IntoTemplateProperty<'a> for CoreTemplatePropertyKind<'a> {
|
||||
fn try_into_boolean(self) -> Option<Box<dyn TemplateProperty<Output = bool> + 'a>> {
|
||||
match self {
|
||||
CoreTemplatePropertyKind::String(property) => {
|
||||
Some(Box::new(TemplateFunction::new(property, |s| {
|
||||
|
@ -179,14 +169,14 @@ impl<'a, I: 'a> IntoTemplateProperty<'a, I> for CoreTemplatePropertyKind<'a, I>
|
|||
}
|
||||
}
|
||||
|
||||
fn try_into_integer(self) -> Option<Box<dyn TemplateProperty<I, Output = i64> + 'a>> {
|
||||
fn try_into_integer(self) -> Option<Box<dyn TemplateProperty<Output = i64> + 'a>> {
|
||||
match self {
|
||||
CoreTemplatePropertyKind::Integer(property) => Some(property),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_into_plain_text(self) -> Option<Box<dyn TemplateProperty<I, Output = String> + 'a>> {
|
||||
fn try_into_plain_text(self) -> Option<Box<dyn TemplateProperty<Output = String> + 'a>> {
|
||||
match self {
|
||||
CoreTemplatePropertyKind::String(property) => Some(property),
|
||||
_ => {
|
||||
|
@ -204,7 +194,7 @@ impl<'a, I: 'a> IntoTemplateProperty<'a, I> for CoreTemplatePropertyKind<'a, I>
|
|||
}
|
||||
}
|
||||
|
||||
fn try_into_template(self) -> Option<Box<dyn Template<I> + 'a>> {
|
||||
fn try_into_template(self) -> Option<Box<dyn Template<()> + 'a>> {
|
||||
match self {
|
||||
CoreTemplatePropertyKind::String(property) => Some(property.into_template()),
|
||||
CoreTemplatePropertyKind::StringList(property) => Some(property.into_template()),
|
||||
|
@ -237,7 +227,7 @@ pub type TemplateBuildMethodFn<'a, L, T> =
|
|||
fn(
|
||||
&L,
|
||||
&BuildContext<<L as TemplateLanguage<'a>>::Property>,
|
||||
Box<dyn TemplateProperty<<L as TemplateLanguage<'a>>::Context, Output = T> + 'a>,
|
||||
Box<dyn TemplateProperty<Output = T> + 'a>,
|
||||
&FunctionCallNode,
|
||||
) -> TemplateParseResult<<L as TemplateLanguage<'a>>::Property>;
|
||||
|
||||
|
@ -331,7 +321,7 @@ impl<'a, L: TemplateLanguage<'a> + ?Sized> CoreTemplateBuildFnTable<'a, L> {
|
|||
&self,
|
||||
language: &L,
|
||||
build_ctx: &BuildContext<L::Property>,
|
||||
property: CoreTemplatePropertyKind<'a, L::Context>,
|
||||
property: CoreTemplatePropertyKind<'a>,
|
||||
function: &FunctionCallNode,
|
||||
) -> TemplateParseResult<L::Property> {
|
||||
match property {
|
||||
|
@ -399,38 +389,22 @@ impl<P> Expression<P> {
|
|||
let labels = vec![label.into()];
|
||||
Expression { property, labels }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_into_boolean<'a, C: 'a>(
|
||||
self,
|
||||
) -> Option<Box<dyn TemplateProperty<C, Output = bool> + 'a>>
|
||||
where
|
||||
P: IntoTemplateProperty<'a, C>,
|
||||
{
|
||||
impl<'a, P: IntoTemplateProperty<'a>> Expression<P> {
|
||||
pub fn try_into_boolean(self) -> Option<Box<dyn TemplateProperty<Output = bool> + 'a>> {
|
||||
self.property.try_into_boolean()
|
||||
}
|
||||
|
||||
pub fn try_into_integer<'a, C: 'a>(
|
||||
self,
|
||||
) -> Option<Box<dyn TemplateProperty<C, Output = i64> + 'a>>
|
||||
where
|
||||
P: IntoTemplateProperty<'a, C>,
|
||||
{
|
||||
pub fn try_into_integer(self) -> Option<Box<dyn TemplateProperty<Output = i64> + 'a>> {
|
||||
self.property.try_into_integer()
|
||||
}
|
||||
|
||||
pub fn try_into_plain_text<'a, C: 'a>(
|
||||
self,
|
||||
) -> Option<Box<dyn TemplateProperty<C, Output = String> + 'a>>
|
||||
where
|
||||
P: IntoTemplateProperty<'a, C>,
|
||||
{
|
||||
pub fn try_into_plain_text(self) -> Option<Box<dyn TemplateProperty<Output = String> + 'a>> {
|
||||
self.property.try_into_plain_text()
|
||||
}
|
||||
|
||||
pub fn try_into_template<'a, C: 'a>(self) -> Option<Box<dyn Template<C> + 'a>>
|
||||
where
|
||||
P: IntoTemplateProperty<'a, C>,
|
||||
{
|
||||
pub fn try_into_template(self) -> Option<Box<dyn Template<()> + 'a>> {
|
||||
let template = self.property.try_into_template()?;
|
||||
if self.labels.is_empty() {
|
||||
Some(template)
|
||||
|
@ -802,7 +776,7 @@ fn builtin_timestamp_range_methods<'a, L: TemplateLanguage<'a> + ?Sized>(
|
|||
fn build_list_template_method<'a, L: TemplateLanguage<'a> + ?Sized>(
|
||||
language: &L,
|
||||
build_ctx: &BuildContext<L::Property>,
|
||||
self_template: Box<dyn ListTemplate<L::Context> + 'a>,
|
||||
self_template: Box<dyn ListTemplate<()> + 'a>,
|
||||
function: &FunctionCallNode,
|
||||
) -> TemplateParseResult<L::Property> {
|
||||
let property = match function.name {
|
||||
|
@ -820,9 +794,9 @@ fn build_list_template_method<'a, L: TemplateLanguage<'a> + ?Sized>(
|
|||
pub fn build_formattable_list_method<'a, L, O>(
|
||||
language: &L,
|
||||
build_ctx: &BuildContext<L::Property>,
|
||||
self_property: impl TemplateProperty<L::Context, Output = Vec<O>> + 'a,
|
||||
self_property: impl TemplateProperty<Output = Vec<O>> + 'a,
|
||||
function: &FunctionCallNode,
|
||||
// TODO: Generic L: WrapProperty<L::Context, O> trait might be needed to support more
|
||||
// TODO: Generic L: WrapProperty<O> trait might be needed to support more
|
||||
// list operations such as first()/slice(). For .map(), a simple callback works.
|
||||
wrap_item: impl Fn(PropertyPlaceholder<O>) -> L::Property,
|
||||
) -> TemplateParseResult<L::Property>
|
||||
|
@ -855,7 +829,7 @@ where
|
|||
pub fn build_unformattable_list_method<'a, L, O>(
|
||||
language: &L,
|
||||
build_ctx: &BuildContext<L::Property>,
|
||||
self_property: impl TemplateProperty<L::Context, Output = Vec<O>> + 'a,
|
||||
self_property: impl TemplateProperty<Output = Vec<O>> + 'a,
|
||||
function: &FunctionCallNode,
|
||||
wrap_item: impl Fn(PropertyPlaceholder<O>) -> L::Property,
|
||||
) -> TemplateParseResult<L::Property>
|
||||
|
@ -890,16 +864,12 @@ fn build_map_operation<'a, L, O, P>(
|
|||
) -> TemplateParseResult<L::Property>
|
||||
where
|
||||
L: TemplateLanguage<'a> + ?Sized,
|
||||
P: TemplateProperty<L::Context> + 'a,
|
||||
P: TemplateProperty + 'a,
|
||||
P::Output: IntoIterator<Item = O>,
|
||||
O: Clone + 'a,
|
||||
{
|
||||
// Build an item template with placeholder property, then evaluate it
|
||||
// for each item.
|
||||
//
|
||||
// It would be nice if we could build a template of (L::Context, O)
|
||||
// input, but doing that for a generic item type wouldn't be easy. It's
|
||||
// also invalid to convert &C to &(C, _).
|
||||
let [lambda_node] = template_parser::expect_exact_arguments(function)?;
|
||||
let item_placeholder = PropertyPlaceholder::new();
|
||||
let item_template = template_parser::expect_lambda_with(lambda_node, |lambda, _span| {
|
||||
|
@ -937,8 +907,8 @@ fn builtin_functions<'a, L: TemplateLanguage<'a> + ?Sized>() -> TemplateBuildFun
|
|||
let [width_node, content_node] = template_parser::expect_exact_arguments(function)?;
|
||||
let width = expect_usize_expression(language, build_ctx, width_node)?;
|
||||
let content = expect_template_expression(language, build_ctx, content_node)?;
|
||||
let template = ReformatTemplate::new(content, move |context, formatter, recorded| {
|
||||
match width.extract(context) {
|
||||
let template = ReformatTemplate::new(content, move |_context, formatter, recorded| {
|
||||
match width.extract() {
|
||||
Ok(width) => text_util::write_wrapped(formatter, recorded, width),
|
||||
Err(err) => err.format(&(), formatter),
|
||||
}
|
||||
|
@ -1099,10 +1069,10 @@ pub type RootTemplate<'a, C> = PlaceholderTemplate<C, Box<dyn Template<()> + 'a>
|
|||
///
|
||||
/// `wrap_self` specifies the type of the top-level property, which should be
|
||||
/// one of the `L::wrap_*()` functions.
|
||||
pub fn build<'a, C: Clone + 'a, L: TemplateLanguage<'a, Context = ()> + ?Sized>(
|
||||
pub fn build<'a, C: Clone + 'a, L: TemplateLanguage<'a> + ?Sized>(
|
||||
language: &L,
|
||||
node: &ExpressionNode,
|
||||
// TODO: Generic L: WrapProperty<(), C> trait might be better. See the
|
||||
// TODO: Generic L: WrapProperty<C> trait might be better. See the
|
||||
// comment in build_formattable_list_method().
|
||||
wrap_self: impl Fn(PropertyPlaceholder<C>) -> L::Property,
|
||||
) -> TemplateParseResult<RootTemplate<'a, C>> {
|
||||
|
@ -1116,7 +1086,7 @@ pub fn build<'a, C: Clone + 'a, L: TemplateLanguage<'a, Context = ()> + ?Sized>(
|
|||
}
|
||||
|
||||
/// Parses text, expands aliases, then builds template evaluation tree.
|
||||
pub fn parse<'a, C: Clone + 'a, L: TemplateLanguage<'a, Context = ()> + ?Sized>(
|
||||
pub fn parse<'a, C: Clone + 'a, L: TemplateLanguage<'a> + ?Sized>(
|
||||
language: &L,
|
||||
template_text: &str,
|
||||
aliases_map: &TemplateAliasesMap,
|
||||
|
@ -1130,7 +1100,7 @@ pub fn expect_boolean_expression<'a, L: TemplateLanguage<'a> + ?Sized>(
|
|||
language: &L,
|
||||
build_ctx: &BuildContext<L::Property>,
|
||||
node: &ExpressionNode,
|
||||
) -> TemplateParseResult<Box<dyn TemplateProperty<L::Context, Output = bool> + 'a>> {
|
||||
) -> TemplateParseResult<Box<dyn TemplateProperty<Output = bool> + 'a>> {
|
||||
build_expression(language, build_ctx, node)?
|
||||
.try_into_boolean()
|
||||
.ok_or_else(|| TemplateParseError::expected_type("Boolean", node.span))
|
||||
|
@ -1140,7 +1110,7 @@ pub fn expect_integer_expression<'a, L: TemplateLanguage<'a> + ?Sized>(
|
|||
language: &L,
|
||||
build_ctx: &BuildContext<L::Property>,
|
||||
node: &ExpressionNode,
|
||||
) -> TemplateParseResult<Box<dyn TemplateProperty<L::Context, Output = i64> + 'a>> {
|
||||
) -> TemplateParseResult<Box<dyn TemplateProperty<Output = i64> + 'a>> {
|
||||
build_expression(language, build_ctx, node)?
|
||||
.try_into_integer()
|
||||
.ok_or_else(|| TemplateParseError::expected_type("Integer", node.span))
|
||||
|
@ -1151,7 +1121,7 @@ pub fn expect_isize_expression<'a, L: TemplateLanguage<'a> + ?Sized>(
|
|||
language: &L,
|
||||
build_ctx: &BuildContext<L::Property>,
|
||||
node: &ExpressionNode,
|
||||
) -> TemplateParseResult<Box<dyn TemplateProperty<L::Context, Output = isize> + 'a>> {
|
||||
) -> TemplateParseResult<Box<dyn TemplateProperty<Output = isize> + 'a>> {
|
||||
let i64_property = expect_integer_expression(language, build_ctx, node)?;
|
||||
let isize_property = TemplateFunction::new(i64_property, |v| Ok(isize::try_from(v)?));
|
||||
Ok(Box::new(isize_property))
|
||||
|
@ -1162,7 +1132,7 @@ pub fn expect_usize_expression<'a, L: TemplateLanguage<'a> + ?Sized>(
|
|||
language: &L,
|
||||
build_ctx: &BuildContext<L::Property>,
|
||||
node: &ExpressionNode,
|
||||
) -> TemplateParseResult<Box<dyn TemplateProperty<L::Context, Output = usize> + 'a>> {
|
||||
) -> TemplateParseResult<Box<dyn TemplateProperty<Output = usize> + 'a>> {
|
||||
let i64_property = expect_integer_expression(language, build_ctx, node)?;
|
||||
let usize_property = TemplateFunction::new(i64_property, |v| Ok(usize::try_from(v)?));
|
||||
Ok(Box::new(usize_property))
|
||||
|
@ -1172,7 +1142,7 @@ pub fn expect_plain_text_expression<'a, L: TemplateLanguage<'a> + ?Sized>(
|
|||
language: &L,
|
||||
build_ctx: &BuildContext<L::Property>,
|
||||
node: &ExpressionNode,
|
||||
) -> TemplateParseResult<Box<dyn TemplateProperty<L::Context, Output = String> + 'a>> {
|
||||
) -> TemplateParseResult<Box<dyn TemplateProperty<Output = String> + 'a>> {
|
||||
// Since any formattable type can be converted to a string property,
|
||||
// the expected type is not a String, but a Template.
|
||||
build_expression(language, build_ctx, node)?
|
||||
|
@ -1184,7 +1154,7 @@ pub fn expect_template_expression<'a, L: TemplateLanguage<'a> + ?Sized>(
|
|||
language: &L,
|
||||
build_ctx: &BuildContext<L::Property>,
|
||||
node: &ExpressionNode,
|
||||
) -> TemplateParseResult<Box<dyn Template<L::Context> + 'a>> {
|
||||
) -> TemplateParseResult<Box<dyn Template<()> + 'a>> {
|
||||
build_expression(language, build_ctx, node)?
|
||||
.try_into_template()
|
||||
.ok_or_else(|| TemplateParseError::expected_type("Template", node.span))
|
||||
|
|
|
@ -148,7 +148,7 @@ impl<T, L> LabelTemplate<T, L> {
|
|||
pub fn new<C>(content: T, labels: L) -> Self
|
||||
where
|
||||
T: Template<C>,
|
||||
L: TemplateProperty<C, Output = Vec<String>>,
|
||||
L: TemplateProperty<Output = Vec<String>>,
|
||||
{
|
||||
LabelTemplate { content, labels }
|
||||
}
|
||||
|
@ -157,10 +157,10 @@ impl<T, L> LabelTemplate<T, L> {
|
|||
impl<C, T, L> Template<C> for LabelTemplate<T, L>
|
||||
where
|
||||
T: Template<C>,
|
||||
L: TemplateProperty<C, Output = Vec<String>>,
|
||||
L: TemplateProperty<Output = Vec<String>>,
|
||||
{
|
||||
fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()> {
|
||||
let labels = match self.labels.extract(context) {
|
||||
let labels = match self.labels.extract() {
|
||||
Ok(labels) => labels,
|
||||
Err(err) => return err.format(&(), formatter),
|
||||
};
|
||||
|
@ -285,27 +285,25 @@ impl Template<()> for TemplatePropertyError {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait TemplateProperty<C> {
|
||||
pub trait TemplateProperty {
|
||||
type Output;
|
||||
|
||||
fn extract(&self, context: &C) -> Result<Self::Output, TemplatePropertyError>;
|
||||
fn extract(&self) -> Result<Self::Output, TemplatePropertyError>;
|
||||
}
|
||||
|
||||
impl<C, P: TemplateProperty<C> + ?Sized> TemplateProperty<C> for Box<P> {
|
||||
type Output = <P as TemplateProperty<C>>::Output;
|
||||
impl<P: TemplateProperty + ?Sized> TemplateProperty for Box<P> {
|
||||
type Output = <P as TemplateProperty>::Output;
|
||||
|
||||
fn extract(&self, context: &C) -> Result<Self::Output, TemplatePropertyError> {
|
||||
<P as TemplateProperty<C>>::extract(self, context)
|
||||
fn extract(&self) -> Result<Self::Output, TemplatePropertyError> {
|
||||
<P as TemplateProperty>::extract(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, P: TemplateProperty<C>> TemplateProperty<C> for Option<P> {
|
||||
impl<P: TemplateProperty> TemplateProperty for Option<P> {
|
||||
type Output = Option<P::Output>;
|
||||
|
||||
fn extract(&self, context: &C) -> Result<Self::Output, TemplatePropertyError> {
|
||||
self.as_ref()
|
||||
.map(|property| property.extract(context))
|
||||
.transpose()
|
||||
fn extract(&self) -> Result<Self::Output, TemplatePropertyError> {
|
||||
self.as_ref().map(|property| property.extract()).transpose()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -313,11 +311,11 @@ impl<C, P: TemplateProperty<C>> TemplateProperty<C> for Option<P> {
|
|||
macro_rules! tuple_impls {
|
||||
($( ( $($n:tt $T:ident),+ ) )+) => {
|
||||
$(
|
||||
impl<C, $($T: TemplateProperty<C>,)+> TemplateProperty<C> for ($($T,)+) {
|
||||
impl<$($T: TemplateProperty,)+> TemplateProperty for ($($T,)+) {
|
||||
type Output = ($($T::Output,)+);
|
||||
|
||||
fn extract(&self, context: &C) -> Result<Self::Output, TemplatePropertyError> {
|
||||
Ok(($(self.$n.extract(context)?,)+))
|
||||
fn extract(&self) -> Result<Self::Output, TemplatePropertyError> {
|
||||
Ok(($(self.$n.extract()?,)+))
|
||||
}
|
||||
}
|
||||
)+
|
||||
|
@ -340,10 +338,10 @@ impl<C, O: Template<()>> Template<C> for Literal<O> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<C, O: Clone> TemplateProperty<C> for Literal<O> {
|
||||
impl<O: Clone> TemplateProperty for Literal<O> {
|
||||
type Output = O;
|
||||
|
||||
fn extract(&self, _context: &C) -> Result<Self::Output, TemplatePropertyError> {
|
||||
fn extract(&self) -> Result<Self::Output, TemplatePropertyError> {
|
||||
Ok(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
@ -354,33 +352,33 @@ pub struct FormattablePropertyTemplate<P> {
|
|||
}
|
||||
|
||||
impl<P> FormattablePropertyTemplate<P> {
|
||||
pub fn new<C>(property: P) -> Self
|
||||
pub fn new(property: P) -> Self
|
||||
where
|
||||
P: TemplateProperty<C>,
|
||||
P: TemplateProperty,
|
||||
P::Output: Template<()>,
|
||||
{
|
||||
FormattablePropertyTemplate { property }
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, P> Template<C> for FormattablePropertyTemplate<P>
|
||||
impl<P> Template<()> for FormattablePropertyTemplate<P>
|
||||
where
|
||||
P: TemplateProperty<C>,
|
||||
P: TemplateProperty,
|
||||
P::Output: Template<()>,
|
||||
{
|
||||
fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()> {
|
||||
match self.property.extract(context) {
|
||||
fn format(&self, _: &(), formatter: &mut dyn Formatter) -> io::Result<()> {
|
||||
match self.property.extract() {
|
||||
Ok(template) => template.format(&(), formatter),
|
||||
Err(err) => err.format(&(), formatter),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, C: 'a, O> IntoTemplate<'a, C> for Box<dyn TemplateProperty<C, Output = O> + 'a>
|
||||
impl<'a, O> IntoTemplate<'a, ()> for Box<dyn TemplateProperty<Output = O> + 'a>
|
||||
where
|
||||
O: Template<()> + 'a,
|
||||
{
|
||||
fn into_template(self) -> Box<dyn Template<C> + 'a> {
|
||||
fn into_template(self) -> Box<dyn Template<()> + 'a> {
|
||||
Box::new(FormattablePropertyTemplate::new(self))
|
||||
}
|
||||
}
|
||||
|
@ -396,13 +394,13 @@ impl<T> PlainTextFormattedProperty<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<C, T: Template<C>> TemplateProperty<C> for PlainTextFormattedProperty<T> {
|
||||
impl<T: Template<()>> TemplateProperty for PlainTextFormattedProperty<T> {
|
||||
type Output = String;
|
||||
|
||||
fn extract(&self, context: &C) -> Result<Self::Output, TemplatePropertyError> {
|
||||
fn extract(&self) -> Result<Self::Output, TemplatePropertyError> {
|
||||
let mut output = vec![];
|
||||
self.template
|
||||
.format(context, &mut PlainTextFormatter::new(&mut output))
|
||||
.format(&(), &mut PlainTextFormatter::new(&mut output))
|
||||
.expect("write() to PlainTextFormatter should never fail");
|
||||
Ok(String::from_utf8(output).map_err(|err| err.utf8_error())?)
|
||||
}
|
||||
|
@ -421,7 +419,7 @@ pub struct ListPropertyTemplate<P, S, F> {
|
|||
impl<P, S, F> ListPropertyTemplate<P, S, F> {
|
||||
pub fn new<C, O>(property: P, separator: S, format_item: F) -> Self
|
||||
where
|
||||
P: TemplateProperty<C>,
|
||||
P: TemplateProperty,
|
||||
P::Output: IntoIterator<Item = O>,
|
||||
S: Template<C>,
|
||||
F: Fn(&C, &mut dyn Formatter, O) -> io::Result<()>,
|
||||
|
@ -436,13 +434,13 @@ impl<P, S, F> ListPropertyTemplate<P, S, F> {
|
|||
|
||||
impl<C, O, P, S, F> Template<C> for ListPropertyTemplate<P, S, F>
|
||||
where
|
||||
P: TemplateProperty<C>,
|
||||
P: TemplateProperty,
|
||||
P::Output: IntoIterator<Item = O>,
|
||||
S: Template<C>,
|
||||
F: Fn(&C, &mut dyn Formatter, O) -> io::Result<()>,
|
||||
{
|
||||
fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()> {
|
||||
let contents = match self.property.extract(context) {
|
||||
let contents = match self.property.extract() {
|
||||
Ok(contents) => contents,
|
||||
Err(err) => return err.format(&(), formatter),
|
||||
};
|
||||
|
@ -458,7 +456,7 @@ where
|
|||
|
||||
impl<C, O, P, S, F> ListTemplate<C> for ListPropertyTemplate<P, S, F>
|
||||
where
|
||||
P: TemplateProperty<C>,
|
||||
P: TemplateProperty,
|
||||
P::Output: IntoIterator<Item = O>,
|
||||
S: Template<C>,
|
||||
F: Fn(&C, &mut dyn Formatter, O) -> io::Result<()>,
|
||||
|
@ -494,7 +492,7 @@ pub struct ConditionalTemplate<P, T, U> {
|
|||
impl<P, T, U> ConditionalTemplate<P, T, U> {
|
||||
pub fn new<C>(condition: P, true_template: T, false_template: Option<U>) -> Self
|
||||
where
|
||||
P: TemplateProperty<C, Output = bool>,
|
||||
P: TemplateProperty<Output = bool>,
|
||||
T: Template<C>,
|
||||
U: Template<C>,
|
||||
{
|
||||
|
@ -508,12 +506,12 @@ impl<P, T, U> ConditionalTemplate<P, T, U> {
|
|||
|
||||
impl<C, P, T, U> Template<C> for ConditionalTemplate<P, T, U>
|
||||
where
|
||||
P: TemplateProperty<C, Output = bool>,
|
||||
P: TemplateProperty<Output = bool>,
|
||||
T: Template<C>,
|
||||
U: Template<C>,
|
||||
{
|
||||
fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()> {
|
||||
let condition = match self.condition.extract(context) {
|
||||
let condition = match self.condition.extract() {
|
||||
Ok(condition) => condition,
|
||||
Err(err) => return err.format(&(), formatter),
|
||||
};
|
||||
|
@ -526,32 +524,30 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: If needed, add a ContextualTemplateFunction where the function also
|
||||
// gets the context
|
||||
pub struct TemplateFunction<P, F> {
|
||||
pub property: P,
|
||||
pub function: F,
|
||||
}
|
||||
|
||||
impl<P, F> TemplateFunction<P, F> {
|
||||
pub fn new<C, O>(property: P, function: F) -> Self
|
||||
pub fn new<O>(property: P, function: F) -> Self
|
||||
where
|
||||
P: TemplateProperty<C>,
|
||||
P: TemplateProperty,
|
||||
F: Fn(P::Output) -> Result<O, TemplatePropertyError>,
|
||||
{
|
||||
TemplateFunction { property, function }
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, O, P, F> TemplateProperty<C> for TemplateFunction<P, F>
|
||||
impl<O, P, F> TemplateProperty for TemplateFunction<P, F>
|
||||
where
|
||||
P: TemplateProperty<C>,
|
||||
P: TemplateProperty,
|
||||
F: Fn(P::Output) -> Result<O, TemplatePropertyError>,
|
||||
{
|
||||
type Output = O;
|
||||
|
||||
fn extract(&self, context: &C) -> Result<Self::Output, TemplatePropertyError> {
|
||||
(self.function)(self.property.extract(context)?)
|
||||
fn extract(&self) -> Result<Self::Output, TemplatePropertyError> {
|
||||
(self.function)(self.property.extract()?)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -590,10 +586,10 @@ impl<O> Default for PropertyPlaceholder<O> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<C, O: Clone> TemplateProperty<C> for PropertyPlaceholder<O> {
|
||||
impl<O: Clone> TemplateProperty for PropertyPlaceholder<O> {
|
||||
type Output = O;
|
||||
|
||||
fn extract(&self, _: &C) -> Result<Self::Output, TemplatePropertyError> {
|
||||
fn extract(&self) -> Result<Self::Output, TemplatePropertyError> {
|
||||
Ok(self
|
||||
.value
|
||||
.borrow()
|
||||
|
|
Loading…
Reference in a new issue