mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 14:18:04 +08:00
Sweep the data-flow wire and edge wording to input and source
This commit is contained in:
@@ -266,7 +266,7 @@ macro_rules! tagged_value {
|
||||
}
|
||||
}
|
||||
|
||||
/// The record layout of this value's edge: leveled for the list-carrying
|
||||
/// The record layout of this value's source: leveled for the list-carrying
|
||||
/// variants, element-only at rank 0 otherwise. `None` for a
|
||||
/// [`Self::TypeDefault`] whose named type is outside `for_each_type_default!`.
|
||||
pub fn value_layout(&self) -> Option<core_types::record::Layout> {
|
||||
@@ -309,7 +309,7 @@ macro_rules! tagged_value {
|
||||
}
|
||||
}
|
||||
|
||||
/// Materializes the value as [`Self::to_dynany`] does, wrapped in a value edge typed by [`Self::ty`].
|
||||
/// Materializes the value as [`Self::to_dynany`] does, wrapped in a value source typed by [`Self::ty`].
|
||||
pub fn to_edge(self) -> Result<EdgeHandle, String> {
|
||||
match self {
|
||||
// ===============
|
||||
@@ -358,7 +358,7 @@ macro_rules! tagged_value {
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluates a typed edge and converts the landed value into a tagged value, with the coverage of [`Self::try_from_any`].
|
||||
/// Evaluates a typed source and converts the landed value into a tagged value, with the coverage of [`Self::try_from_any`].
|
||||
pub fn from_edge<'f>(handle: EdgeHandle, ctx: &Context<'f>, frames: &core_types::record::Frames<'f>) -> Result<GPoll<Self>, String> {
|
||||
let ty = handle.ty().clone();
|
||||
// =======================
|
||||
@@ -447,7 +447,7 @@ macro_rules! tagged_value {
|
||||
$( if name == core_types::normalize_type_name(std::any::type_name::<$ty>()) { return Some(TaggedValue::$identifier(Default::default())) } )*
|
||||
if name == core_types::normalize_type_name(std::any::type_name::<List<f64>>()) { return Some(TaggedValue::F64Array(Vec::new())) }
|
||||
if name == core_types::normalize_type_name(std::any::type_name::<List<BrushStroke>>()) { return Some(TaggedValue::BrushStrokes(Vec::new())) }
|
||||
// Leveled wires type by their element; each element name maps to the
|
||||
// Leveled inputs type by their element; each element name maps to the
|
||||
// same tagged default as its legacy list form.
|
||||
if name == core_types::normalize_type_name(std::any::type_name::<Color>()) { return Some(TaggedValue::Color(Some(Color::default()))) }
|
||||
if name == core_types::normalize_type_name(std::any::type_name::<GradientStops>()) { return Some(TaggedValue::Gradient(GradientStops::default())) }
|
||||
@@ -705,7 +705,7 @@ impl TaggedValue {
|
||||
|
||||
match ty {
|
||||
Type::Generic(_) => None,
|
||||
// A leveled wire's default is its element's default, as in `from_type`.
|
||||
// A leveled input's default is its element's default, as in `from_type`.
|
||||
Type::Record(inner) => TaggedValue::from_primitive_string(string, inner),
|
||||
Type::Concrete(concrete_type) => {
|
||||
let ty = concrete_type.id?;
|
||||
|
||||
@@ -1041,8 +1041,8 @@ fn valid_type(from: &Type, to: &Type) -> bool {
|
||||
// Graphite doesn't have subtyping currently, but it used to have it, and may do so again, so we make sure to compare types in this way to make things easier.
|
||||
// More details explained here: <https://github.com/GraphiteEditor/Graphite/issues/1741>
|
||||
(Type::Fn(in1, out1), Type::Fn(in2, out2)) => valid_type(out2, out1) && valid_type(in1, in2),
|
||||
// A lend edge is substitutable exactly when the lent values are.
|
||||
// A record edge is substitutable exactly when the elements are.
|
||||
// A lend input is substitutable exactly when the lent values are.
|
||||
// A record input is substitutable exactly when the elements are.
|
||||
(Type::Record(in1), Type::Record(in2)) => valid_type(in1, in2),
|
||||
// If either the proposed input or the allowed input are generic, we allow the substitution (meaning this is a valid subtype).
|
||||
// TODO: Add proper generic counting which is not based on the name
|
||||
|
||||
@@ -173,7 +173,7 @@ impl DynamicExecutor {
|
||||
/// Calls the `Node::serialize` for that specific node. A monitor serializes
|
||||
/// its stored context snapshot, and this entry recreates the monitored
|
||||
/// value from it as the legacy value the editor's downcasts expect: a
|
||||
/// rank-0 wire yields its element and a leveled wire its legacy list.
|
||||
/// rank-0 input yields its element and a leveled input its legacy list.
|
||||
pub fn introspect(&self, node_path: &[NodeId]) -> Result<Arc<dyn std::any::Any + Send + Sync + 'static>, IntrospectError> {
|
||||
let result = self.tree.introspect(node_path)?;
|
||||
if result.downcast_ref::<core_types::context::CtxSnapshot>().is_some() {
|
||||
@@ -184,7 +184,7 @@ impl DynamicExecutor {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Re-evaluates the monitored edge at `node_path` with its stored context
|
||||
/// Re-evaluates the monitored input at `node_path` with its stored context
|
||||
/// snapshot and hands the resulting resident batch to `read`, inside the
|
||||
/// introspection window. The monitor stores only the context; the value is
|
||||
/// recreated against current source data, so a read right after an
|
||||
@@ -222,7 +222,7 @@ impl DynamicExecutor {
|
||||
match core_types::record::serve_input(&edge, &ctx, &frames) {
|
||||
GPoll::Final(value) | GPoll::Partial(value) => {
|
||||
let rec = layout.rec(&value);
|
||||
// SAFETY: the serve produced one live record of the edge's layout.
|
||||
// SAFETY: the serve produced one live record of the input's layout.
|
||||
let batch = unsafe { core_types::node::RecordBatch::new(rec.ptr(), 1, layout) };
|
||||
read(layout, batch, &arena)
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, Vec<RegistryEntry>> {
|
||||
.into_iter()
|
||||
.map(|entry| (graphene_std::graphic::to_graphic::IDENTIFIER.clone(), entry)),
|
||||
);
|
||||
// The transitional level bridge: a leveled wire materializes into the legacy
|
||||
// The transitional level bridge: a leveled input materializes into the legacy
|
||||
// list an unconverted consumer expects. The rows are keyed under the legacy
|
||||
// convert identifiers and die with the last legacy consumer.
|
||||
node_types.extend(
|
||||
@@ -367,7 +367,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// One wire kind: every row consumes and produces record wires. A plain
|
||||
/// One input kind: every row consumes and produces records. A plain
|
||||
/// io type here would need a bridge adapter, and those are gone.
|
||||
#[test]
|
||||
fn every_registry_row_is_record_typed() {
|
||||
|
||||
@@ -244,7 +244,7 @@ impl IndexLevels {
|
||||
self.0 == u32::MAX
|
||||
}
|
||||
|
||||
/// The same requirement seen from outside an edge whose innermost `supplied`
|
||||
/// The same requirement seen from outside an input whose innermost `supplied`
|
||||
/// levels the reading node drives itself, and whose chain sits `delta`
|
||||
/// deeper than that node's. A supplied level leaves no requirement behind;
|
||||
/// the rest renumber by the depth difference. An all-levels mask stays
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
use crate::gpoll::{Extent, GPoll};
|
||||
|
||||
/// A wired value input; `get` evaluates the edge and yields the typed element.
|
||||
/// A wired value input; `get` evaluates the input and yields the typed element.
|
||||
pub struct ValueIn<'a, T> {
|
||||
read: &'a dyn Fn() -> GPoll<T>,
|
||||
}
|
||||
@@ -21,9 +21,9 @@ impl<'a, T> ValueIn<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// An upstream edge's extents. For derived (per-copy) content the query runs
|
||||
/// An upstream input's extents. For derived (per-copy) content the query runs
|
||||
/// at the given copy's promoted context; `at` queries copy 0, the uniform
|
||||
/// default. For ordinary edges the copy is ignored.
|
||||
/// default. For ordinary inputs the copy is ignored.
|
||||
pub struct ExtentIn<'a> {
|
||||
query: &'a dyn Fn(u64, u8) -> GPoll<Extent>,
|
||||
}
|
||||
@@ -62,7 +62,7 @@ impl<'a, T> ListIn<'a, T> {
|
||||
(self.get)()
|
||||
}
|
||||
|
||||
/// The subject wire's total flat extent as a plain query.
|
||||
/// The subject input's total flat extent as a plain query.
|
||||
pub fn total(&self) -> GPoll<crate::gpoll::Extent> {
|
||||
(self.total)()
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ impl Extent {
|
||||
}
|
||||
|
||||
/// The sum of two extents, used to concatenate a level; a free operand
|
||||
/// counts as one lane, so a scalar edge joins a concat as a single item,
|
||||
/// counts as one lane, so a scalar input joins a concat as a single item,
|
||||
/// and a lower-bound operand keeps the sum a lower bound.
|
||||
pub fn sum(a: GPoll<Extent>, b: GPoll<Extent>) -> GPoll<Extent> {
|
||||
let lanes = |extent| match extent {
|
||||
|
||||
@@ -16,7 +16,7 @@ pub enum BatchStatus<'a> {
|
||||
/// mutate the lanes or reclaim the buffer for in-place reuse. The extent
|
||||
/// hint is as for `Lent`.
|
||||
Filled(RecordBatchMut<'a>, Finality, Extent),
|
||||
/// No batch implementation behind this edge; a driver answers with the
|
||||
/// No batch implementation behind this input; a driver answers with the
|
||||
/// per-lane serve and copy-out loop ([`crate::record::fill_frames`]).
|
||||
Unbatched,
|
||||
Pending,
|
||||
@@ -519,9 +519,9 @@ impl StatusCell {
|
||||
Self { no_partial: true, ..Self::new() }
|
||||
}
|
||||
|
||||
/// Claims the edge's own frame out of `frames`, serves through it, and
|
||||
/// Claims the input's own frame out of `frames`, serves through it, and
|
||||
/// folds the poll's status into the cell. The claim is the caller's, so
|
||||
/// the edge's frame is claimed exactly once per evaluation.
|
||||
/// the input's frame is claimed exactly once per evaluation.
|
||||
#[inline(always)]
|
||||
pub fn eval_input<'e, Input, N: Node<Input> + ?Sized>(&self, input_index: usize, node: &N, input: &Input, frames: &crate::record::Frames<'e>) -> Result<crate::record::RecordValue<'e>, Interrupt>
|
||||
where
|
||||
@@ -612,7 +612,7 @@ impl<'a, 'f, N> LazyInput<'a, 'f, N> {
|
||||
self.node.eval_derived(self.cell, self.input_index, ctx, self.frames)
|
||||
}
|
||||
|
||||
/// The edge's composite extent, for kernels that split or shift indices
|
||||
/// The input's composite extent, for kernels that split or shift indices
|
||||
/// over their sources.
|
||||
#[inline(always)]
|
||||
pub fn extent<'e, Input>(&self, ctx: &Input, at: Level) -> GPoll<Extent>
|
||||
|
||||
@@ -44,7 +44,7 @@ impl<U, T: ListConvert<U> + Send> Convert<List<U>, ()> for List<T> {
|
||||
|
||||
/// Wraps each row's element into a type-erased attribute. Lets nodes that accept a source attribute
|
||||
/// from any `List<U>` express their signature as `AttributeDyn` and avoid monomorphizing
|
||||
/// over `U`; the compiler inserts this convert to bridge concrete-typed graph wires to the dyn input.
|
||||
/// over `U`; the compiler inserts this convert to bridge concrete-typed graph sources to the dyn input.
|
||||
impl<T: Clone + Send + Sync + Default + std::fmt::Debug + PartialEq + CacheHash + 'static> Convert<AttributeDyn, ()> for List<T> {
|
||||
fn convert(self, _: Footprint, _: ()) -> AttributeDyn {
|
||||
let values: Vec<T> = self.into_iter().map(|row| row.into_element()).collect();
|
||||
@@ -54,7 +54,7 @@ impl<T: Clone + Send + Sync + Default + std::fmt::Debug + PartialEq + CacheHash
|
||||
|
||||
/// Wraps a value into a type-erased attribute value. Lets nodes that take a per-item value source
|
||||
/// (such as `write_attribute`'s value-producing input) be generic over the destination list type
|
||||
/// alone, with the compiler-inserted convert handling each concrete value type at the wire level.
|
||||
/// alone, with the compiler-inserted convert handling each concrete value type at the input level.
|
||||
impl<T: Clone + Send + Sync + Default + std::fmt::Debug + PartialEq + CacheHash + 'static> Convert<AttributeValueDyn, ()> for T {
|
||||
fn convert(self, _: Footprint, _: ()) -> AttributeValueDyn {
|
||||
AttributeValueDyn(Box::new(self))
|
||||
|
||||
@@ -45,7 +45,7 @@ impl FrameArena {
|
||||
/// node's inputs claim beyond its frame, one after another, and the space they
|
||||
/// used is free again once the claim dies: the release is the claim's
|
||||
/// lifetime, not a rewind contract. The cursor is shared through `&self` so
|
||||
/// the lazy edges a kernel holds claim beyond each other rather than over each
|
||||
/// the lazy inputs a kernel holds claim beyond each other rather than over each
|
||||
/// other. Covariant in `'e`, so a claim minted at the evaluation shortens onto
|
||||
/// a derived context's arena lifetime.
|
||||
pub struct Frames<'e> {
|
||||
|
||||
@@ -7,7 +7,7 @@ use super::serve::{FrameClaim, Served, serve_input};
|
||||
use crate::gpoll::GPoll;
|
||||
use crate::node::Node;
|
||||
|
||||
/// A record edge evaluable at a derived context, yielding the record at that
|
||||
/// A record input evaluable at a derived context, yielding the record at that
|
||||
/// context's lifetime. The lifetime is a trait parameter because a bound like
|
||||
/// `for<'d> Node<Derived<'d, C>>` cannot also say the derived context's arena
|
||||
/// is at `'d`: the equality binding `ExtractArena<ArenaRef = &'d Arena>` is an
|
||||
@@ -31,7 +31,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Fills caller scratch with one frame per lane of `range`: the edge serves
|
||||
/// Fills caller scratch with one frame per lane of `range`: the input serves
|
||||
/// into the lane's own region of the slab, and the lane's own frame space is
|
||||
/// free again at the next lane, so the frame peak stays at one lane's need and
|
||||
/// every lane's bytes are distinct.
|
||||
@@ -78,9 +78,9 @@ where
|
||||
BatchStatus::Filled(run.finish(), finality, hint)
|
||||
}
|
||||
|
||||
/// The driver a consumer runs on a record edge: a resident batch returns with
|
||||
/// The driver a consumer runs on a record input: a resident batch returns with
|
||||
/// no allocation, a node's own batch impl gets `n * frame_bytes` of arena
|
||||
/// scratch, and an unbatched edge falls back to the [`fill_frames`] loop.
|
||||
/// scratch, and an unbatched input falls back to the [`fill_frames`] loop.
|
||||
pub fn materialize_batch<'a, 'e, C, N>(node: &'a N, input: &'a C, range: std::ops::Range<u64>, arena: &'a crate::arena::Arena, frames: &Frames<'e>) -> crate::node::BatchStatus<'a>
|
||||
where
|
||||
C: crate::context::InjectIndex + Copy + crate::context::ExtractArena<ArenaRef = &'e crate::arena::Arena>,
|
||||
@@ -110,14 +110,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// The outcome of materializing a leveled edge's whole flat span.
|
||||
/// The outcome of materializing a leveled input's whole flat span.
|
||||
pub enum LevelStatus<'a> {
|
||||
Batch(crate::node::RecordBatch<'a>, crate::gpoll::Finality),
|
||||
Pending,
|
||||
Error(crate::gpoll::GraphError),
|
||||
}
|
||||
|
||||
/// Evaluates a leveled edge's whole flat span into one batch: an exact total
|
||||
/// Evaluates a leveled input's whole flat span into one batch: an exact total
|
||||
/// fills once, a lower bound drains by guess-and-double until a short fill,
|
||||
/// each reply's hint seeding the next guess. The boundary consumers' driver;
|
||||
/// reducers inline the same protocol with their span offsets.
|
||||
@@ -167,10 +167,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// The raw lazy record edge handed to a record-opaque kernel: the wire plus
|
||||
/// The raw lazy record input handed to a record-opaque kernel: the input plus
|
||||
/// its wiring-proven layout, the pairing the kernel's unsafe record
|
||||
/// operations rely on. The kernel must only pair the layout with values this
|
||||
/// edge produced.
|
||||
/// input produced.
|
||||
pub struct RecordInput<'a, 'e, N> {
|
||||
node: &'a N,
|
||||
layout: &'a Layout,
|
||||
@@ -186,8 +186,8 @@ impl<'a, 'e, N> RecordInput<'a, 'e, N> {
|
||||
self.layout
|
||||
}
|
||||
|
||||
/// Serves the edge through the kernel's own claim: the kernel's output
|
||||
/// layout is the edge's, so the claim it was handed is the edge's frame.
|
||||
/// Serves the input through the kernel's own claim: the kernel's output
|
||||
/// layout is the input's, so the claim it was handed is the input's frame.
|
||||
pub fn serve<'l, C>(&self, ctx: &C, slot: FrameClaim<'e, 'l>) -> GPoll<Served<'e>>
|
||||
where
|
||||
N: Node<C>,
|
||||
@@ -196,7 +196,7 @@ impl<'a, 'e, N> RecordInput<'a, 'e, N> {
|
||||
self.node.serve(ctx, slot)
|
||||
}
|
||||
|
||||
/// [`materialize_level`] over the edge: the wire's whole flat span as one
|
||||
/// [`materialize_level`] over the input: the input's whole flat span as one
|
||||
/// batch.
|
||||
pub fn materialize_level<'b, C>(&'b self, ctx: &'b C, arena: &'b crate::arena::Arena) -> LevelStatus<'b>
|
||||
where
|
||||
@@ -207,7 +207,7 @@ impl<'a, 'e, N> RecordInput<'a, 'e, N> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The raw lazy edge handed to a poll kernel whose wire rides records while
|
||||
/// The raw lazy input handed to a poll kernel whose input rides records while
|
||||
/// the kernel consumes the plain element.
|
||||
/// # Safety
|
||||
/// `rec` must be a record of the layout the offsets were resolved against
|
||||
@@ -243,7 +243,7 @@ impl<'a, 'e, Out, N> ElementInput<'a, 'e, Out, N> {
|
||||
Self { node, layout, reads, read, frames }
|
||||
}
|
||||
|
||||
/// The edge's element at `ctx`, read out of a record claimed beyond the
|
||||
/// The input's element at `ctx`, read out of a record claimed beyond the
|
||||
/// kernel's own frame; the claim dies with the call, so the record is free
|
||||
/// again at the next one.
|
||||
pub fn eval<'d, C>(&self, ctx: &C) -> GPoll<Out>
|
||||
@@ -254,14 +254,14 @@ impl<'a, 'e, Out, N> ElementInput<'a, 'e, Out, N> {
|
||||
let cell = crate::node::StatusCell::new();
|
||||
let scope = self.frames.scope();
|
||||
match self.node.eval_derived(&cell, 0, ctx, &scope) {
|
||||
// SAFETY: the read copies out by value against the edge's own layout.
|
||||
// SAFETY: the read copies out by value against the input's own layout.
|
||||
Ok(value) => cell.finish(unsafe { (self.read)(self.layout.rec(&value), self.reads) }),
|
||||
Err(interrupt) => interrupt.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The lazy input handed to a kernel whose edge rides a record wire while
|
||||
/// The lazy input handed to a kernel whose input rides a record while
|
||||
/// the kernel consumes the plain element, or the element beside its declared
|
||||
/// attribute reads.
|
||||
#[derive(Clone, Copy)]
|
||||
@@ -321,12 +321,12 @@ impl<'a, 'e, Out, N> ElementLazyInput<'a, 'e, Out, N> {
|
||||
{
|
||||
let scope = self.frames.scope();
|
||||
let value = self.node.eval_derived(self.cell, self.input_index, ctx, &scope)?;
|
||||
// SAFETY: the reads are the edge's own layout's, resolved at wiring.
|
||||
// SAFETY: the reads are the input's own layout's, resolved at wiring.
|
||||
Ok(unsafe { (self.read)(self.layout.rec(&value), self.reads) })
|
||||
}
|
||||
}
|
||||
|
||||
/// The lazy record input handed to a kernel that evaluates its edges under
|
||||
/// The lazy record input handed to a kernel that evaluates its inputs under
|
||||
/// derived contexts: evaluating rebinds the record to the kernel's routing
|
||||
/// lifetime, so the value escapes the derivation scope.
|
||||
#[derive(Clone, Copy)]
|
||||
@@ -357,7 +357,7 @@ impl<'a, 'e, N> RecordLazyInput<'a, 'e, N> {
|
||||
Ok(self.node.eval_derived(self.cell, self.input_index, ctx, self.frames)?.rebind())
|
||||
}
|
||||
|
||||
/// The flat lane count of one copy: the product of the edge's inner-level
|
||||
/// The flat lane count of one copy: the product of the input's inner-level
|
||||
/// extents, queried uniform across copies (at copy 0). The dividend of a
|
||||
/// structure node's decompose-and-promote.
|
||||
pub fn inner_extent<B>(&self, ctx: &B) -> Result<u64, crate::gpoll::Interrupt>
|
||||
@@ -368,7 +368,7 @@ impl<'a, 'e, N> RecordLazyInput<'a, 'e, N> {
|
||||
inner_extent_of(self.node, ctx, 0, self.inner_levels, self.input_index, self.frames)
|
||||
}
|
||||
|
||||
/// The flat lane count of the copy at `copy`, for edges whose inner
|
||||
/// The flat lane count of the copy at `copy`, for inputs whose inner
|
||||
/// extents vary per copy.
|
||||
pub fn inner_extent_at<B>(&self, ctx: &B, copy: u64) -> Result<u64, crate::gpoll::Interrupt>
|
||||
where
|
||||
@@ -399,7 +399,7 @@ where
|
||||
Ok(inner)
|
||||
}
|
||||
|
||||
/// The flat lane count of one copy of a lower-bound edge, probed by
|
||||
/// The flat lane count of one copy of a lower-bound input, probed by
|
||||
/// evaluating lanes to the past-end signal. The probed records are
|
||||
/// discarded, and their statuses land in a scratch cell.
|
||||
fn probed_inner<B, N>(node: &N, ctx: &B, copy: u64, input_index: usize, frames: &Frames<'_>) -> Result<u64, crate::gpoll::Interrupt>
|
||||
@@ -483,9 +483,9 @@ impl<'a, 'e, Out, N> DerivedLazyInput<'a, 'e, Out, N> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A plain probe over a record wire, cloning the element out of the parked
|
||||
/// A plain probe over a record input, cloning the element out of the parked
|
||||
/// reference when it carries drop glue. Registry constructors wrap a record
|
||||
/// edge in one to feed a node's plain value input, keeping the wire kind
|
||||
/// input in one to feed a node's plain value input, keeping the input kind
|
||||
/// uniform.
|
||||
pub struct RecordExtract<El, N> {
|
||||
edge: N,
|
||||
@@ -504,13 +504,13 @@ impl<El, N> RecordExtract<El, N> {
|
||||
}
|
||||
|
||||
impl<El: Clone + 'static, N> RecordExtract<El, N> {
|
||||
/// The edge's element, copied out of its record.
|
||||
/// The input's element, copied out of its record.
|
||||
pub fn eval<'e, C>(&self, input: &C, frames: &Frames<'e>) -> GPoll<El>
|
||||
where
|
||||
N: Node<C>,
|
||||
C: crate::context::ExtractArena<ArenaRef = &'e crate::arena::Arena>,
|
||||
{
|
||||
// The element copies out by value, so the edge's claim dies with
|
||||
// The element copies out by value, so the input's claim dies with
|
||||
// the scope.
|
||||
let scope = frames.scope();
|
||||
serve_input(&self.edge, input, &scope).map(|value| unsafe { read_element::<El>(self.layout.rec(&value)) })
|
||||
|
||||
@@ -347,7 +347,7 @@ pub struct RecordLayout {
|
||||
pub lane_invariant: u32,
|
||||
}
|
||||
|
||||
/// its registry entry so the compiler can fold each wire's layout without
|
||||
/// its registry entry so the compiler can fold each input's layout without
|
||||
/// running the node's constructor. [`fold`](LayoutMeta::fold) reproduces the
|
||||
/// layout the constructor derives at wiring today; the compiler layout pass
|
||||
/// calls it over the proto graph instead.
|
||||
@@ -371,7 +371,7 @@ pub struct LayoutMeta {
|
||||
/// `+1` for a creator, `-1` for a reducer.
|
||||
pub level_delta: i8,
|
||||
/// The materialized subject a reducer folds, as `(input, levels)`. The fold
|
||||
/// consumes the whole subject wire, so only the node's own levels remain.
|
||||
/// consumes the whole subject input, so only the node's own levels remain.
|
||||
pub folded: Option<(u8, u8)>,
|
||||
}
|
||||
|
||||
@@ -419,7 +419,7 @@ impl LayoutMeta {
|
||||
}
|
||||
.without(&self.removes);
|
||||
let depth = match self.folded {
|
||||
// A fold consumes the whole subject wire (a deeper wire folds its
|
||||
// A fold consumes the whole subject input (a deeper input folds its
|
||||
// total flat span), so only the node's own levels remain.
|
||||
Some(_) => self.level_delta.max(0) as u8,
|
||||
None => (base.depth as i8 + self.level_delta).max(0) as u8,
|
||||
@@ -484,7 +484,7 @@ pub const fn element_parked<T>() -> bool {
|
||||
std::mem::needs_drop::<T>()
|
||||
}
|
||||
|
||||
/// The element (size, align) a record wire of `T` carries.
|
||||
/// The element (size, align) a record input of `T` carries.
|
||||
pub fn element_dims<T>() -> (usize, usize) {
|
||||
match element_parked::<T>() {
|
||||
true => (size_of::<*const u8>(), align_of::<*const u8>()),
|
||||
@@ -492,7 +492,7 @@ pub fn element_dims<T>() -> (usize, usize) {
|
||||
}
|
||||
}
|
||||
|
||||
/// The element slot a record wire of `T` carries, its erased glue bound at
|
||||
/// The element slot a record input of `T` carries, its erased glue bound at
|
||||
/// the statically-known type.
|
||||
pub fn element_write<T: Clone + Send + Sync + dyn_any::StaticTypeSized>() -> ElementWrite
|
||||
where
|
||||
|
||||
@@ -61,7 +61,7 @@ impl SourcePlan {
|
||||
}
|
||||
}
|
||||
|
||||
/// A routing input's claimed edge plus its wiring-resolved [`SourcePlan`].
|
||||
/// A routing input's claimed source plus its wiring-resolved [`SourcePlan`].
|
||||
/// Evaluating it yields the source's record translated to the union layout
|
||||
/// (or forwarded untouched when the layouts already agree), so the kernel
|
||||
/// holds and returns record values without ever seeing the representation.
|
||||
@@ -99,7 +99,7 @@ where
|
||||
};
|
||||
match serve_input(&self.edge, input, &mut slot.frames().reborrow()) {
|
||||
GPoll::Final(value) => {
|
||||
// SAFETY: the value came from this edge, so it carries the
|
||||
// SAFETY: the value came from this source, so it carries the
|
||||
// plan's source layout.
|
||||
unsafe { slot.translate(plan.source.rec(&value), plan) };
|
||||
// SAFETY: the translation completes the union record.
|
||||
|
||||
@@ -179,7 +179,7 @@ impl<'e, 'l> FrameClaim<'e, 'l> {
|
||||
Served { value: unsafe { self.finish() } }
|
||||
}
|
||||
|
||||
/// Fills the frame from a record a forwarded wire already served, and
|
||||
/// Fills the frame from a record a forwarded input already served, and
|
||||
/// closes it: the source's frame sits above this claim and dies with its
|
||||
/// drop, so the served record is this claim's own.
|
||||
///
|
||||
|
||||
@@ -90,8 +90,8 @@ where
|
||||
}
|
||||
|
||||
/// Law-test scaffolding: a kernel closure served onto an element-only record
|
||||
/// wire (the element lands at offset 0, parked when it carries drop glue). No
|
||||
/// production path constructs one; value edges are
|
||||
/// input (the element lands at offset 0, parked when it carries drop glue). No
|
||||
/// production path constructs one; value sources are
|
||||
/// [`crate::value::ValueSource`].
|
||||
pub struct LiftedSource<El, F> {
|
||||
kernel: F,
|
||||
|
||||
@@ -72,7 +72,7 @@ pub static NODE_METADATA: LazyLock<Mutex<HashMap<ProtoNodeIdentifier, NodeMetada
|
||||
|
||||
pub use crate::NodeIOTypes;
|
||||
|
||||
/// Element-independent by erasure; the wire's `Type::Record(El)` keeps element reads proven at wiring.
|
||||
/// Element-independent by erasure; the input's `Type::Record(El)` keeps element reads proven at wiring.
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
pub type ErasedRecordNode = dyn for<'c> Node<ContextImpl<'c>> + Send + Sync;
|
||||
#[cfg(target_family = "wasm")]
|
||||
@@ -133,7 +133,7 @@ impl<N: ?Sized> SharedSource<N> {
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: `ptr` is derived from the owned Arc and never mutated through, so the edge is exactly as
|
||||
// SAFETY: `ptr` is derived from the owned Arc and never mutated through, so the source is exactly as
|
||||
// thread safe as the payload it shares.
|
||||
unsafe impl<N: ?Sized + Send + Sync> Send for SharedSource<N> {}
|
||||
// SAFETY: as in Send.
|
||||
|
||||
@@ -232,7 +232,7 @@ pub enum Type {
|
||||
Fn(Box<Type>, Box<Type>),
|
||||
/// Represents a future which promises to return the inner type.
|
||||
Future(Box<Type>),
|
||||
/// A packed record wire over the element type; the layout stays node-resident metadata.
|
||||
/// A packed record input over the element type; the layout stays node-resident metadata.
|
||||
Record(Box<Type>),
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/// The node behind every value edge: clones its constant onto the record
|
||||
/// wire per evaluation.
|
||||
/// The node behind every value source: clones its constant onto the record
|
||||
/// input per evaluation.
|
||||
pub struct ValueSource<T> {
|
||||
value: T,
|
||||
layout: crate::record::Layout,
|
||||
@@ -41,7 +41,7 @@ where
|
||||
crate::registry::EdgeHandle::new_record::<T>(std::sync::Arc::new(ValueSource::new(value)) as std::sync::Arc<crate::registry::ErasedRecordNode>)
|
||||
}
|
||||
|
||||
/// The node behind a leveled value edge: a constant list served as one level,
|
||||
/// The node behind a leveled value source: a constant list served as one level,
|
||||
/// one lane per item, with the list's length as the exact extent.
|
||||
pub struct LeveledValueSource<T> {
|
||||
values: Vec<T>,
|
||||
|
||||
@@ -431,8 +431,8 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
register_metadata();
|
||||
}
|
||||
};
|
||||
// Record nodes construct through the generated `wire` fn, which resolves
|
||||
// offsets from the carrier layout; `new` cannot fill that state.
|
||||
// Record nodes construct through `new` with the carrier layout, which
|
||||
// resolves the offsets their reads and writes address.
|
||||
let routing_layout_param = (routing_generic.is_some() || opaque).then(|| quote!(__layout: &gcore::record::Layout,)).into_iter();
|
||||
let routing_layout_init = (routing_generic.is_some() || opaque).then(|| quote!(__layout: __layout.clone(),)).into_iter();
|
||||
// The lane-invariance mask arrives with the resolved layout, so `new` starts
|
||||
@@ -878,7 +878,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
})
|
||||
});
|
||||
let derive_routing = derives && routing_generic.is_some();
|
||||
// A kernel that holds records (a forwarded routing wire, or a lazy edge it
|
||||
// A kernel that holds records (a forwarded routing source, or a lazy input it
|
||||
// serves itself) names the record lifetime; unless it declared a serving
|
||||
// lifetime of its own, the context binds the arena at that lifetime.
|
||||
let kernel_lazy = parsed.fields.iter().any(|field| !field.is_data_field && matches!(field.ty, ParsedFieldType::Node(_)));
|
||||
@@ -935,7 +935,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
})
|
||||
.map(|param| match param {
|
||||
// Flipped kernels clone bare-typed elements out of their records,
|
||||
// so those generics carry the bound wire values satisfy; a
|
||||
// so those generics carry the bound input values satisfy; a
|
||||
// generic only nested in a field's type stays as declared.
|
||||
GenericParam::Type(type_param)
|
||||
if flip
|
||||
@@ -1044,7 +1044,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
}
|
||||
}
|
||||
}
|
||||
// The record lifetime the kernel's wire types and arena bound name; the
|
||||
// The record lifetime the kernel's input types and arena bound name; the
|
||||
// impl infers it from the serving lifetime at every call.
|
||||
if wants_record_lifetime {
|
||||
generics.insert(0, quote!('__record));
|
||||
@@ -1156,7 +1156,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
|
||||
let node_bounds = regular_fields.iter().enumerate().zip(&node_generics).map(|((index, field), node_generic)| {
|
||||
let plain = quote!(#node_generic: #core_types::node::Node<#ctx_ident>);
|
||||
// A lazy edge the kernel evaluates at derived contexts needs the
|
||||
// A lazy input the kernel evaluates at derived contexts needs the
|
||||
// derived form: the derived context's arena binding is unnameable
|
||||
// under a higher rank.
|
||||
let derived = quote!(#node_generic: #derived_edge);
|
||||
@@ -1173,7 +1173,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
true => derived,
|
||||
false => plain,
|
||||
},
|
||||
// An element-consuming lazy secondary rides a record edge, derivable
|
||||
// An element-consuming lazy secondary rides a record input, derivable
|
||||
// when the kernel evaluates it at derived contexts.
|
||||
ParsedFieldType::Node(_) if record_io && matches!(ir::lazy_binding(&node, index), LazyBinding::Element) => match derives {
|
||||
true => derived_plus,
|
||||
@@ -1188,8 +1188,8 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
let bound = lazy_bound();
|
||||
quote!(#node_generic: #bound)
|
||||
}
|
||||
// Every wire is a record edge; a value input's element copies out of
|
||||
// the record its edge serves.
|
||||
// Every input is a record input; a value input's element copies out of
|
||||
// the record its source serves.
|
||||
ParsedFieldType::Regular(_) => plain,
|
||||
}
|
||||
});
|
||||
@@ -1202,7 +1202,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
lend_outlives.push(quote!(#inner: #lifetime));
|
||||
}
|
||||
|
||||
// The slot persists the plain value even on record wires, so the Clone
|
||||
// The slot persists the plain value even on record inputs, so the Clone
|
||||
// bound targets the slot type, not the (possibly lifted) trait output.
|
||||
let slot_ty = crate::codegen::classify::slot_static_type(&parsed.output_type);
|
||||
let mut async_bounds = match (async_fn, future_kernel) {
|
||||
@@ -1263,8 +1263,8 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
#[allow(unused_mut, unused_variables)]
|
||||
let mut __frame = __run.slot(__lane, &__lane_frames);
|
||||
};
|
||||
// A lazy edge claims beyond every input frame this node holds, and its
|
||||
// cursor is shared, so the edges a kernel drives claim past each other.
|
||||
// A lazy input claims beyond every input frame this node holds, and its
|
||||
// cursor is shared, so the inputs a kernel drives claim past each other.
|
||||
let lazy_frames_entry = quote! {
|
||||
let __lazy_frames = __frame.frames().reborrow();
|
||||
};
|
||||
@@ -1296,7 +1296,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
let non_exact = fail(quote!(#core_types::gpoll::GraphError::new(::std::concat!("reduce over a non-exact extent in ", ::std::stringify!(#fn_name)))));
|
||||
let batch_error = fail(quote!(__error));
|
||||
let batch_failed = fail(quote!(#core_types::gpoll::GraphError::new("reduce batch failed")));
|
||||
// A fold consumes the whole subject wire: a deeper wire's
|
||||
// A fold consumes the whole subject input: a deeper input's
|
||||
// total flat span, sized under the evaluation context, so a
|
||||
// fold inside a pushed level covers that copy's span. The
|
||||
// span caches per (lane-normalized context, generation):
|
||||
@@ -1369,7 +1369,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
let #name = unsafe { #core_types::node::List::<#ty>::new(__batch) };
|
||||
}
|
||||
}
|
||||
// A reading secondary input claims a record edge: the element and
|
||||
// A reading secondary input claims a record input: the element and
|
||||
// the declared reads copy out right after its eval.
|
||||
ValueBinding::ReadingSecondary => {
|
||||
let slot = format_ident!("__in_{index}");
|
||||
@@ -1398,7 +1398,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
let #name = unsafe { #core_types::record::borrow_element::<#ty>(self.#slot.rec(&#record_local)) };
|
||||
}
|
||||
}
|
||||
// A flip value or a routing non-source value rides a record edge; the
|
||||
// A flip value or a routing non-source value rides a record input; the
|
||||
// element copies out into `name`. The mark/rewind that reclaims the
|
||||
// record's frame is applied by the step lowering (see `reads_out`).
|
||||
ValueBinding::RecordElement => {
|
||||
@@ -1411,8 +1411,8 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
let #name: #ty = unsafe { #core_types::record::read_element(self.#slot.rec(&#name)) };
|
||||
}
|
||||
}
|
||||
// A plain value rides a record edge like every other input; the
|
||||
// element copies out against the edge's own layout, except for a
|
||||
// A plain value rides a record input like every other input; the
|
||||
// element copies out against the input's own layout, except for a
|
||||
// routing source, whose record is what the kernel forwards.
|
||||
ValueBinding::Plain => {
|
||||
let read = (!routing_source(ty)).then(|| {
|
||||
@@ -1432,7 +1432,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
}
|
||||
},
|
||||
ParsedFieldType::Node(NodeParsedField { output_type, .. }) => match (ir::lazy_binding(&node, index), raw_lazy) {
|
||||
// A raw poll edge is threaded straight through, so it does not bind here.
|
||||
// A raw poll input is threaded straight through, so it does not bind here.
|
||||
(LazyBinding::Generic, true) => quote!(),
|
||||
(LazyBinding::DeriveRouting, _) => quote! {
|
||||
let #name = #core_types::record::RecordLazyInput::new(&self.#name, &__cell, #index, self.__layout.depth.saturating_sub(#pushed_levels), &__lazy_frames);
|
||||
@@ -1493,7 +1493,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
}
|
||||
};
|
||||
|
||||
// A bind whose element copies out reclaims the edge's frame; a forwarded
|
||||
// A bind whose element copies out reclaims the input's frame; a forwarded
|
||||
// record must outlive the bind, so its frame stays.
|
||||
let _reads_out_at = |index: usize| match ®ular_fields[index].ty {
|
||||
ParsedFieldType::Regular(RegularParsedField { ty, .. }) => !routing_source(ty) && ir::value_binding(&node, index).reads_out(),
|
||||
@@ -1518,7 +1518,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
let call_args = regular_fields.iter().enumerate().filter(|(_, field)| !injected_name(&field.pat_ident.ident)).map(|(index, field)| {
|
||||
let name = &field.pat_ident.ident;
|
||||
match &field.ty {
|
||||
// A lend param binds an owned edge; the kernel borrows the
|
||||
// A lend param binds an owned input; the kernel borrows the
|
||||
// evaluated value.
|
||||
ParsedFieldType::Regular(RegularParsedField { lend: Some(_), .. }) if !flip => quote!(&#name),
|
||||
ParsedFieldType::Regular(_) => quote!(#name),
|
||||
@@ -1534,7 +1534,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
// composite `extent(ctx, Level)`, which the trait derives from it. A node
|
||||
// without `extent = fn` keeps the scalar default (one item at every level).
|
||||
// The typed extent surface: the node's inputs in declaration order (values
|
||||
// readable without unsafe, edges as per-level extent queries, derived
|
||||
// readable without unsafe, inputs as per-level extent queries, derived
|
||||
// content promoted per copy), then the level paired with the node's depth.
|
||||
let extent_impl = if let Some(path) = &parsed.attributes.extent {
|
||||
let mut arg_decls: Vec<TokenStream2> = Vec::new();
|
||||
@@ -1565,7 +1565,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
_ => extent_edge(&query, &arg),
|
||||
},
|
||||
ParsedFieldType::Regular(RegularParsedField { ty, .. }) => match ir::value_binding(&node, index) {
|
||||
// A ranked input materializes whole (the wire's total flat
|
||||
// A ranked input materializes whole (the input's total flat
|
||||
// span, as in eval), so a data-dependent extent can walk
|
||||
// its lanes.
|
||||
ValueBinding::Materialized => {
|
||||
@@ -1603,7 +1603,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
};
|
||||
quote! {
|
||||
let #query = || {
|
||||
// The element copies out by value, so the edge's
|
||||
// The element copies out by value, so the input's
|
||||
// claim dies with the query.
|
||||
let __scope = __frames.scope();
|
||||
#core_types::record::serve_input(&self.#name, __input, &__scope)
|
||||
@@ -1613,7 +1613,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
}
|
||||
}
|
||||
// A carrier, lent, or materialized ranked input is a record
|
||||
// edge; its extents are the queryable quantity.
|
||||
// input; its extents are the queryable quantity.
|
||||
_ => extent_edge(&query, &arg),
|
||||
},
|
||||
};
|
||||
@@ -1853,7 +1853,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
})
|
||||
});
|
||||
// Async slots persist plain values across evaluations; the source lifts
|
||||
// the slot value onto its record wire at every merge point, into the
|
||||
// the slot value onto its record input at every merge point, into the
|
||||
// carried frame when the node has a carrier.
|
||||
// A writing source stores the kernel's whole tuple as that plain value:
|
||||
// the lift writes the attributes through the claim, then lifts the
|
||||
@@ -1961,7 +1961,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
let value_args = regular_fields.iter().skip(if skips_carrier { 0 } else { 1 }).map(|field| {
|
||||
let name = &field.pat_ident.ident;
|
||||
match &field.ty {
|
||||
// A lend param binds an owned edge; the kernel borrows the
|
||||
// A lend param binds an owned input; the kernel borrows the
|
||||
// evaluated value.
|
||||
ParsedFieldType::Regular(RegularParsedField { lend: Some(_), .. }) => quote!(&#name),
|
||||
_ => tuple_arg(field, quote!(#name)),
|
||||
@@ -2230,7 +2230,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
&lazy_frames_entry,
|
||||
);
|
||||
// The rebind path with nothing hoisted: every non-carrier input binds
|
||||
// fresh per lane, so an index-dependent edge reaches its own lane.
|
||||
// fresh per lane, so an index-dependent input reaches its own lane.
|
||||
let rebound_lane_binds: Vec<TokenStream2> = lazy_last(
|
||||
regular_fields
|
||||
.iter()
|
||||
|
||||
@@ -131,7 +131,7 @@ pub(crate) fn lazy_read_fields<'a>(regular_fields: &[&'a ParsedField]) -> Vec<(u
|
||||
}
|
||||
|
||||
/// The indices (into the unit-skipped regular fields) of value inputs whose
|
||||
/// reads resolve against their own wire rather than the carrier's.
|
||||
/// reads resolve against their own input rather than the carrier's.
|
||||
pub(crate) fn reading_secondary_indices(regular_fields: &[&ParsedField], skips_carrier: bool) -> Vec<usize> {
|
||||
regular_fields
|
||||
.iter()
|
||||
@@ -177,7 +177,7 @@ pub(crate) fn substitute_ident_types(ty: &Type, assignments: &[(Ident, Type)]) -
|
||||
}
|
||||
|
||||
/// Replaces the routing generic in a derive-routing kernel's return type with
|
||||
/// the routing record value, since the kernel's edges rebind to '__record.
|
||||
/// the routing record value, since the kernel's inputs rebind to '__record.
|
||||
pub(crate) fn substitute_routing_record(output: &Type, generic: &Ident, core_types: &TokenStream2) -> Type {
|
||||
struct Subst<'a> {
|
||||
generic: &'a Ident,
|
||||
@@ -295,7 +295,7 @@ pub(crate) fn record_shape(parsed: &ParsedNodeFn) -> Option<RecordShape> {
|
||||
return None;
|
||||
}
|
||||
// An async source's slot stores the kernel's plain tuple; the per-eval lift
|
||||
// writes it through the claim, and the reads have no wire to bind against.
|
||||
// writes it through the claim, and the reads have no input to bind against.
|
||||
if source && (has_reads || writes.is_none()) {
|
||||
return None;
|
||||
}
|
||||
@@ -306,7 +306,7 @@ pub(crate) fn record_shape(parsed: &ParsedNodeFn) -> Option<RecordShape> {
|
||||
// A first-field lazy carrier: the kernel evaluates the derived content
|
||||
// itself and returns its opaque row token beside the write set.
|
||||
let lazy_carrier = matches!(&carrier_field.ty, ParsedFieldType::Node(_));
|
||||
// Lazy secondaries are consumed as plain elements; raw record edges and
|
||||
// Lazy secondaries are consumed as plain elements; raw record inputs and
|
||||
// ranked outputs have no element binding here.
|
||||
let unsupported_lazy_secondary = |field: &ParsedField| match &field.ty {
|
||||
ParsedFieldType::Node(NodeParsedField { output_type, .. }) => is_served(output_type) || crate::codegen::ir::strip_ilist(output_type).1 > 0 || !field.attribute_reads.is_empty(),
|
||||
@@ -423,7 +423,7 @@ pub(crate) fn flip_carrier(parsed: &ParsedNodeFn) -> bool {
|
||||
!(async_kernel && lend.is_some())
|
||||
}
|
||||
|
||||
/// Whether a plain node's lowering flips onto record wires: sync,
|
||||
/// Whether a plain node's lowering flips onto record inputs: sync,
|
||||
/// fully-concrete value-input nodes in this cut; batch, shader, async, lend,
|
||||
/// lazy, and generic nodes keep the plain lowering until their record forms
|
||||
/// land.
|
||||
@@ -467,7 +467,7 @@ pub(crate) fn record_flip(parsed: &ParsedNodeFn) -> bool {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// A named lifetime is the serving lifetime: wire types substitute
|
||||
// A named lifetime is the serving lifetime: input types substitute
|
||||
// its erased projection in registry and layout contexts.
|
||||
GenericParam::Lifetime(_) => {}
|
||||
GenericParam::Const(_) => return false,
|
||||
@@ -520,7 +520,7 @@ pub(crate) fn is_served(ty: &Type) -> bool {
|
||||
}
|
||||
|
||||
/// Whether a kernel operates on whole records: it serves through the claim it
|
||||
/// was handed, receives raw record edges paired with the node's layout, and
|
||||
/// was handed, receives raw record inputs paired with the node's layout, and
|
||||
/// takes on the record APIs' unsafe contracts itself.
|
||||
pub(crate) fn record_opaque(parsed: &ParsedNodeFn) -> bool {
|
||||
is_served(&slot_value_type(&parsed.output_type))
|
||||
@@ -723,7 +723,7 @@ pub(crate) fn type_disqualifies(ty: &Type) -> bool {
|
||||
visitor.found
|
||||
}
|
||||
|
||||
/// The wire type with every named serving lifetime replaced: `'static` for
|
||||
/// The input type with every named serving lifetime replaced: `'static` for
|
||||
/// registry, layout, and declaration contexts (the erased projection shares
|
||||
/// its type id and layout), `'_` for eval bindings, where inference recovers
|
||||
/// the serving lifetime.
|
||||
@@ -749,7 +749,7 @@ pub(crate) fn substitute_lifetimes(ty: &Type, replacement: &str) -> Type {
|
||||
ty
|
||||
}
|
||||
|
||||
/// The serving lifetime a wire type names, so a materialized binding can tie
|
||||
/// The serving lifetime an input type names, so a materialized binding can tie
|
||||
/// the list view to the element's own region.
|
||||
pub(crate) fn named_serving_lifetime(ty: &Type) -> Option<Lifetime> {
|
||||
struct Find {
|
||||
|
||||
@@ -15,7 +15,7 @@ pub(crate) fn entries_tokens(parsed: &ParsedNodeFn, struct_name: &Ident, data_fi
|
||||
}
|
||||
}
|
||||
|
||||
/// The registry rows of a flipped plain node: every wire is a record wire,
|
||||
/// The registry rows of a flipped plain node: every input is a record input,
|
||||
/// inputs resolve their layouts off the claimed handles, and the output is an
|
||||
/// element-only record of the kernel's return type.
|
||||
fn flip_entries_tokens(parsed: &ParsedNodeFn, struct_name: &Ident, regular_fields: &[&ParsedField]) -> TokenStream2 {
|
||||
@@ -179,20 +179,20 @@ fn flip_entries_tokens(parsed: &ParsedNodeFn, struct_name: &Ident, regular_field
|
||||
}
|
||||
}
|
||||
|
||||
/// Which record wire an input claims and how its value is recovered. Base slots
|
||||
/// are the record edges whose layouts form the output; value slots are record
|
||||
/// edges read for their layout.
|
||||
/// Which record an input claims and how its value is recovered. Base slots
|
||||
/// are the record inputs whose layouts form the output; value slots are record
|
||||
/// inputs read for their layout.
|
||||
enum SlotKind {
|
||||
/// A generic record edge whose element is only known at runtime; the runtime
|
||||
/// A generic record input whose element is only known at runtime; the runtime
|
||||
/// type is captured for the output wrap or the union.
|
||||
BaseGeneric(String),
|
||||
/// A concrete record carrier read for its layout.
|
||||
BaseConcrete(Type),
|
||||
/// A concrete record edge read for its layout only.
|
||||
/// A concrete record input read for its layout only.
|
||||
Value(Type),
|
||||
/// A record edge whose element extracts to the node's plain value input.
|
||||
/// A record input whose element extracts to the node's plain value input.
|
||||
Extracted(Type),
|
||||
/// A ranked record edge consumed whole; no layout rides to the constructor.
|
||||
/// A ranked record input consumed whole; no layout rides to the constructor.
|
||||
Ranked(Type),
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ impl SlotKind {
|
||||
}
|
||||
|
||||
/// The single registry row shared by record-io, routing, and opaque nodes: one
|
||||
/// instance covers the wire, each input's edge type and downcast follow its
|
||||
/// instance covers the input, each input's type and downcast follow its
|
||||
/// slot, and the output layout folds from the base slots.
|
||||
fn single_row_entries(parsed: &ParsedNodeFn, struct_name: &Ident, regular_fields: &[&ParsedField]) -> TokenStream2 {
|
||||
use crate::codegen::ir;
|
||||
@@ -212,8 +212,8 @@ fn single_row_entries(parsed: &ParsedNodeFn, struct_name: &Ident, regular_fields
|
||||
let core_types = quote!(gcore);
|
||||
let lend = |field: &ParsedField| matches!(&field.ty, ParsedFieldType::Regular(RegularParsedField { lend: Some(_), .. }));
|
||||
|
||||
// A subject is its record edge (concrete carrier or erased generic); a
|
||||
// non-subject value rides a record edge when it reads its layout.
|
||||
// A subject is its record input (concrete carrier or erased generic); a
|
||||
// non-subject value rides a record input when it reads its layout.
|
||||
let slots: Option<Vec<SlotKind>> = regular_fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
@@ -228,7 +228,7 @@ fn single_row_entries(parsed: &ParsedNodeFn, struct_name: &Ident, regular_fields
|
||||
}
|
||||
match &field.ty {
|
||||
// An element-consuming lazy secondary of a record node rides a
|
||||
// record edge with a layout slot, like a reading secondary.
|
||||
// record input with a layout slot, like a reading secondary.
|
||||
ParsedFieldType::Node(NodeParsedField { output_type, .. })
|
||||
if matches!(ir::node_kind(&node), ir::NodeKind::RecordIo) && matches!(ir::lazy_binding(&node, index), ir::LazyBinding::Element) =>
|
||||
{
|
||||
@@ -241,8 +241,8 @@ fn single_row_entries(parsed: &ParsedNodeFn, struct_name: &Ident, regular_fields
|
||||
ParsedFieldType::Regular(RegularParsedField { ty, .. }) => match ir::value_binding(&node, index) {
|
||||
ir::ValueBinding::Materialized => Some(SlotKind::Ranked(ty.clone())),
|
||||
ir::ValueBinding::ReadingSecondary | ir::ValueBinding::RecordElement => Some(SlotKind::Value(ty.clone())),
|
||||
// One wire kind: a record node's plain value still rides a
|
||||
// record edge, extracted to its element at construction.
|
||||
// One input kind: a record node's plain value still rides a
|
||||
// record input, extracted to its element at construction.
|
||||
_ if matches!(ir::node_kind(&node), ir::NodeKind::RecordIo) => Some(SlotKind::Extracted(ty.clone())),
|
||||
_ => {
|
||||
emit_error!(field.pat_ident.span(), "plain (non-record) io is unsupported: this value input needs a record edge");
|
||||
@@ -359,7 +359,7 @@ fn single_row_entries(parsed: &ParsedNodeFn, struct_name: &Ident, regular_fields
|
||||
let #layout = #handle.layout().clone();
|
||||
let #name = #handle.downcast_record::<#value_ty>()?;
|
||||
},
|
||||
// The node reads the element off the edge's own layout, so
|
||||
// The node reads the element off the input's own layout, so
|
||||
// neither slot rides a layout to the constructor.
|
||||
SlotKind::Extracted(value_ty) | SlotKind::Ranked(value_ty) => quote! {
|
||||
let #name = inputs.next().unwrap().downcast_record::<#value_ty>()?;
|
||||
@@ -382,7 +382,7 @@ fn single_row_entries(parsed: &ParsedNodeFn, struct_name: &Ident, regular_fields
|
||||
quote!(Some(#meta))
|
||||
};
|
||||
|
||||
// The output wire and node wrap follow the output element: a concrete (or
|
||||
// The output type and node wrap follow the output element: a concrete (or
|
||||
// row-assigned) element is a typed record; a generic or opaque element is
|
||||
// an erased record carrying the first base slot's runtime type.
|
||||
let output_element = match &node.output.shape.element {
|
||||
|
||||
@@ -388,13 +388,13 @@ pub(crate) enum LazyBinding {
|
||||
}
|
||||
|
||||
impl ValueBinding {
|
||||
/// Copies an element out of a record edge, so the frame is reclaimed after.
|
||||
/// Copies an element out of a record input, so the frame is reclaimed after.
|
||||
pub(crate) fn reads_out(&self) -> bool {
|
||||
matches!(self, ValueBinding::ReadingSecondary | ValueBinding::RecordElement | ValueBinding::Plain)
|
||||
}
|
||||
}
|
||||
|
||||
/// A record node's lazy inputs consumed as plain elements: their record edges
|
||||
/// A record node's lazy inputs consumed as plain elements: their record inputs
|
||||
/// need a layout slot at wiring, like the reading secondaries.
|
||||
pub(crate) fn element_lazy_indices(regular_fields: &[&ParsedField], node: &Node) -> Vec<usize> {
|
||||
if !matches!(node_kind(node), NodeKind::RecordIo) {
|
||||
@@ -454,7 +454,7 @@ fn has_attr_io(node: &Node) -> bool {
|
||||
pub(crate) fn materialized_levels(node: &Node, index: usize) -> u8 {
|
||||
let input = &node.inputs[index];
|
||||
// An eager input's declared `IList` nesting IS its materialization count,
|
||||
// independent of the rank delta; lazy edges never materialize.
|
||||
// independent of the rank delta; lazy inputs never materialize.
|
||||
match input.evaluation {
|
||||
Evaluation::Eager => input.shape.depth,
|
||||
Evaluation::Lazy => 0,
|
||||
|
||||
@@ -44,7 +44,7 @@ pub(crate) struct ParsedNodeFn {
|
||||
}
|
||||
|
||||
/// An `Attr<Marker>` slot in a parameter's read tuple: a declared attribute
|
||||
/// read on that input's wire, not a wired input of its own.
|
||||
/// read on that input, not a wired input of its own.
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct AttributeRead {
|
||||
pub(crate) pat_ident: PatIdent,
|
||||
@@ -152,7 +152,7 @@ pub(crate) struct NodeFnAttributes {
|
||||
pub(crate) batch: Option<Path>,
|
||||
/// Whether partial upstream values are mapped to `Pending` instead of flowing into this node
|
||||
pub(crate) no_partial: bool,
|
||||
/// Whether this node keeps the plain-wire lowering during the record transition
|
||||
/// Whether this node keeps the plain-input lowering during the record transition
|
||||
pub(crate) plain: bool,
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ pub struct ParsedField {
|
||||
pub unit: Option<LitStr>,
|
||||
pub is_data_field: bool,
|
||||
/// The attribute reads destructured from this input's tuple, resolved
|
||||
/// against this input's wire.
|
||||
/// against this input.
|
||||
pub(crate) attribute_reads: Vec<AttributeRead>,
|
||||
}
|
||||
|
||||
@@ -829,7 +829,7 @@ fn is_frame_claim(ty: &Type) -> bool {
|
||||
}
|
||||
|
||||
/// Splits a lazy input's `Output = (T, Attr<..>..)` tuple into the element
|
||||
/// type (the wire type) and the declared reads on that edge. A tuple without
|
||||
/// type (the input type) and the declared reads on that input. A tuple without
|
||||
/// `Attr` slots is an ordinary tuple output and passes through untouched.
|
||||
fn split_lazy_reads(output_type: Type) -> syn::Result<(Type, Vec<AttributeRead>)> {
|
||||
let Type::Tuple(tuple) = &output_type else {
|
||||
@@ -865,7 +865,7 @@ fn split_lazy_reads(output_type: Type) -> syn::Result<(Type, Vec<AttributeRead>)
|
||||
|
||||
/// Parses a `(value, reads..): (T, Attr<..>..)` parameter: the value component
|
||||
/// is an ordinary field of the value type, each `Attr` component a read bound
|
||||
/// to this input's wire.
|
||||
/// to this input.
|
||||
fn parse_read_tuple(pat_tuple: &syn::PatTuple, ty: &Type, attrs: &[Attribute], index: usize) -> syn::Result<ParsedField> {
|
||||
let spelling = "an input with attribute reads destructures as `(value, Attr<..>)` over `(T, Attr<..>)`";
|
||||
let Type::Tuple(ty_tuple) = ty else {
|
||||
@@ -1031,7 +1031,7 @@ fn parse_field(pat_ident: PatIdent, ty: Type, attrs: &[Attribute]) -> syn::Resul
|
||||
// Data fields act as internal state, using interior mutability to cache data between node evaluations.
|
||||
//
|
||||
// Normally, an input parameter is a construction argument to the node that is stored as a field on the node struct.
|
||||
// Specifically, its struct field stores the connected upstream node (an evaluatable lambda that returns data of the connection wire's type).
|
||||
// Specifically, its struct field stores the connected upstream node (an evaluatable lambda that returns data of the connection's type).
|
||||
// By comparison, a data field is also stored as a field on the node struct, allowing it to persist state between evaluations.
|
||||
// But it acts as internal state only, not exposed as a parameter in the UI or able to be wired to another node.
|
||||
//
|
||||
@@ -1166,7 +1166,7 @@ fn parse_field(pat_ident: PatIdent, ty: Type, attrs: &[Attribute]) -> syn::Resul
|
||||
}
|
||||
|
||||
let input_type = node_input_type.ok_or_else(|| Error::new_spanned(&ty, "Invalid Node type. Expected `impl Node<Input>` or `impl Node<Input, Output = OutputType>`"))?;
|
||||
// A subject named without an output is a whole-record wire: the kernel
|
||||
// A subject named without an output is a whole-record input: the kernel
|
||||
// serves it through its own claim rather than reading an element.
|
||||
let output_type = node_output_type.unwrap_or_else(|| syn::parse_quote!(Served<'_>));
|
||||
if !matches!(&value_source, ParsedValueSource::None) {
|
||||
|
||||
@@ -54,7 +54,7 @@ fn validate_record_io(parsed: &ParsedNodeFn) {
|
||||
|
||||
for field in parsed.fields.iter().skip(1) {
|
||||
if let ParsedFieldType::Node(NodeParsedField { output_type, .. }) = &field.ty {
|
||||
// Lazy secondaries are consumed as plain elements through the wire.
|
||||
// Lazy secondaries are consumed as plain elements through the input.
|
||||
if crate::codegen::classify::is_served(output_type) || crate::codegen::ir::strip_ilist(output_type).1 > 0 {
|
||||
emit_error!(field.pat_ident.span(), "a record node's lazy inputs consume plain elements, not record or ranked wires");
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ fn read_index(
|
||||
/// In programming terms: inside the double loop `i { j { ... } }`, *Loop Level* 0 = `j` and 1 = `i`. After inserting a third loop `k { ... }`, inside it, levels would be 0 = `k`, 1 = `j`, and 2 = `i`.
|
||||
loop_level: u32,
|
||||
) -> f64 {
|
||||
// The chain's innermost entry is the consuming wire's own lane from the
|
||||
// The chain's innermost entry is the consuming input's own lane from the
|
||||
// decompose-and-promote split; the loops the reader counts sit above it.
|
||||
ctx.try_index().and_then(|mut iter| iter.nth(loop_level as usize + 1)).unwrap_or(0) as f64
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ fn unwrap_option<T: Default>(_: impl Ctx, #[implementations(Option<f64>, Option<
|
||||
input.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Clones the element out of its record wire.
|
||||
/// Clones the element out of its record input.
|
||||
#[node_macro::node(category("Debug"))]
|
||||
fn clone<T: Clone>(_: impl Ctx, #[implementations(Raster<CPU>, f64)] value: &T) -> T {
|
||||
value.clone()
|
||||
|
||||
@@ -21,11 +21,11 @@ pub struct MemoLevel {
|
||||
|
||||
/// Helps speed up repeated renders in a computationally-heavy part of the node graph.
|
||||
///
|
||||
/// Stores a deep copy of the last record (a scalar wire) or the last whole
|
||||
/// level (a leveled wire) that flowed through this node and replays it on
|
||||
/// Stores a deep copy of the last record (a scalar input) or the last whole
|
||||
/// level (a leveled input) that flowed through this node and replays it on
|
||||
/// subsequent renders if the context has not changed. The owned copies survive
|
||||
/// a persistent flush, so this is the memo for content whose recomputation is
|
||||
/// expensive. A leveled wire's cache key normalizes the addressed lane away,
|
||||
/// expensive. A leveled input's cache key normalizes the addressed lane away,
|
||||
/// so per-lane pulls share one materialization of the content instead of
|
||||
/// re-evaluating it per lane.
|
||||
#[node_macro::node(category("General"), path(graphene_core::memo))]
|
||||
@@ -35,8 +35,8 @@ fn memoize<'e, 'l>(
|
||||
content: impl Node<Context<'_>>,
|
||||
slot: FrameClaim<'e, 'l>,
|
||||
) -> GPoll<Served<'e>> {
|
||||
// A scalar wire's value may depend on the consuming lane (index readers),
|
||||
// so only a leveled wire, whose level covers every lane by construction,
|
||||
// A scalar input's value may depend on the consuming lane (index readers),
|
||||
// so only a leveled input, whose level covers every lane by construction,
|
||||
// keys with the lane normalized away.
|
||||
let leveled = content.layout().depth > 0;
|
||||
let lane = match leveled {
|
||||
@@ -89,7 +89,7 @@ fn memoize<'e, 'l>(
|
||||
return match content.materialize_level(&ctx, ctx.arena()) {
|
||||
LevelStatus::Batch(batch, finality) => {
|
||||
let layout = content.layout();
|
||||
// SAFETY: the batch came from this edge, so it carries the edge's layout.
|
||||
// SAFETY: the batch came from this input, so it carries the input's layout.
|
||||
let lanes: Vec<OwnedRecord> = (0..batch.len()).map(|index| unsafe { OwnedRecord::copy_out(layout, batch.get(index).rec()) }).collect();
|
||||
let entry = MemoLevel {
|
||||
key,
|
||||
@@ -115,7 +115,7 @@ fn memoize<'e, 'l>(
|
||||
};
|
||||
if let Some((value, finality)) = publishable {
|
||||
let layout = content.layout();
|
||||
// SAFETY: the value came from this edge, so it carries the edge's
|
||||
// SAFETY: the value came from this input, so it carries the input's
|
||||
// layout, and one record of it is a batch of one lane.
|
||||
let batch = unsafe { core_types::node::RecordBatch::new(layout.rec(value).ptr(), 1, layout) };
|
||||
// SAFETY: as above.
|
||||
@@ -151,8 +151,8 @@ fn frame_memo<'e, 'l>(
|
||||
content: impl Node<Context<'_>>,
|
||||
slot: FrameClaim<'e, 'l>,
|
||||
) -> GPoll<Served<'e>> {
|
||||
// A scalar wire's value may depend on the consuming lane (index readers),
|
||||
// so only a leveled wire, whose level covers every lane by construction,
|
||||
// A scalar input's value may depend on the consuming lane (index readers),
|
||||
// so only a leveled input, whose level covers every lane by construction,
|
||||
// keys with the lane normalized away.
|
||||
let leveled = content.layout().depth > 0;
|
||||
let lane = match leveled {
|
||||
@@ -198,7 +198,7 @@ fn frame_memo<'e, 'l>(
|
||||
if leveled {
|
||||
return match content.materialize_level(&ctx, ctx.arena()) {
|
||||
LevelStatus::Batch(batch, finality) => {
|
||||
// SAFETY: the batch came from this edge, so it carries the edge's layout.
|
||||
// SAFETY: the batch came from this input, so it carries the input's layout.
|
||||
let span = unsafe { MaterializedSpan::to_persistent(&batch, &promotion) };
|
||||
*cache.lock().unwrap() = span.map(|span| SpanLevel { key, span, finality });
|
||||
match lane < batch.len() {
|
||||
@@ -220,7 +220,7 @@ fn frame_memo<'e, 'l>(
|
||||
};
|
||||
if let Some((value, finality)) = publishable {
|
||||
let layout = content.layout();
|
||||
// SAFETY: the value came from this edge, so it carries the edge's
|
||||
// SAFETY: the value came from this input, so it carries the input's
|
||||
// layout, and one record of it is a batch of one lane.
|
||||
let batch = unsafe { core_types::node::RecordBatch::new(layout.rec(value).ptr(), 1, layout) };
|
||||
// SAFETY: as above.
|
||||
@@ -235,7 +235,7 @@ type MonitorValue = Arc<Mutex<Option<CtxSnapshot>>>;
|
||||
/// The Monitor node is used by the editor to access the data flowing through
|
||||
/// it. It stores only the evaluation context: the output is pure over
|
||||
/// (context, source generations), so introspection recreates it by
|
||||
/// re-evaluating this edge with the rehydrated snapshot.
|
||||
/// re-evaluating this input with the rehydrated snapshot.
|
||||
#[node_macro::node(category(""), path(graphene_core::memo), serialize(serialize_monitor), properties("monitor_properties"))]
|
||||
fn monitor<'e, 'l>(
|
||||
ctx: impl Ctx + DeriveCtx + ExtractAll + ExtractArena<'e> + ModifyIndex + Copy,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//! Pilot record nodes exercising the macro's record-tier attribute io:
|
||||
//! per-input tuple reads resolved against each input's wire, offset writes,
|
||||
//! per-input tuple reads resolved against each input, offset writes,
|
||||
//! `RemoveAttr` layout subtraction, the ElToken byte-carry for passthrough
|
||||
//! elements, and the `_: ()` no-carrier form. These are the flat-wave law
|
||||
//! tests; the node forms are the production authoring surface, and the
|
||||
@@ -1494,8 +1494,8 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// The compiler clears an input's bit when its edge reads the addressed
|
||||
/// lane; the batch must then re-evaluate that edge per lane, since hoisting
|
||||
/// The compiler clears an input's bit when its source reads the addressed
|
||||
/// lane; the batch must then re-evaluate that source per lane, since hoisting
|
||||
/// a lane-varying value serves the range's first lane to all of them.
|
||||
#[test]
|
||||
fn batch_rebinds_an_eager_input_the_compiler_cannot_prove_invariant() {
|
||||
|
||||
@@ -372,9 +372,9 @@ pub fn stamp_layer_path<'e, T>(ctx: impl Ctx + ExtractArena<'e>, element: T, pat
|
||||
#[node_macro::node(category("General"), extent(extend_extent))]
|
||||
pub fn extend<T>(
|
||||
ctx: impl Ctx + ExtractIndex + InjectIndex + Copy,
|
||||
/// The wire whose lanes appear at the start of the extended level.
|
||||
/// The input whose lanes appear at the start of the extended level.
|
||||
base: impl Node<Context<'_>, Output = T>,
|
||||
/// The wire whose lanes appear at the end of the extended level.
|
||||
/// The input whose lanes appear at the end of the extended level.
|
||||
#[expose]
|
||||
new: impl Node<Context<'_>, Output = T>,
|
||||
) -> Result<T, Interrupt> {
|
||||
@@ -488,7 +488,7 @@ pub fn to_graphic<'e, T: graphic_types::graphic::IntoGraphicElement>(
|
||||
}
|
||||
|
||||
/// The elementwise `Graphic` coercion the compiler-inserted converts use: each
|
||||
/// lane's element converts on its own, so a typed wire feeds a graphic input
|
||||
/// lane's element converts on its own, so a typed source feeds a graphic input
|
||||
/// without changing the level's shape. Registered under the convert identifier.
|
||||
#[node_macro::node(category(""))]
|
||||
pub fn to_graphic_element<'e, T: graphic_types::graphic::IntoGraphicElement>(
|
||||
@@ -537,7 +537,7 @@ fn to_graphic_unit_extent(_content: core_types::extent::ValueIn<'_, ()>, _level:
|
||||
GPoll::Final(Extent::Exactly(0))
|
||||
}
|
||||
|
||||
/// The transitional level bridge: the wire's records as the legacy list an
|
||||
/// The transitional level bridge: the input's records as the legacy list an
|
||||
/// unconverted consumer expects, attributes copied through their erased
|
||||
/// reads and content kept in its native form. Registered under the legacy
|
||||
/// convert identifiers; the rows die with the last legacy consumer.
|
||||
|
||||
@@ -178,7 +178,7 @@ fn flat_map<Row: Clone + Send + Sync + core_types::CacheHash + 'static, T>(
|
||||
}
|
||||
|
||||
/// Rank-model level collapse: two nested levels become one flat level. The
|
||||
/// flat index already spans the edge's depth, so the eval forwards it.
|
||||
/// flat index already spans the input's depth, so the eval forwards it.
|
||||
#[node_macro::node(category("Test"), extent(flatten_levels_extent))]
|
||||
fn flatten_levels<T>(ctx: impl Ctx + DeriveCtx + ExtractIndex, content: impl Node<Context<'_>, Output = IList<IList<T>>>) -> Result<IList<T>, Interrupt> {
|
||||
let head = ctx.index_head();
|
||||
|
||||
@@ -75,7 +75,7 @@ fn render_intermediate<T: dyn_any::StaticTypeSized + 'static + Render + WasmNotS
|
||||
Ok(intermediate_of(&data, render_params))
|
||||
}
|
||||
|
||||
/// The leveled form of `render_intermediate`: the wire's records materialize
|
||||
/// The leveled form of `render_intermediate`: the input's records materialize
|
||||
/// into a run, which renders directly.
|
||||
#[node_macro::node(category(""))]
|
||||
fn render_intermediate_leveled<T: Clone + Send + Sync + core_types::CacheHash + dyn_any::StaticTypeSized + 'static>(
|
||||
|
||||
@@ -1027,7 +1027,7 @@ mod graphene_test {
|
||||
core_types::record::test_frames(layouts.iter().map(|layout| layout.frame_bytes()).sum::<usize>().max(1 << 12))
|
||||
}
|
||||
|
||||
/// Lifts a plain-element test source onto a record wire, returned beside its
|
||||
/// Lifts a plain-element test source onto a record input, returned beside its
|
||||
/// element-only layout for the generated node's constructor.
|
||||
fn lifted<T, F>(kernel: F) -> (LiftedSource<T, F>, Layout)
|
||||
where
|
||||
|
||||
@@ -102,7 +102,7 @@ fn boolean_core<'e>(
|
||||
#[node_macro::node(category("Vector: Modifier"), memoize)]
|
||||
fn boolean_operation<'e>(
|
||||
ctx: impl Ctx + ExtractArena<'e> + core_types::InjectIndex + Copy,
|
||||
/// The wire of vector paths to perform the boolean operation on. Nested groups are automatically flattened.
|
||||
/// The input of vector paths to perform the boolean operation on. Nested groups are automatically flattened.
|
||||
content: IList<Graphic<'static>>,
|
||||
/// Which boolean operation to perform on the paths.
|
||||
///
|
||||
|
||||
@@ -11,7 +11,7 @@ use graphic_types::Vector;
|
||||
use graphic_types::raster_types::{CPU, GPU, Raster};
|
||||
use vector_types::GradientStops;
|
||||
|
||||
/// Applies the specified transform to each lane of the input wire, composing onto the lane's transform attribute.
|
||||
/// Applies the specified transform to each lane of the input, composing onto the lane's transform attribute.
|
||||
#[node_macro::node(category("Math: Transform"), extent(transform_extent))]
|
||||
fn transform<T>(
|
||||
ctx: impl Ctx + DeriveCtx + ModifyFootprint,
|
||||
@@ -88,14 +88,14 @@ fn reset_transform<T>(_: impl Ctx, (element, transform): (T, Attr<TransformAttr>
|
||||
(element, Attr(row_transform))
|
||||
}
|
||||
|
||||
/// Overwrites the transform of each lane of the input wire with the specified transform.
|
||||
/// Overwrites the transform of each lane of the input with the specified transform.
|
||||
#[node_macro::node(category("Math: Transform"))]
|
||||
fn replace_transform<T>(_: impl Ctx + InjectFootprint, (element, _content_transform): (T, Attr<TransformAttr>), transform: DAffine2) -> (T, Attr<TransformAttr>) {
|
||||
(element, Attr(transform))
|
||||
}
|
||||
|
||||
// TODO: Figure out how this node should behave once #2982 is implemented.
|
||||
/// Obtains the transform of the first lane of the input wire, if present.
|
||||
/// Obtains the transform of the first lane of the input, if present.
|
||||
#[node_macro::node(category("Math: Transform"), path(core_types::vector))]
|
||||
fn extract_transform<T: Clone + Send + Sync + CacheHash + 'static>(_: impl Ctx, #[implementations(Graphic, Vector, Raster<CPU>, Raster<GPU>, Color, GradientStops)] content: IList<T>) -> DAffine2 {
|
||||
match content.len() {
|
||||
|
||||
Reference in New Issue
Block a user