diff --git a/packages/core/src/arbitrary_value.rs b/packages/core/src/arbitrary_value.rs index 718c990d6..dbf92c16f 100644 --- a/packages/core/src/arbitrary_value.rs +++ b/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::() { + if let Some(b) = b.as_any().downcast_ref::() { + a == b + } else { + false + } + } else { + false + } + }, + }) + } +} + // todo #[allow(missing_docs)] impl<'a> AttributeValue<'a> { diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index 8161620e9..c970ea835 100644 --- a/packages/core/src/lib.rs +++ b/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, }; } diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index 86e7762ef..52d61322e 100644 --- a/packages/core/src/nodes.rs +++ b/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), } } diff --git a/packages/rsx/src/template.rs b/packages/rsx/src/template.rs index b94b816e8..4e3c742a3 100644 --- a/packages/rsx/src/template.rs +++ b/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, }