diff --git a/packages/core/Cargo.toml b/packages/core/Cargo.toml index fc2ec2ee8..05ef482b1 100644 --- a/packages/core/Cargo.toml +++ b/packages/core/Cargo.toml @@ -45,6 +45,9 @@ serde = { version = "1", features = ["derive"], optional = true } # todo: I want to get rid of this backtrace = "0.3" +# allows cloing trait objects +dyn-clone = "1.0.9" + [features] default = [] serialize = ["serde"] diff --git a/packages/core/src/arbitrary_value.rs b/packages/core/src/arbitrary_value.rs index d1b7cfc36..037e1804f 100644 --- a/packages/core/src/arbitrary_value.rs +++ b/packages/core/src/arbitrary_value.rs @@ -1,5 +1,7 @@ use std::fmt::Formatter; +use dyn_clone::{clone_box, DynClone}; + /// Possible values for an attribute // trying to keep values at 3 bytes #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] @@ -74,8 +76,8 @@ impl<'a> std::fmt::Display for AttributeValue<'a> { #[derive(Clone, Copy)] #[allow(missing_docs)] pub struct ArbitraryAttributeValue<'a> { - pub value: &'a dyn std::any::Any, - pub cmp: fn(&'a dyn std::any::Any, &'a dyn std::any::Any) -> bool, + pub value: &'a dyn AnyClone, + pub cmp: fn(&dyn AnyClone, &dyn AnyClone) -> bool, } impl PartialEq for ArbitraryAttributeValue<'_> { @@ -118,6 +120,79 @@ impl<'de, 'a> serde::Deserialize<'de> for ArbitraryAttributeValue<'a> { } } +/// A clone, sync and send version of `Any` +// we only need the Sync + Send bound when hot reloading is enabled +#[cfg(any(feature = "hot-reload", debug_assertions))] +pub trait AnyClone: std::any::Any + DynClone + Send + Sync { + fn as_any(&self) -> &dyn std::any::Any; +} +#[cfg(not(any(feature = "hot-reload", debug_assertions)))] +pub trait AnyClone: std::any::Any + DynClone { + fn as_any(&self) -> &dyn std::any::Any; +} + +#[cfg(any(feature = "hot-reload", debug_assertions))] +impl AnyClone for T { + fn as_any(&self) -> &dyn std::any::Any { + self + } +} +#[cfg(not(any(feature = "hot-reload", debug_assertions)))] +impl AnyClone for T { + fn as_any(&self) -> &dyn std::any::Any { + self + } +} + +dyn_clone::clone_trait_object!(AnyClone); + +#[derive(Clone)] +#[allow(missing_docs)] +pub struct OwnedArbitraryAttributeValue { + pub value: Box, + pub cmp: fn(&dyn AnyClone, &dyn AnyClone) -> bool, +} + +impl PartialEq for OwnedArbitraryAttributeValue { + fn eq(&self, other: &Self) -> bool { + (self.cmp)(&*self.value, &*other.value) + } +} + +impl std::fmt::Debug for OwnedArbitraryAttributeValue { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("OwnedArbitraryAttributeValue").finish() + } +} + +#[cfg(feature = "serialize")] +impl<'a> serde::Serialize for OwnedArbitraryAttributeValue { + fn serialize(&self, _serializer: S) -> Result + where + S: serde::Serializer, + { + panic!("OwnedArbitraryAttributeValue should not be serialized") + } +} +#[cfg(feature = "serialize")] +impl<'de, 'a> serde::Deserialize<'de> for &'a OwnedArbitraryAttributeValue { + fn deserialize(_deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + panic!("OwnedArbitraryAttributeValue is not deserializable!") + } +} +#[cfg(feature = "serialize")] +impl<'de, 'a> serde::Deserialize<'de> for OwnedArbitraryAttributeValue { + fn deserialize(_deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + panic!("OwnedArbitraryAttributeValue is not deserializable!") + } +} + // todo #[allow(missing_docs)] impl<'a> AttributeValue<'a> { @@ -261,7 +336,7 @@ pub enum OwnedAttributeValue { Bytes(Vec), // TODO: support other types - // Any(ArbitraryAttributeValue<'a>), + Any(OwnedArbitraryAttributeValue), } impl PartialEq> for OwnedAttributeValue { @@ -321,7 +396,10 @@ impl<'a> From> for OwnedAttributeValue { OwnedAttributeValue::Vec4Uint(f1, f2, f3, f4) } AttributeValue::Bytes(b) => OwnedAttributeValue::Bytes(b.to_owned()), - AttributeValue::Any(_) => todo!(), + AttributeValue::Any(a) => OwnedAttributeValue::Any(OwnedArbitraryAttributeValue { + value: clone_box(a.value), + cmp: a.cmp, + }), } } } diff --git a/packages/core/src/template.rs b/packages/core/src/template.rs index cf02a39ac..819d80ac8 100644 --- a/packages/core/src/template.rs +++ b/packages/core/src/template.rs @@ -790,6 +790,12 @@ impl TemplateValue for OwnedAttributeValue { OwnedAttributeValue::Vec4Uint(u1, u2, u3, u4) => { AttributeValue::Vec4Uint(u1, u2, u3, u4) } + OwnedAttributeValue::Any(owned) => { + AttributeValue::Any(crate::ArbitraryAttributeValue { + value: bump.alloc(owned.value), + cmp: owned.cmp, + }) + } } } } diff --git a/packages/rsx/src/template.rs b/packages/rsx/src/template.rs index ba94735f0..b94b816e8 100644 --- a/packages/rsx/src/template.rs +++ b/packages/rsx/src/template.rs @@ -216,6 +216,7 @@ impl ToTokens for TemplateAttributeBuilder { OwnedAttributeValue::Bytes(b) => { quote! {StaticAttributeValue::Bytes(&[#(#b),*])} } + OwnedAttributeValue::Any(_) => todo!(), }; quote! {TemplateAttributeValue::Static(#val)} }