mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-16 23:08:05 +08:00
Make Node::layout non-optional, defaulting to a shared empty layout
This commit is contained in:
@@ -71,12 +71,12 @@ pub trait Node<Input> {
|
||||
None
|
||||
}
|
||||
|
||||
/// The record layout of this node's output; `None` for element-only
|
||||
/// producers. Consumers read their carrier's layout through this at
|
||||
/// wiring, and the wiring layer derives stack sizing from the same
|
||||
/// The record layout of this node's output; the shared empty layout for
|
||||
/// element-only producers. Consumers read their carrier's layout through
|
||||
/// this at wiring, and the wiring layer derives stack sizing from the same
|
||||
/// layouts, in the dynamic executor and exported source alike.
|
||||
fn layout(&self) -> Option<&crate::record::Layout> {
|
||||
None
|
||||
fn layout(&self) -> &crate::record::Layout {
|
||||
crate::record::empty_layout()
|
||||
}
|
||||
|
||||
fn eval_batch<'a>(&self, input: &'a Input, range: Range<u64>, scratch: Option<&'a mut [MaybeUninit<Self::Output>]>) -> BatchStatus<'a, Self::Output>
|
||||
@@ -141,7 +141,7 @@ where
|
||||
(**self).serialize()
|
||||
}
|
||||
|
||||
fn layout(&self) -> Option<&crate::record::Layout> {
|
||||
fn layout(&self) -> &crate::record::Layout {
|
||||
(**self).layout()
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ where
|
||||
(**self).serialize()
|
||||
}
|
||||
|
||||
fn layout(&self) -> Option<&crate::record::Layout> {
|
||||
fn layout(&self) -> &crate::record::Layout {
|
||||
(**self).layout()
|
||||
}
|
||||
|
||||
@@ -201,6 +201,10 @@ where
|
||||
(**self).serialize()
|
||||
}
|
||||
|
||||
fn layout(&self) -> &crate::record::Layout {
|
||||
(**self).layout()
|
||||
}
|
||||
|
||||
fn eval_batch<'a>(&self, input: &'a Input, range: Range<u64>, scratch: Option<&'a mut [MaybeUninit<Self::Output>]>) -> BatchStatus<'a, Self::Output>
|
||||
where
|
||||
Input: InjectIndex + Copy,
|
||||
|
||||
@@ -234,6 +234,14 @@ impl Layout {
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct ElToken;
|
||||
|
||||
/// The shared empty layout: `depth` 0, no element, no fields, so `frame_bytes`
|
||||
/// is 0. The `Node::layout` default returns it for element-only and test nodes,
|
||||
/// which carry no record.
|
||||
pub fn empty_layout() -> &'static Layout {
|
||||
static EMPTY: std::sync::OnceLock<Layout> = std::sync::OnceLock::new();
|
||||
EMPTY.get_or_init(Layout::default)
|
||||
}
|
||||
|
||||
/// A view of one record: a pointer whose layout is proven at wiring.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Rec(*const u8);
|
||||
@@ -1081,8 +1089,8 @@ where
|
||||
lift_poll(self.edge.eval(input), &self.layout, input.arena())
|
||||
}
|
||||
|
||||
fn layout(&self) -> Option<&Layout> {
|
||||
Some(&self.layout)
|
||||
fn layout(&self) -> &Layout {
|
||||
&self.layout
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1139,8 +1147,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn layout(&self) -> Option<&Layout> {
|
||||
Some(&self.union)
|
||||
fn layout(&self) -> &Layout {
|
||||
&self.union
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ where
|
||||
#[cfg(debug_assertions)]
|
||||
debug_assert_eq!(
|
||||
crate::record::stack::sp(),
|
||||
sp_before + self.layout().map_or(0, |layout| layout.frame_bytes()),
|
||||
sp_before + self.layout().frame_bytes(),
|
||||
"{} left the record stack misaligned",
|
||||
std::any::type_name::<N>(),
|
||||
);
|
||||
@@ -175,7 +175,7 @@ where
|
||||
unsafe { self.ptr.as_ref() }.serialize()
|
||||
}
|
||||
|
||||
fn layout(&self) -> Option<&crate::record::Layout> {
|
||||
fn layout(&self) -> &crate::record::Layout {
|
||||
// SAFETY: as in eval.
|
||||
unsafe { self.ptr.as_ref() }.layout()
|
||||
}
|
||||
@@ -228,7 +228,7 @@ impl EdgeHandle {
|
||||
node: Box::new(SharedEdge::new(node)),
|
||||
share: |edge| Box::new(edge.downcast_ref::<SharedEdge<N>>().expect("share hook matches the stored edge type").share()),
|
||||
serialize: |edge| Node::<ContextImpl>::serialize(edge.downcast_ref::<SharedEdge<N>>().expect("serialize hook matches the stored edge type")),
|
||||
layout: |edge| Node::<ContextImpl>::layout(edge.downcast_ref::<SharedEdge<N>>().expect("layout hook matches the stored edge type")),
|
||||
layout: |edge| Some(Node::<ContextImpl>::layout(edge.downcast_ref::<SharedEdge<N>>().expect("layout hook matches the stored edge type"))),
|
||||
ty,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,8 +40,8 @@ where
|
||||
crate::record::lift_poll(crate::gpoll::GPoll::Final(self.value.clone()), &self.layout, input.arena())
|
||||
}
|
||||
|
||||
fn layout(&self) -> Option<&crate::record::Layout> {
|
||||
Some(&self.layout)
|
||||
fn layout(&self) -> &crate::record::Layout {
|
||||
&self.layout
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1702,8 +1702,8 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
|
||||
let record_layout_impl = match record.is_some() || routing.is_some() || flip || opaque {
|
||||
true => quote! {
|
||||
fn layout(&self) -> Option<&#core_types::record::Layout> {
|
||||
Some(&self.__layout)
|
||||
fn layout(&self) -> &#core_types::record::Layout {
|
||||
&self.__layout
|
||||
}
|
||||
},
|
||||
false => quote!(),
|
||||
|
||||
@@ -208,7 +208,7 @@ mod tests {
|
||||
|
||||
fn lifted_value<T: Clone + Send + Sync + 'static>(value: T) -> (core_types::record::RecordLift<T, ValueNode<T>>, Layout) {
|
||||
let lift = core_types::record::RecordLift::<T, _>::new(ValueNode(value));
|
||||
let layout = Node::<ContextImpl>::layout(&lift).unwrap().clone();
|
||||
let layout = Node::<ContextImpl>::layout(&lift).clone();
|
||||
(lift, layout)
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ mod tests {
|
||||
reserve_for(&[&source_layout, &modified, &stacked]);
|
||||
|
||||
let chain = MultiplyOpacityNode::new(MultiplyOpacityNode::new(bare_source(&source_layout, 2.), ValueNode(0.5), &source_layout), ValueNode(0.5), &modified);
|
||||
assert_eq!(chain.layout(), Some(&stacked));
|
||||
assert_eq!(chain.layout(), &stacked);
|
||||
let GPoll::Final(value) = chain.eval(&ctx) else {
|
||||
panic!("expected a final record");
|
||||
};
|
||||
@@ -361,7 +361,7 @@ mod tests {
|
||||
reserve_for(&[&layout]);
|
||||
|
||||
let node = SourceOpacityNode::new(ValueNode(3.), ValueNode(0.25));
|
||||
assert_eq!(Node::<ContextImpl>::layout(&node), Some(&layout));
|
||||
assert_eq!(Node::<ContextImpl>::layout(&node), &layout);
|
||||
let GPoll::Final(value) = node.eval(&ctx) else {
|
||||
panic!("expected a final record");
|
||||
};
|
||||
@@ -490,7 +490,7 @@ mod tests {
|
||||
|
||||
let source_layout = f64_layout(&["opacity"]);
|
||||
let factor = core_types::record::RecordLift::<f64, _>::new(ValueNode(3.));
|
||||
let factor_layout = Node::<ContextImpl>::layout(&factor).unwrap().clone();
|
||||
let factor_layout = Node::<ContextImpl>::layout(&factor).clone();
|
||||
reserve_for(&[&source_layout]);
|
||||
|
||||
let node = BoostNode::new(
|
||||
@@ -499,7 +499,7 @@ mod tests {
|
||||
&source_layout,
|
||||
&factor_layout,
|
||||
);
|
||||
let out_layout = Node::<ContextImpl>::layout(&node).unwrap().clone();
|
||||
let out_layout = Node::<ContextImpl>::layout(&node).clone();
|
||||
let opacity_offset = out_layout.offset_of(Opacity::NAME, 0).expect("the primary input's fields pass through to the output");
|
||||
let GPoll::Final(value) = node.eval(&ctx) else {
|
||||
panic!("expected a final record");
|
||||
@@ -526,7 +526,7 @@ mod tests {
|
||||
&source_layout,
|
||||
&factor_layout,
|
||||
);
|
||||
let out_layout = Node::<ContextImpl>::layout(&node).unwrap().clone();
|
||||
let out_layout = Node::<ContextImpl>::layout(&node).clone();
|
||||
let opacity_offset = out_layout.offset_of(Opacity::NAME, 0).expect("the primary input's fields pass through the poll kernel");
|
||||
let GPoll::Final(value) = node.eval(&ctx) else {
|
||||
panic!("expected a final record");
|
||||
@@ -554,7 +554,7 @@ mod tests {
|
||||
&carrier_layout,
|
||||
&by_layout,
|
||||
);
|
||||
let out_layout = Node::<ContextImpl>::layout(&node).unwrap().clone();
|
||||
let out_layout = Node::<ContextImpl>::layout(&node).clone();
|
||||
let GPoll::Final(value) = node.eval(&ctx) else {
|
||||
panic!("expected a final record");
|
||||
};
|
||||
@@ -593,7 +593,7 @@ mod tests {
|
||||
&runtime_layout,
|
||||
&source_id_layout,
|
||||
);
|
||||
let out_layout = Node::<ContextImpl>::layout(&node).unwrap().clone();
|
||||
let out_layout = Node::<ContextImpl>::layout(&node).clone();
|
||||
let opacity_offset = out_layout.offset_of(Opacity::NAME, 0).expect("the carrier's fields pass through the async source");
|
||||
|
||||
let GPoll::Final(value) = node.eval(&ctx) else {
|
||||
@@ -619,14 +619,14 @@ mod tests {
|
||||
let ctx = ContextImpl::root(&scope);
|
||||
|
||||
let unit = core_types::record::RecordLift::<(), _>::new(ValueNode(()));
|
||||
let unit_layout = Node::<ContextImpl>::layout(&unit).unwrap().clone();
|
||||
let unit_layout = Node::<ContextImpl>::layout(&unit).clone();
|
||||
let content_layout = f64_layout(&["opacity"]);
|
||||
reserve_for(&[&content_layout]);
|
||||
|
||||
let run = |opacity: Option<f64>| {
|
||||
let evals = std::sync::Arc::new(std::sync::atomic::AtomicU32::new(0));
|
||||
let alternate = core_types::record::RecordLift::<f64, _>::new(CountingValue(evals.clone()));
|
||||
let alternate_layout = Node::<ContextImpl>::layout(&alternate).unwrap().clone();
|
||||
let alternate_layout = Node::<ContextImpl>::layout(&alternate).clone();
|
||||
let (content_layout, fields) = match opacity {
|
||||
Some(value) => (content_layout.clone(), vec![(content_layout.offset_of("opacity", 0).unwrap(), value)]),
|
||||
None => (f64_layout(&[]), vec![]),
|
||||
@@ -642,7 +642,7 @@ mod tests {
|
||||
let GPoll::Final(value) = node.eval(&ctx) else {
|
||||
panic!("expected a final record");
|
||||
};
|
||||
let element = unsafe { Node::<ContextImpl>::layout(&node).unwrap().rec(&value).element::<f64>() };
|
||||
let element = unsafe { Node::<ContextImpl>::layout(&node).rec(&value).element::<f64>() };
|
||||
(element, evals.load(std::sync::atomic::Ordering::Relaxed))
|
||||
};
|
||||
|
||||
@@ -892,7 +892,7 @@ mod tests {
|
||||
let probed = |features: ContextFeatures| {
|
||||
let (modification, modification_layout) = lifted_value(ContextModification::from_sources(features, &[]));
|
||||
let node = crate::context_modification::ContextModificationNode::new(RealTimeProbe { layout: layout.clone() }, modification, &layout, &modification_layout);
|
||||
assert_eq!(Node::<ContextImpl>::layout(&node), Some(&layout));
|
||||
assert_eq!(Node::<ContextImpl>::layout(&node), &layout);
|
||||
let GPoll::Final(value) = node.eval(&ctx) else {
|
||||
panic!("expected a final record");
|
||||
};
|
||||
@@ -944,7 +944,7 @@ mod tests {
|
||||
let ctx = ContextImpl::root(&scope);
|
||||
|
||||
let lift = core_types::record::RecordLift::<String, _>::new(ValueNode(String::from("parked")));
|
||||
let layout = Node::<ContextImpl>::layout(&lift).unwrap().clone();
|
||||
let layout = Node::<ContextImpl>::layout(&lift).clone();
|
||||
let chain = core_types::record::RecordExtract::<String, _>::new(lift, &layout);
|
||||
|
||||
let GPoll::Final(text) = chain.eval(&ctx) else {
|
||||
@@ -1029,7 +1029,7 @@ mod tests {
|
||||
|
||||
let evals = std::sync::Arc::new(std::sync::atomic::AtomicU32::new(0));
|
||||
let lift = core_types::record::RecordLift::<f64, _>::new(CountingValue(evals.clone()));
|
||||
let layout = Node::<ContextImpl>::layout(&lift).unwrap().clone();
|
||||
let layout = Node::<ContextImpl>::layout(&lift).clone();
|
||||
let memo = crate::memo::MemoizeNode::new(lift, &layout);
|
||||
|
||||
let GPoll::Final(value) = memo.eval(&ctx) else {
|
||||
|
||||
@@ -269,7 +269,7 @@ mod test {
|
||||
let x_translations = |values: [f64; 3]| values.map(|x| DVec2::new(x, 0.)).to_vec();
|
||||
|
||||
let lift = RecordLift::<List<Vector>, _>::new(IndexProbe);
|
||||
let layout = Node::<ContextImpl>::layout(&lift).unwrap().clone();
|
||||
let layout = Node::<ContextImpl>::layout(&lift).clone();
|
||||
|
||||
let forward = super::repeat(&ctx, ElementLazyInput::new(&lift, &cell, 0, &layout), 3, false).unwrap();
|
||||
assert_eq!(row_translations(&forward, ATTR_TRANSFORM), x_translations([0., 1., 2.]));
|
||||
@@ -285,7 +285,7 @@ mod test {
|
||||
let count = 3;
|
||||
|
||||
let lift = RecordLift::<List<Vector>, _>::new(ValueNode(single_default_vector()));
|
||||
let layout = Node::<ContextImpl>::layout(&lift).unwrap().clone();
|
||||
let layout = Node::<ContextImpl>::layout(&lift).clone();
|
||||
let repeated = super::repeat_array(&ctx, ElementLazyInput::new(&lift, &cell, 0, &layout), direction, 0., count).unwrap();
|
||||
|
||||
assert_eq!(repeated.len(), count as usize);
|
||||
@@ -300,7 +300,7 @@ mod test {
|
||||
test_ctx!(ctx, cell);
|
||||
|
||||
let lift = RecordLift::<List<Vector>, _>::new(ValueNode(single_default_vector()));
|
||||
let layout = Node::<ContextImpl>::layout(&lift).unwrap().clone();
|
||||
let layout = Node::<ContextImpl>::layout(&lift).clone();
|
||||
let repeated = super::repeat_array(&ctx, ElementLazyInput::<List<Vector>, _>::new(&lift, &cell, 0, &layout), DVec2::new(12., 10.), 45., 1).unwrap();
|
||||
|
||||
assert_eq!(repeated.len(), 1);
|
||||
@@ -314,7 +314,7 @@ mod test {
|
||||
let (radius, count) = (5., 4);
|
||||
|
||||
let lift = RecordLift::<List<Vector>, _>::new(ValueNode(single_default_vector()));
|
||||
let layout = Node::<ContextImpl>::layout(&lift).unwrap().clone();
|
||||
let layout = Node::<ContextImpl>::layout(&lift).clone();
|
||||
let repeated = super::repeat_radial(&ctx, ElementLazyInput::<List<Vector>, _>::new(&lift, &cell, 0, &layout), 0., radius, count).unwrap();
|
||||
|
||||
assert_eq!(repeated.len(), count as usize);
|
||||
@@ -332,7 +332,7 @@ mod test {
|
||||
let points = List::new_from_element(Vector::from_subpath(Subpath::from_anchors(positions, false)));
|
||||
|
||||
let lift = RecordLift::<List<Vector>, _>::new(PositionProbe);
|
||||
let layout = Node::<ContextImpl>::layout(&lift).unwrap().clone();
|
||||
let layout = Node::<ContextImpl>::layout(&lift).clone();
|
||||
|
||||
let generated = super::repeat_on_points(&ctx, points.clone(), ElementLazyInput::new(&lift, &cell, 0, &layout), false).unwrap();
|
||||
assert_eq!(row_translations(&generated, ATTR_TRANSFORM), positions.to_vec());
|
||||
|
||||
Reference in New Issue
Block a user