any_props.rs 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. use std::{ panic::AssertUnwindSafe};
  2. use crate::{
  3. innerlude::Scoped,
  4. nodes::RenderReturn,
  5. scopes::{Scope, ScopeState},
  6. Element,
  7. };
  8. /// A trait that essentially allows VComponentProps to be used generically
  9. ///
  10. /// # Safety
  11. ///
  12. /// This should not be implemented outside this module
  13. pub(crate) unsafe trait AnyProps<'a> {
  14. fn props_ptr(&self) -> *const ();
  15. fn render(&'a self, bump: &'a ScopeState) -> RenderReturn<'a>;
  16. unsafe fn memoize(&self, other: &dyn AnyProps) -> bool;
  17. }
  18. pub(crate) struct VProps<'a, P> {
  19. pub render_fn: fn(Scope<'a, P>) -> Element<'a>,
  20. pub memo: unsafe fn(&P, &P) -> bool,
  21. pub props: P,
  22. }
  23. impl<'a, P> VProps<'a, P> {
  24. pub(crate) fn new(
  25. render_fn: fn(Scope<'a, P>) -> Element<'a>,
  26. memo: unsafe fn(&P, &P) -> bool,
  27. props: P,
  28. ) -> Self {
  29. Self {
  30. render_fn,
  31. memo,
  32. props,
  33. }
  34. }
  35. }
  36. unsafe impl<'a, P> AnyProps<'a> for VProps<'a, P> {
  37. fn props_ptr(&self) -> *const () {
  38. &self.props as *const _ as *const ()
  39. }
  40. // Safety:
  41. // this will downcast the other ptr as our swallowed type!
  42. // you *must* make this check *before* calling this method
  43. // if your functions are not the same, then you will downcast a pointer into a different type (UB)
  44. unsafe fn memoize(&self, other: &dyn AnyProps) -> bool {
  45. let real_other: &P = &*(other.props_ptr() as *const _ as *const P);
  46. let real_us: &P = &*(self.props_ptr() as *const _ as *const P);
  47. (self.memo)(real_us, real_other)
  48. }
  49. fn render(&'a self, cx: &'a ScopeState) -> RenderReturn<'a> {
  50. let res = std::panic::catch_unwind(AssertUnwindSafe(move || {
  51. // Call the render function directly
  52. let scope: &mut Scoped<P> = cx.bump().alloc(Scoped {
  53. props: &self.props,
  54. scope: cx,
  55. });
  56. (self.render_fn)(scope)
  57. }));
  58. match res {
  59. Ok(Some(e)) => RenderReturn::Ready(e),
  60. _ => RenderReturn::default(),
  61. }
  62. }
  63. }