use crate::{Node, RenderContext};
use std::any::Any;
use std::rc::Rc;
use wasm_bindgen::UnwrapThrowExt;
pub trait Render<'a> {
fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a>;
}
impl<'a, 'r, R> Render<'a> for &'r R
where
R: Render<'a>,
{
fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
(**self).render(cx)
}
}
impl<'a, R> Render<'a> for Rc<R>
where
R: Render<'a>,
{
fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
(**self).render(cx)
}
}
pub trait RootRender: Any + for<'a> Render<'a> {
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
impl<T> RootRender for T
where
T: Any + for<'a> Render<'a>,
{
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl dyn RootRender {
pub fn unwrap_ref<R>(&self) -> &R
where
R: RootRender,
{
self.as_any()
.downcast_ref::<R>()
.expect_throw("bad `RootRender::unwrap_ref` call")
}
pub fn unwrap_mut<R>(&mut self) -> &mut R
where
R: RootRender,
{
self.as_any_mut()
.downcast_mut::<R>()
.expect_throw("bad `RootRender::unwrap_ref` call")
}
}
#[cfg(test)]
mod tests {
#[test]
fn render_is_object_safe() {
#[allow(dead_code)]
fn takes_dyn_render(_: &dyn super::Render) {}
}
#[test]
fn root_render_is_object_safe() {
#[allow(dead_code)]
fn takes_dyn_render(_: &dyn super::RootRender) {}
}
#[test]
fn render_bump_scoped_child() {
use crate::{builder::*, bumpalo::collections::String, Node, Render, RenderContext};
struct Child<'a> {
name: &'a str,
}
impl<'a> Render<'a> for Child<'a> {
fn render(&self, _cx: &mut RenderContext<'a>) -> Node<'a> {
text(self.name)
}
}
struct Parent;
impl<'a> Render<'a> for Parent {
fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
let child_name = String::from_str_in("child", cx.bump).into_bump_str();
div(&cx)
.children([Child { name: child_name }.render(cx)])
.finish()
}
}
}
}