Support embedding whole items into Graphic variants so their attributes survive the conversion (#4440)

Add embedding conversion adapters that move a whole ranked value inside a Graphic variant
This commit is contained in:
Keavon Chambers
2026-08-16 19:51:58 -07:00
committed by GitHub
parent f635c56eab
commit 104b8b71e6
5 changed files with 132 additions and 11 deletions

View File

@@ -77,6 +77,19 @@ fn into_list<'i, T: 'i + Send + Into<E>, E: 'i + Send>(_: impl Ctx, value: List<
.collect()
}
/// Moves a whole `Item` wire inside an element type like `Graphic` that embeds ranked values as its variants.
/// The attributes describe the element they arrived with, so they travel inside it and the fresh envelope starts empty.
#[node_macro::node(category(""), skip_impl)]
fn embed_item<'i, T: 'i + Send, E: 'i + Send + From<Item<T>>>(_: impl Ctx, value: Item<T>, _element_ty: PhantomData<E>) -> Item<E> {
Item::new_from_element(value.into())
}
/// The `List` counterpart of `embed_item`, each item moving whole inside its own embedding element.
#[node_macro::node(category(""), skip_impl)]
fn embed_list<'i, T: 'i + Send, E: 'i + Send + From<Item<T>>>(_: impl Ctx, value: List<T>, _element_ty: PhantomData<E>) -> List<E> {
value.into_iter().map(|item| Item::new_from_element(E::from(item))).collect()
}
/// The [`Convert`]-based counterpart of `into_item`, casting an `Item` wire's element to a connector's numeric element type.
#[node_macro::node(category(""), skip_impl)]
async fn convert_item<'i, T: 'i + Send + Convert<E, ()>, E: 'i + Send>(ctx: impl Ctx + ExtractFootprint, value: Item<T>, _element_ty: PhantomData<E>) -> Item<E> {

View File

@@ -3975,10 +3975,10 @@ mod test {
let fill = appearance.first_paint_of(Cover::Fill).expect("Morph should keep the fill paint at the midpoint");
// Interpolated color between red and blue should have >0 value on both R and B
let Graphic::ColorList(colors) = fill else {
let Graphic::Color(color) = fill else {
panic!("Expected a solid color fill, got {fill:?}");
};
let color = *colors.element(0).expect("Color present");
let color = *color.element();
assert!(color.r() > 0. && color.b() > 0., "Fill should be a red-to-blue blend, got {color:?}");
}
@@ -3992,10 +3992,10 @@ mod test {
let paint_color = |appearance: &Appearance, cover| {
let paint = appearance.first_paint_of(cover).expect("Morph should keep both paints at the midpoint");
let Graphic::ColorList(colors) = paint else {
let Graphic::Color(color) = paint else {
panic!("Expected a solid color paint, got {paint:?}");
};
*colors.element(0).expect("Color present")
*color.element()
};
// The two endpoints list their covers in opposite paint orders, which pairing by position would cross