pub use dyn_any::StaticType; use dyn_any::{DynAny, Upcast}; use dyn_clone::DynClone; pub use glam::{DAffine2, DVec2}; use graphene_core::raster::{BlendMode, LuminanceCalculation}; use graphene_core::{Color, Node, Type}; use std::hash::Hash; pub use std::sync::Arc; use crate::executor::Any; pub use crate::imaginate_input::{ImaginateMaskStartingFill, ImaginateSamplingMethod, ImaginateStatus}; /// A type that is known, allowing serialization (serde::Deserialize is not object safe) #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum TaggedValue { None, String(String), U32(u32), F32(f32), F64(f64), Bool(bool), DVec2(DVec2), OptionalDVec2(Option), DAffine2(DAffine2), Image(graphene_core::raster::Image), RcImage(Option>>), ImageFrame(graphene_core::raster::ImageFrame), Color(graphene_core::raster::color::Color), Subpaths(Vec>), RcSubpath(Arc>), BlendMode(BlendMode), LuminanceCalculation(LuminanceCalculation), ImaginateSamplingMethod(ImaginateSamplingMethod), ImaginateMaskStartingFill(ImaginateMaskStartingFill), ImaginateStatus(ImaginateStatus), LayerPath(Option>), VectorData(graphene_core::vector::VectorData), Fill(graphene_core::vector::style::Fill), Stroke(graphene_core::vector::style::Stroke), VecF32(Vec), LineCap(graphene_core::vector::style::LineCap), LineJoin(graphene_core::vector::style::LineJoin), FillType(graphene_core::vector::style::FillType), GradientType(graphene_core::vector::style::GradientType), GradientPositions(Vec<(f64, Option)>), Quantization(graphene_core::quantization::QuantizationChannels), OptionalColor(Option), ManipulatorGroupIds(Vec), VecDVec2(Vec), Segments(Vec>), } #[allow(clippy::derived_hash_with_manual_eq)] impl Hash for TaggedValue { fn hash(&self, state: &mut H) { core::mem::discriminant(self).hash(state); match self { Self::None => {} Self::String(s) => s.hash(state), Self::U32(u) => u.hash(state), Self::F32(f) => f.to_bits().hash(state), Self::F64(f) => f.to_bits().hash(state), Self::Bool(b) => b.hash(state), Self::DVec2(v) => v.to_array().iter().for_each(|x| x.to_bits().hash(state)), Self::OptionalDVec2(None) => 0.hash(state), Self::OptionalDVec2(Some(v)) => { 1.hash(state); Self::DVec2(*v).hash(state) } Self::DAffine2(m) => m.to_cols_array().iter().for_each(|x| x.to_bits().hash(state)), Self::Image(i) => i.hash(state), Self::RcImage(i) => i.hash(state), Self::Color(c) => c.hash(state), Self::Subpaths(s) => s.iter().for_each(|subpath| subpath.hash(state)), Self::RcSubpath(s) => s.hash(state), Self::BlendMode(b) => b.hash(state), Self::LuminanceCalculation(l) => l.hash(state), Self::ImaginateSamplingMethod(m) => m.hash(state), Self::ImaginateMaskStartingFill(f) => f.hash(state), Self::ImaginateStatus(s) => s.hash(state), Self::LayerPath(p) => p.hash(state), Self::ImageFrame(i) => { i.image.hash(state); i.transform.to_cols_array().iter().for_each(|x| x.to_bits().hash(state)) } Self::VectorData(vector_data) => { vector_data.subpaths.hash(state); vector_data.transform.to_cols_array().iter().for_each(|x| x.to_bits().hash(state)); vector_data.style.hash(state); } Self::Fill(fill) => fill.hash(state), Self::Stroke(stroke) => stroke.hash(state), Self::VecF32(vec_f32) => vec_f32.iter().for_each(|val| val.to_bits().hash(state)), Self::LineCap(line_cap) => line_cap.hash(state), Self::LineJoin(line_join) => line_join.hash(state), Self::FillType(fill_type) => fill_type.hash(state), Self::GradientType(gradient_type) => gradient_type.hash(state), Self::GradientPositions(gradient_positions) => { gradient_positions.len().hash(state); for (position, color) in gradient_positions { position.to_bits().hash(state); color.hash(state); } } Self::Quantization(quantized_image) => quantized_image.hash(state), Self::OptionalColor(color) => color.hash(state), Self::ManipulatorGroupIds(mirror) => mirror.hash(state), Self::VecDVec2(vec_dvec2) => { vec_dvec2.len().hash(state); for dvec2 in vec_dvec2 { dvec2.to_array().iter().for_each(|x| x.to_bits().hash(state)); } } Self::Segments(segments) => { 32.hash(state); for segment in segments { segment.hash(state) } } } } } impl<'a> TaggedValue { /// Converts to a Box - this isn't very neat but I'm not sure of a better approach pub fn to_any(self) -> Any<'a> { match self { TaggedValue::None => Box::new(()), TaggedValue::String(x) => Box::new(x), TaggedValue::U32(x) => Box::new(x), TaggedValue::F32(x) => Box::new(x), TaggedValue::F64(x) => Box::new(x), TaggedValue::Bool(x) => Box::new(x), TaggedValue::DVec2(x) => Box::new(x), TaggedValue::OptionalDVec2(x) => Box::new(x), TaggedValue::DAffine2(x) => Box::new(x), TaggedValue::Image(x) => Box::new(x), TaggedValue::RcImage(x) => Box::new(x), TaggedValue::ImageFrame(x) => Box::new(x), TaggedValue::Color(x) => Box::new(x), TaggedValue::Subpaths(x) => Box::new(x), TaggedValue::RcSubpath(x) => Box::new(x), TaggedValue::BlendMode(x) => Box::new(x), TaggedValue::LuminanceCalculation(x) => Box::new(x), TaggedValue::ImaginateSamplingMethod(x) => Box::new(x), TaggedValue::ImaginateMaskStartingFill(x) => Box::new(x), TaggedValue::ImaginateStatus(x) => Box::new(x), TaggedValue::LayerPath(x) => Box::new(x), TaggedValue::VectorData(x) => Box::new(x), TaggedValue::Fill(x) => Box::new(x), TaggedValue::Stroke(x) => Box::new(x), TaggedValue::VecF32(x) => Box::new(x), TaggedValue::LineCap(x) => Box::new(x), TaggedValue::LineJoin(x) => Box::new(x), TaggedValue::FillType(x) => Box::new(x), TaggedValue::GradientType(x) => Box::new(x), TaggedValue::GradientPositions(x) => Box::new(x), TaggedValue::Quantization(x) => Box::new(x), TaggedValue::OptionalColor(x) => Box::new(x), TaggedValue::ManipulatorGroupIds(x) => Box::new(x), TaggedValue::VecDVec2(x) => Box::new(x), TaggedValue::Segments(x) => Box::new(x), } } pub fn ty(&self) -> Type { use graphene_core::TypeDescriptor; use std::borrow::Cow; match self { TaggedValue::None => concrete!(()), TaggedValue::String(_) => concrete!(String), TaggedValue::U32(_) => concrete!(u32), TaggedValue::F32(_) => concrete!(f32), TaggedValue::F64(_) => concrete!(f64), TaggedValue::Bool(_) => concrete!(bool), TaggedValue::DVec2(_) => concrete!(DVec2), TaggedValue::OptionalDVec2(_) => concrete!(Option), TaggedValue::Image(_) => concrete!(graphene_core::raster::Image), TaggedValue::RcImage(_) => concrete!(Option>>), TaggedValue::ImageFrame(_) => concrete!(graphene_core::raster::ImageFrame), TaggedValue::Color(_) => concrete!(graphene_core::raster::Color), TaggedValue::Subpaths(_) => concrete!(Vec>), TaggedValue::RcSubpath(_) => concrete!(Arc>), TaggedValue::BlendMode(_) => concrete!(BlendMode), TaggedValue::ImaginateSamplingMethod(_) => concrete!(ImaginateSamplingMethod), TaggedValue::ImaginateMaskStartingFill(_) => concrete!(ImaginateMaskStartingFill), TaggedValue::ImaginateStatus(_) => concrete!(ImaginateStatus), TaggedValue::LayerPath(_) => concrete!(Option>), TaggedValue::DAffine2(_) => concrete!(DAffine2), TaggedValue::LuminanceCalculation(_) => concrete!(LuminanceCalculation), TaggedValue::VectorData(_) => concrete!(graphene_core::vector::VectorData), TaggedValue::Fill(_) => concrete!(graphene_core::vector::style::Fill), TaggedValue::Stroke(_) => concrete!(graphene_core::vector::style::Stroke), TaggedValue::VecF32(_) => concrete!(Vec), TaggedValue::LineCap(_) => concrete!(graphene_core::vector::style::LineCap), TaggedValue::LineJoin(_) => concrete!(graphene_core::vector::style::LineJoin), TaggedValue::FillType(_) => concrete!(graphene_core::vector::style::FillType), TaggedValue::GradientType(_) => concrete!(graphene_core::vector::style::GradientType), TaggedValue::GradientPositions(_) => concrete!(Vec<(f64, Option)>), TaggedValue::Quantization(_) => concrete!(graphene_core::quantization::QuantizationChannels), TaggedValue::OptionalColor(_) => concrete!(Option), TaggedValue::ManipulatorGroupIds(_) => concrete!(Vec), TaggedValue::VecDVec2(_) => concrete!(Vec), TaggedValue::Segments(_) => concrete!(graphene_core::raster::IndexNode>>), } } } pub struct UpcastNode { value: TaggedValue, } impl<'input> Node<'input, Box + 'input>> for UpcastNode { type Output = Box + 'input>; fn eval<'s: 'input>(&'s self, _: Box + 'input>) -> Self::Output { self.value.clone().to_any() } } impl UpcastNode { pub fn new(value: TaggedValue) -> Self { Self { value } } } pub type Value<'a> = Box ValueTrait<'i> + 'a>; pub trait ValueTrait<'a>: DynAny<'a> + Upcast + 'a> + std::fmt::Debug + DynClone + Sync + Send + 'a {} pub trait IntoValue<'a>: Sized + for<'i> ValueTrait<'i> + 'a { fn into_any(self) -> Value<'a> { Box::new(self) } } impl<'a, T: 'a + StaticType + Upcast + 'a> + std::fmt::Debug + PartialEq + Clone + Sync + Send + 'a> ValueTrait<'a> for T {} impl<'a, T: for<'i> ValueTrait<'i> + 'a> IntoValue<'a> for T {} #[repr(C)] pub(crate) struct Vtable { pub(crate) destructor: unsafe fn(*mut ()), pub(crate) size: usize, pub(crate) align: usize, } #[repr(C)] pub(crate) struct TraitObject { pub(crate) self_ptr: *mut u8, pub(crate) vtable: &'static Vtable, } impl<'a> PartialEq for Box ValueTrait<'i> + 'a> { #[cfg_attr(miri, ignore)] fn eq(&self, other: &Self) -> bool { if self.type_id() != other.type_id() { return false; } let self_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(self.as_ref()) }; let other_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(other.as_ref()) }; let size = self_trait_object.vtable.size; let self_mem = unsafe { std::slice::from_raw_parts(self_trait_object.self_ptr, size) }; let other_mem = unsafe { std::slice::from_raw_parts(other_trait_object.self_ptr, size) }; self_mem == other_mem } } impl<'a> Hash for Value<'a> { fn hash(&self, state: &mut H) { let self_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(self.as_ref()) }; let size = self_trait_object.vtable.size; let self_mem = unsafe { std::slice::from_raw_parts(self_trait_object.self_ptr, size) }; self_mem.hash(state); } } impl<'a> Clone for Value<'a> { fn clone(&self) -> Self { let self_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(self.as_ref()) }; let size = self_trait_object.vtable.size; let self_mem = unsafe { std::slice::from_raw_parts(self_trait_object.self_ptr, size) }.to_owned(); let ptr = Vec::leak(self_mem); unsafe { std::mem::transmute(TraitObject { self_ptr: ptr as *mut [u8] as *mut u8, vtable: self_trait_object.vtable, }) } } } #[cfg(test)] mod test { use super::*; #[test] #[cfg_attr(miri, ignore)] fn test_any_src() { assert!(2_u32.into_any() == 2_u32.into_any()); assert!(2_u32.into_any() != 3_u32.into_any()); assert!(2_u32.into_any() != 3_i32.into_any()); } }