Write an attribute under a name the graph supplies

`Named<X>` in parameter position declares where a placeholder's name is
wired, and the macro gives that input constant text; `Attr<Named<X, V>>`
in the return writes under it. The kernel is handed the bare placeholder,
since the name is spent resolving the layout and a folded offset is all
the write needs, so the hot path matches a marker node's exactly.

A name-generic write names its value type through the wired generic,
which only an implementations row resolves, so those nodes emit their
layout meta per row rather than sharing one across rows.

`write_attribute` is the catalog's set half, restoring the identifier
master's documents carry with its input positions. Its name input is a
constant, so those documents resolve without migration, and the reset
marker that stood in for the missing node retires with it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Dennis Kobert
2026-09-09 09:26:17 +00:00
parent db9a59aa7d
commit 81d72b159b
10 changed files with 364 additions and 34 deletions

View File

@@ -149,7 +149,7 @@ fn flip_entries_tokens(parsed: &ParsedNodeFn, struct_name: &Ident, regular_field
quote!(&#layout,)
});
let element_spec = quote!(gcore::record::ElementSpec::Concrete({ use gcore::record::{ElementWritePickHashed as _, ElementWritePickPlain as _}; (&gcore::record::ElementWritePick::<#row_output>(::core::marker::PhantomData)).element_write() }));
let layout_meta = crate::codegen::ir::layout_meta_tokens(&node, element_spec, &core_types);
let layout_meta = crate::codegen::ir::layout_meta_tokens(&node, element_spec, &core_types, &assignments);
Some(quote! {
gcore::registry::RegistryEntry {
layout_meta: Some(#layout_meta),
@@ -382,7 +382,7 @@ fn single_row_entries(parsed: &ParsedNodeFn, struct_name: &Ident, regular_fields
.collect();
let carried_meta = || {
let meta = ir::layout_meta_tokens(&node, quote!(gcore::record::ElementSpec::Carried), &core_types);
let meta = ir::layout_meta_tokens(&node, quote!(gcore::record::ElementSpec::Carried), &core_types, &[]);
quote!(Some(#meta))
};
@@ -417,7 +417,25 @@ fn single_row_entries(parsed: &ParsedNodeFn, struct_name: &Ident, regular_fields
ir::NodeKind::RecordIo => {
let carrier_arg = (node.inputs.first().is_some_and(|input| input.subject) && ir::materialized_levels(&node, 0) == 0).then(|| quote!(&__layout_0,));
let layout_meta_fn = format_ident!("{}_layout_meta", fn_name);
(quote!(), quote!(#carrier_arg #(#value_layout_args)*), quote!(Some(self::#layout_meta_fn())))
// A name-generic write names its value type through a wired
// generic, which only the row resolves, so such a node's
// meta is emitted per row instead of shared across them.
let named = node.output.shape.attrs.iter().any(|attr| crate::parsing::named_marker(&attr.marker).is_some());
let meta = match named {
false => quote!(Some(self::#layout_meta_fn())),
true => {
let element_spec = match &node.output.shape.element {
ir::Element::Concrete(element) => {
let ty = substitute_ident_types(element, assignments);
quote!(gcore::record::ElementSpec::Concrete({ use gcore::record::{ElementWritePickHashed as _, ElementWritePickPlain as _}; (&gcore::record::ElementWritePick::<#ty>(::core::marker::PhantomData)).element_write() }))
}
_ => quote!(gcore::record::ElementSpec::Carried),
};
let meta = ir::layout_meta_tokens(&node, element_spec, &core_types, assignments);
quote!(Some(#meta))
}
};
(quote!(), quote!(#carrier_arg #(#value_layout_args)*), meta)
}
ir::NodeKind::Routing => {
let source_layouts = base_indices.iter().map(|index| format_ident!("__layout_{index}"));