ok/jj
1
0
Fork 0
forked from mirrors/jj

templater: add trait that represents a mapped template

A mapped template is basically a combined function that takes context: &C,
extracts Vec<O>, and formats each item with Template<C>. It cannot be cleanly
turned into a function of (&C) -> Vec<Template<()>> type. So list-like methods
are implemented on Box<dyn ListTemplate<C>> instead.
This commit is contained in:
Yuya Nishihara 2023-03-11 19:14:49 +09:00
parent ec5dd96e66
commit 2fbe581a71

View file

@ -25,6 +25,20 @@ pub trait Template<C> {
fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()>;
}
/// Template that supports list-like behavior.
pub trait ListTemplate<C>: Template<C> {
/// Concatenates items with the given separator.
fn join<'a>(self: Box<Self>, separator: Box<dyn Template<C> + 'a>) -> Box<dyn Template<C> + 'a>
where
Self: 'a,
C: 'a;
/// Upcasts to the template type.
fn into_template<'a>(self: Box<Self>) -> Box<dyn Template<C> + 'a>
where
Self: 'a;
}
pub trait IntoTemplate<'a, C> {
fn into_template(self) -> Box<dyn Template<C> + 'a>;
}
@ -413,6 +427,35 @@ where
}
}
impl<C, O, P, S, F> ListTemplate<C> for ListPropertyTemplate<P, S, F>
where
P: TemplateProperty<C>,
P::Output: IntoIterator<Item = O>,
S: Template<C>,
F: Fn(&C, &mut dyn Formatter, O) -> io::Result<()>,
{
fn join<'a>(self: Box<Self>, separator: Box<dyn Template<C> + 'a>) -> Box<dyn Template<C> + 'a>
where
Self: 'a,
C: 'a,
{
// Once join()-ed, list-like API should be dropped. This is guaranteed by
// the return type.
Box::new(ListPropertyTemplate::new(
self.property,
separator,
self.format_item,
))
}
fn into_template<'a>(self: Box<Self>) -> Box<dyn Template<C> + 'a>
where
Self: 'a,
{
self
}
}
pub struct ConditionalTemplate<P, T, U> {
pub condition: P,
pub true_template: T,