From 1f860aae6a2135912e850e4107c94fa00f9cd506 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Tue, 1 Sep 2026 22:51:18 +0000 Subject: [PATCH] Move group-free graphic and artboard headers at the promote --- .../libraries/graphic-types/src/artboard.rs | 13 ++++++++++++- node-graph/libraries/graphic-types/src/graphic.rs | 15 +++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/node-graph/libraries/graphic-types/src/artboard.rs b/node-graph/libraries/graphic-types/src/artboard.rs index 8815d6a629..afd2c9dd20 100644 --- a/node-graph/libraries/graphic-types/src/artboard.rs +++ b/node-graph/libraries/graphic-types/src/artboard.rs @@ -74,13 +74,24 @@ unsafe fn deep_repark_artboard(value: &(dyn std::any::Any + Send + Sync), dst: * } /// The promote for `Artboard` elements: as for `Graphic`, content groups the -/// persistent region already holds are shared rather than copied. +/// persistent region already holds are shared rather than copied, and +/// group-free content moves its header instead of copying its heap. /// /// # Safety /// `src` must point at a live parked `Artboard` element field, and `dst` at /// the element field the promoted reference is written to. unsafe fn promote_artboard(src: *const u8, dst: *mut u8, promotion: &core_types::record::Promotion<'_>) -> Option<()> { let artboard = unsafe { core_types::record::borrow_element::(core_types::record::Rec::new(src)) }; + if !crate::graphic::list_contains_groups(&artboard.0) { + // SAFETY: a parked element slot holds one reference at offset 0, and + // group-free content owns all of itself. + let header = unsafe { src.cast::<*const u8>().read() }; + if let Some(moved) = unsafe { promotion.move_park::(header, 0) } { + // SAFETY: as above, into the promoted image's own element slot. + unsafe { dst.cast::<*const Artboard>().write(moved) }; + return Some(()); + } + } let mut content = List::new(); for item in artboard.0.clone().into_iter() { let (element, attributes) = item.into_parts(); diff --git a/node-graph/libraries/graphic-types/src/graphic.rs b/node-graph/libraries/graphic-types/src/graphic.rs index 42b6563613..a4a2488a0e 100644 --- a/node-graph/libraries/graphic-types/src/graphic.rs +++ b/node-graph/libraries/graphic-types/src/graphic.rs @@ -1220,13 +1220,24 @@ pub fn map_groups_to_persistent<'p>(graphic: &Graphic<'_>, promotion: &core_type /// The promote for `Graphic` elements: the generic path would deep-copy every /// interior through an owned intermediate, while this shares the interiors the -/// persistent region already holds. +/// persistent region already holds. A group-free graphic references nothing the +/// evaluation owns, so its header moves and its heap is never copied. /// /// # Safety /// `src` must point at a live parked `Graphic` element field, and `dst` at the /// element field the promoted reference is written to. unsafe fn promote_graphic(src: *const u8, dst: *mut u8, promotion: &core_types::record::Promotion<'_>) -> Option<()> { let graphic = unsafe { core_types::record::borrow_element::(core_types::record::Rec::new(src)) }; + if !graphic_contains_groups(graphic) { + // SAFETY: a parked element slot holds one reference at offset 0, and a + // group-free graphic owns all of its content. + let header = unsafe { src.cast::<*const u8>().read() }; + if let Some(moved) = unsafe { promotion.move_park::>(header, graphic_retained_heap(graphic)) } { + // SAFETY: as above, into the promoted image's own element slot. + unsafe { dst.cast::<*const Graphic<'static>>().write(moved) }; + return Some(()); + } + } let promoted = map_groups_to_persistent(graphic, promotion)?; let retained = graphic_retained_heap(&promoted); unsafe { core_types::record::write_element_sized(dst, promoted, promotion.persistent(), retained) } @@ -1263,7 +1274,7 @@ fn graphic_contains_groups(graphic: &Graphic) -> bool { } } -fn list_contains_groups(list: &List) -> bool { +pub(crate) fn list_contains_groups(list: &List) -> bool { (0..list.len()).any(|index| list.element(index).is_some_and(graphic_contains_groups)) }