diff options
Diffstat (limited to 'src/render.rs')
-rw-r--r-- | src/render.rs | 60 |
1 files changed, 50 insertions, 10 deletions
diff --git a/src/render.rs b/src/render.rs index 8addbdb..6ae948b 100644 --- a/src/render.rs +++ b/src/render.rs @@ -7,7 +7,13 @@ pub trait Component { fn render(self: Box<Self>) -> RenderNode; } +pub enum DoctypeElem { + Word(&'static str), + String(&'static str), +} + pub enum RenderNode { + Doctype(Vec<DoctypeElem>), Suspense { fallback: Box<RenderNode>, children: Pin<Box<dyn Future<Output = Vec<RenderNode>>>> @@ -30,19 +36,29 @@ pub enum RenderNode { impl RenderNode { pub(crate) fn render_to_string(self) -> Pin<Box<dyn Future<Output = String>>> { match self { + RenderNode::Doctype(elements) => { + let strings = elements.iter().map(|elem| match elem { + DoctypeElem::Word(word) => word.to_string(), + DoctypeElem::String(string) => format!("\"{}\"", string), + }).collect::<Vec<_>>().join(" ").clone(); + + Box::pin(async move { + format!("<!doctype {}>", strings) + }) + }, RenderNode::Component(component) => { let result_root = component.render(); - Box::pin((async move || { + Box::pin(async move { result_root.render_to_string().await - })()) + }) }, RenderNode::Suspense {fallback: _, children} => { - Box::pin((async move || { + Box::pin(async move { join_all(children.await.into_iter() .map(|child| child.render_to_string())).await .join("") - })()) + }) }, RenderNode::Element { name, attributes, children } => { @@ -50,25 +66,49 @@ impl RenderNode { .map(|(key, value)| format!(" {key}=\"{value}\"")) .collect::<Vec<_>>().join(""); - Box::pin((async move || { + Box::pin(async move { let rendered_children = join_all(children.into_iter() .map(|child| child.render_to_string()) .collect::<Vec<_>>()).await.join(""); format!("<{name}{text_attributes}>{rendered_children}</{name}>") - })()) + }) }, RenderNode::Fragment { children } => { - Box::pin((async move || { + Box::pin(async move { join_all(children.into_iter() .map(|child| child.render_to_string())).await .join("") - })()) + }) } - RenderNode::TextNode { content } => Box::pin((async move || content)()), - RenderNode::Null => Box::pin((async move || "".to_string())()), + RenderNode::TextNode { content } => Box::pin(async move { content }), + RenderNode::Null => Box::pin(async move { "".to_string() }), + } + } +} + +pub trait IntoRender { + fn into_render(self) -> Vec<RenderNode>; +} + +macro_rules! impl_str { + ($t:ty) => { + impl IntoRender for $t { + fn into_render(self) -> Vec<RenderNode> { + vec![RenderNode::TextNode { content: String::from(self) }] + } } + }; +} + +impl_str!(String); +impl_str!(&str); +impl_str!(std::borrow::Cow<'_,str>); + +impl IntoRender for Vec<RenderNode> { + fn into_render(self) -> Vec<RenderNode> { + self } } |