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