wick_config/config/common/
component_definition.rs1#![allow(missing_docs, deprecated)]
2use std::collections::HashMap;
3use std::path::Path;
4
5use serde::de::{IgnoredAny, SeqAccess, Visitor};
7use serde::Deserializer;
8use wick_interface_types::OperationSignatures;
9use wick_packet::{Entity, RuntimeConfig};
10
11use super::template_config::Renderable;
12use super::Binding;
13use crate::config::{self, ExecutionSettings, ImportDefinition, LiquidJsonConfig};
14use crate::error::ManifestError;
15
16#[derive(
18 Debug,
19 Clone,
20 PartialEq,
21 derive_asset_container::AssetManager,
22 property::Property,
23 serde::Serialize,
24 derive_builder::Builder,
25)]
26#[builder(setter(into))]
27#[property(get(public), set(public), mut(public, suffix = "_mut"))]
28#[asset(asset(config::AssetReference))]
29
30pub struct ComponentOperationExpression {
31 #[asset(skip)]
33 pub(crate) name: String,
34 pub(crate) component: ComponentDefinition,
36 #[asset(skip)]
38 #[builder(default)]
39 #[serde(skip_serializing_if = "Option::is_none")]
40 pub(crate) config: Option<LiquidJsonConfig>,
41 #[asset(skip)]
43 #[builder(default)]
44 #[serde(skip_serializing_if = "Option::is_none")]
45 pub(crate) settings: Option<ExecutionSettings>,
46}
47
48impl ComponentOperationExpression {
49 pub fn new_default<T: Into<String>>(operation: T, component: ComponentDefinition) -> Self {
51 Self {
52 name: operation.into(),
53 component,
54 config: Default::default(),
55 settings: Default::default(),
56 }
57 }
58
59 pub fn new<T: Into<String>>(
61 operation: T,
62 component: ComponentDefinition,
63 config: Option<LiquidJsonConfig>,
64 settings: Option<ExecutionSettings>,
65 ) -> Self {
66 Self {
67 name: operation.into(),
68 component,
69 config,
70 settings,
71 }
72 }
73
74 pub fn maybe_import(&mut self, import_name: &str, bindings: &mut Vec<Binding<ImportDefinition>>) {
75 if self.component.is_reference() {
76 return;
77 }
78
79 tracing::Span::current().in_scope(|| {
80 tracing::debug!("importing inline component as {}", import_name);
81 let def = std::mem::replace(
82 &mut self.component,
83 ComponentDefinition::Reference(config::components::ComponentReference::new(import_name)),
84 );
85 bindings.push(Binding::new(import_name, config::ImportDefinition::Component(def)));
86 });
87 }
88
89 #[must_use]
91 pub fn as_entity(&self) -> Option<Entity> {
92 if let ComponentDefinition::Reference(r) = &self.component {
93 Some(Entity::operation(&r.id, &self.name))
94 } else {
95 None
96 }
97 }
98
99 pub fn component_id(&self) -> Result<&str, ManifestError> {
100 match &self.component {
101 ComponentDefinition::Reference(r) => Ok(r.id()),
102 _ => Err(ManifestError::InvalidReference),
103 }
104 }
105}
106
107impl Renderable for ComponentOperationExpression {
108 fn render_config(
109 &mut self,
110 source: Option<&Path>,
111 root_config: Option<&RuntimeConfig>,
112 env: Option<&HashMap<String, String>>,
113 ) -> Result<(), ManifestError> {
114 if let Some(config) = self.config.as_mut() {
115 config.set_value(Some(config.render(source, root_config, None, env, None)?));
116 }
117 Ok(())
118 }
119}
120
121impl std::str::FromStr for ComponentOperationExpression {
122 type Err = crate::Error;
123
124 fn from_str(s: &str) -> Result<Self, Self::Err> {
125 let mut parts = s.split("::");
126
127 let operation = parts
128 .next()
129 .ok_or_else(|| crate::Error::InvalidOperationExpression(s.to_owned()))?
130 .to_owned();
131 let component = parts
132 .next()
133 .ok_or_else(|| crate::Error::InvalidOperationExpression(s.to_owned()))?
134 .to_owned();
135
136 Ok(Self {
137 name: operation,
138 component: ComponentDefinition::Reference(config::components::ComponentReference { id: component }),
139 config: Default::default(),
140 settings: Default::default(),
141 })
142 }
143}
144
145#[derive(Debug, Clone, PartialEq, derive_asset_container::AssetManager, serde::Serialize)]
146#[asset(asset(config::AssetReference))]
147#[must_use]
149#[serde(rename_all = "kebab-case")]
150pub enum HighLevelComponent {
151 #[asset(skip)]
153 Sql(config::components::SqlComponentConfig),
154 #[asset(skip)]
155 HttpClient(config::components::HttpClientComponentConfig),
157}
158
159impl OperationSignatures for HighLevelComponent {
160 fn operation_signatures(&self) -> Vec<wick_interface_types::OperationSignature> {
161 match self {
162 HighLevelComponent::Sql(c) => c.operation_signatures(),
163 HighLevelComponent::HttpClient(c) => c.operation_signatures(),
164 }
165 }
166}
167
168#[derive(Debug, Clone, PartialEq, derive_asset_container::AssetManager, serde::Serialize)]
170#[asset(asset(config::AssetReference))]
171#[must_use]
172#[serde(rename_all = "kebab-case")]
173pub enum ComponentDefinition {
174 #[doc(hidden)]
175 #[asset(skip)]
176 Native(config::components::NativeComponent),
177 #[deprecated(note = "Use ManifestComponent instead")]
179 Wasm(config::components::WasmComponent),
180 #[asset(skip)]
182 Reference(config::components::ComponentReference),
183 #[asset(skip)]
185 GrpcUrl(config::components::GrpcUrlComponent),
186 Manifest(config::components::ManifestComponent),
188 #[asset(skip)]
190 HighLevelComponent(HighLevelComponent),
191}
192
193#[derive(Debug, Clone, Copy)]
194pub enum ComponentDefinitionKind {
195 Native,
196 Wasm,
197 Reference,
198 GrpcUrl,
199 Manifest,
200 HighLevelComponent,
201}
202
203impl std::fmt::Display for ComponentDefinitionKind {
204 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205 match self {
206 ComponentDefinitionKind::Native => write!(f, "native"),
207 ComponentDefinitionKind::Wasm => write!(f, "wasm"),
208 ComponentDefinitionKind::Reference => write!(f, "reference"),
209 ComponentDefinitionKind::GrpcUrl => write!(f, "grpc-url"),
210 ComponentDefinitionKind::Manifest => write!(f, "manifest"),
211 ComponentDefinitionKind::HighLevelComponent => write!(f, "high-level-component"),
212 }
213 }
214}
215
216impl ComponentDefinition {
217 #[must_use]
219 pub const fn is_reference(&self) -> bool {
220 matches!(self, ComponentDefinition::Reference(_))
221 }
222
223 #[must_use]
225 pub const fn kind(&self) -> ComponentDefinitionKind {
226 match self {
227 ComponentDefinition::Native(_) => ComponentDefinitionKind::Native,
228 ComponentDefinition::Wasm(_) => ComponentDefinitionKind::Wasm,
229 ComponentDefinition::Reference(_) => ComponentDefinitionKind::Reference,
230 ComponentDefinition::GrpcUrl(_) => ComponentDefinitionKind::GrpcUrl,
231 ComponentDefinition::Manifest(_) => ComponentDefinitionKind::Manifest,
232 ComponentDefinition::HighLevelComponent(_) => ComponentDefinitionKind::HighLevelComponent,
233 }
234 }
235
236 #[must_use]
238 pub const fn config(&self) -> Option<&LiquidJsonConfig> {
239 match self {
240 #[allow(deprecated)]
241 ComponentDefinition::Wasm(c) => c.config.as_ref(),
242 ComponentDefinition::GrpcUrl(c) => c.config.as_ref(),
243 ComponentDefinition::Manifest(c) => c.config.as_ref(),
244 ComponentDefinition::Native(_) => None,
245 ComponentDefinition::Reference(_) => None,
246 ComponentDefinition::HighLevelComponent(_) => None,
247 }
248 }
249
250 #[must_use]
252 pub fn provide(&self) -> Option<&HashMap<String, String>> {
253 match self {
254 #[allow(deprecated)]
255 ComponentDefinition::Wasm(c) => Some(c.provide()),
256 ComponentDefinition::GrpcUrl(_) => None,
257 ComponentDefinition::Manifest(c) => Some(c.provide()),
258 ComponentDefinition::Native(_) => None,
259 ComponentDefinition::Reference(_) => None,
260 ComponentDefinition::HighLevelComponent(_) => None,
261 }
262 }
263
264 #[must_use]
266 pub fn config_mut(&mut self) -> Option<&mut LiquidJsonConfig> {
267 match self {
268 #[allow(deprecated)]
269 ComponentDefinition::Wasm(c) => c.config.as_mut(),
270 ComponentDefinition::GrpcUrl(c) => c.config.as_mut(),
271 ComponentDefinition::Manifest(c) => c.config.as_mut(),
272 ComponentDefinition::Native(_) => None,
273 ComponentDefinition::Reference(_) => None,
274 ComponentDefinition::HighLevelComponent(_) => None,
275 }
276 }
277
278 pub fn set_config(&mut self, config: Option<RuntimeConfig>) {
280 match self {
281 #[allow(deprecated)]
282 ComponentDefinition::Wasm(c) => c.config.as_mut().map(|c| c.set_value(config)),
283 ComponentDefinition::GrpcUrl(c) => c.config.as_mut().map(|c| c.set_value(config)),
284 ComponentDefinition::Manifest(c) => c.config.as_mut().map(|c| c.set_value(config)),
285 ComponentDefinition::Native(_) => None,
286 ComponentDefinition::Reference(_) => None,
287 ComponentDefinition::HighLevelComponent(_) => None,
288 };
289 }
290}
291
292impl Renderable for ComponentDefinition {
293 fn render_config(
294 &mut self,
295 source: Option<&Path>,
296 root_config: Option<&RuntimeConfig>,
297 env: Option<&HashMap<String, String>>,
298 ) -> Result<(), ManifestError> {
299 let val = if let Some(config) = self.config() {
300 Some(config.render(source, root_config, None, env, None)?)
301 } else {
302 None
303 };
304 self.set_config(val);
305 Ok(())
306 }
307}
308
309impl OperationSignatures for &ComponentDefinition {
310 fn operation_signatures(&self) -> Vec<wick_interface_types::OperationSignature> {
311 match self {
312 ComponentDefinition::Manifest(c) => c.operation_signatures(),
313 ComponentDefinition::HighLevelComponent(c) => c.operation_signatures(),
314 ComponentDefinition::Native(_) => unreachable!(),
315 ComponentDefinition::Reference(_) => unreachable!(),
316 ComponentDefinition::GrpcUrl(_) => unreachable!(),
317 #[allow(deprecated)]
318 ComponentDefinition::Wasm(_) => unreachable!(),
319 }
320 }
321}
322
323#[derive(Default, Debug)]
324struct StringPair(String, String);
325
326impl<'de> serde::Deserialize<'de> for StringPair {
327 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
328 where
329 D: Deserializer<'de>,
330 {
331 struct StringPairVisitor;
332
333 impl<'de> Visitor<'de> for StringPairVisitor {
334 type Value = StringPair;
335
336 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
337 formatter.write_str("a String pair")
338 }
339
340 fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
341 where
342 V: SeqAccess<'de>,
343 {
344 let s = seq
345 .next_element()?
346 .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
347 let n = seq
348 .next_element()?
349 .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
350
351 while matches!(seq.next_element()?, Some(IgnoredAny)) {
353 }
355
356 Ok(StringPair(s, n))
357 }
358 }
359
360 deserializer.deserialize_seq(StringPairVisitor)
361 }
362}