use super::{Document, Node};
pub trait Render: Sized {
fn render(self, into: Document) -> Document;
fn into_fragment(self) -> Document {
self.render(Document::empty())
}
fn add<Right: Render>(self, other: Right) -> Combine<Self, Right> {
Combine {
left: self,
right: other,
}
}
}
pub struct Combine<Left: Render, Right: Render> {
pub(crate) left: Left,
pub(crate) right: Right,
}
impl<Left: Render, Right: Render> Render for Combine<Left, Right> {
fn render(self, into: Document) -> Document {
into.add(self.left).add(self.right)
}
}
impl Render for Node {
fn render(self, document: Document) -> Document {
document.add_node(self)
}
}
impl Render for Document {
fn render(self, into: Document) -> Document {
into.extend(self)
}
}
struct IfSome<'item, T: 'item, R: Render, F: Fn(&T) -> R + 'item> {
option: &'item Option<T>,
callback: F,
}
impl<'item, T, R, F> Render for IfSome<'item, T, R, F>
where
T: 'item,
R: Render,
F: Fn(&T) -> R,
{
fn render(self, mut into: Document) -> Document {
if let Some(inner) = self.option {
into = into.add((self.callback)(inner));
}
into
}
}
#[allow(non_snake_case)]
pub fn IfSome<'item, T: 'item, R: Render + 'item>(
option: &'item Option<T>,
callback: impl Fn(&T) -> R + 'item,
) -> impl Render + 'item {
IfSome { option, callback }
}
struct SomeValue<'item, T: 'item> {
option: &'item Option<T>,
}
impl<'item, T> Render for SomeValue<'item, T>
where
T: Render + Clone + 'item,
{
fn render(self, mut into: Document) -> Document {
if let Some(inner) = self.option {
into = inner.clone().render(into)
}
into
}
}
#[allow(non_snake_case)]
pub fn SomeValue<'item, R: Render + Clone>(option: &'item Option<R>) -> impl Render + 'item {
SomeValue { option }
}
pub struct Empty;
impl Render for Empty {
fn render(self, document: Document) -> Document {
document
}
}
impl<T: ::std::fmt::Display> Render for T {
fn render(self, document: Document) -> Document {
document.add(Node::Text(self.to_string()))
}
}