vegafusion_core/task_graph/
task.rs

1use crate::error::{Result, VegaFusionError};
2use crate::proto::gen::tasks::{
3    task::TaskKind, DataSourceTask, DataUrlTask, DataValuesTask, NodeValueIndex, Task, TzConfig,
4    Variable,
5};
6use crate::proto::gen::tasks::{SignalTask, TaskValue as ProtoTaskValue};
7use crate::task_graph::task_value::TaskValue;
8use std::convert::TryFrom;
9
10use crate::proto::gen::expression::Expression;
11use prost::Message;
12use std::hash::{Hash, Hasher};
13
14#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
15pub struct InputVariable {
16    pub var: Variable,
17    pub propagate: bool,
18}
19
20impl Task {
21    pub fn task_kind(&self) -> &TaskKind {
22        self.task_kind.as_ref().unwrap()
23    }
24    pub fn variable(&self) -> &Variable {
25        self.variable.as_ref().unwrap()
26    }
27
28    pub fn scope(&self) -> &[u32] {
29        self.scope.as_slice()
30    }
31
32    pub fn new_value(variable: Variable, scope: &[u32], value: TaskValue) -> Self {
33        Self {
34            variable: Some(variable),
35            scope: Vec::from(scope),
36            task_kind: Some(TaskKind::Value(ProtoTaskValue::try_from(&value).unwrap())),
37            tz_config: None,
38        }
39    }
40
41    pub fn to_value(&self) -> Result<TaskValue> {
42        if let TaskKind::Value(value) = self.task_kind() {
43            Ok(TaskValue::try_from(value)?)
44        } else {
45            Err(VegaFusionError::internal("Task is not a TaskValue"))
46        }
47    }
48
49    pub fn new_data_url(
50        variable: Variable,
51        scope: &[u32],
52        task: DataUrlTask,
53        tz_config: &TzConfig,
54    ) -> Self {
55        Self {
56            variable: Some(variable),
57            scope: Vec::from(scope),
58            task_kind: Some(TaskKind::DataUrl(task)),
59            tz_config: Some(tz_config.clone()),
60        }
61    }
62
63    pub fn new_data_values(
64        variable: Variable,
65        scope: &[u32],
66        task: DataValuesTask,
67        tz_config: &TzConfig,
68    ) -> Self {
69        Self {
70            variable: Some(variable),
71            scope: Vec::from(scope),
72            task_kind: Some(TaskKind::DataValues(task)),
73            tz_config: Some(tz_config.clone()),
74        }
75    }
76
77    pub fn new_data_source(
78        variable: Variable,
79        scope: &[u32],
80        task: DataSourceTask,
81        tz_config: &TzConfig,
82    ) -> Self {
83        Self {
84            variable: Some(variable),
85            scope: Vec::from(scope),
86            task_kind: Some(TaskKind::DataSource(task)),
87            tz_config: Some(tz_config.clone()),
88        }
89    }
90
91    pub fn new_signal(
92        variable: Variable,
93        scope: &[u32],
94        expr: Expression,
95        tz_config: &TzConfig,
96    ) -> Self {
97        let task_kind = TaskKind::Signal(SignalTask { expr: Some(expr) });
98        Self {
99            variable: Some(variable),
100            scope: Vec::from(scope),
101            task_kind: Some(task_kind),
102            tz_config: Some(tz_config.clone()),
103        }
104    }
105
106    pub fn input_vars(&self) -> Vec<InputVariable> {
107        match self.task_kind() {
108            TaskKind::Value(_) => Vec::new(),
109            TaskKind::DataUrl(task) => task.input_vars(),
110            TaskKind::DataSource(task) => task.input_vars(),
111            TaskKind::DataValues(task) => task.input_vars(),
112            TaskKind::Signal(task) => {
113                let expr = task.expr.as_ref().unwrap();
114                expr.input_vars()
115            }
116        }
117    }
118
119    pub fn output_vars(&self) -> Vec<Variable> {
120        match self.task_kind() {
121            TaskKind::Value(_) => Vec::new(),
122            TaskKind::DataUrl(task) => task.output_vars(),
123            TaskKind::DataSource(task) => task.output_vars(),
124            TaskKind::DataValues(task) => task.output_vars(),
125            TaskKind::Signal(_) => Vec::new(),
126        }
127    }
128}
129
130#[allow(clippy::derived_hash_with_manual_eq)]
131impl Hash for Task {
132    fn hash<H: Hasher>(&self, state: &mut H) {
133        let mut proto_bytes: Vec<u8> = Vec::with_capacity(self.encoded_len());
134
135        // Unwrap is safe, since we have reserved sufficient capacity in the vector.
136        self.encode(&mut proto_bytes).unwrap();
137        proto_bytes.hash(state);
138    }
139}
140
141pub trait TaskDependencies {
142    fn input_vars(&self) -> Vec<InputVariable> {
143        Vec::new()
144    }
145    fn output_vars(&self) -> Vec<Variable> {
146        Vec::new()
147    }
148}
149
150#[allow(clippy::derived_hash_with_manual_eq)]
151impl Hash for NodeValueIndex {
152    fn hash<H: Hasher>(&self, state: &mut H) {
153        self.node_index.hash(state);
154        self.output_index.hash(state);
155    }
156}
157
158impl Eq for NodeValueIndex {}