Accept any paint element on the fill and stroke inputs

This commit is contained in:
Dennis Kobert
2026-09-08 18:54:21 +00:00
parent a593430e38
commit 35a34168d7
6 changed files with 181 additions and 22 deletions

View File

@@ -280,7 +280,8 @@ impl PartialEq for TypeDescriptor {
/// Graph runtime type information used for type inference.
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(Clone, PartialEq, Eq, Hash, graphene_hash::CacheHash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "PascalCase"))]
pub enum Type {
/// A wrapper for some type variable used within the inference system. Resolved at inference time and replaced with a concrete type.
Generic(Cow<'static, str>),
@@ -294,6 +295,41 @@ pub enum Type {
Record(Box<Type>),
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Type {
/// Documents written against the structural rank model store `Item` and `List` wire types.
/// Our one wire kind has neither, so an `Item` reduces to the element it wraps and a `List`
/// becomes the concrete `List<..>` type it names.
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(serde::Deserialize)]
enum Stored {
Generic(Cow<'static, str>),
Concrete(TypeDescriptor),
Fn(Box<Type>, Box<Type>),
Future(Box<Type>),
Record(Box<Type>),
Item(Box<Type>),
List(Box<Type>),
}
Ok(match Stored::deserialize(deserializer)? {
Stored::Generic(name) => Type::Generic(name),
Stored::Concrete(descriptor) => Type::Concrete(descriptor),
Stored::Fn(input, output) => Type::Fn(input, output),
Stored::Future(inner) => Type::Future(inner),
Stored::Record(inner) => Type::Record(inner),
Stored::Item(element) => *element,
Stored::List(element) => Type::Concrete(TypeDescriptor {
id: None,
name: Cow::Owned(format!("core_types::list::List<{}>", element.identifier_name())),
alias: None,
size: 0,
align: 0,
}),
})
}
}
impl Default for Type {
fn default() -> Self {
concrete!(())

View File

@@ -516,6 +516,46 @@ impl<'e> ListConvert<Graphic<'e>> for Raster<GPU> {
Graphic::RasterGPU(self)
}
}
// A leveled paint input types by its element, so the same embedding is needed one rank down.
macro_rules! convert_leaf_to_graphic {
($($element:ty),* $(,)?) => {
$(
impl<'e> core_types::ops::Convert<Graphic<'e>, ()> for $element {
fn convert(self, _: core_types::transform::Footprint, _: ()) -> Graphic<'e> {
core_types::ops::ListConvert::convert_item(self)
}
}
)*
};
}
convert_leaf_to_graphic!(Vector, Raster<CPU>, Raster<GPU>, Color, Gradient, String, Stroke);
// The paint wires accept any leaf element, the role master's `From<X> for Graphic` embedding adapters play.
impl<'e> ListConvert<Graphic<'e>> for Graphic<'e> {
fn convert_item(self) -> Graphic<'e> {
self
}
}
impl<'e> ListConvert<Graphic<'e>> for Color {
fn convert_item(self) -> Graphic<'e> {
Graphic::Color(self)
}
}
impl<'e> ListConvert<Graphic<'e>> for Gradient {
fn convert_item(self) -> Graphic<'e> {
Graphic::Gradient(self)
}
}
impl<'e> ListConvert<Graphic<'e>> for String {
fn convert_item(self) -> Graphic<'e> {
Graphic::Text(self)
}
}
impl<'e> ListConvert<Graphic<'e>> for Stroke {
fn convert_item(self) -> Graphic<'e> {
Graphic::Stroke(self)
}
}
impl RenderComplexity for Graphic<'_> {
fn render_complexity(&self) -> usize {