diff options
author | Ashelyn Rose <git@ashen.earth> | 2025-04-19 18:39:22 -0600 |
---|---|---|
committer | Ashelyn Rose <git@ashen.earth> | 2025-04-19 18:39:22 -0600 |
commit | 55dd47aff347ee882f375b5cf880a299e633f556 (patch) | |
tree | b643473071db0ae1023d8b9856395ee1aeaaa507 /src | |
parent | a35d336dc9a61fda931f4a9158205d590af87bd5 (diff) |
Async rendering
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 9 | ||||
-rw-r--r-- | src/render.rs | 41 |
2 files changed, 36 insertions, 14 deletions
diff --git a/src/lib.rs b/src/lib.rs index 717d715..0178d60 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,11 @@ mod render; pub use render::{Component, RenderNode}; -pub fn render_tree(parent_node: RenderNode) -> String { - parent_node.render_to_string() +pub async fn render_tree(parent_node: RenderNode) -> String { + parent_node.render_to_string().await +} + +#[cfg(feature = "blocking")] +pub fn render_tree_blocking(parent_node: RenderNode) -> String { + futures::executor::block_on(render_tree(parent_node)) } diff --git a/src/render.rs b/src/render.rs index 33469e0..3bb6e41 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,10 +1,17 @@ +use std::pin::Pin; use std::collections::HashMap; +use std::future::Future; +use futures::future::join_all; pub trait Component { fn render(self: Box<Self>) -> Vec<RenderNode>; } pub enum RenderNode { + Suspense { + fallback: Box<RenderNode>, + children: Pin<Box<dyn Future<Output = Vec<RenderNode>>>> + }, Component(Box<dyn Component>), Element { name: String, @@ -14,19 +21,27 @@ pub enum RenderNode { TextNode { content: String, }, - Portal, Null, } impl RenderNode { - pub(crate) fn render_to_string(self) -> String { + pub(crate) fn render_to_string(self) -> Pin<Box<dyn Future<Output = String>>> { match self { RenderNode::Component(component) => { let elements = component.render(); - elements.into_iter() - .map(|child| child.render_to_string()) - .collect::<Vec<_>>().join("") + Box::pin((async move || { + join_all(elements.into_iter() + .map(|child| child.render_to_string()) + .collect::<Vec<_>>()).await.join("") + })()) + }, + RenderNode::Suspense {fallback: _, children} => { + Box::pin((async move || { + join_all(children.await.into_iter() + .map(|child| child.render_to_string())).await + .join("") + })()) }, RenderNode::Element { name, attributes, children } => { @@ -34,16 +49,18 @@ impl RenderNode { .map(|(key, value)| format!(" {key}=\"{value}\"")) .collect::<Vec<_>>().join(""); - let rendered_children = children.into_iter() - .map(|child| child.render_to_string()) - .collect::<Vec<_>>().join(""); + 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}>") - format!("<{name}{text_attributes}>{rendered_children}</{name}>") + })()) }, - RenderNode::TextNode { content } => content, - RenderNode::Portal => todo!(), - RenderNode::Null => "".to_string(), + RenderNode::TextNode { content } => Box::pin((async move || content)()), + RenderNode::Null => Box::pin((async move || "".to_string())()), } } } |