factory.rs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. use std::{cell::Cell, fmt::Arguments, pin::Pin};
  2. use bumpalo::boxed::Box as BumpBox;
  3. use bumpalo::Bump;
  4. use futures_util::Future;
  5. use crate::{
  6. any_props::{AnyProps, VComponentProps},
  7. arena::ElementId,
  8. innerlude::DynamicNode,
  9. Attribute, AttributeValue, Element, LazyNodes, Properties, Scope, ScopeState, VNode,
  10. };
  11. impl ScopeState {
  12. /// Create some text that's allocated along with the other vnodes
  13. pub fn text<'a>(&'a self, args: Arguments) -> DynamicNode<'a> {
  14. let (text, _) = self.raw_text(args);
  15. DynamicNode::Text {
  16. id: Cell::new(ElementId(0)),
  17. value: text,
  18. }
  19. }
  20. pub fn raw_text_inline<'a>(&'a self, args: Arguments) -> &'a str {
  21. self.raw_text(args).0
  22. }
  23. pub fn raw_text<'a>(&'a self, args: Arguments) -> (&'a str, bool) {
  24. match args.as_str() {
  25. Some(static_str) => (static_str, true),
  26. None => {
  27. use bumpalo::core_alloc::fmt::Write;
  28. let mut str_buf = bumpalo::collections::String::new_in(self.bump());
  29. str_buf.write_fmt(args).unwrap();
  30. (str_buf.into_bump_str(), false)
  31. }
  32. }
  33. }
  34. pub fn fragment_from_iter<'a, I, F: IntoVnode<'a, I>>(
  35. &'a self,
  36. it: impl IntoIterator<Item = F>,
  37. ) -> DynamicNode {
  38. let mut bump_vec = bumpalo::vec![in self.bump();];
  39. for item in it {
  40. bump_vec.push(item.into_dynamic_node(self));
  41. }
  42. match bump_vec.len() {
  43. 0 => DynamicNode::Placeholder(Cell::new(ElementId(0))),
  44. _ => DynamicNode::Fragment(bump_vec.into_bump_slice()),
  45. }
  46. }
  47. /// Create a new [`Attribute`]
  48. pub fn attr<'a>(
  49. &'a self,
  50. name: &'static str,
  51. val: impl IntoAttributeValue<'a>,
  52. namespace: Option<&'static str>,
  53. volatile: bool,
  54. ) -> Attribute<'a> {
  55. Attribute {
  56. name,
  57. namespace,
  58. volatile,
  59. value: val.into_value(self.bump()),
  60. mounted_element: Cell::new(ElementId(0)),
  61. }
  62. }
  63. /// Create a new [`VNode::Component`]
  64. pub fn component<'a, P, A, F: ComponentReturn<'a, A>>(
  65. &'a self,
  66. component: fn(Scope<'a, P>) -> F,
  67. props: P,
  68. fn_name: &'static str,
  69. ) -> DynamicNode<'a>
  70. where
  71. P: Properties + 'a,
  72. {
  73. let props = self.bump().alloc(props);
  74. let as_component = component;
  75. let vcomp = VComponentProps::new(as_component, P::memoize, props);
  76. let as_dyn = self.bump().alloc(vcomp) as &mut dyn AnyProps;
  77. let detached_dyn: *mut dyn AnyProps = unsafe { std::mem::transmute(as_dyn) };
  78. // todo: clean up borrowed props
  79. // if !P::IS_STATIC {
  80. // let vcomp = &*vcomp;
  81. // let vcomp = unsafe { std::mem::transmute(vcomp) };
  82. // self.scope.items.borrow_mut().borrowed_props.push(vcomp);
  83. // }
  84. DynamicNode::Component {
  85. name: fn_name,
  86. is_static: P::IS_STATIC,
  87. props: Cell::new(detached_dyn),
  88. }
  89. }
  90. }
  91. pub trait ComponentReturn<'a, A = ()> {
  92. fn as_return(self, cx: &'a ScopeState) -> RenderReturn<'a>;
  93. }
  94. impl<'a> ComponentReturn<'a> for Element<'a> {
  95. fn as_return(self, _cx: &ScopeState) -> RenderReturn<'a> {
  96. RenderReturn::Sync(self)
  97. }
  98. }
  99. pub struct AsyncMarker;
  100. impl<'a, F> ComponentReturn<'a, AsyncMarker> for F
  101. where
  102. F: Future<Output = Element<'a>> + 'a,
  103. {
  104. fn as_return(self, cx: &'a ScopeState) -> RenderReturn<'a> {
  105. let f: &mut dyn Future<Output = Element<'a>> = cx.bump().alloc(self);
  106. let boxed = unsafe { BumpBox::from_raw(f) };
  107. let pined: Pin<BumpBox<_>> = boxed.into();
  108. RenderReturn::Async(pined)
  109. }
  110. }
  111. #[test]
  112. fn takes_it() {
  113. fn demo(cx: Scope) -> Element {
  114. todo!()
  115. }
  116. }
  117. pub enum RenderReturn<'a> {
  118. Sync(Element<'a>),
  119. Async(Pin<BumpBox<'a, dyn Future<Output = Element<'a>> + 'a>>),
  120. }
  121. pub trait IntoVnode<'a, A = ()> {
  122. fn into_dynamic_node(self, cx: &'a ScopeState) -> VNode<'a>;
  123. }
  124. impl<'a, 'b> IntoVnode<'a> for LazyNodes<'a, 'b> {
  125. fn into_dynamic_node(self, cx: &'a ScopeState) -> VNode<'a> {
  126. self.call(cx)
  127. }
  128. }
  129. impl<'a, 'b> IntoVnode<'a> for VNode<'a> {
  130. fn into_dynamic_node(self, _cx: &'a ScopeState) -> VNode<'a> {
  131. self
  132. }
  133. }
  134. impl<'a, 'b> IntoVnode<'a> for &'a VNode<'a> {
  135. fn into_dynamic_node(self, _cx: &'a ScopeState) -> VNode<'a> {
  136. VNode {
  137. node_id: self.node_id.clone(),
  138. parent: self.parent,
  139. template: self.template,
  140. root_ids: self.root_ids,
  141. key: self.key,
  142. dynamic_nodes: self.dynamic_nodes,
  143. dynamic_attrs: self.dynamic_attrs,
  144. }
  145. }
  146. }
  147. /// A value that can be converted into an attribute value
  148. pub trait IntoAttributeValue<'a> {
  149. /// Convert into an attribute value
  150. fn into_value(self, bump: &'a Bump) -> AttributeValue<'a>;
  151. }
  152. impl<'a> IntoAttributeValue<'a> for &'a str {
  153. fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
  154. AttributeValue::Text(self)
  155. }
  156. }
  157. impl<'a> IntoAttributeValue<'a> for f32 {
  158. fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
  159. AttributeValue::Float(self)
  160. }
  161. }
  162. impl<'a> IntoAttributeValue<'a> for i32 {
  163. fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
  164. AttributeValue::Int(self)
  165. }
  166. }
  167. impl<'a> IntoAttributeValue<'a> for bool {
  168. fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
  169. AttributeValue::Bool(self)
  170. }
  171. }
  172. impl<'a> IntoAttributeValue<'a> for Arguments<'_> {
  173. fn into_value(self, bump: &'a Bump) -> AttributeValue<'a> {
  174. use bumpalo::core_alloc::fmt::Write;
  175. let mut str_buf = bumpalo::collections::String::new_in(bump);
  176. str_buf.write_fmt(self).unwrap();
  177. AttributeValue::Text(str_buf.into_bump_str())
  178. }
  179. }