Browse Source

Fix attribute value in macro (#577)

* create into AttributeValue trait to allow arbitraty attribute values

* allow attributevalue in non-template macro
Demonthos 2 năm trước cách đây
mục cha
commit
ab10d327ac

+ 129 - 1
packages/core/src/arbitrary_value.rs

@@ -1,5 +1,6 @@
-use std::fmt::Formatter;
+use std::fmt::{Arguments, Formatter};
 
+use bumpalo::Bump;
 use dyn_clone::{clone_box, DynClone};
 
 /// Possible values for an attribute
@@ -30,6 +31,133 @@ pub enum AttributeValue<'a> {
     Any(ArbitraryAttributeValue<'a>),
 }
 
+/// A value that can be converted into an attribute value
+pub trait IntoAttributeValue<'a> {
+    /// Convert into an attribute value
+    fn into_value(self, bump: &'a Bump) -> AttributeValue<'a>;
+}
+
+impl<'a> IntoAttributeValue<'a> for u32 {
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        AttributeValue::Uint32(self)
+    }
+}
+
+impl<'a> IntoAttributeValue<'a> for u64 {
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        AttributeValue::Uint64(self)
+    }
+}
+
+impl<'a> IntoAttributeValue<'a> for i32 {
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        AttributeValue::Int32(self)
+    }
+}
+
+impl<'a> IntoAttributeValue<'a> for i64 {
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        AttributeValue::Int64(self)
+    }
+}
+
+impl<'a> IntoAttributeValue<'a> for f32 {
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        AttributeValue::Float32(self)
+    }
+}
+
+impl<'a> IntoAttributeValue<'a> for f64 {
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        AttributeValue::Float64(self)
+    }
+}
+
+impl<'a> IntoAttributeValue<'a> for bool {
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        AttributeValue::Bool(self)
+    }
+}
+
+impl<'a> IntoAttributeValue<'a> for &'a str {
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        AttributeValue::Text(self)
+    }
+}
+
+impl<'a> IntoAttributeValue<'a> for Arguments<'_> {
+    fn into_value(self, bump: &'a Bump) -> AttributeValue<'a> {
+        use bumpalo::core_alloc::fmt::Write;
+        let mut str_buf = bumpalo::collections::String::new_in(bump);
+        str_buf.write_fmt(self).unwrap();
+        AttributeValue::Text(str_buf.into_bump_str())
+    }
+}
+
+impl<'a> IntoAttributeValue<'a> for &'a [u8] {
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        AttributeValue::Bytes(self)
+    }
+}
+
+impl<'a> IntoAttributeValue<'a> for (f32, f32, f32) {
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        AttributeValue::Vec3Float(self.0, self.1, self.2)
+    }
+}
+
+impl<'a> IntoAttributeValue<'a> for (i32, i32, i32) {
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        AttributeValue::Vec3Int(self.0, self.1, self.2)
+    }
+}
+
+impl<'a> IntoAttributeValue<'a> for (u32, u32, u32) {
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        AttributeValue::Vec3Uint(self.0, self.1, self.2)
+    }
+}
+
+impl<'a> IntoAttributeValue<'a> for (f32, f32, f32, f32) {
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        AttributeValue::Vec4Float(self.0, self.1, self.2, self.3)
+    }
+}
+
+impl<'a> IntoAttributeValue<'a> for (i32, i32, i32, i32) {
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        AttributeValue::Vec4Int(self.0, self.1, self.2, self.3)
+    }
+}
+
+impl<'a> IntoAttributeValue<'a> for (u32, u32, u32, u32) {
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        AttributeValue::Vec4Uint(self.0, self.1, self.2, self.3)
+    }
+}
+
+impl<'a, T> IntoAttributeValue<'a> for &'a T
+where
+    T: AnyClone + PartialEq,
+{
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        AttributeValue::Any(ArbitraryAttributeValue {
+            value: self,
+            cmp: |a, b| {
+                if let Some(a) = a.as_any().downcast_ref::<T>() {
+                    if let Some(b) = b.as_any().downcast_ref::<T>() {
+                        a == b
+                    } else {
+                        false
+                    }
+                } else {
+                    false
+                }
+            },
+        })
+    }
+}
+
 // todo
 #[allow(missing_docs)]
 impl<'a> AttributeValue<'a> {

+ 14 - 12
packages/core/src/lib.rs

@@ -69,13 +69,14 @@ pub(crate) mod innerlude {
 pub use crate::innerlude::{
     AnyEvent, ArbitraryAttributeValue, Attribute, AttributeDiscription, AttributeValue,
     CodeLocation, Component, DioxusElement, DomEdit, DynamicNodeMapping, Element, ElementId,
-    ElementIdIterator, EventHandler, EventPriority, GlobalNodeId, IntoVNode, LazyNodes, Listener,
-    Mutations, NodeFactory, OwnedAttributeValue, Properties, RendererTemplateId, SchedulerMsg,
-    Scope, ScopeId, ScopeState, StaticCodeLocation, StaticDynamicNodeMapping, StaticTemplateNode,
-    StaticTemplateNodes, TaskId, Template, TemplateAttribute, TemplateAttributeValue,
-    TemplateContext, TemplateElement, TemplateId, TemplateNode, TemplateNodeId, TemplateNodeType,
-    TemplateValue, TextTemplate, TextTemplateSegment, UiEvent, UserEvent, VComponent, VElement,
-    VFragment, VNode, VPlaceholder, VText, VirtualDom, JS_MAX_INT,
+    ElementIdIterator, EventHandler, EventPriority, GlobalNodeId, IntoAttributeValue, IntoVNode,
+    LazyNodes, Listener, Mutations, NodeFactory, OwnedAttributeValue, Properties,
+    RendererTemplateId, SchedulerMsg, Scope, ScopeId, ScopeState, StaticCodeLocation,
+    StaticDynamicNodeMapping, StaticTemplateNode, StaticTemplateNodes, TaskId, Template,
+    TemplateAttribute, TemplateAttributeValue, TemplateContext, TemplateElement, TemplateId,
+    TemplateNode, TemplateNodeId, TemplateNodeType, TemplateValue, TextTemplate,
+    TextTemplateSegment, UiEvent, UserEvent, VComponent, VElement, VFragment, VNode, VPlaceholder,
+    VText, VirtualDom, JS_MAX_INT,
 };
 #[cfg(any(feature = "hot-reload", debug_assertions))]
 pub use crate::innerlude::{
@@ -92,11 +93,12 @@ pub mod prelude {
     pub use crate::innerlude::OwnedTemplate;
     pub use crate::innerlude::{
         fc_to_builder, AttributeDiscription, AttributeValue, Attributes, CodeLocation, Component,
-        DioxusElement, Element, EventHandler, Fragment, LazyNodes, LazyStaticVec, NodeFactory,
-        Properties, Scope, ScopeId, ScopeState, StaticAttributeValue, StaticCodeLocation,
-        StaticDynamicNodeMapping, StaticTemplate, StaticTemplateNodes, Template, TemplateAttribute,
-        TemplateAttributeValue, TemplateContext, TemplateElement, TemplateId, TemplateNode,
-        TemplateNodeId, TemplateNodeType, TextTemplate, TextTemplateSegment, VNode, VirtualDom,
+        DioxusElement, Element, EventHandler, Fragment, IntoAttributeValue, LazyNodes,
+        LazyStaticVec, NodeFactory, Properties, Scope, ScopeId, ScopeState, StaticAttributeValue,
+        StaticCodeLocation, StaticDynamicNodeMapping, StaticTemplate, StaticTemplateNodes,
+        Template, TemplateAttribute, TemplateAttributeValue, TemplateContext, TemplateElement,
+        TemplateId, TemplateNode, TemplateNodeId, TemplateNodeType, TextTemplate,
+        TextTemplateSegment, VNode, VirtualDom,
     };
 }
 

+ 8 - 10
packages/core/src/nodes.rs

@@ -5,8 +5,8 @@
 use crate::{
     dynamic_template_context::TemplateContext,
     innerlude::{
-        AttributeValue, ComponentPtr, Element, Properties, Scope, ScopeId, ScopeState, Template,
-        TemplateId,
+        AttributeValue, ComponentPtr, Element, IntoAttributeValue, Properties, Scope, ScopeId,
+        ScopeState, Template, TemplateId,
     },
     lazynodes::LazyNodes,
     template::{TemplateNodeId, VTemplateRef},
@@ -698,13 +698,12 @@ impl<'a> NodeFactory<'a> {
     pub fn attr_disciption(
         &self,
         discription: AttributeDiscription,
-        val: Arguments,
+        val: impl IntoAttributeValue<'a>,
     ) -> Attribute<'a> {
-        let (value, is_static) = self.raw_text(val);
         Attribute {
             attribute: discription,
-            is_static,
-            value: AttributeValue::Text(value),
+            is_static: false,
+            value: val.into_value(self.bump),
         }
     }
 
@@ -712,19 +711,18 @@ impl<'a> NodeFactory<'a> {
     pub fn attr(
         &self,
         name: &'static str,
-        val: Arguments,
+        val: impl IntoAttributeValue<'a>,
         namespace: Option<&'static str>,
         is_volatile: bool,
     ) -> Attribute<'a> {
-        let (value, is_static) = self.raw_text(val);
         Attribute {
             attribute: AttributeDiscription {
                 name,
                 namespace,
                 volatile: is_volatile,
             },
-            is_static,
-            value: AttributeValue::Text(value),
+            is_static: false,
+            value: val.into_value(self.bump),
         }
     }
 

+ 5 - 17
packages/rsx/src/template.rs

@@ -421,10 +421,7 @@ impl TemplateBuilder {
                                     element_tag: el.name.clone(),
                                     name: AttributeName::Ident(name),
                                     value: TemplateAttributeValue::Dynamic(
-                                        self.dynamic_context.add_attr(quote!(AttributeValue::Text(
-                                            dioxus::core::exports::bumpalo::format!(in __bump, "{}", #value)
-                                                .into_bump_str()
-                                        ))),
+                                        self.dynamic_context.add_attr(quote!(#value)),
                                     ),
                                 })
                             }
@@ -443,10 +440,7 @@ impl TemplateBuilder {
                                     element_tag: el.name.clone(),
                                     name: AttributeName::Str(name),
                                     value: TemplateAttributeValue::Dynamic(
-                                        self.dynamic_context.add_attr(quote!(AttributeValue::Text(
-                                            dioxus::core::exports::bumpalo::format!(in __bump, "{}", #value)
-                                                .into_bump_str()
-                                        ))),
+                                        self.dynamic_context.add_attr(quote!(#value)),
                                     ),
                                 })
                             }
@@ -456,10 +450,7 @@ impl TemplateBuilder {
                                 element_tag: el.name.clone(),
                                 name: AttributeName::Ident(name),
                                 value: TemplateAttributeValue::Dynamic(
-                                    self.dynamic_context.add_attr(quote!(AttributeValue::Text(
-                                        dioxus::core::exports::bumpalo::format!(in __bump, "{}", #value)
-                                            .into_bump_str()
-                                    ))),
+                                    self.dynamic_context.add_attr(quote!(#value)),
                                 ),
                             })
                         }
@@ -468,10 +459,7 @@ impl TemplateBuilder {
                                 element_tag: el.name.clone(),
                                 name: AttributeName::Str(name),
                                 value: TemplateAttributeValue::Dynamic(
-                                    self.dynamic_context.add_attr(quote!(AttributeValue::Text(
-                                        dioxus::core::exports::bumpalo::format!(in __bump, "{}", #value)
-                                            .into_bump_str()
-                                    ))),
+                                    self.dynamic_context.add_attr(quote!(#value)),
                                 ),
                             })
                         }
@@ -879,7 +867,7 @@ impl ToTokens for DynamicTemplateContextBuilder {
             TemplateContext {
                 nodes: __cx.bump().alloc([#(#nodes),*]),
                 text_segments: __cx.bump().alloc([#(&*dioxus::core::exports::bumpalo::format!(in __bump, "{}", #text).into_bump_str()),*]),
-                attributes: __cx.bump().alloc([#(#attributes),*]),
+                attributes: __cx.bump().alloc([#({#attributes}.into_value(__cx.bump())),*]),
                 listeners: __cx.bump().alloc([#(dioxus_elements::on::#listeners_names(__cx, #listeners_exprs)),*]),
                 key: #key,
             }