on 9bb3bdf help sign in
dodrio/src/render.rs
141 lines 3.7 kB history raw
1use crate::{Node, RenderContext};
2use std::any::Any;
3use std::rc::Rc;
4use wasm_bindgen::UnwrapThrowExt;
6/// A trait for any component that can be rendered to HTML.
7///
8/// Takes a shared reference to `self` and generates the virtual DOM that
9/// represents its rendered HTML.
10///
11/// ## `Bump` Allocation
12///
13/// `Render` implementations can use the `Bump` inside the provided
14/// `RenderContext` for very fast allocation for anything that needs to be
15/// temporarily allocated during rendering.
16///
17/// ## Example
18///
19/// ```no_run
20/// use dodrio::{Node, Render, RenderContext};
21///
22/// pub struct MyComponent;
23///
24/// impl Render for MyComponent {
25/// fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
26/// use dodrio::builder::*;
27///
28/// p(&cx)
29/// .children([
30/// text("This is "),
31/// strong(&cx).children([text("my component")]).finish(),
32/// text(" rendered!"),
33/// ])
34/// .finish()
35/// }
36/// }
37/// ```
38pub trait Render {
39 /// Render `self` as a virtual DOM. Use the given context's `Bump` for
40 /// temporary allocations.
41 fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a>;
44impl<'r, R> Render for &'r R
45where
46 R: Render,
48 fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
49 (**self).render(cx)
50 }
53impl<R> Render for Rc<R>
54where
55 R: Render,
57 fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
58 (**self).render(cx)
59 }
62/// A `RootRender` is a render component that can be the root rendering component
63/// mounted to a virtual DOM.
64///
65/// In addition to rendering, it must also be `'static` so that it can be owned
66/// by the virtual DOM and `Any` so that it can be downcast to its concrete type
67/// by event listener callbacks.
68///
69/// You do not need to implement this trait by hand: there is a blanket
70/// implementation for all `Render` types that fulfill the `RootRender`
71/// requirements.
72pub trait RootRender: Any + Render {
73 /// Get this `&RootRender` trait object as an `&Any` trait object reference.
74 fn as_any(&self) -> &Any;
76 /// Get this `&mut RootRender` trait object as an `&mut Any` trait object
77 /// reference.
78 fn as_any_mut(&mut self) -> &mut Any;
81impl<T> RootRender for T
82where
83 T: Any + Render,
85 fn as_any(&self) -> &Any {
86 self
87 }
89 fn as_any_mut(&mut self) -> &mut Any {
90 self
91 }
94impl dyn RootRender {
95 /// Downcast this shared `&dyn RootRender` trait object reference to its
96 /// underlying concrete type.
97 ///
98 /// # Panics
99 ///
100 /// Panics if this virtual DOM's root rendering component is not an `R`
101 /// instance.
102 pub fn unwrap_ref<R>(&self) -> &R
103 where
104 R: RootRender,
105 {
106 self.as_any()
107 .downcast_ref::<R>()
108 .expect_throw("bad `RootRender::unwrap_ref` call")
109 }
111 /// Downcast this exclusive `&mut dyn RootRender` trait object reference to
112 /// its underlying concrete type.
113 ///
114 /// # Panics
115 ///
116 /// Panics if this virtual DOM's root rendering component is not an `R`
117 /// instance.
118 pub fn unwrap_mut<R>(&mut self) -> &mut R
119 where
120 R: RootRender,
121 {
122 self.as_any_mut()
123 .downcast_mut::<R>()
124 .expect_throw("bad `RootRender::unwrap_ref` call")
125 }
128#[cfg(test)]
129mod tests {
130 #[test]
131 fn render_is_object_safe() {
132 #[allow(dead_code)]
133 fn takes_dyn_render(_: &dyn super::Render) {}
134 }
136 #[test]
137 fn root_render_is_object_safe() {
138 #[allow(dead_code)]
139 fn takes_dyn_render(_: &dyn super::RootRender) {}
140 }