1use std::{borrow::Cow, fmt::Debug};
2
3use downcast_rs::{impl_downcast, Downcast};
4use thiserror::Error;
5
6use super::{
7 Edge, InputSlotError, OutputSlotError, RenderGraphContext, RenderGraphError, RunSubGraphError,
8 SlotInfo, SlotInfos,
9};
10use crate::{render::RenderResources, tcs::world::World};
11
12pub struct RenderContext<'d> {
17 pub device: &'d wgpu::Device,
18 pub command_encoder: wgpu::CommandEncoder,
19}
20
21#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
26pub struct NodeId(usize);
27
28impl NodeId {
29 #[allow(clippy::new_without_default)]
30 pub fn new(id: usize) -> Self {
31 NodeId(id)
32 }
33}
34
35pub trait Node: Downcast + Send + Sync + 'static {
48 fn input(&self) -> Vec<SlotInfo> {
51 Vec::new()
52 }
53
54 fn output(&self) -> Vec<SlotInfo> {
57 Vec::new()
58 }
59
60 fn update(&mut self, _state: &mut RenderResources) {}
62
63 fn run(
67 &self,
68 graph: &mut RenderGraphContext,
69 render_context: &mut RenderContext,
70 resources: &RenderResources,
71 world: &World,
72 ) -> Result<(), NodeRunError>;
73}
74
75impl_downcast!(Node);
76
77#[derive(Error, Debug, Eq, PartialEq)]
78pub enum NodeRunError {
79 #[error("encountered an input slot error")]
80 InputSlotError(#[from] InputSlotError),
81 #[error("encountered an output slot error")]
82 OutputSlotError(#[from] OutputSlotError),
83 #[error("encountered an error when running a sub-graph")]
84 RunSubGraphError(#[from] RunSubGraphError),
85}
86
87#[derive(Debug)]
89pub struct Edges {
90 id: NodeId,
91 input_edges: Vec<Edge>,
92 output_edges: Vec<Edge>,
93}
94
95impl Edges {
96 #[inline]
98 pub fn input_edges(&self) -> &[Edge] {
99 &self.input_edges
100 }
101
102 #[inline]
104 pub fn output_edges(&self) -> &[Edge] {
105 &self.output_edges
106 }
107
108 #[inline]
110 pub fn id(&self) -> NodeId {
111 self.id
112 }
113
114 pub(crate) fn add_input_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> {
116 if self.has_input_edge(&edge) {
117 return Err(RenderGraphError::EdgeAlreadyExists(edge));
118 }
119 self.input_edges.push(edge);
120 Ok(())
121 }
122
123 pub(crate) fn remove_input_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> {
125 if let Some((index, _)) = self
126 .input_edges
127 .iter()
128 .enumerate()
129 .find(|(_i, e)| **e == edge)
130 {
131 self.input_edges.swap_remove(index);
132 Ok(())
133 } else {
134 Err(RenderGraphError::EdgeDoesNotExist(edge))
135 }
136 }
137
138 pub(crate) fn add_output_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> {
140 if self.has_output_edge(&edge) {
141 return Err(RenderGraphError::EdgeAlreadyExists(edge));
142 }
143 self.output_edges.push(edge);
144 Ok(())
145 }
146
147 pub(crate) fn remove_output_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> {
149 if let Some((index, _)) = self
150 .output_edges
151 .iter()
152 .enumerate()
153 .find(|(_i, e)| **e == edge)
154 {
155 self.output_edges.swap_remove(index);
156 Ok(())
157 } else {
158 Err(RenderGraphError::EdgeDoesNotExist(edge))
159 }
160 }
161
162 pub fn has_input_edge(&self, edge: &Edge) -> bool {
164 self.input_edges.contains(edge)
165 }
166
167 pub fn has_output_edge(&self, edge: &Edge) -> bool {
169 self.output_edges.contains(edge)
170 }
171
172 pub fn get_input_slot_edge(&self, index: usize) -> Result<&Edge, RenderGraphError> {
175 self.input_edges
176 .iter()
177 .find(|e| {
178 if let Edge::SlotEdge { input_index, .. } = e {
179 *input_index == index
180 } else {
181 false
182 }
183 })
184 .ok_or(RenderGraphError::UnconnectedNodeInputSlot {
185 input_slot: index,
186 node: self.id,
187 })
188 }
189
190 pub fn get_output_slot_edge(&self, index: usize) -> Result<&Edge, RenderGraphError> {
193 self.output_edges
194 .iter()
195 .find(|e| {
196 if let Edge::SlotEdge { output_index, .. } = e {
197 *output_index == index
198 } else {
199 false
200 }
201 })
202 .ok_or(RenderGraphError::UnconnectedNodeOutputSlot {
203 output_slot: index,
204 node: self.id,
205 })
206 }
207}
208
209pub struct NodeState {
214 pub id: NodeId,
215 pub name: Option<Cow<'static, str>>,
216 pub type_name: &'static str,
218 pub node: Box<dyn Node>,
219 pub input_slots: SlotInfos,
220 pub output_slots: SlotInfos,
221 pub edges: Edges,
222}
223
224impl Debug for NodeState {
225 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
226 writeln!(f, "{:?} ({:?})", self.id, self.name)
227 }
228}
229
230impl NodeState {
231 pub fn new<T>(id: NodeId, node: T) -> Self
234 where
235 T: Node,
236 {
237 NodeState {
238 id,
239 name: None,
240 input_slots: node.input().into(),
241 output_slots: node.output().into(),
242 node: Box::new(node),
243 type_name: std::any::type_name::<T>(),
244 edges: Edges {
245 id,
246 input_edges: Vec::new(),
247 output_edges: Vec::new(),
248 },
249 }
250 }
251
252 pub fn node<T>(&self) -> Result<&T, RenderGraphError>
254 where
255 T: Node,
256 {
257 self.node
258 .downcast_ref::<T>()
259 .ok_or(RenderGraphError::WrongNodeType)
260 }
261
262 pub fn node_mut<T>(&mut self) -> Result<&mut T, RenderGraphError>
264 where
265 T: Node,
266 {
267 self.node
268 .downcast_mut::<T>()
269 .ok_or(RenderGraphError::WrongNodeType)
270 }
271
272 pub fn validate_input_slots(&self) -> Result<(), RenderGraphError> {
274 for i in 0..self.input_slots.len() {
275 self.edges.get_input_slot_edge(i)?;
276 }
277
278 Ok(())
279 }
280
281 pub fn validate_output_slots(&self) -> Result<(), RenderGraphError> {
283 for i in 0..self.output_slots.len() {
284 self.edges.get_output_slot_edge(i)?;
285 }
286
287 Ok(())
288 }
289}
290
291#[derive(Debug, Clone, Eq, PartialEq)]
294pub enum NodeLabel {
295 Id(NodeId),
296 Name(Cow<'static, str>),
297}
298
299impl From<&NodeLabel> for NodeLabel {
300 fn from(value: &NodeLabel) -> Self {
301 value.clone()
302 }
303}
304
305impl From<String> for NodeLabel {
306 fn from(value: String) -> Self {
307 NodeLabel::Name(value.into())
308 }
309}
310
311impl From<&'static str> for NodeLabel {
312 fn from(value: &'static str) -> Self {
313 NodeLabel::Name(value.into())
314 }
315}
316
317impl From<NodeId> for NodeLabel {
318 fn from(value: NodeId) -> Self {
319 NodeLabel::Id(value)
320 }
321}
322
323pub struct EmptyNode;
327
328impl Node for EmptyNode {
329 fn run(
330 &self,
331 _graph: &mut RenderGraphContext,
332 _render_context: &mut RenderContext,
333 _state: &RenderResources,
334 _world: &World,
335 ) -> Result<(), NodeRunError> {
336 Ok(())
337 }
338}