diff --git a/editor/src/messages/portfolio/document/node_graph/utility_types.rs b/editor/src/messages/portfolio/document/node_graph/utility_types.rs index 375b522cb3..cf377381fd 100644 --- a/editor/src/messages/portfolio/document/node_graph/utility_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/utility_types.rs @@ -31,11 +31,11 @@ impl FrontendGraphDataType { TaggedValue::String(_) => Self::Typography, // Types whose `TaggedValue` variant has been removed are routed through `TypeDefault` and identified by the descriptor's type name. TaggedValue::TypeDefault(td) => match td.name.as_ref() { - n if n == std::any::type_name::>() => Self::Graphic, - n if n == std::any::type_name::>() => Self::Artboard, - n if n == std::any::type_name::>>() => Self::Raster, - n if n == std::any::type_name::>() => Self::Vector, - n if n == std::any::type_name::>() => Self::Typography, + n if n == graphene_std::core_types::normalize_type_name(std::any::type_name::>()) => Self::Graphic, + n if n == graphene_std::core_types::normalize_type_name(std::any::type_name::>()) => Self::Artboard, + n if n == graphene_std::core_types::normalize_type_name(std::any::type_name::>>()) => Self::Raster, + n if n == graphene_std::core_types::normalize_type_name(std::any::type_name::>()) => Self::Vector, + n if n == graphene_std::core_types::normalize_type_name(std::any::type_name::>()) => Self::Typography, _ => Self::General, }, _ => Self::General, diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface/resolved_types.rs b/editor/src/messages/portfolio/document/utility_types/network_interface/resolved_types.rs index a618475665..8eaebc35a9 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface/resolved_types.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface/resolved_types.rs @@ -65,11 +65,11 @@ impl TypeSource { TaggedValue::String(_) => FrontendGraphDataType::Typography, // Types whose `TaggedValue` variant has been removed are routed through `TypeDefault` and identified by the descriptor's type name. TaggedValue::TypeDefault(td) => match td.name.as_ref() { - n if n == std::any::type_name::>() => FrontendGraphDataType::Graphic, - n if n == std::any::type_name::>() => FrontendGraphDataType::Artboard, - n if n == std::any::type_name::>>() => FrontendGraphDataType::Raster, - n if n == std::any::type_name::>() => FrontendGraphDataType::Vector, - n if n == std::any::type_name::>() => FrontendGraphDataType::Typography, + n if n == graphene_std::core_types::normalize_type_name(std::any::type_name::>()) => FrontendGraphDataType::Graphic, + n if n == graphene_std::core_types::normalize_type_name(std::any::type_name::>()) => FrontendGraphDataType::Artboard, + n if n == graphene_std::core_types::normalize_type_name(std::any::type_name::>>()) => FrontendGraphDataType::Raster, + n if n == graphene_std::core_types::normalize_type_name(std::any::type_name::>()) => FrontendGraphDataType::Vector, + n if n == graphene_std::core_types::normalize_type_name(std::any::type_name::>()) => FrontendGraphDataType::Typography, _ => FrontendGraphDataType::General, }, _ => FrontendGraphDataType::General, diff --git a/node-graph/graph-craft/src/document/value.rs b/node-graph/graph-craft/src/document/value.rs index 583cc760d3..d2a6703eff 100644 --- a/node-graph/graph-craft/src/document/value.rs +++ b/node-graph/graph-craft/src/document/value.rs @@ -147,7 +147,7 @@ macro_rules! tagged_value { let name = td.name.as_ref(); macro_rules! check { ($type_default:ty) => { - if name == std::any::type_name::<$type_default>() { return Box::new(<$type_default>::default()); } + if name == core_types::normalize_type_name(std::any::type_name::<$type_default>()) { return Box::new(<$type_default>::default()); } }; } for_each_type_default!(check); @@ -194,7 +194,7 @@ macro_rules! tagged_value { let name = td.name.as_ref(); macro_rules! check { ($type_default:ty) => { - if name == std::any::type_name::<$type_default>() { return Arc::new(<$type_default>::default()); } + if name == core_types::normalize_type_name(std::any::type_name::<$type_default>()) { return Arc::new(<$type_default>::default()); } }; } for_each_type_default!(check); @@ -240,11 +240,11 @@ macro_rules! tagged_value { // `Type` axis, it rides the layout proven at wiring. Self::TypeDefault(td) => { let name = td.name.as_ref(); - if name == std::any::type_name::>() { return concrete!(Graphic); } - if name == std::any::type_name::>() { return concrete!(Artboard); } - if name == std::any::type_name::>>() { return concrete!(Raster); } - if name == std::any::type_name::>() { return concrete!(Vector); } - if name == std::any::type_name::>() { return concrete!(String); } + if name == core_types::normalize_type_name(std::any::type_name::>()) { return concrete!(Graphic); } + if name == core_types::normalize_type_name(std::any::type_name::>()) { return concrete!(Artboard); } + if name == core_types::normalize_type_name(std::any::type_name::>>()) { return concrete!(Raster); } + if name == core_types::normalize_type_name(std::any::type_name::>()) { return concrete!(Vector); } + if name == core_types::normalize_type_name(std::any::type_name::>()) { return concrete!(String); } Type::Concrete(td.clone()) } Self::F64Array(_) => concrete!(f64), @@ -271,23 +271,29 @@ macro_rules! tagged_value { /// variants, element-only at rank 0 otherwise. `None` for a /// [`Self::TypeDefault`] whose named type is outside `for_each_type_default!`. pub fn value_layout(&self) -> Option { - fn leveled() -> Option { + fn leveled() -> Option + where + T::Static: Clone + Send + Sync, + { Some(core_types::record::Layout::default().with_writes(1, core_types::record::element_write_hashed::(), &[])) } - fn scalar() -> Option { + fn scalar() -> Option + where + T::Static: Clone + Send + Sync, + { Some(core_types::record::Layout::default().with_writes(0, core_types::record::element_write::(), &[])) } match self { Self::None => scalar::<()>(), Self::TypeDefault(td) => { let name = td.name.as_ref(); - if name == std::any::type_name::>() { return leveled::(); } - if name == std::any::type_name::>() { return leveled::(); } - if name == std::any::type_name::>>() { return leveled::>(); } - if name == std::any::type_name::>() { return leveled::(); } - if name == std::any::type_name::>() { return leveled::(); } - if name == std::any::type_name::() { return scalar::(); } - if name == std::any::type_name::() { return scalar::(); } + if name == core_types::normalize_type_name(std::any::type_name::>()) { return leveled::(); } + if name == core_types::normalize_type_name(std::any::type_name::>()) { return leveled::(); } + if name == core_types::normalize_type_name(std::any::type_name::>>()) { return leveled::>(); } + if name == core_types::normalize_type_name(std::any::type_name::>()) { return leveled::(); } + if name == core_types::normalize_type_name(std::any::type_name::>()) { return leveled::(); } + if name == core_types::normalize_type_name(std::any::type_name::()) { return scalar::(); } + if name == core_types::normalize_type_name(std::any::type_name::()) { return scalar::(); } None } Self::F64Array(_) => leveled::(), @@ -317,7 +323,7 @@ macro_rules! tagged_value { // their default directly, mirroring `to_dynany`'s recursion guard. macro_rules! check_level { ($list:ty, $element:ty) => { - if name == std::any::type_name::<$list>() { + if name == core_types::normalize_type_name(std::any::type_name::<$list>()) { return Ok(leveled_record_value_edge(Vec::<$element>::new())); } }; @@ -327,10 +333,10 @@ macro_rules! tagged_value { check_level!(List>, Raster); // One default lane rather than an empty level: an unwired path input // starts from a blank vector, as the legacy path modify synthesized itself. - if name == std::any::type_name::>() { return Ok(leveled_record_value_edge(vec![Vector::default()])); } + if name == core_types::normalize_type_name(std::any::type_name::>()) { return Ok(leveled_record_value_edge(vec![Vector::default()])); } check_level!(List, String); - if name == std::any::type_name::() { return Ok(record_value_edge(DocumentNode::default())); } - if name == std::any::type_name::() { return Ok(record_value_edge(Resource::default())); } + if name == core_types::normalize_type_name(std::any::type_name::()) { return Ok(record_value_edge(DocumentNode::default())); } + if name == core_types::normalize_type_name(std::any::type_name::()) { return Ok(record_value_edge(Resource::default())); } Self::from_type_or_none(&Type::Concrete(td)).to_edge() } Self::F64Array(values) => Ok(leveled_record_value_edge(values)), @@ -458,26 +464,26 @@ macro_rules! tagged_value { let name = concrete_type.name.as_ref(); // TODO: Add default implementations for types such as TaggedValue::Subpaths, and use the defaults here and in document_node_types // Tries using the default for the tagged value type. If it not implemented, then uses the default used in document_node_types. If it is not used there, then TaggedValue::None is returned. - if name == std::any::type_name::<()>() { return Some(TaggedValue::None) } + if name == core_types::normalize_type_name(std::any::type_name::<()>()) { return Some(TaggedValue::None) } // List-wrapped types need a single-item default with the element's default, not an empty list - if name == std::any::type_name::>() { return Some(TaggedValue::Color(Some(Color::default()))) } - if name == std::any::type_name::>() { return Some(TaggedValue::Gradient(GradientStops::default())) } - $( if name == std::any::type_name::<$ty>() { return Some(TaggedValue::$identifier(Default::default())) } )* - if name == std::any::type_name::>() { return Some(TaggedValue::F64Array(Vec::new())) } - if name == std::any::type_name::>() { return Some(TaggedValue::BrushStrokes(Vec::new())) } + if name == core_types::normalize_type_name(std::any::type_name::>()) { return Some(TaggedValue::Color(Some(Color::default()))) } + if name == core_types::normalize_type_name(std::any::type_name::>()) { return Some(TaggedValue::Gradient(GradientStops::default())) } + $( if name == core_types::normalize_type_name(std::any::type_name::<$ty>()) { return Some(TaggedValue::$identifier(Default::default())) } )* + if name == core_types::normalize_type_name(std::any::type_name::>()) { return Some(TaggedValue::F64Array(Vec::new())) } + if name == core_types::normalize_type_name(std::any::type_name::>()) { return Some(TaggedValue::BrushStrokes(Vec::new())) } // Leveled wires type by their element; each element name maps to the // same tagged default as its legacy list form. - if name == std::any::type_name::() { return Some(TaggedValue::Color(Some(Color::default()))) } - if name == std::any::type_name::() { return Some(TaggedValue::Gradient(GradientStops::default())) } - if name == std::any::type_name::() { return Some(TaggedValue::BrushStrokes(Vec::new())) } - if name == std::any::type_name::() { return Some(TaggedValue::TypeDefault(core_types::descriptor!(List))) } - if name == std::any::type_name::() { return Some(TaggedValue::TypeDefault(core_types::descriptor!(List))) } - if name == std::any::type_name::>() { return Some(TaggedValue::TypeDefault(core_types::descriptor!(List>))) } - if name == std::any::type_name::() { return Some(TaggedValue::TypeDefault(core_types::descriptor!(List))) } + if name == core_types::normalize_type_name(std::any::type_name::()) { return Some(TaggedValue::Color(Some(Color::default()))) } + if name == core_types::normalize_type_name(std::any::type_name::()) { return Some(TaggedValue::Gradient(GradientStops::default())) } + if name == core_types::normalize_type_name(std::any::type_name::()) { return Some(TaggedValue::BrushStrokes(Vec::new())) } + if name == core_types::normalize_type_name(std::any::type_name::()) { return Some(TaggedValue::TypeDefault(core_types::descriptor!(List))) } + if name == core_types::normalize_type_name(std::any::type_name::()) { return Some(TaggedValue::TypeDefault(core_types::descriptor!(List))) } + if name == core_types::normalize_type_name(std::any::type_name::>()) { return Some(TaggedValue::TypeDefault(core_types::descriptor!(List>))) } + if name == core_types::normalize_type_name(std::any::type_name::()) { return Some(TaggedValue::TypeDefault(core_types::descriptor!(List))) } // Types whose `TaggedValue` variant has been removed. They route through `TypeDefault` instead, with `to_dynany`/`to_any` constructing the actual default at execution time. macro_rules! check { ($type_default:ty) => { - if name == std::any::type_name::<$type_default>() { return Some(TaggedValue::TypeDefault(concrete_type.clone())); } + if name == core_types::normalize_type_name(std::any::type_name::<$type_default>()) { return Some(TaggedValue::TypeDefault(concrete_type.clone())); } }; } for_each_type_default!(check); @@ -917,7 +923,7 @@ mod typedefault_dispatch { DynAny::type_id(&*dyn_value), expected_type_id, "`to_dynany(TypeDefault({0}))` did not produce a `{0}` — `for_each_type_default!` lists this type but the unwrap site doesn't handle it. Without a match, `to_dynany` falls back to `from_type_or_none`, which returns `TypeDefault({0})` again and recurses forever.", - std::any::type_name::<$type_default>(), + core_types::normalize_type_name(std::any::type_name::<$type_default>()), ); let arc_value = TaggedValue::TypeDefault(descriptor).to_any(); @@ -925,7 +931,7 @@ mod typedefault_dispatch { (*arc_value).type_id(), expected_type_id, "`to_any(TypeDefault({0}))` did not produce a `{0}` — same recursion hazard as above for the `to_any` path.", - std::any::type_name::<$type_default>(), + core_types::normalize_type_name(std::any::type_name::<$type_default>()), ); }}; } diff --git a/node-graph/libraries/core-types/src/types.rs b/node-graph/libraries/core-types/src/types.rs index 523b45395d..2cfc05f4f4 100644 --- a/node-graph/libraries/core-types/src/types.rs +++ b/node-graph/libraries/core-types/src/types.rs @@ -12,12 +12,21 @@ macro_rules! concrete { }; } +/// The type's name with lifetime arguments stripped, so a lifetimed type +/// keeps its pre-lifetime registry and document name. +pub fn normalize_type_name<'a>(name: &'a str) -> std::borrow::Cow<'a, str> { + if !name.contains("<'") && !name.contains(", '") { + return std::borrow::Cow::Borrowed(name); + } + std::borrow::Cow::Owned(name.replace("<'_>", "").replace("<'_, ", "<").replace(", '_", "")) +} + #[macro_export] macro_rules! descriptor { ($type:ty) => { $crate::TypeDescriptor { id: Some(std::any::TypeId::of::<$type>()), - name: $crate::Cow::Borrowed(std::any::type_name::<$type>()), + name: $crate::normalize_type_name(std::any::type_name::<$type>()), alias: None, size: std::mem::size_of::<$type>(), align: std::mem::align_of::<$type>(), @@ -26,7 +35,7 @@ macro_rules! descriptor { ($type:ty, $name:ty) => { $crate::TypeDescriptor { id: Some(std::any::TypeId::of::<$type>()), - name: $crate::Cow::Borrowed(std::any::type_name::<$type>()), + name: $crate::normalize_type_name(std::any::type_name::<$type>()), alias: Some($crate::Cow::Borrowed(stringify!($name))), size: std::mem::size_of::<$type>(), align: std::mem::align_of::<$type>(), @@ -192,13 +201,13 @@ pub struct TypeDescriptor { impl std::hash::Hash for TypeDescriptor { fn hash(&self, state: &mut H) { - self.name.hash(state); + normalize_type_name(&self.name).hash(state); } } impl graphene_hash::CacheHash for TypeDescriptor { fn cache_hash(&self, state: &mut H) { - graphene_hash::CacheHash::cache_hash(&self.name, state); + graphene_hash::CacheHash::cache_hash(&normalize_type_name(&self.name), state); } } @@ -216,7 +225,7 @@ impl PartialEq for TypeDescriptor { _ => { // TODO: Add a flag to disable this warning // warn!("TypeDescriptor::eq: comparing types without ids based on name"); - self.name == other.name + normalize_type_name(&self.name) == normalize_type_name(&other.name) } } } @@ -297,7 +306,7 @@ impl Type { pub fn new() -> Self { Self::Concrete(TypeDescriptor { id: Some(TypeId::of::()), - name: Cow::Borrowed(std::any::type_name::()), + name: normalize_type_name(std::any::type_name::()), alias: None, size: size_of::(), align: align_of::(),