Loosen the Graphene type system to allow contravariant function arguments (#1740)
* Accept any input for nodes that expect () as input * Add comments * More comments --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
07fd2c2782
commit
ce96ae66f2
|
|
@ -326,7 +326,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
category: "Structural",
|
category: "Structural",
|
||||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
||||||
imports: vec![NodeId(0), NodeId(0)],
|
imports: vec![NodeId(0), NodeId(0)],
|
||||||
exports: vec![NodeOutput::new(NodeId(2), 0)],
|
exports: vec![NodeOutput::new(NodeId(1), 0)],
|
||||||
nodes: [
|
nodes: [
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
name: "Load Resource".to_string(),
|
name: "Load Resource".to_string(),
|
||||||
|
|
@ -340,13 +340,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::DecodeImageNode")),
|
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::DecodeImageNode")),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
DocumentNode {
|
|
||||||
name: "Cull".to_string(),
|
|
||||||
inputs: vec![NodeInput::node(NodeId(1), 0)],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")),
|
|
||||||
manual_composition: Some(concrete!(Footprint)),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
|
@ -646,64 +639,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
name: "Noise Pattern",
|
name: "Noise Pattern",
|
||||||
category: "General",
|
category: "General",
|
||||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
implementation: DocumentNodeImplementation::proto("graphene_std::raster::NoisePatternNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _>"),
|
||||||
imports: vec![
|
|
||||||
NodeId(0),
|
|
||||||
NodeId(0),
|
|
||||||
NodeId(0),
|
|
||||||
NodeId(0),
|
|
||||||
NodeId(0),
|
|
||||||
NodeId(0),
|
|
||||||
NodeId(0),
|
|
||||||
NodeId(0),
|
|
||||||
NodeId(0),
|
|
||||||
NodeId(0),
|
|
||||||
NodeId(0),
|
|
||||||
NodeId(0),
|
|
||||||
NodeId(0),
|
|
||||||
NodeId(0),
|
|
||||||
NodeId(0),
|
|
||||||
NodeId(0),
|
|
||||||
],
|
|
||||||
exports: vec![NodeOutput::new(NodeId(1), 0)],
|
|
||||||
nodes: vec![
|
|
||||||
DocumentNode {
|
|
||||||
name: "Noise Pattern".to_string(),
|
|
||||||
inputs: vec![
|
|
||||||
NodeInput::Network(concrete!(())),
|
|
||||||
NodeInput::Network(concrete!(UVec2)),
|
|
||||||
NodeInput::Network(concrete!(u32)),
|
|
||||||
NodeInput::Network(concrete!(f64)),
|
|
||||||
NodeInput::Network(concrete!(graphene_core::raster::NoiseType)),
|
|
||||||
NodeInput::Network(concrete!(graphene_core::raster::FractalType)),
|
|
||||||
NodeInput::Network(concrete!(f64)),
|
|
||||||
NodeInput::Network(concrete!(graphene_core::raster::FractalType)),
|
|
||||||
NodeInput::Network(concrete!(u32)),
|
|
||||||
NodeInput::Network(concrete!(f64)),
|
|
||||||
NodeInput::Network(concrete!(f64)),
|
|
||||||
NodeInput::Network(concrete!(f64)),
|
|
||||||
NodeInput::Network(concrete!(f64)),
|
|
||||||
NodeInput::Network(concrete!(graphene_core::raster::CellularDistanceFunction)),
|
|
||||||
NodeInput::Network(concrete!(graphene_core::raster::CellularReturnType)),
|
|
||||||
NodeInput::Network(concrete!(f64)),
|
|
||||||
],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::raster::NoisePatternNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _>")),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
DocumentNode {
|
|
||||||
name: "Cull".to_string(),
|
|
||||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")),
|
|
||||||
manual_composition: Some(concrete!(Footprint)),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(id, node)| (NodeId(id as u64), node))
|
|
||||||
.collect(),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
DocumentInputType::value("None", TaggedValue::None, false),
|
DocumentInputType::value("None", TaggedValue::None, false),
|
||||||
// All
|
// All
|
||||||
|
|
@ -945,6 +881,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
// The input image feeds into the identity, then we take its passed-through value when the other channels are reading from it instead of the original input.
|
// The input image feeds into the identity, then we take its passed-through value when the other channels are reading from it instead of the original input.
|
||||||
// We do this for technical restrictions imposed by Graphene which doesn't allow an input to feed into multiple interior nodes in the subgraph.
|
// We do this for technical restrictions imposed by Graphene which doesn't allow an input to feed into multiple interior nodes in the subgraph.
|
||||||
// Diagram: <https://files.keavon.com/-/AchingSecondHypsilophodon/capture.png>
|
// Diagram: <https://files.keavon.com/-/AchingSecondHypsilophodon/capture.png>
|
||||||
|
// TODO: Remove this limitation by either making the `imports` above into a double-vec or making each of these DocumentNodes request their imported data based on its index.
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
name: "Identity".to_string(),
|
name: "Identity".to_string(),
|
||||||
inputs: vec![NodeInput::Network(concrete!(ImageFrame<Color>))],
|
inputs: vec![NodeInput::Network(concrete!(ImageFrame<Color>))],
|
||||||
|
|
@ -2230,30 +2167,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
name: "Ellipse",
|
name: "Ellipse",
|
||||||
category: "Vector",
|
category: "Vector",
|
||||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
implementation: DocumentNodeImplementation::proto("graphene_core::vector::generator_nodes::EllipseGenerator<_, _>"),
|
||||||
imports: vec![NodeId(0), NodeId(0), NodeId(0)],
|
|
||||||
exports: vec![NodeOutput::new(NodeId(1), 0)],
|
|
||||||
nodes: vec![
|
|
||||||
DocumentNode {
|
|
||||||
name: "Ellipse Generator".to_string(),
|
|
||||||
inputs: vec![NodeInput::Network(concrete!(())), NodeInput::Network(concrete!(f64)), NodeInput::Network(concrete!(f64))],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::EllipseGenerator<_, _>")),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
DocumentNode {
|
|
||||||
name: "Cull".to_string(),
|
|
||||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")),
|
|
||||||
manual_composition: Some(concrete!(Footprint)),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(id, node)| (NodeId(id as u64), node))
|
|
||||||
.collect(),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
DocumentInputType::none(),
|
DocumentInputType::none(),
|
||||||
DocumentInputType::value("Radius X", TaggedValue::F64(50.), false),
|
DocumentInputType::value("Radius X", TaggedValue::F64(50.), false),
|
||||||
|
|
@ -2266,37 +2180,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
name: "Rectangle",
|
name: "Rectangle",
|
||||||
category: "Vector",
|
category: "Vector",
|
||||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
implementation: DocumentNodeImplementation::proto("graphene_core::vector::generator_nodes::RectangleGenerator<_, _, _, _, _>"),
|
||||||
imports: vec![NodeId(0), NodeId(0), NodeId(0), NodeId(0), NodeId(0), NodeId(0)],
|
|
||||||
exports: vec![NodeOutput::new(NodeId(1), 0)],
|
|
||||||
nodes: vec![
|
|
||||||
DocumentNode {
|
|
||||||
name: "Rectangle Generator".to_string(),
|
|
||||||
inputs: vec![
|
|
||||||
NodeInput::Network(concrete!(())),
|
|
||||||
NodeInput::Network(concrete!(f64)),
|
|
||||||
NodeInput::Network(concrete!(f64)),
|
|
||||||
NodeInput::Network(concrete!(bool)),
|
|
||||||
NodeInput::Network(generic!(T)),
|
|
||||||
NodeInput::Network(concrete!(bool)),
|
|
||||||
],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::RectangleGenerator<_, _, _, _, _>")),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
DocumentNode {
|
|
||||||
name: "Cull".to_string(),
|
|
||||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")),
|
|
||||||
manual_composition: Some(concrete!(Footprint)),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(id, node)| (NodeId(id as u64), node))
|
|
||||||
.collect(),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
DocumentInputType::none(),
|
DocumentInputType::none(),
|
||||||
DocumentInputType::value("Size X", TaggedValue::F64(100.), false),
|
DocumentInputType::value("Size X", TaggedValue::F64(100.), false),
|
||||||
|
|
@ -2312,30 +2196,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
name: "Regular Polygon",
|
name: "Regular Polygon",
|
||||||
category: "Vector",
|
category: "Vector",
|
||||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
implementation: DocumentNodeImplementation::proto("graphene_core::vector::generator_nodes::RegularPolygonGenerator<_, _>"),
|
||||||
imports: vec![NodeId(0), NodeId(0), NodeId(0)],
|
|
||||||
exports: vec![NodeOutput::new(NodeId(1), 0)],
|
|
||||||
nodes: vec![
|
|
||||||
DocumentNode {
|
|
||||||
name: "Regular Polygon Generator".to_string(),
|
|
||||||
inputs: vec![NodeInput::Network(concrete!(())), NodeInput::Network(concrete!(u32)), NodeInput::Network(concrete!(f64))],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::RegularPolygonGenerator<_, _>")),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
DocumentNode {
|
|
||||||
name: "Cull".to_string(),
|
|
||||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")),
|
|
||||||
manual_composition: Some(concrete!(Footprint)),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(id, node)| (NodeId(id as u64), node))
|
|
||||||
.collect(),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
DocumentInputType::none(),
|
DocumentInputType::none(),
|
||||||
DocumentInputType::value("Sides", TaggedValue::U32(6), false),
|
DocumentInputType::value("Sides", TaggedValue::U32(6), false),
|
||||||
|
|
@ -2348,35 +2209,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
name: "Star",
|
name: "Star",
|
||||||
category: "Vector",
|
category: "Vector",
|
||||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
implementation: DocumentNodeImplementation::proto("graphene_core::vector::generator_nodes::StarGenerator<_, _, _>"),
|
||||||
imports: vec![NodeId(0), NodeId(0), NodeId(0), NodeId(0)],
|
|
||||||
exports: vec![NodeOutput::new(NodeId(1), 0)],
|
|
||||||
nodes: vec![
|
|
||||||
DocumentNode {
|
|
||||||
name: "Star Generator".to_string(),
|
|
||||||
inputs: vec![
|
|
||||||
NodeInput::Network(concrete!(())),
|
|
||||||
NodeInput::Network(concrete!(u32)),
|
|
||||||
NodeInput::Network(concrete!(f64)),
|
|
||||||
NodeInput::Network(concrete!(f64)),
|
|
||||||
],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::StarGenerator<_, _, _>")),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
DocumentNode {
|
|
||||||
name: "Cull".to_string(),
|
|
||||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")),
|
|
||||||
manual_composition: Some(concrete!(Footprint)),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(id, node)| (NodeId(id as u64), node))
|
|
||||||
.collect(),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
DocumentInputType::none(),
|
DocumentInputType::none(),
|
||||||
DocumentInputType::value("Sides", TaggedValue::U32(5), false),
|
DocumentInputType::value("Sides", TaggedValue::U32(5), false),
|
||||||
|
|
@ -2390,30 +2223,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
name: "Line",
|
name: "Line",
|
||||||
category: "Vector",
|
category: "Vector",
|
||||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
implementation: DocumentNodeImplementation::proto("graphene_core::vector::generator_nodes::LineGenerator<_, _>"),
|
||||||
imports: vec![NodeId(0), NodeId(0), NodeId(0)],
|
|
||||||
exports: vec![NodeOutput::new(NodeId(1), 0)],
|
|
||||||
nodes: vec![
|
|
||||||
DocumentNode {
|
|
||||||
name: "Line Generator".to_string(),
|
|
||||||
inputs: vec![NodeInput::Network(concrete!(())), NodeInput::Network(concrete!(DVec2)), NodeInput::Network(concrete!(DVec2))],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::LineGenerator<_, _>")),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
DocumentNode {
|
|
||||||
name: "Cull".to_string(),
|
|
||||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")),
|
|
||||||
manual_composition: Some(concrete!(Footprint)),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(id, node)| (NodeId(id as u64), node))
|
|
||||||
.collect(),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
DocumentInputType::none(),
|
DocumentInputType::none(),
|
||||||
DocumentInputType::value("Start", TaggedValue::DVec2(DVec2::new(0., -50.)), false),
|
DocumentInputType::value("Start", TaggedValue::DVec2(DVec2::new(0., -50.)), false),
|
||||||
|
|
@ -2426,30 +2236,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
name: "Spline",
|
name: "Spline",
|
||||||
category: "Vector",
|
category: "Vector",
|
||||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
implementation: DocumentNodeImplementation::proto("graphene_core::vector::generator_nodes::SplineGenerator<_>"),
|
||||||
imports: vec![NodeId(0), NodeId(0)],
|
|
||||||
exports: vec![NodeOutput::new(NodeId(1), 0)],
|
|
||||||
nodes: vec![
|
|
||||||
DocumentNode {
|
|
||||||
name: "Spline Generator".to_string(),
|
|
||||||
inputs: vec![NodeInput::Network(concrete!(())), NodeInput::Network(concrete!(Vec<DVec2>))],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::SplineGenerator<_>")),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
DocumentNode {
|
|
||||||
name: "Cull".to_string(),
|
|
||||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")),
|
|
||||||
manual_composition: Some(concrete!(Footprint)),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(id, node)| (NodeId(id as u64), node))
|
|
||||||
.collect(),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
DocumentInputType::none(),
|
DocumentInputType::none(),
|
||||||
DocumentInputType::value("Points", TaggedValue::VecDVec2(vec![DVec2::new(0., -50.), DVec2::new(25., 0.), DVec2::new(0., 50.)]), false),
|
DocumentInputType::value("Points", TaggedValue::VecDVec2(vec![DVec2::new(0., -50.), DVec2::new(25., 0.), DVec2::new(0., 50.)]), false),
|
||||||
|
|
@ -2461,33 +2248,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
name: "Shape",
|
name: "Shape",
|
||||||
category: "Vector",
|
category: "Vector",
|
||||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
implementation: DocumentNodeImplementation::proto("graphene_core::vector::generator_nodes::PathGenerator<_>"),
|
||||||
imports: vec![NodeId(0), NodeId(0)],
|
|
||||||
exports: vec![NodeOutput::new(NodeId(1), 0)],
|
|
||||||
nodes: vec![
|
|
||||||
DocumentNode {
|
|
||||||
name: "Path Generator".to_string(),
|
|
||||||
inputs: vec![
|
|
||||||
NodeInput::Network(concrete!(Vec<bezier_rs::Subpath<graphene_core::uuid::ManipulatorGroupId>>)),
|
|
||||||
NodeInput::Network(concrete!(Vec<graphene_core::uuid::ManipulatorGroupId>)),
|
|
||||||
],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::PathGenerator<_>")),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
DocumentNode {
|
|
||||||
name: "Cull".to_string(),
|
|
||||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")),
|
|
||||||
manual_composition: Some(concrete!(Footprint)),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(id, node)| (NodeId(id as u64), node))
|
|
||||||
.collect(),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
DocumentInputType::value("Path Data", TaggedValue::Subpaths(vec![]), false),
|
DocumentInputType::value("Path Data", TaggedValue::Subpaths(vec![]), false),
|
||||||
DocumentInputType::value("Colinear Manipulators", TaggedValue::ManipulatorGroupIds(vec![]), false),
|
DocumentInputType::value("Colinear Manipulators", TaggedValue::ManipulatorGroupIds(vec![]), false),
|
||||||
|
|
@ -2525,35 +2286,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
name: "Text",
|
name: "Text",
|
||||||
category: "Vector",
|
category: "Vector",
|
||||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
implementation: DocumentNodeImplementation::proto("graphene_core::text::TextGeneratorNode<_, _, _>"),
|
||||||
imports: vec![NodeId(0), NodeId(0), NodeId(0), NodeId(0)],
|
|
||||||
exports: vec![NodeOutput::new(NodeId(1), 0)],
|
|
||||||
nodes: vec![
|
|
||||||
DocumentNode {
|
|
||||||
name: "Text Generator".to_string(),
|
|
||||||
inputs: vec![
|
|
||||||
NodeInput::Network(concrete!(application_io::EditorApi<graphene_std::wasm_application_io::WasmApplicationIo>)),
|
|
||||||
NodeInput::Network(concrete!(String)),
|
|
||||||
NodeInput::Network(concrete!(graphene_core::text::Font)),
|
|
||||||
NodeInput::Network(concrete!(f64)),
|
|
||||||
],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::text::TextGeneratorNode<_, _, _>")),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
DocumentNode {
|
|
||||||
name: "Cull".to_string(),
|
|
||||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")),
|
|
||||||
manual_composition: Some(concrete!(Footprint)),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(id, node)| (NodeId(id as u64), node))
|
|
||||||
.collect(),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
DocumentInputType::none(),
|
DocumentInputType::none(),
|
||||||
DocumentInputType::value("Text", TaggedValue::String("Lorem ipsum".to_string()), false),
|
DocumentInputType::value("Text", TaggedValue::String("Lorem ipsum".to_string()), false),
|
||||||
|
|
|
||||||
|
|
@ -969,7 +969,7 @@ impl NodeNetwork {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace value inputs with value nodes
|
// Replace value inputs with value nodes
|
||||||
for input in node.inputs.iter_mut() {
|
for input in node.inputs.iter_mut() {
|
||||||
// Skip inputs that are already value nodes
|
// Skip inputs that are already value nodes
|
||||||
if node.implementation == DocumentNodeImplementation::ProtoNode("graphene_core::value::ClonedNode".into()) {
|
if node.implementation == DocumentNodeImplementation::ProtoNode("graphene_core::value::ClonedNode".into()) {
|
||||||
|
|
|
||||||
|
|
@ -735,14 +735,28 @@ impl TypingContext {
|
||||||
}) {
|
}) {
|
||||||
return Err(vec![GraphError::new(node, GraphErrorType::UnexpectedGenerics { index, parameters })]);
|
return Err(vec![GraphError::new(node, GraphErrorType::UnexpectedGenerics { index, parameters })]);
|
||||||
}
|
}
|
||||||
fn covariant(from: &Type, to: &Type) -> bool {
|
|
||||||
|
/// Checks if a proposed input to a particular (primary or secondary) input is valid for its type signature.
|
||||||
|
/// `from` indicates the value given to a input, `to` indicates the input's allowed type as specified by its type signature.
|
||||||
|
fn valid_subtype(from: &Type, to: &Type) -> bool {
|
||||||
match (from, to) {
|
match (from, to) {
|
||||||
(Type::Concrete(t1), Type::Concrete(t2)) => t1 == t2,
|
// Direct comparison of two concrete types.
|
||||||
(Type::Fn(a1, b1), Type::Fn(a2, b2)) => covariant(a1, a2) && covariant(b1, b2),
|
(Type::Concrete(type1), Type::Concrete(type2)) => type1 == type2,
|
||||||
|
// Loose comparison of function types, where loose means that functions are considered on a "greater than or equal to" basis of its function type's generality.
|
||||||
|
// That means we compare their types with a contravariant relationship, which means that a more general type signature may be substituted for a more specific type signature.
|
||||||
|
// For example, we allow `T -> V` to be substituted with `T' -> V` or `() -> V` where T' and () are more specific than T.
|
||||||
|
// This allows us to supply anything to a function that is satisfied with `()`.
|
||||||
|
// In other words, we are implementing these two relations, where the >= operator means that the left side is more general than the right side:
|
||||||
|
// - `T >= T' ⇒ (T' -> V) >= (T -> V)` (functions are contravariant in their input types)
|
||||||
|
// - `V >= V' ⇒ (T -> V) >= (T -> V')` (functions are covariant in their output types)
|
||||||
|
// While these two relations aren't a truth about the universe, they are a design decision that we are employing in our language design that is also common in other languages.
|
||||||
|
// For example, Rust implements these same relations as it describes here: <https://doc.rust-lang.org/nomicon/subtyping.html>
|
||||||
|
// More details explained here: <https://github.com/GraphiteEditor/Graphite/issues/1741>
|
||||||
|
(Type::Fn(in1, out1), Type::Fn(in2, out2)) => valid_subtype(out1, out2) && (valid_subtype(in1, in2) || **in1 == concrete!(())),
|
||||||
|
// 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
|
// TODO: Add proper generic counting which is not based on the name
|
||||||
(Type::Generic(_), Type::Generic(_)) => true,
|
(Type::Generic(_), _) | (_, Type::Generic(_)) => true,
|
||||||
(Type::Generic(_), _) => true,
|
// Reject unknown type relationships.
|
||||||
(_, Type::Generic(_)) => true,
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -750,7 +764,7 @@ impl TypingContext {
|
||||||
// List of all implementations that match the input and parameter types
|
// List of all implementations that match the input and parameter types
|
||||||
let valid_output_types = impls
|
let valid_output_types = impls
|
||||||
.keys()
|
.keys()
|
||||||
.filter(|node_io| covariant(&input, &node_io.input) && parameters.iter().zip(node_io.parameters.iter()).all(|(p1, p2)| covariant(p1, p2)))
|
.filter(|node_io| valid_subtype(&input, &node_io.input) && parameters.iter().zip(node_io.parameters.iter()).all(|(p1, p2)| valid_subtype(p1, p2)))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// Attempt to substitute generic types with concrete types and save the list of results
|
// Attempt to substitute generic types with concrete types and save the list of results
|
||||||
|
|
@ -785,7 +799,7 @@ impl TypingContext {
|
||||||
.cloned()
|
.cloned()
|
||||||
.zip([&node_io.input].into_iter().chain(&node_io.parameters).cloned())
|
.zip([&node_io.input].into_iter().chain(&node_io.parameters).cloned())
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|(_, (p1, p2))| !covariant(p1, p2))
|
.filter(|(_, (p1, p2))| !valid_subtype(p1, p2))
|
||||||
.map(|(index, ty)| (node.original_location.inputs(index).min_by_key(|s| s.node.len()).map(|s| s.index).unwrap_or(index), ty))
|
.map(|(index, ty)| (node.original_location.inputs(index).min_by_key(|s| s.node.len()).map(|s| s.index).unwrap_or(index), ty))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
if current_errors.len() < best_errors {
|
if current_errors.len() < best_errors {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
use dyn_any::StaticType;
|
|
||||||
pub use graph_craft::proto::{Any, NodeContainer, TypeErasedBox, TypeErasedNode};
|
pub use graph_craft::proto::{Any, NodeContainer, TypeErasedBox, TypeErasedNode};
|
||||||
use graph_craft::proto::{DynFuture, FutureAny, SharedNodeContainer};
|
use graph_craft::proto::{DynFuture, FutureAny, SharedNodeContainer};
|
||||||
use graphene_core::NodeIO;
|
use graphene_core::NodeIO;
|
||||||
pub use graphene_core::{generic, ops, Node};
|
pub use graphene_core::{generic, ops, Node};
|
||||||
|
|
||||||
|
use dyn_any::StaticType;
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
pub struct DynAnyNode<I, O, Node> {
|
pub struct DynAnyNode<I, O, Node> {
|
||||||
|
|
@ -19,12 +21,21 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eval(&'input self, input: Any<'input>) -> Self::Output {
|
fn eval(&'input self, input: Any<'input>) -> Self::Output {
|
||||||
let node_name = core::any::type_name::<N>();
|
let node_name = core::any::type_name::<N>();
|
||||||
let input: Box<_I> = dyn_any::downcast(input).unwrap_or_else(|e| panic!("DynAnyNode Input, {0} in:\n{1}", e, node_name));
|
let output = |input| async move {
|
||||||
let output = async move {
|
let result = self.node.eval(input).await;
|
||||||
let result = self.node.eval(*input).await;
|
|
||||||
Box::new(result) as Any<'input>
|
Box::new(result) as Any<'input>
|
||||||
};
|
};
|
||||||
Box::pin(output)
|
match dyn_any::downcast(input) {
|
||||||
|
Ok(input) => Box::pin(output(*input)),
|
||||||
|
// If the input type of the node is `()` and we supply an invalid type, we can still call the
|
||||||
|
// node and just ignore the input and call it with the unit type instead.
|
||||||
|
Err(_) if core::any::TypeId::of::<_I::Static>() == core::any::TypeId::of::<()>() => {
|
||||||
|
assert_eq!(std::mem::size_of::<_I>(), 0);
|
||||||
|
// Rust can't know, that `_I` and `()` are the same size, so we have to use a `transmute_copy()` here
|
||||||
|
Box::pin(output(unsafe { std::mem::transmute_copy(&()) }))
|
||||||
|
}
|
||||||
|
Err(e) => panic!("DynAnyNode Input, {0} in:\n{1}", e, node_name),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset(&self) {
|
fn reset(&self) {
|
||||||
|
|
@ -67,6 +78,9 @@ where
|
||||||
fn reset(&self) {
|
fn reset(&self) {
|
||||||
self.node.reset();
|
self.node.reset();
|
||||||
}
|
}
|
||||||
|
fn serialize(&self) -> Option<std::sync::Arc<dyn core::any::Any>> {
|
||||||
|
self.node.serialize()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<_I, _O, S0> DynAnyRefNode<_I, _O, S0> {
|
impl<_I, _O, S0> DynAnyRefNode<_I, _O, S0> {
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ let
|
||||||
rustc-wasm = pkgs.rust-bin.stable.latest.default.override {
|
rustc-wasm = pkgs.rust-bin.stable.latest.default.override {
|
||||||
targets = [ "wasm32-unknown-unknown" ];
|
targets = [ "wasm32-unknown-unknown" ];
|
||||||
# wasm-pack needs this
|
# wasm-pack needs this
|
||||||
extensions = [ "rust-src" ];
|
extensions = [ "rust-src" "rust-analyzer" "clippy" ];
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
# Make a shell with the dependencies we need
|
# Make a shell with the dependencies we need
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue