vegafusion_core/task_graph/
scope.rs1use crate::error::{Result, ResultWithContext, VegaFusionError};
2use crate::expression::supported::BUILT_IN_SIGNALS;
3use crate::proto::gen::tasks::{Variable, VariableNamespace};
4use std::collections::{HashMap, HashSet};
5
6#[derive(Clone, Debug, Default)]
7pub struct TaskScope {
8 pub signals: HashSet<String>,
9 pub data: HashSet<String>,
10 pub scales: HashSet<String>,
11 pub output_var_defs: HashMap<Variable, Variable>,
13 pub children: Vec<TaskScope>,
14}
15
16impl TaskScope {
17 pub fn new() -> Self {
18 Self {
19 signals: Default::default(),
20 data: Default::default(),
21 output_var_defs: Default::default(),
22 scales: Default::default(),
23 children: Default::default(),
24 }
25 }
26
27 pub fn get_child(&self, scope: &[u32]) -> Result<&TaskScope> {
28 let mut child = self;
29 for index in scope {
30 child = child
31 .children
32 .get(*index as usize)
33 .with_context(|| format!("No group with scope {scope:?} found"))?;
34 }
35 Ok(child)
36 }
37
38 pub fn get_child_mut(&mut self, scope: &[u32]) -> Result<&mut TaskScope> {
39 let mut child = self;
40 for index in scope {
41 child = child
42 .children
43 .get_mut(*index as usize)
44 .with_context(|| format!("No group with scope {scope:?} found"))?;
45 }
46 Ok(child)
47 }
48
49 pub fn add_variable(&mut self, variable: &Variable, scope: &[u32]) -> Result<()> {
50 let child = self.get_child_mut(scope)?;
51
52 match variable.ns() {
53 VariableNamespace::Signal => {
54 child.signals.insert(variable.name.clone());
55 }
56 VariableNamespace::Data => {
57 child.data.insert(variable.name.clone());
58 }
59 VariableNamespace::Scale => {
60 child.scales.insert(variable.name.clone());
61 }
62 }
63
64 Ok(())
65 }
66
67 pub fn add_data_signal(&mut self, data: &str, signal: &str, scope: &[u32]) -> Result<()> {
68 let child = self.get_child_mut(scope)?;
69 child
70 .output_var_defs
71 .insert(Variable::new_signal(signal), Variable::new_data(data));
72 Ok(())
73 }
74
75 pub fn remove_data_signal(&mut self, signal: &str, scope: &[u32]) -> Result<Variable> {
76 let child = self.get_child_mut(scope)?;
77 child
78 .output_var_defs
79 .remove(&Variable::new_signal(signal))
80 .with_context(|| format!("No data signal named: {signal}"))
81 }
82
83 pub fn resolve_scope(&self, variable: &Variable, usage_scope: &[u32]) -> Result<Resolved> {
84 for level in (0..=usage_scope.len()).rev() {
86 let curr_scope = &usage_scope[0..level];
87 let task_scope = self.get_child(curr_scope)?;
88
89 let found_it = match variable.ns() {
90 VariableNamespace::Signal => task_scope.signals.contains(&variable.name),
91 VariableNamespace::Data => task_scope.data.contains(&variable.name),
92 VariableNamespace::Scale => task_scope.scales.contains(&variable.name),
93 };
94 if found_it {
95 return Ok(Resolved {
97 var: variable.clone(),
98 scope: Vec::from(curr_scope),
99 output_var: None,
100 });
101 }
102
103 if let Some(main_var) = task_scope.output_var_defs.get(variable) {
105 return Ok(Resolved {
106 var: main_var.clone(),
107 scope: Vec::from(curr_scope),
108 output_var: Some(variable.clone()),
109 });
110 }
111
112 if matches!(variable.ns(), VariableNamespace::Signal)
114 && BUILT_IN_SIGNALS.contains(variable.name.as_str())
115 {
116 return Ok(Resolved {
117 var: variable.clone(),
118 scope: Vec::new(),
119 output_var: None,
120 });
121 }
122 }
123
124 Err(VegaFusionError::internal(format!(
126 "Failed to resolve variable {variable:?} used in scope {usage_scope:?}"
127 )))
128 }
129}
130
131pub struct Resolved {
132 pub var: Variable,
133 pub scope: Vec<u32>,
134 pub output_var: Option<Variable>,
135}