mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Add leveled vararg sources beside the production read nodes
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
use core_types::gpoll::{Extent, GPoll, GraphError, Interrupt};
|
||||
use core_types::list::List;
|
||||
use core_types::{Color, ExtractVarArgs};
|
||||
use core_types::{Ctx, ExtractIndex, ExtractPosition};
|
||||
@@ -46,6 +47,78 @@ fn read_gradient(ctx: impl Ctx + ExtractVarArgs) -> List<GradientStops> {
|
||||
var_arg.downcast_ref().cloned().unwrap_or_default()
|
||||
}
|
||||
|
||||
/// The mapped row riding as vararg 0, in the production single-item shape.
|
||||
fn vararg_list<'a, T: 'static>(ctx: &'a impl ExtractVarArgs) -> Option<&'a List<T>> {
|
||||
let arg = ctx.vararg(0).ok()?;
|
||||
(arg as &dyn std::any::Any).downcast_ref::<List<T>>()
|
||||
}
|
||||
|
||||
/// Lanes of a leveled vararg source: one per item, none without a row,
|
||||
/// matching the legacy empty-list return.
|
||||
fn vararg_lanes<T: 'static>(ctx: &impl ExtractVarArgs, level: u8) -> GPoll<Extent> {
|
||||
match level {
|
||||
0 => GPoll::Final(Extent::Exactly(vararg_list::<T>(ctx).map_or(0, List::len))),
|
||||
_ => GPoll::Final(Extent::Exactly(1)),
|
||||
}
|
||||
}
|
||||
|
||||
fn vararg_element<T: Clone + 'static>(ctx: &(impl ExtractVarArgs + ExtractIndex)) -> Result<T, Interrupt> {
|
||||
vararg_list::<T>(ctx)
|
||||
.and_then(|list| list.element(ctx.innermost_index() as usize))
|
||||
.cloned()
|
||||
.ok_or_else(|| GraphError::new("vararg row addressed past its items").into())
|
||||
}
|
||||
|
||||
/// Rank-model vararg source: the mapped row's items as lanes, elements only.
|
||||
#[node_macro::node(category("Test"), extent_raw(read_graphic_row_extent))]
|
||||
pub fn read_graphic_row(ctx: impl Ctx + ExtractVarArgs + ExtractIndex) -> Result<IList<Graphic>, Interrupt> {
|
||||
vararg_element(ctx)
|
||||
}
|
||||
|
||||
fn read_graphic_row_extent<C: Ctx + ExtractVarArgs>(_: &ReadGraphicRowNode, ctx: &C, level: u8) -> GPoll<Extent> {
|
||||
vararg_lanes::<Graphic>(ctx, level)
|
||||
}
|
||||
|
||||
/// Rank-model vararg source: the mapped row's items as lanes, elements only.
|
||||
#[node_macro::node(category("Test"), extent_raw(read_vector_row_extent))]
|
||||
pub fn read_vector_row(ctx: impl Ctx + ExtractVarArgs + ExtractIndex) -> Result<IList<Vector>, Interrupt> {
|
||||
vararg_element(ctx)
|
||||
}
|
||||
|
||||
fn read_vector_row_extent<C: Ctx + ExtractVarArgs>(_: &ReadVectorRowNode, ctx: &C, level: u8) -> GPoll<Extent> {
|
||||
vararg_lanes::<Vector>(ctx, level)
|
||||
}
|
||||
|
||||
/// Rank-model vararg source: the mapped row's items as lanes, elements only.
|
||||
#[node_macro::node(category("Test"), extent_raw(read_raster_row_extent))]
|
||||
pub fn read_raster_row(ctx: impl Ctx + ExtractVarArgs + ExtractIndex) -> Result<IList<Raster<CPU>>, Interrupt> {
|
||||
vararg_element(ctx)
|
||||
}
|
||||
|
||||
fn read_raster_row_extent<C: Ctx + ExtractVarArgs>(_: &ReadRasterRowNode, ctx: &C, level: u8) -> GPoll<Extent> {
|
||||
vararg_lanes::<Raster<CPU>>(ctx, level)
|
||||
}
|
||||
|
||||
/// Rank-model vararg source: the mapped row's items as lanes, elements only.
|
||||
#[node_macro::node(category("Test"), extent_raw(read_color_row_extent))]
|
||||
pub fn read_color_row(ctx: impl Ctx + ExtractVarArgs + ExtractIndex) -> Result<IList<Color>, Interrupt> {
|
||||
vararg_element(ctx)
|
||||
}
|
||||
|
||||
fn read_color_row_extent<C: Ctx + ExtractVarArgs>(_: &ReadColorRowNode, ctx: &C, level: u8) -> GPoll<Extent> {
|
||||
vararg_lanes::<Color>(ctx, level)
|
||||
}
|
||||
|
||||
/// Rank-model vararg source: the mapped row's items as lanes, elements only.
|
||||
#[node_macro::node(category("Test"), extent_raw(read_gradient_row_extent))]
|
||||
pub fn read_gradient_row(ctx: impl Ctx + ExtractVarArgs + ExtractIndex) -> Result<IList<GradientStops>, Interrupt> {
|
||||
vararg_element(ctx)
|
||||
}
|
||||
|
||||
fn read_gradient_row_extent<C: Ctx + ExtractVarArgs>(_: &ReadGradientRowNode, ctx: &C, level: u8) -> GPoll<Extent> {
|
||||
vararg_lanes::<GradientStops>(ctx, level)
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Context"), path(core_types::vector))]
|
||||
fn read_position(
|
||||
ctx: impl Ctx + ExtractPosition,
|
||||
|
||||
@@ -1518,6 +1518,38 @@ mod tests {
|
||||
assert_eq!(unsafe { out.rec(&value).element::<f64>() }, 42.);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_row_exposes_the_vararg_items_as_lanes() {
|
||||
use core_types::Color;
|
||||
|
||||
let arena = Arena::new(1024).unwrap();
|
||||
let generations = [];
|
||||
let scope = scope_fixture(&generations, &arena);
|
||||
let ctx = ContextImpl::root(&scope);
|
||||
|
||||
let node = install(crate::context::ReadColorRowNode::new(), crate::context::read_color_row_layout_meta(), &[]);
|
||||
let out = Node::<ContextImpl>::layout(&node).clone();
|
||||
assert_eq!(out.depth, 1);
|
||||
// No row pushed: an empty level, matching the legacy empty-list return.
|
||||
assert_eq!(node.extent_at(&ctx, 0), GPoll::Final(Extent::Exactly(0)));
|
||||
|
||||
let mut item = core_types::list::List::new_from_element(Color::BLACK);
|
||||
item.push(core_types::list::Item::new_from_element(Color::WHITE));
|
||||
let scoped = ctx.push_vararg(&item);
|
||||
let base = scoped.ctx();
|
||||
assert_eq!(node.extent_at(&base, 0), GPoll::Final(Extent::Exactly(2)));
|
||||
|
||||
let head = base.index_head();
|
||||
for (lane, expected) in [(0u64, Color::BLACK), (1, Color::WHITE)] {
|
||||
let mark = stack::sp();
|
||||
let GPoll::Final(value) = node.eval(&base.promoted(&head, lane)) else {
|
||||
panic!("expected a final record at lane {lane}");
|
||||
};
|
||||
assert_eq!(unsafe { out.rec(&value).element::<Color>() }, expected, "lane {lane}");
|
||||
unsafe { stack::rewind(mark) };
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reducer_drains_a_lower_bound_level() {
|
||||
let arena = Arena::new(1 << 16).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user