Fast way to build string - HTML builder

Hi!

I would like to create an HTML builder library to my project. My goal is to have a library where I can use pre defined HTML tags to build up GUI using rust compile time check and to be able to write gui for web with a similarity writing gui with GTK.

Currently the only way to do it using html macros like Maud, but in this way I need to write html tags and class manually.

I tried to prototype it, but using structs and enums, to hold the HTML structure and render it into a string buffer at last seems to be very slow. Using ~200 html tags inside each other to simulaty a smaller HTML, it takes ~700.000 nanosec. I tried to measure what is slow, and it seems to me, that each render means to build up the page inside the memory as well, and then render it, and the memory build up takes time.

I have already figured it out to use a string buffer, and using push_str() to build up html HTML during the render process - instead of creating plenty of small Strings and then concat them.

Do you have and advice in which way I can get to my point? Somehow I would like to use a nice API to build the UI, and make it fast to build it up and render. Maybe build and concat statics at compile time somehow from the smaller pieces?

An example API how I would like to use it:

let mut div = Tag::new("div");
let mut p = Tag::new("p");
let text = Tag::new_text("Hello, this is a demo paragraph");
p.add_tag(text);
let mut h1 = Tag::new("h1");
let h1_text = Tag::new_text("Lorem ipsum dolorem");
h1.add_attribute(Attribute::Quoted("class", "is-size-2"));
h1.add_tag(h1_text);
div.add_tag(h1);
div.add_tag(p);

let mut buffer = String::new();
div.render_to(buffer);

println("{}", buffer);

And that would print the following:

<div><h1 class="is-size-2">Lorem ipsum dolorem</h1><p>Hello, this is a demo paragraph</p></div>

Do you have any advice in which way I should go ahead?

Using simple enums, and structs, using linked lists and using buffer to render seems to be too slow.

Thank you in advance.

My current struct and enum:

pub enum Attribute {
    Empty(Option<Box<Attribute>>, &'static str),
    Quoted(Option<Box<Attribute>>, &'static str, &'static str),
}

pub struct Tag<'a> {
    name: &'a str,
    is_text: bool,
    attributes: Option<Box<Attribute>>,
    inner: Option<Box<Tag<'a>>>,
    next: Option<Box<Tag<'a>>>,
    close: Option<&'a str>,
}

And the final API would look like this:

let mut p = P::new();
let mut title = H1::new_with_text("Lorem ipsum dolorem");
title.add_class("is-size-2");
let mut text = P::new_with_text("Hello, this is a demo paragraph");
let holder = Div::new();
div.add_tag(title);
div.add_tag(text);
...