panopticon_core/operation/
context.rs1use crate::imports::*;
2
3pub struct Context<'a> {
21 metadata: OperationMetadata,
22 param_prefix: &'a str,
23 store: &'a Store<StoreEntry>,
24 operation_outputs: Store<StoreEntry>,
25 global_outputs: Store<StoreEntry>,
26 extensions: &'a Extensions,
27}
28
29impl Context<'_> {
30 pub fn new<'a>(
34 metadata: OperationMetadata,
35 param_prefix: &'a str,
36 store: &'a Store<StoreEntry>,
37 extensions: &'a Extensions,
38 ) -> Context<'a> {
39 Context {
40 metadata,
41 param_prefix,
42 store,
43 operation_outputs: Store::<StoreEntry>::new(),
44 global_outputs: Store::<StoreEntry>::new(),
45 extensions,
46 }
47 }
48
49 pub fn input(&self, name: &str) -> Result<&StoreEntry, OperationError> {
54 let _spec = self
55 .metadata
56 .inputs
57 .iter()
58 .find(|s| s.name == name)
59 .ok_or_else(|| OperationError::UndeclaredInput {
60 operation: self.metadata.name,
61 input: name.to_string(),
62 })?;
63
64 let path = format!("{}.{}", self.param_prefix, name);
65 Ok(self.store.get(&path)?)
66 }
67
68 pub fn set_static_output(
73 &mut self,
74 name: &'static str,
75 entry: impl Into<StoreEntry>,
76 ) -> Result<(), OperationError> {
77 let spec = self
78 .metadata
79 .outputs
80 .iter()
81 .find(|s| matches!(&s.name, NameSpec::Static(n) if *n == name))
82 .ok_or_else(|| OperationError::UndeclaredOutput {
83 operation: self.metadata.name,
84 output: name.to_string(),
85 })?;
86
87 self.insert_by_scope(&spec.scope, name.to_string(), entry.into())
88 }
89
90 pub fn set_derived_output(
96 &mut self,
97 input_name: &str,
98 entry: impl Into<StoreEntry>,
99 ) -> Result<(), OperationError> {
100 let spec = self
101 .metadata
102 .outputs
103 .iter()
104 .find(|s| matches!(&s.name, NameSpec::DerivedFrom(n) | NameSpec::DerivedWithDefault { input_name: n, .. } if *n == input_name))
105 .ok_or_else(|| OperationError::UndeclaredDerivedOutput {
106 operation: self.metadata.name,
107 input: input_name.to_string(),
108 })?;
109
110 let output_key = match &spec.name {
111 NameSpec::DerivedFrom(input_name) => {
112 let path = format!("{}.{}", self.param_prefix, input_name);
113 self.store.get(&path)?.get_value()?.as_text()?.to_string()
114 }
115 NameSpec::DerivedWithDefault {
116 input_name,
117 default,
118 } => {
119 let path = format!("{}.{}", self.param_prefix, input_name);
120 match self.store.get(&path) {
121 Ok(entry) => entry.get_value()?.as_text()?.to_string(),
122 Err(_) => default.to_string(),
123 }
124 }
125 NameSpec::Static(_) => unreachable!(),
126 };
127
128 self.insert_by_scope(&spec.scope, output_key, entry.into())
129 }
130
131 fn insert_by_scope(
132 &mut self,
133 scope: &OutputScope,
134 name: String,
135 entry: StoreEntry,
136 ) -> Result<(), OperationError> {
137 let store = match scope {
138 OutputScope::Operation => &mut self.operation_outputs,
139 OutputScope::Global => &mut self.global_outputs,
140 };
141 Ok(store.insert(name, entry)?)
142 }
143
144 pub fn extension<T: Extension>(&self, spec_name: &str) -> Result<&T, OperationError> {
149 let spec = self
150 .metadata
151 .requires_extensions
152 .iter()
153 .find(|s| match &s.name {
154 NameSpec::Static(n) => *n == spec_name,
155 NameSpec::DerivedFrom(n) => *n == spec_name,
156 NameSpec::DerivedWithDefault { input_name, .. } => *input_name == spec_name,
157 })
158 .ok_or_else(|| OperationError::ExtensionNotFound {
159 operation: self.metadata.name.to_string(),
160 extension: spec_name.to_string(),
161 })?;
162
163 let resolved_name = match &spec.name {
164 NameSpec::Static(name) => name.to_string(),
165 NameSpec::DerivedFrom(input_name) => {
166 let path = format!("{}.{}", self.param_prefix, input_name);
167 self.store.get(&path)?.get_value()?.as_text()?.to_string()
168 }
169 NameSpec::DerivedWithDefault {
170 input_name,
171 default,
172 } => {
173 let path = format!("{}.{}", self.param_prefix, input_name);
174 match self.store.get(&path) {
175 Ok(entry) => entry.get_value()?.as_text()?.to_string(),
176 Err(_) => default.to_string(),
177 }
178 }
179 };
180
181 self.extensions
182 .get::<T>(&resolved_name)
183 .ok_or_else(|| OperationError::ExtensionNotFound {
184 operation: self.metadata.name.to_string(),
185 extension: resolved_name,
186 })
187 }
188
189 pub fn error(&self, message: impl Into<String>) -> OperationError {
194 OperationError::Custom {
195 operation: self.metadata.name.into(),
196 message: message.into(),
197 }
198 }
199
200 pub(crate) fn consume(self) -> (Store<StoreEntry>, Store<StoreEntry>) {
201 (self.operation_outputs, self.global_outputs)
202 }
203}