Add the owned attribute crossing over the deep field glue

This commit is contained in:
Dennis Kobert
2026-09-05 11:52:42 +00:00
parent aa50c42930
commit ab93e1f071
2 changed files with 78 additions and 16 deletions

View File

@@ -79,6 +79,45 @@ impl<'e, A: Attribute> std::fmt::Debug for Attr<'e, A> {
}
}
/// An attribute write that outlives the evaluation producing it: an async
/// source's slot persists across generations, so a reference value cannot
/// cross as itself. The value crosses deep-copied through the field glue and
/// parks into the serving arena at every lift, which is why the copy is paid
/// once per invocation rather than once per evaluation.
pub struct OwnedAttr<A: Attribute>(Box<dyn AnyAttributeValue>, PhantomData<fn() -> A>);
impl<A: Attribute> OwnedAttr<A> {
/// Deep-copies `value` out of the evaluation that produced it.
pub fn new(value: A::Value<'_>) -> Self {
// SAFETY: the read addresses a live local of the marker's value type.
let erased = unsafe { A::read_erased((&raw const value).cast()) };
OwnedAttr(crate::record::deepen_field_value(erased), PhantomData)
}
/// Parks the copy into `arena` for one evaluation; `None` reports arena
/// exhaustion.
pub fn park<'e>(&self, arena: &'e crate::arena::Arena) -> Option<A::Value<'e>> {
let resident = crate::record::replay_field_value(&*self.0, arena)?;
let mut value = A::default();
// SAFETY: the slot is a live field of the marker's value type, and the
// stored value is the copy `new` took at that same type.
unsafe { write_stored::<A>(resident.as_deref().unwrap_or(&*self.0), (&raw mut value).cast(), arena) }?;
Some(value)
}
}
impl<A: Attribute> Clone for OwnedAttr<A> {
fn clone(&self) -> Self {
OwnedAttr(self.0.clone(), PhantomData)
}
}
impl<A: Attribute> std::fmt::Debug for OwnedAttr<A> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple(A::NAME).field(&self.0.display_string()).finish()
}
}
/// A deletion of `A` in a node's return tuple: the name leaves the output
/// layout, so downstream reads yield the declared default again. Functionally
/// a write of the default; the value carries nothing.
@@ -410,6 +449,27 @@ mod tests {
assert_eq!(row.size, size_of::<&str>());
}
#[test]
fn an_owned_reference_crossing_parks_into_the_serving_arena() {
let owned = OwnedAttr::<Name>::new("crossing");
let arena = crate::arena::Arena::new(1024).unwrap();
assert_eq!(owned.park(&arena).unwrap(), "crossing");
assert_eq!(owned.clone().park(&arena).unwrap(), "crossing", "the crossing parks again on every evaluation");
}
#[test]
fn an_owned_plain_crossing_rides_its_bytes() {
let arena = crate::arena::Arena::new(64).unwrap();
assert_eq!(OwnedAttr::<Opacity>::new(0.25).park(&arena).unwrap(), 0.25);
}
#[test]
fn an_exhausted_arena_refuses_an_owned_reference_crossing() {
let owned = OwnedAttr::<Name>::new("too long for this arena");
let arena = crate::arena::Arena::new(8).unwrap();
assert!(owned.park(&arena).is_none());
}
#[test]
fn reregistration_at_the_same_type_is_idempotent() {
register::<Opacity>();

View File

@@ -1426,13 +1426,25 @@ fn deep_field_glue(type_id: std::any::TypeId) -> Option<DeepFieldGlue> {
DEEP_FIELD_VALUES.lock().unwrap().get(&type_id).copied()
}
fn deepen_field_value(value: Box<dyn crate::list::AnyAttributeValue>) -> Box<dyn crate::list::AnyAttributeValue> {
/// The copy-out half over an erased field value: the owned form a value takes
/// when it crosses out of the evaluation whose arena its content borrows. A
/// value with no registered glue already owns everything and passes through.
pub fn deepen_field_value(value: Box<dyn crate::list::AnyAttributeValue>) -> Box<dyn crate::list::AnyAttributeValue> {
match deep_field_glue(value.as_any().type_id()) {
Some(glue) => (glue.copy_out)(&*value).unwrap_or(value),
None => value,
}
}
/// The replay half over an erased field value: `Some(None)` where the value
/// already owns its content, `None` on arena exhaustion.
pub fn replay_field_value(value: &dyn crate::list::AnyAttributeValue, arena: &crate::arena::Arena) -> Option<Option<Box<dyn crate::list::AnyAttributeValue>>> {
match deep_field_glue(value.as_any().type_id()) {
Some(glue) => (glue.replay)(value, arena),
None => Some(None),
}
}
/// The element slot a record wire of `T` carries, its erased glue bound at
/// the statically-known type.
pub fn element_write<T: Clone + Send + Sync + dyn_any::StaticTypeSized>() -> ElementWrite
@@ -1918,14 +1930,9 @@ unsafe fn promote_record(layout: &Layout, dst: *mut u8, promotion: &Promotion<'_
}
// SAFETY: the slot images a parked field of this descriptor.
let value = deepen_field_value(unsafe { (field.read_erased)(slot.cast_const()) });
match deep_field_glue(value.as_any().type_id()) {
Some(glue) => match (glue.replay)(&*value, promotion.persistent)? {
// SAFETY: the replay produced this field's own value type.
Some(resident) => unsafe { repark(&*resident, slot, promotion.persistent) }?,
None => unsafe { repark(&*value, slot, promotion.persistent) }?,
},
None => unsafe { repark(&*value, slot, promotion.persistent) }?,
}
let resident = replay_field_value(&*value, promotion.persistent)?;
// SAFETY: the replay produced this field's own value type.
unsafe { repark(resident.as_deref().unwrap_or(&*value), slot, promotion.persistent) }?;
}
Some(())
}
@@ -2203,13 +2210,8 @@ impl OwnedRecord {
for (index, value) in &self.fields {
let field = &layout.fields[*index];
let repark = field.repark.expect("copied fields carry re-park glue");
match deep_field_glue(value.as_any().type_id()) {
Some(glue) => match (glue.replay)(&**value, arena)? {
Some(resident) => unsafe { repark(&*resident, dst.add(field.offset), arena) }?,
None => unsafe { repark(&**value, dst.add(field.offset), arena) }?,
},
None => unsafe { repark(&**value, dst.add(field.offset), arena) }?,
}
let resident = replay_field_value(&**value, arena)?;
unsafe { repark(resident.as_deref().unwrap_or(&**value), dst.add(field.offset), arena) }?;
}
Some(())
}