1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
use std::fmt::Write;

pub const DOCTYPE: &str = "<!DOCTYPE html>";
pub type Buffer = String;
pub type Result<T> = std::result::Result<T, std::fmt::Error>;

pub fn node<'tag, Attrs, Children>(
    tag: &'tag str,
    attrs: Attrs,
    children: Children,
) -> impl FnOnce(&mut Buffer) -> Result<&mut Buffer> + 'tag
where
    Attrs: FnOnce(&mut Buffer) -> Result<&mut Buffer> + 'tag,
    Children: FnOnce(&mut Buffer) -> Result<&mut Buffer> + 'tag,
{
    |buf| {
        buf.push('<');
        buf.push_str(tag);
        attrs(buf)?;
        buf.push('>');
        children(buf)?;
        buf.push_str("</");
        buf.push_str(tag);
        buf.push('>');
        Ok(buf)
    }
}

pub fn text(value: &str) -> impl FnOnce(&mut Buffer) -> Result<&mut Buffer> + '_ {
    |buf| {
        buf.push_str(value);
        Ok(buf)
    }
}

pub fn attr<'txt>(
    key: &'txt str,
    value: &'txt str,
) -> impl FnOnce(&mut Buffer) -> Result<&mut Buffer> + 'txt {
    move |buf| {
        write!(buf, " {key}={value:?}")?;
        Ok(buf)
    }
}

pub fn noop(buf: &mut Buffer) -> Result<&mut Buffer> {
    Ok(buf)
}

pub trait Component {
    fn render<'b>(&self, buf: &'b mut Buffer) -> Result<&'b mut Buffer> {
        Ok(buf)
    }
}