use crate::Node; use bumpalo::Bump; use std::any::Any; use std::rc::Rc; use wasm_bindgen::UnwrapThrowExt; pub trait Render { fn render<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump> where 'a: 'bump; } impl<'r, R> Render for &'r R where R: Render, { fn render<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump> where 'a: 'bump, { (**self).render(bump) } } impl Render for Rc where R: Render, { fn render<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump> where 'a: 'bump, { (**self).render(bump) } } /// A `RootRender` is a render component that can be the root rendering component /// mounted to a virtual DOM. /// /// In addition to rendering, it must also be `'static` so that it can be owned /// by the virtual DOM and `Any` so that it can be downcast to its concrete type /// by event listener callbacks. /// /// You do not need to implement this trait by hand: there is a blanket /// implementation for all `Render` types that fulfill the `RootRender` /// requirements. pub trait RootRender: Any + Render { /// Get this `&RootRender` trait object as an `&Any` trait object reference. fn as_any(&self) -> &Any; /// Get this `&mut RootRender` trait object as an `&mut Any` trait object /// reference. fn as_any_mut(&mut self) -> &mut Any; } impl RootRender for T { fn as_any(&self) -> &Any { self } fn as_any_mut(&mut self) -> &mut Any { self } } impl dyn RootRender { /// Downcast this shared `&dyn RootRender` trait object reference to its /// underlying concrete type. /// /// # Panics /// /// Panics if this virtual DOM's root rendering component is not an `R` /// instance. pub fn unwrap_ref(&self) -> &R { self.as_any() .downcast_ref::() .expect_throw("bad `RootRender::unwrap_ref` call") } /// Downcast this exclusive `&mut dyn RootRender` trait object reference to /// its underlying concrete type. /// /// # Panics /// /// Panics if this virtual DOM's root rendering component is not an `R` /// instance. pub fn unwrap_mut(&mut self) -> &mut R { self.as_any_mut() .downcast_mut::() .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) {} } }