1use std::borrow::Cow;
4
5use super::{OpTag, OpTrait, impl_op_name};
6
7use crate::extension::SignatureError;
8use crate::ops::StaticTag;
9use crate::types::{
10 EdgeKind, PolyFuncType, Signature, Substitution, Type, TypeArg, TypeRow, TypeRowLike,
11};
12use crate::{IncomingPort, type_row};
13
14#[cfg(test)]
15use {crate::types::proptest_utils::any_serde_type_arg_vec, proptest_derive::Arbitrary};
16
17pub trait DataflowOpTrait: Sized {
19 const TAG: OpTag;
21
22 fn description(&self) -> &str;
24
25 fn signature(&self) -> Cow<'_, Signature>;
27
28 #[inline]
34 fn other_input(&self) -> Option<EdgeKind> {
35 Some(EdgeKind::StateOrder)
36 }
37 #[inline]
43 fn other_output(&self) -> Option<EdgeKind> {
44 Some(EdgeKind::StateOrder)
45 }
46
47 #[inline]
53 fn static_input(&self) -> Option<EdgeKind> {
54 None
55 }
56
57 fn substitute(&self, _subst: &Substitution) -> Self;
60}
61
62pub trait IOTrait {
64 fn new(types: impl Into<TypeRow>) -> Self;
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
71#[cfg_attr(test, derive(Arbitrary))]
72pub struct Input {
73 pub types: TypeRow,
75}
76
77impl_op_name!(Input);
78
79impl IOTrait for Input {
80 fn new(types: impl Into<TypeRow>) -> Self {
81 Input {
82 types: types.into(),
83 }
84 }
85}
86
87#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
89#[cfg_attr(test, derive(Arbitrary))]
90pub struct Output {
91 pub types: TypeRow,
93}
94
95impl_op_name!(Output);
96
97impl IOTrait for Output {
98 fn new(types: impl Into<TypeRow>) -> Self {
99 Output {
100 types: types.into(),
101 }
102 }
103}
104
105impl DataflowOpTrait for Input {
106 const TAG: OpTag = OpTag::Input;
107
108 fn description(&self) -> &'static str {
109 "The input node for this dataflow subgraph"
110 }
111
112 fn other_input(&self) -> Option<EdgeKind> {
113 None
114 }
115
116 fn signature(&self) -> Cow<'_, Signature> {
117 Cow::Owned(Signature::new(TypeRow::new(), self.types.clone()))
119 }
120
121 fn substitute(&self, subst: &Substitution) -> Self {
122 Self {
123 types: self.types.substitute(subst),
124 }
125 }
126}
127impl DataflowOpTrait for Output {
128 const TAG: OpTag = OpTag::Output;
129
130 fn description(&self) -> &'static str {
131 "The output node for this dataflow subgraph"
132 }
133
134 fn signature(&self) -> Cow<'_, Signature> {
137 Cow::Owned(Signature::new(self.types.clone(), TypeRow::new()))
139 }
140
141 fn other_output(&self) -> Option<EdgeKind> {
142 None
143 }
144
145 fn substitute(&self, subst: &Substitution) -> Self {
146 Self {
147 types: self.types.substitute(subst),
148 }
149 }
150}
151
152impl<T: DataflowOpTrait + Clone> OpTrait for T {
153 fn description(&self) -> &str {
154 DataflowOpTrait::description(self)
155 }
156
157 fn tag(&self) -> OpTag {
158 T::TAG
159 }
160
161 fn dataflow_signature(&self) -> Option<Cow<'_, Signature>> {
162 Some(DataflowOpTrait::signature(self))
163 }
164
165 fn other_input(&self) -> Option<EdgeKind> {
166 DataflowOpTrait::other_input(self)
167 }
168
169 fn other_output(&self) -> Option<EdgeKind> {
170 DataflowOpTrait::other_output(self)
171 }
172
173 fn static_input(&self) -> Option<EdgeKind> {
174 DataflowOpTrait::static_input(self)
175 }
176
177 fn substitute(&self, subst: &crate::types::Substitution) -> Self {
178 DataflowOpTrait::substitute(self, subst)
179 }
180}
181impl<T: DataflowOpTrait> StaticTag for T {
182 const TAG: OpTag = T::TAG;
183}
184
185#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
191#[cfg_attr(test, derive(Arbitrary))]
192pub struct Call {
193 pub func_sig: PolyFuncType,
195 #[cfg_attr(test, proptest(strategy = "any_serde_type_arg_vec()"))]
197 pub type_args: Vec<TypeArg>,
198 pub instantiation: Signature, }
201impl_op_name!(Call);
202
203impl DataflowOpTrait for Call {
204 const TAG: OpTag = OpTag::FnCall;
205
206 fn description(&self) -> &'static str {
207 "Call a function directly"
208 }
209
210 fn signature(&self) -> Cow<'_, Signature> {
211 Cow::Borrowed(&self.instantiation)
212 }
213
214 fn static_input(&self) -> Option<EdgeKind> {
215 Some(EdgeKind::Function(self.called_function_type().clone()))
216 }
217
218 fn substitute(&self, subst: &Substitution) -> Self {
219 let type_args = self
220 .type_args
221 .iter()
222 .map(|ta| ta.substitute(subst))
223 .collect::<Vec<_>>();
224 let instantiation = self.instantiation.substitute(subst);
225 debug_assert_eq!(
226 self.func_sig.instantiate(&type_args).as_ref(),
227 Ok(&instantiation)
228 );
229 Self {
230 type_args,
231 instantiation,
232 func_sig: self.func_sig.clone(),
233 }
234 }
235}
236impl Call {
237 pub fn try_new(
242 func_sig: PolyFuncType,
243 type_args: impl Into<Vec<TypeArg>>,
244 ) -> Result<Self, SignatureError> {
245 let type_args: Vec<_> = type_args.into();
246 let instantiation = func_sig.instantiate(&type_args)?;
247 Ok(Self {
248 func_sig,
249 type_args,
250 instantiation,
251 })
252 }
253
254 #[inline]
255 #[must_use]
257 pub fn called_function_type(&self) -> &PolyFuncType {
258 &self.func_sig
259 }
260
261 #[inline]
279 #[must_use]
280 pub fn called_function_port(&self) -> IncomingPort {
281 self.instantiation.input_count().into()
282 }
283
284 pub(crate) fn validate(&self) -> Result<(), SignatureError> {
285 let other = Self::try_new(self.func_sig.clone(), self.type_args.clone())?;
286 if other.instantiation == self.instantiation {
287 Ok(())
288 } else {
289 Err(SignatureError::CallIncorrectlyAppliesType {
290 cached: Box::new(self.instantiation.clone()),
291 expected: Box::new(other.instantiation.clone()),
292 })
293 }
294 }
295}
296
297#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
300#[cfg_attr(test, derive(Arbitrary))]
301pub struct CallIndirect {
302 pub signature: Signature,
304}
305impl_op_name!(CallIndirect);
306
307impl DataflowOpTrait for CallIndirect {
308 const TAG: OpTag = OpTag::DataflowChild;
309
310 fn description(&self) -> &'static str {
311 "Call a function indirectly"
312 }
313
314 fn signature(&self) -> Cow<'_, Signature> {
315 let mut s = self.signature.clone();
317 s.input
318 .to_mut()
319 .insert(0, Type::new_function(self.signature.clone()));
320 Cow::Owned(s)
321 }
322
323 fn substitute(&self, subst: &Substitution) -> Self {
324 Self {
325 signature: self.signature.substitute(subst),
326 }
327 }
328}
329
330#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
332#[cfg_attr(test, derive(Arbitrary))]
333pub struct LoadConstant {
334 pub datatype: Type,
336}
337impl_op_name!(LoadConstant);
338impl DataflowOpTrait for LoadConstant {
339 const TAG: OpTag = OpTag::LoadConst;
340
341 fn description(&self) -> &'static str {
342 "Load a static constant in to the local dataflow graph"
343 }
344
345 fn signature(&self) -> Cow<'_, Signature> {
346 Cow::Owned(Signature::new(TypeRow::new(), vec![self.datatype.clone()]))
348 }
349
350 fn static_input(&self) -> Option<EdgeKind> {
351 Some(EdgeKind::Const(self.constant_type().clone()))
352 }
353
354 fn substitute(&self, _subst: &Substitution) -> Self {
355 self.clone()
357 }
358}
359
360impl LoadConstant {
361 #[inline]
362 #[must_use]
364 pub fn constant_type(&self) -> &Type {
365 &self.datatype
366 }
367
368 #[inline]
384 #[must_use]
385 pub fn constant_port(&self) -> IncomingPort {
386 0.into()
387 }
388}
389
390#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
392#[cfg_attr(test, derive(Arbitrary))]
393pub struct LoadFunction {
394 pub func_sig: PolyFuncType,
396 #[cfg_attr(test, proptest(strategy = "any_serde_type_arg_vec()"))]
398 pub type_args: Vec<TypeArg>,
399 pub instantiation: Signature, }
402impl_op_name!(LoadFunction);
403impl DataflowOpTrait for LoadFunction {
404 const TAG: OpTag = OpTag::LoadFunc;
405
406 fn description(&self) -> &'static str {
407 "Load a static function in to the local dataflow graph"
408 }
409
410 fn signature(&self) -> Cow<'_, Signature> {
411 Cow::Owned(Signature::new(
412 type_row![],
413 [Type::new_function(self.instantiation.clone())],
414 ))
415 }
416
417 fn static_input(&self) -> Option<EdgeKind> {
418 Some(EdgeKind::Function(self.func_sig.clone()))
419 }
420
421 fn substitute(&self, subst: &Substitution) -> Self {
422 let type_args = self
423 .type_args
424 .iter()
425 .map(|ta| ta.substitute(subst))
426 .collect::<Vec<_>>();
427 let instantiation = self.instantiation.substitute(subst);
428 debug_assert_eq!(
429 self.func_sig.instantiate(&type_args).as_ref(),
430 Ok(&instantiation)
431 );
432 Self {
433 func_sig: self.func_sig.clone(),
434 type_args,
435 instantiation,
436 }
437 }
438}
439impl LoadFunction {
440 pub fn try_new(
445 func_sig: PolyFuncType,
446 type_args: impl Into<Vec<TypeArg>>,
447 ) -> Result<Self, SignatureError> {
448 let type_args: Vec<_> = type_args.into();
449 let instantiation = func_sig.instantiate(&type_args)?;
450 Ok(Self {
451 func_sig,
452 type_args,
453 instantiation,
454 })
455 }
456
457 #[inline]
458 #[must_use]
460 pub fn function_type(&self) -> &PolyFuncType {
461 &self.func_sig
462 }
463
464 #[inline]
470 #[must_use]
471 pub fn function_port(&self) -> IncomingPort {
472 0.into()
473 }
474
475 pub(crate) fn validate(&self) -> Result<(), SignatureError> {
476 let other = Self::try_new(self.func_sig.clone(), self.type_args.clone())?;
477 if other.instantiation == self.instantiation {
478 Ok(())
479 } else {
480 Err(SignatureError::LoadFunctionIncorrectlyAppliesType {
481 cached: Box::new(self.instantiation.clone()),
482 expected: Box::new(other.instantiation.clone()),
483 })
484 }
485 }
486}
487
488pub trait DataflowParent {
493 fn inner_signature(&self) -> Cow<'_, Signature>;
495}
496
497#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
499#[cfg_attr(test, derive(Arbitrary))]
500pub struct DFG {
501 pub signature: Signature,
503}
504
505impl_op_name!(DFG);
506
507impl DataflowParent for DFG {
508 fn inner_signature(&self) -> Cow<'_, Signature> {
509 Cow::Borrowed(&self.signature)
510 }
511}
512
513impl DataflowOpTrait for DFG {
514 const TAG: OpTag = OpTag::Dfg;
515
516 fn description(&self) -> &'static str {
517 "A simply nested dataflow graph"
518 }
519
520 fn signature(&self) -> Cow<'_, Signature> {
521 self.inner_signature()
522 }
523
524 fn substitute(&self, subst: &Substitution) -> Self {
525 Self {
526 signature: self.signature.substitute(subst),
527 }
528 }
529}