1use crate::one_or_many::OneOrMany;
6use crate::types::common::*;
7use crate::{
8 AnyRef, AsClauseContext, ContextPathClause, Error, FromClauseContext, OfferFromRef,
9 merge_spanned_vec,
10};
11pub use cm_types::{
12 Availability, BorrowedName, BoundedName, DeliveryType, DependencyType, HandleType, Name,
13 OnTerminate, ParseError, Path, RelativePath, StartupMode, StorageId, Url,
14};
15use cml_macro::Reference;
16use reference_doc::ReferenceDoc;
17use serde::{Deserialize, Serialize, de};
18
19use std::fmt;
20use std::sync::Arc;
21
22#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
46#[serde(deny_unknown_fields)]
47#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
48pub struct Environment {
49 pub name: Name,
53
54 #[serde(skip_serializing_if = "Option::is_none")]
58 pub extends: Option<EnvironmentExtends>,
59
60 #[reference_doc(recurse)]
63 #[serde(skip_serializing_if = "Option::is_none")]
64 pub runners: Option<Vec<RunnerRegistration>>,
65
66 #[reference_doc(recurse)]
69 #[serde(skip_serializing_if = "Option::is_none")]
70 pub resolvers: Option<Vec<ResolverRegistration>>,
71
72 #[reference_doc(recurse)]
75 #[serde(skip_serializing_if = "Option::is_none")]
76 pub debug: Option<Vec<DebugRegistration>>,
77
78 #[serde(rename = "__stop_timeout_ms")]
82 #[reference_doc(json_type = "number", rename = "__stop_timeout_ms")]
83 #[serde(skip_serializing_if = "Option::is_none")]
84 pub stop_timeout_ms: Option<StopTimeoutMs>,
85}
86
87#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
89#[reference(expected = "\"#<environment-name>\"")]
90pub enum EnvironmentRef {
91 Named(Name),
93}
94
95#[derive(Deserialize, Debug, PartialEq, Serialize)]
96#[serde(rename_all = "lowercase")]
97pub enum EnvironmentExtends {
98 Realm,
99 None,
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
104pub struct StopTimeoutMs(pub u32);
105
106impl<'de> de::Deserialize<'de> for StopTimeoutMs {
107 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
108 where
109 D: de::Deserializer<'de>,
110 {
111 struct Visitor;
112
113 impl<'de> de::Visitor<'de> for Visitor {
114 type Value = StopTimeoutMs;
115
116 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 f.write_str("an unsigned 32-bit integer")
118 }
119
120 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
121 where
122 E: de::Error,
123 {
124 if v < 0 || v > i64::from(u32::MAX) {
125 return Err(E::invalid_value(
126 de::Unexpected::Signed(v),
127 &"an unsigned 32-bit integer",
128 ));
129 }
130 Ok(StopTimeoutMs(v as u32))
131 }
132
133 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
134 where
135 E: de::Error,
136 {
137 self.visit_i64(value as i64)
138 }
139 }
140
141 deserializer.deserialize_i64(Visitor)
142 }
143}
144
145#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
147#[reference(expected = "\"parent\", \"self\", or \"#<child-name>\"")]
148pub enum RegistrationRef {
149 Named(Name),
151 Parent,
153 Self_,
155}
156
157#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
158#[serde(deny_unknown_fields)]
159#[reference_doc(fields_as = "list")]
160pub struct RunnerRegistration {
161 pub runner: Name,
163
164 pub from: RegistrationRef,
170
171 #[serde(skip_serializing_if = "Option::is_none")]
174 pub r#as: Option<Name>,
175}
176
177impl Hydrate for RunnerRegistration {
178 type Output = ContextRunnerRegistration;
179
180 fn hydrate(self, file: &Arc<std::path::Path>) -> Result<Self::Output, Error> {
181 let runner = hydrate_simple(self.runner, file);
182
183 let r#as = hydrate_opt_simple(self.r#as, file);
184
185 let from = hydrate_simple(self.from, file);
186
187 Ok(ContextRunnerRegistration { runner, r#as, from })
188 }
189}
190
191#[derive(Debug, PartialEq, Serialize)]
192pub struct ContextRunnerRegistration {
193 pub runner: ContextSpanned<Name>,
194 pub from: ContextSpanned<RegistrationRef>,
195 #[serde(skip_serializing_if = "Option::is_none")]
196 pub r#as: Option<ContextSpanned<Name>>,
197}
198
199impl FromClauseContext for ContextRunnerRegistration {
200 fn from_(&self) -> ContextSpanned<OneOrMany<AnyRef<'_>>> {
201 let origin = self.from.origin.clone();
202 let value = OneOrMany::One(AnyRef::from(&self.from.value));
203
204 ContextSpanned { value, origin }
205 }
206}
207
208#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
209#[serde(deny_unknown_fields)]
210#[reference_doc(fields_as = "list")]
211pub struct ResolverRegistration {
212 pub resolver: Name,
215
216 pub from: RegistrationRef,
222
223 pub scheme: cm_types::UrlScheme,
226}
227
228impl Hydrate for ResolverRegistration {
229 type Output = ContextResolverRegistration;
230
231 fn hydrate(self, file: &Arc<std::path::Path>) -> Result<Self::Output, Error> {
232 let resolver = hydrate_simple(self.resolver, file);
233
234 let from = hydrate_simple(self.from, file);
235 let scheme = hydrate_simple(self.scheme, file);
236
237 Ok(ContextResolverRegistration { resolver, from, scheme })
238 }
239}
240
241#[derive(Debug, PartialEq, Serialize)]
242pub struct ContextResolverRegistration {
243 pub resolver: ContextSpanned<Name>,
244 pub from: ContextSpanned<RegistrationRef>,
245 pub scheme: ContextSpanned<cm_types::UrlScheme>,
246}
247
248impl FromClauseContext for ContextResolverRegistration {
249 fn from_(&self) -> ContextSpanned<OneOrMany<AnyRef<'_>>> {
250 let origin = self.from.origin.clone();
251 let value = OneOrMany::One(AnyRef::from(&self.from.value));
252
253 ContextSpanned { value, origin }
254 }
255}
256
257#[derive(Deserialize, Debug, Clone, PartialEq, ReferenceDoc, Serialize)]
258#[serde(deny_unknown_fields)]
259#[reference_doc(fields_as = "list")]
260pub struct DebugRegistration {
261 pub protocol: Option<OneOrMany<Name>>,
263
264 pub from: OfferFromRef,
270
271 #[serde(skip_serializing_if = "Option::is_none")]
274 pub r#as: Option<Name>,
275}
276
277impl Hydrate for DebugRegistration {
278 type Output = ContextDebugRegistration;
279
280 fn hydrate(self, file: &Arc<std::path::Path>) -> Result<Self::Output, Error> {
281 let origin = file.clone();
282 let protocol = hydrate_opt_simple(self.protocol, file);
283 let from = hydrate_simple(self.from, file);
284 let r#as = hydrate_opt_simple(self.r#as, file);
285
286 Ok(ContextDebugRegistration { origin, protocol, from, r#as })
287 }
288}
289
290#[derive(Debug, Clone, PartialEq, Serialize)]
291pub struct ContextDebugRegistration {
292 #[serde(skip)]
293 pub origin: Arc<std::path::Path>,
294 #[serde(skip_serializing_if = "Option::is_none")]
295 pub protocol: Option<ContextSpanned<OneOrMany<Name>>>,
296 pub from: ContextSpanned<OfferFromRef>,
297 #[serde(skip_serializing_if = "Option::is_none")]
298 pub r#as: Option<ContextSpanned<Name>>,
299}
300
301impl FromClauseContext for ContextDebugRegistration {
302 fn from_(&self) -> ContextSpanned<OneOrMany<AnyRef<'_>>> {
303 let origin = self.from.origin.clone();
304 let value = OneOrMany::One(AnyRef::from(&self.from.value));
305
306 ContextSpanned { value, origin }
307 }
308}
309
310impl AsClauseContext for ContextDebugRegistration {
311 fn r#as(&self) -> Option<ContextSpanned<&BorrowedName>> {
312 self.r#as.as_ref().map(|spanned_name| ContextSpanned {
313 value: spanned_name.value.as_ref(),
314 origin: spanned_name.origin.clone(),
315 })
316 }
317}
318
319impl ContextPathClause for ContextDebugRegistration {
320 fn path(&self) -> Option<&ContextSpanned<Path>> {
321 None
322 }
323}
324
325impl ContextCapabilityClause for ContextDebugRegistration {
326 fn service(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
327 None
328 }
329 fn protocol(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
330 option_one_or_many_as_ref_context(&self.protocol)
331 }
332 fn directory(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
333 None
334 }
335 fn storage(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
336 None
337 }
338 fn runner(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
339 None
340 }
341 fn resolver(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
342 None
343 }
344 fn event_stream(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
345 None
346 }
347 fn dictionary(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
348 None
349 }
350 fn config(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
351 None
352 }
353
354 fn decl_type(&self) -> &'static str {
355 "debug"
356 }
357 fn supported(&self) -> &[&'static str] {
358 &["service", "protocol"]
359 }
360 fn are_many_names_allowed(&self) -> bool {
361 ["protocol"].contains(&self.capability_type(None).unwrap())
362 }
363
364 fn set_service(&mut self, _o: Option<ContextSpanned<OneOrMany<Name>>>) {}
365 fn set_protocol(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
366 self.protocol = o;
367 }
368 fn set_directory(&mut self, _o: Option<ContextSpanned<OneOrMany<Name>>>) {}
369 fn set_storage(&mut self, _o: Option<ContextSpanned<OneOrMany<Name>>>) {}
370 fn set_runner(&mut self, _o: Option<ContextSpanned<OneOrMany<Name>>>) {}
371 fn set_resolver(&mut self, _o: Option<ContextSpanned<OneOrMany<Name>>>) {}
372 fn set_event_stream(&mut self, _o: Option<ContextSpanned<OneOrMany<Name>>>) {}
373 fn set_dictionary(&mut self, _o: Option<ContextSpanned<OneOrMany<Name>>>) {}
374 fn set_config(&mut self, _o: Option<ContextSpanned<OneOrMany<Name>>>) {}
375
376 fn origin(&self) -> &Arc<std::path::Path> {
377 &self.origin
378 }
379
380 fn availability(&self) -> Option<ContextSpanned<Availability>> {
381 None
382 }
383 fn set_availability(&mut self, _a: Option<ContextSpanned<Availability>>) {}
384}
385
386impl Hydrate for Environment {
387 type Output = ContextEnvironment;
388
389 fn hydrate(self, file: &Arc<std::path::Path>) -> Result<Self::Output, Error> {
390 let name = hydrate_simple(self.name, file);
391
392 let extends = hydrate_opt_simple(self.extends, file);
393 let stop_timeout_ms = hydrate_opt_simple(self.stop_timeout_ms, file);
394
395 let runners = hydrate_list(self.runners, file)?;
396 let resolvers = hydrate_list(self.resolvers, file)?;
397 let debug = hydrate_list(self.debug, file)?;
398
399 Ok(ContextEnvironment { name, extends, runners, resolvers, debug, stop_timeout_ms })
400 }
401}
402
403#[derive(Debug, PartialEq, Serialize)]
404pub struct ContextEnvironment {
405 pub name: ContextSpanned<Name>,
406 #[serde(skip_serializing_if = "Option::is_none")]
407 pub extends: Option<ContextSpanned<EnvironmentExtends>>,
408 #[serde(skip_serializing_if = "Option::is_none")]
409 pub runners: Option<Vec<ContextSpanned<ContextRunnerRegistration>>>,
410 #[serde(skip_serializing_if = "Option::is_none")]
411 pub resolvers: Option<Vec<ContextSpanned<ContextResolverRegistration>>>,
412 #[serde(skip_serializing_if = "Option::is_none")]
413 pub debug: Option<Vec<ContextSpanned<ContextDebugRegistration>>>,
414 #[serde(skip_serializing_if = "Option::is_none")]
415 #[serde(rename = "__stop_timeout_ms")]
416 pub stop_timeout_ms: Option<ContextSpanned<StopTimeoutMs>>,
417}
418
419impl ContextEnvironment {
420 pub fn merge_from(&mut self, mut other: Self) -> Result<(), Error> {
421 if let Some(other_extends) = other.extends.take() {
422 if let Some(my_extends) = &self.extends {
423 if my_extends.value != other_extends.value {
424 return Err(Error::merge(
425 format!(
426 "Conflicting 'extends' field in environment '{}': found '{:?}' and '{:?}'",
427 self.name.value, my_extends.value, other_extends.value
428 ),
429 Some(other_extends.origin),
430 ));
431 }
432 } else {
433 self.extends = Some(other_extends);
434 }
435 }
436
437 if let Some(other_timeout) = other.stop_timeout_ms.take() {
438 if let Some(my_timeout) = &self.stop_timeout_ms {
439 if my_timeout.value != other_timeout.value {
440 return Err(Error::merge(
441 format!(
442 "Conflicting 'stop_timeout_ms' in environment '{}'",
443 self.name.value
444 ),
445 Some(other_timeout.origin),
446 ));
447 }
448 } else {
449 self.stop_timeout_ms = Some(other_timeout);
450 }
451 }
452
453 merge_spanned_vec!(self, other, runners);
454 merge_spanned_vec!(self, other, resolvers);
455 merge_spanned_vec!(self, other, debug);
456
457 Ok(())
458 }
459}