Consolidate and rename Graphene data types, and add many comments (#1620)

* Document ProtoNodeInput

* More comments

* Comment improvements

* Comment and split ProtoNodeInput::NodeLambda from ProtoNodeInput::Node

* Combine NodeImplementation into DocumentNodeImplementation

---------

Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
Keavon Chambers
2024-02-20 17:53:04 -08:00
committed by GitHub
co-authored by Dennis Kobert
parent dc7de4d973
commit a02b162e30
20 changed files with 468 additions and 467 deletions
+54 -36
View File
@@ -26,7 +26,7 @@ pub type TypeErasedPinned<'n> = Pin<Box<TypeErasedNode<'n>>>;
pub type SharedNodeContainer = std::rc::Rc<NodeContainer>;
pub type NodeConstructor = for<'a> fn(Vec<SharedNodeContainer>) -> DynFuture<'static, TypeErasedBox<'static>>;
pub type NodeConstructor = fn(Vec<SharedNodeContainer>) -> DynFuture<'static, TypeErasedBox<'static>>;
#[derive(Clone)]
pub struct NodeContainer {
@@ -109,7 +109,8 @@ impl core::fmt::Display for ProtoNetwork {
match &node.input {
ProtoNodeInput::None => f.write_str("None")?,
ProtoNodeInput::ManualComposition(ty) => f.write_fmt(format_args!("Manual Composition (type = {ty:?})"))?,
ProtoNodeInput::Node(_, _) => f.write_str("Node")?,
ProtoNodeInput::Node(_) => f.write_str("Node")?,
ProtoNodeInput::NodeLambda(_) => f.write_str("Lambda Node")?,
}
f.write_str("\n")?;
@@ -232,28 +233,31 @@ impl Default for ProtoNode {
pub enum ProtoNodeInput {
/// [`ProtoNode`]s do not require any input, e.g. the value node just takes in [`ConstructionArgs`].
None,
/// A ManualComposition input represents an input that opts out of being resolved through the default `ComposeNode`, which first runs the previous (upstream) node, then passes that evaluated result to this node
/// Instead, ManualComposition lets this node actually consume the provided input instead of passing it to its predecessor.
/// A ManualComposition input represents an input that opts out of being resolved through the default `ComposeNode`, which first runs the previous (upstream) node, then passes that evaluated
/// result to this node. Instead, ManualComposition lets this node actually consume the provided input instead of passing it to its predecessor.
///
/// Say we have the network `a -> b -> c` where `c` is the output node and `a` is the input node.
/// We would expect `a` to get input from the network, `b` to get input from `a`, and `c` to get input from `b`.
/// This could be represented as `f(x) = c(b(a(x)))`. `a` is run with input `x` from the network. `b` is run with input from `a`. `c` is run with input from `b`.
///
/// However if `b`'s input is using manual composition, this means it would instead be `f(x) = c(b(x))`. This means that `b` actually gets input from the network, and `a` is not automatically executed as it would be using the default ComposeNode flow.
/// However if `b`'s input is using manual composition, this means it would instead be `f(x) = c(b(x))`. This means that `b` actually gets input from the network, and `a` is not automatically
/// executed as it would be using the default ComposeNode flow. Now `b` can use its own logic to decide when or if it wants to run `a` and how to use its output. For example, the CacheNode can
/// look up `x` in its cache and return the result, or otherwise call `a`, cache the result, and return it.
ManualComposition(Type),
/// the bool indicates whether to treat the node as lambda node.
/// When treating it as a lambda, only the node that is connected itself is fed as input.
/// Otherwise, the the entire network of which the node is the output is fed as input.
Node(NodeId, bool),
}
impl ProtoNodeInput {
pub fn unwrap_node(self) -> NodeId {
match self {
ProtoNodeInput::Node(id, _) => id,
_ => panic!("tried to unwrap id from non node input \n node: {self:#?}"),
}
}
/// The previous node where automatic (not manual) composition occurs when compiled. The entire network, of which the node is the output, is fed as input.
///
/// Grayscale example:
///
/// We're interested in receiving an input of the desaturated image data which has been fed through a grayscale filter.
/// (If we were interested in the grayscale filter itself, we would use the `NodeLambda` variant.)
Node(NodeId),
/// Unlike the `Node` variant, with `NodeLambda` we treat the connected node singularly as a lambda node while ignoring all nodes which feed into it from upstream.
///
/// Grayscale example:
///
/// We're interested in receiving an input of a particular image filter, such as a grayscale filter in the form of a grayscale node lambda.
/// (If we were interested in some image data that had been fed through a grayscale filter, we would use the `Node` variant.)
NodeLambda(NodeId),
}
impl ProtoNode {
@@ -275,7 +279,8 @@ impl ProtoNode {
ProtoNodeInput::ManualComposition(ref ty) => {
ty.hash(&mut hasher);
}
ProtoNodeInput::Node(id, lambda) => (id, lambda).hash(&mut hasher),
ProtoNodeInput::Node(id) => (id, false).hash(&mut hasher),
ProtoNodeInput::NodeLambda(id) => (id, true).hash(&mut hasher),
};
Some(NodeId(hasher.finish()))
}
@@ -303,11 +308,16 @@ impl ProtoNode {
/// Converts all references to other node IDs into new IDs by running the specified function on them.
/// This can be used when changing the IDs of the nodes, for example in the case of generating stable IDs.
pub fn map_ids(&mut self, f: impl Fn(NodeId) -> NodeId, skip_lambdas: bool) {
if let ProtoNodeInput::Node(id, lambda) = self.input {
if !(skip_lambdas && lambda) {
self.input = ProtoNodeInput::Node(f(id), lambda)
match self.input {
ProtoNodeInput::Node(id) => self.input = ProtoNodeInput::Node(f(id)),
ProtoNodeInput::NodeLambda(id) => {
if !skip_lambdas {
self.input = ProtoNodeInput::NodeLambda(f(id))
}
}
_ => (),
}
if let ConstructionArgs::Nodes(ids) = &mut self.construction_args {
ids.iter_mut().filter(|(_, lambda)| !(skip_lambdas && *lambda)).for_each(|(id, _)| *id = f(*id));
}
@@ -333,10 +343,14 @@ impl ProtoNetwork {
pub fn collect_outwards_edges(&self) -> HashMap<NodeId, Vec<NodeId>> {
let mut edges: HashMap<NodeId, Vec<NodeId>> = HashMap::new();
for (id, node) in &self.nodes {
if let ProtoNodeInput::Node(ref_id, _) = &node.input {
self.check_ref(ref_id, id);
edges.entry(*ref_id).or_default().push(*id)
match &node.input {
ProtoNodeInput::Node(ref_id) | ProtoNodeInput::NodeLambda(ref_id) => {
self.check_ref(ref_id, id);
edges.entry(*ref_id).or_default().push(*id)
}
_ => (),
}
if let ConstructionArgs::Nodes(ref_nodes) = &node.construction_args {
for (ref_id, _) in ref_nodes {
self.check_ref(ref_id, id);
@@ -366,10 +380,14 @@ impl ProtoNetwork {
pub fn collect_inwards_edges(&self) -> HashMap<NodeId, Vec<NodeId>> {
let mut edges: HashMap<NodeId, Vec<NodeId>> = HashMap::new();
for (id, node) in &self.nodes {
if let ProtoNodeInput::Node(ref_id, _) = &node.input {
self.check_ref(ref_id, id);
edges.entry(*id).or_default().push(*ref_id)
match &node.input {
ProtoNodeInput::Node(ref_id) | ProtoNodeInput::NodeLambda(ref_id) => {
self.check_ref(ref_id, id);
edges.entry(*id).or_default().push(*ref_id)
}
_ => (),
}
if let ConstructionArgs::Nodes(ref_nodes) = &node.construction_args {
for (ref_id, _) in ref_nodes {
self.check_ref(ref_id, id);
@@ -396,7 +414,7 @@ impl ProtoNetwork {
let (_, node) = &mut self.nodes[node_id.0 as usize];
if let ProtoNodeInput::Node(input_node_id, false) = node.input {
if let ProtoNodeInput::Node(input_node_id) = node.input {
// Create a new node that composes the current node and its input node
let compose_node_id = NodeId(self.nodes.len() as u64);
@@ -701,11 +719,11 @@ impl TypingContext {
ConstructionArgs::Inline(ref inline) => vec![inline.ty.clone()],
};
// Get the node input type from the proto node declaration
// Get the node input type from the protonode declaration
let input = match node.input {
ProtoNodeInput::None => concrete!(()),
ProtoNodeInput::ManualComposition(ref ty) => ty.clone(),
ProtoNodeInput::Node(id, _) => {
ProtoNodeInput::Node(id) | ProtoNodeInput::NodeLambda(id) => {
let input = self.inferred.get(&id).ok_or_else(|| vec![GraphError::new(node, GraphErrorType::InputNodeNotFound(id))])?;
input.output.clone()
}
@@ -919,7 +937,7 @@ mod test {
NodeId(7),
ProtoNode {
identifier: "id".into(),
input: ProtoNodeInput::Node(NodeId(11), false),
input: ProtoNodeInput::Node(NodeId(11)),
construction_args: ConstructionArgs::Nodes(vec![]),
..Default::default()
},
@@ -928,7 +946,7 @@ mod test {
NodeId(1),
ProtoNode {
identifier: "id".into(),
input: ProtoNodeInput::Node(NodeId(11), false),
input: ProtoNodeInput::Node(NodeId(11)),
construction_args: ConstructionArgs::Nodes(vec![]),
..Default::default()
},
@@ -946,7 +964,7 @@ mod test {
NodeId(11),
ProtoNode {
identifier: "add".into(),
input: ProtoNodeInput::Node(NodeId(10), false),
input: ProtoNodeInput::Node(NodeId(10)),
construction_args: ConstructionArgs::Nodes(vec![]),
..Default::default()
},
@@ -975,7 +993,7 @@ mod test {
NodeId(1),
ProtoNode {
identifier: "id".into(),
input: ProtoNodeInput::Node(NodeId(2), false),
input: ProtoNodeInput::Node(NodeId(2)),
construction_args: ConstructionArgs::Nodes(vec![]),
..Default::default()
},
@@ -984,7 +1002,7 @@ mod test {
NodeId(2),
ProtoNode {
identifier: "id".into(),
input: ProtoNodeInput::Node(NodeId(1), false),
input: ProtoNodeInput::Node(NodeId(1)),
construction_args: ConstructionArgs::Nodes(vec![]),
..Default::default()
},