Skip to content

Commit 75f3fa1

Browse files
committed
Refactor Typesource
1 parent e3073bf commit 75f3fa1

File tree

3 files changed

+111
-21
lines changed

3 files changed

+111
-21
lines changed

editor/src/messages/portfolio/document/utility_types/network_interface.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -671,7 +671,7 @@ impl NodeNetworkInterface {
671671
resolved_type,
672672
name,
673673
description,
674-
valid_types: self.valid_input_types(input_connector, network_path).iter().map(|ty| ty.to_string()).collect(),
674+
valid_types: self.potential_valid_input_types(input_connector, network_path).iter().map(|ty| ty.to_string()).collect(),
675675
connected_to,
676676
})
677677
}

editor/src/messages/portfolio/document/utility_types/network_interface/resolved_types.rs

Lines changed: 96 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
22

33
use graph_craft::document::value::TaggedValue;
44
use graph_craft::document::{DocumentNodeImplementation, InlineRust, NodeInput};
5-
use graph_craft::{Type, concrete};
5+
use graph_craft::{ProtoNodeIdentifier, Type, concrete};
66
use graphene_std::uuid::NodeId;
77
use interpreted_executor::dynamic_executor::{NodeTypes, ResolvedDocumentNodeTypesDelta};
88
use interpreted_executor::node_registry::NODE_REGISTRY;
@@ -43,6 +43,32 @@ pub enum TypeSource {
4343
}
4444

4545
impl TypeSource {
46+
/// The reduced set of frontend types for displaying color.
47+
pub fn displayed_type(&self) -> FrontendGraphDataType {
48+
match self.compiled_nested_type() {
49+
Some(nested_type) => match TaggedValue::from_type_or_none(nested_type) {
50+
TaggedValue::U32(_)
51+
| TaggedValue::U64(_)
52+
| TaggedValue::F32(_)
53+
| TaggedValue::F64(_)
54+
| TaggedValue::DVec2(_)
55+
| TaggedValue::F64Array4(_)
56+
| TaggedValue::VecF64(_)
57+
| TaggedValue::VecDVec2(_)
58+
| TaggedValue::DAffine2(_) => FrontendGraphDataType::Number,
59+
TaggedValue::Artboard(_) => FrontendGraphDataType::Artboard,
60+
TaggedValue::Graphic(_) => FrontendGraphDataType::Graphic,
61+
TaggedValue::Raster(_) => FrontendGraphDataType::Raster,
62+
TaggedValue::Vector(_) => FrontendGraphDataType::Vector,
63+
TaggedValue::Color(_) => FrontendGraphDataType::Color,
64+
TaggedValue::Gradient(_) | TaggedValue::GradientStops(_) | TaggedValue::GradientTable(_) => FrontendGraphDataType::Gradient,
65+
TaggedValue::String(_) => FrontendGraphDataType::Typography,
66+
_ => FrontendGraphDataType::General,
67+
},
68+
None => FrontendGraphDataType::General,
69+
}
70+
}
71+
4672
pub fn compiled_nested_type(&self) -> Option<&Type> {
4773
match self {
4874
TypeSource::Compiled(compiled_type) => Some(compiled_type.nested_type()),
@@ -71,14 +97,6 @@ impl TypeSource {
7197
TypeSource::Error(_) => "Error".to_string(),
7298
}
7399
}
74-
75-
/// The reduced set of frontend types for displaying color.
76-
pub fn displayed_type(&self) -> FrontendGraphDataType {
77-
match self.compiled_nested_type() {
78-
Some(nested_type) => FrontendGraphDataType::from_type(nested_type),
79-
None => FrontendGraphDataType::General,
80-
}
81-
}
82100
}
83101

84102
impl NodeNetworkInterface {
@@ -126,7 +144,7 @@ impl NodeNetworkInterface {
126144
TypeSource::TaggedValue(value) => value,
127145
TypeSource::DocumentNodeDefinition(definition) => definition,
128146
TypeSource::Unknown => {
129-
let mut valid_types = self.valid_input_types(input_connector, network_path);
147+
let mut valid_types = self.potential_valid_input_types(input_connector, network_path);
130148

131149
match valid_types.pop() {
132150
Some(valid_type) => valid_type,
@@ -147,7 +165,8 @@ impl NodeNetworkInterface {
147165
TaggedValue::from_type_or_none(&guaranteed_type)
148166
}
149167

150-
pub fn valid_input_types(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) -> Vec<Type> {
168+
/// A list of all valid input types for this specific node.
169+
pub fn potential_valid_input_types(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) -> Vec<Type> {
151170
let InputConnector::Node { node_id, input_index } = input_connector else {
152171
// An export can have any type connected to it
153172
return vec![graph_craft::generic!(T)];
@@ -171,7 +190,7 @@ impl NodeNetworkInterface {
171190
let intersection: HashSet<Type> = inputs_from_import
172191
.clone()
173192
.iter()
174-
.map(|input_connector| self.valid_input_types(input_connector, &nested_path).into_iter().collect::<HashSet<_>>())
193+
.map(|input_connector| self.potential_valid_input_types(input_connector, &nested_path).into_iter().collect::<HashSet<_>>())
175194
.fold(None, |acc: Option<HashSet<Type>>, set| match acc {
176195
Some(acc_set) => Some(acc_set.intersection(&set).cloned().collect()),
177196
None => Some(set),
@@ -191,10 +210,9 @@ impl NodeNetworkInterface {
191210
.filter_map(|(node_io, _)| {
192211
let valid_implementation = (0..number_of_inputs).filter(|iterator_index| iterator_index != input_index).all(|iterator_index| {
193212
let input_type = self.input_type(&InputConnector::node(*node_id, iterator_index), network_path);
194-
// Value inputs are stored as concrete, so they are compared to the nested type. Node inputs are stored as fn, so they are compared to the entire type.
195-
// For example a node input of (Footprint) -> Vector would not be compatible with () -> Vector
196-
node_io.inputs.get(iterator_index).map(|ty| ty.nested_type().clone()).as_ref() == input_type.compiled_nested_type()
197-
|| node_io.inputs.get(iterator_index) == input_type.compiled_nested_type()
213+
// TODO: Fix type checking for different call arguments
214+
// For example a node input of (Footprint) -> Vector would not be compatible with a node that is called with () and returns Vector
215+
node_io.inputs.get(iterator_index).map(|ty| ty.nested_type()) == input_type.compiled_nested_type()
198216
});
199217
if valid_implementation { node_io.inputs.get(*input_index).cloned() } else { None }
200218
})
@@ -207,6 +225,66 @@ impl NodeNetworkInterface {
207225
}
208226
}
209227

228+
/// Performs a downstream traversal to ensure input type will work in the full context of the graph.
229+
pub fn complete_valid_input_types(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) -> Result<Vec<Type>, String> {
230+
match input_connector {
231+
InputConnector::Node { node_id, input_index } => {
232+
let Some(implementation) = self.implementation(node_id, network_path) else {
233+
return Err(format!("Could not get node implementation for {:?} {} in valid_input_types", network_path, *node_id));
234+
};
235+
match implementation {
236+
DocumentNodeImplementation::Network(_) => self.valid_output_types(&OutputConnector::Import(input_connector.input_index()), &[network_path, &[*node_id]].concat()),
237+
DocumentNodeImplementation::ProtoNode(proto_node_identifier) => {
238+
let Some(implementations) = NODE_REGISTRY.get(proto_node_identifier) else {
239+
return Err(format!("Protonode {proto_node_identifier:?} not found in registry"));
240+
};
241+
let valid_output_types = match self.valid_output_types(&OutputConnector::node(*node_id, 0), network_path) {
242+
Ok(valid_types) => valid_types,
243+
Err(e) => return Err(e),
244+
};
245+
246+
let valid_types = implementations
247+
.iter()
248+
.filter_map(|(node_io, _)| {
249+
if !valid_output_types.iter().any(|output_type| output_type.nested_type() == node_io.return_value.nested_type()) {
250+
return None;
251+
}
252+
253+
let valid_inputs = (0..node_io.inputs.len()).filter(|iterator_index| iterator_index != input_index).all(|iterator_index| {
254+
let input_type = self.input_type(&InputConnector::node(*node_id, iterator_index), network_path);
255+
match input_type.compiled_nested_type() {
256+
Some(input_type) => node_io.inputs.get(iterator_index).is_some_and(|node_io_input_type| node_io_input_type.nested_type() == input_type),
257+
None => true,
258+
}
259+
});
260+
if valid_inputs { node_io.inputs.get(*input_index).cloned() } else { None }
261+
})
262+
.collect::<Vec<_>>();
263+
Ok(valid_types)
264+
}
265+
DocumentNodeImplementation::Extract => {
266+
log::error!("Input types for extract node not supported");
267+
Ok(Vec::new())
268+
}
269+
}
270+
}
271+
InputConnector::Export(export_index) => {
272+
match network_path.split_last() {
273+
Some((encapsulating_node, encapsulating_path)) => self.valid_output_types(&OutputConnector::node(*encapsulating_node, *export_index), encapsulating_path),
274+
None => {
275+
// Valid types for the export are all types that can be fed into the render node
276+
// TODO: Use ::IDENTIFIER
277+
let render_node = "graphene_std::wasm_application_io::RenderNode";
278+
let Some(implementations) = NODE_REGISTRY.get(&ProtoNodeIdentifier::new(render_node)) else {
279+
return Err(format!("Protonode {render_node:?} not found in registry"));
280+
};
281+
Ok(implementations.iter().map(|(types, _)| types.inputs[1].clone()).collect())
282+
}
283+
}
284+
}
285+
}
286+
}
287+
210288
pub fn output_type(&mut self, output_connector: &OutputConnector, network_path: &[NodeId]) -> TypeSource {
211289
match output_connector {
212290
OutputConnector::Node { node_id, output_index } => {
@@ -243,7 +321,7 @@ impl NodeNetworkInterface {
243321
let intersection = inputs_from_import
244322
.clone()
245323
.iter()
246-
.map(|input_connector| self.valid_input_types(input_connector, &network_path).into_iter().collect::<HashSet<_>>())
324+
.map(|input_connector| self.potential_valid_input_types(input_connector, &network_path).into_iter().collect::<HashSet<_>>())
247325
.fold(None, |acc: Option<HashSet<Type>>, set| match acc {
248326
Some(acc_set) => Some(acc_set.intersection(&set).cloned().collect()),
249327
None => Some(set),
@@ -281,7 +359,7 @@ impl NodeNetworkInterface {
281359
log::error!("Protonode {proto_node_identifier:?} not found in registry");
282360
return None;
283361
};
284-
implementations.keys().next().and_then(|node_io| node_io.inputs.get(input_connector.input_index())).cloned()
362+
implementations.keys().min().and_then(|node_io| node_io.inputs.get(input_connector.input_index())).cloned()
285363
}
286364
DocumentNodeImplementation::Extract => None,
287365
}

node-graph/gcore/src/types.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ macro_rules! fn_type_fut {
7777
};
7878
}
7979

80-
#[derive(Clone, PartialEq, Eq, Hash, Default, serde::Serialize, serde::Deserialize)]
80+
#[derive(Clone, PartialEq, Eq, Hash, Default, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
8181
pub struct NodeIOTypes {
8282
pub call_argument: Type,
8383
pub return_value: Type,
@@ -229,8 +229,20 @@ impl PartialEq for TypeDescriptor {
229229
}
230230
}
231231

232+
impl Ord for TypeDescriptor {
233+
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
234+
self.name.cmp(&other.name)
235+
}
236+
}
237+
238+
impl PartialOrd for TypeDescriptor {
239+
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
240+
Some(self.cmp(other))
241+
}
242+
}
243+
232244
/// Graph runtime type information used for type inference.
233-
#[derive(Clone, PartialEq, Eq, Hash, specta::Type, serde::Serialize, serde::Deserialize)]
245+
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, specta::Type, serde::Serialize, serde::Deserialize)]
234246
pub enum Type {
235247
/// A wrapper for some type variable used within the inference system. Resolved at inference time and replaced with a concrete type.
236248
Generic(Cow<'static, str>),

0 commit comments

Comments
 (0)