1use crate::{
6 AnyRef, AsClause, CapabilityClause, Error, FromClause, OfferFromRef, PathClause,
7 option_one_or_many_as_ref,
8};
9
10use crate::one_or_many::OneOrMany;
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;
20
21#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
45#[serde(deny_unknown_fields)]
46#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
47pub struct Environment {
48 pub name: Name,
52
53 #[serde(skip_serializing_if = "Option::is_none")]
57 pub extends: Option<EnvironmentExtends>,
58
59 #[reference_doc(recurse)]
62 #[serde(skip_serializing_if = "Option::is_none")]
63 pub runners: Option<Vec<RunnerRegistration>>,
64
65 #[reference_doc(recurse)]
68 #[serde(skip_serializing_if = "Option::is_none")]
69 pub resolvers: Option<Vec<ResolverRegistration>>,
70
71 #[reference_doc(recurse)]
74 #[serde(skip_serializing_if = "Option::is_none")]
75 pub debug: Option<Vec<DebugRegistration>>,
76
77 #[serde(rename = "__stop_timeout_ms")]
81 #[reference_doc(json_type = "number", rename = "__stop_timeout_ms")]
82 #[serde(skip_serializing_if = "Option::is_none")]
83 pub stop_timeout_ms: Option<StopTimeoutMs>,
84}
85
86impl Environment {
87 pub fn merge_from(&mut self, other: &mut Self) -> Result<(), Error> {
88 if self.extends.is_none() {
89 self.extends = other.extends.take();
90 } else if other.extends.is_some() && other.extends != self.extends {
91 return Err(Error::validate(
92 "cannot merge `environments` that declare conflicting `extends`",
93 ));
94 }
95
96 if self.stop_timeout_ms.is_none() {
97 self.stop_timeout_ms = other.stop_timeout_ms;
98 } else if other.stop_timeout_ms.is_some() && other.stop_timeout_ms != self.stop_timeout_ms {
99 return Err(Error::validate(
100 "cannot merge `environments` that declare conflicting `stop_timeout_ms`",
101 ));
102 }
103
104 match &mut self.runners {
107 Some(r) => {
108 if let Some(o) = &mut other.runners {
109 r.append(o);
110 }
111 }
112 None => self.runners = other.runners.take(),
113 }
114
115 match &mut self.resolvers {
116 Some(r) => {
117 if let Some(o) = &mut other.resolvers {
118 r.append(o);
119 }
120 }
121 None => self.resolvers = other.resolvers.take(),
122 }
123
124 match &mut self.debug {
125 Some(r) => {
126 if let Some(o) = &mut other.debug {
127 r.append(o);
128 }
129 }
130 None => self.debug = other.debug.take(),
131 }
132 Ok(())
133 }
134}
135
136#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
138#[reference(expected = "\"#<environment-name>\"")]
139pub enum EnvironmentRef {
140 Named(Name),
142}
143
144#[derive(Deserialize, Debug, PartialEq, Serialize)]
145#[serde(rename_all = "lowercase")]
146pub enum EnvironmentExtends {
147 Realm,
148 None,
149}
150
151#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
153pub struct StopTimeoutMs(pub u32);
154
155impl<'de> de::Deserialize<'de> for StopTimeoutMs {
156 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
157 where
158 D: de::Deserializer<'de>,
159 {
160 struct Visitor;
161
162 impl<'de> de::Visitor<'de> for Visitor {
163 type Value = StopTimeoutMs;
164
165 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166 f.write_str("an unsigned 32-bit integer")
167 }
168
169 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
170 where
171 E: de::Error,
172 {
173 if v < 0 || v > i64::from(u32::max_value()) {
174 return Err(E::invalid_value(
175 de::Unexpected::Signed(v),
176 &"an unsigned 32-bit integer",
177 ));
178 }
179 Ok(StopTimeoutMs(v as u32))
180 }
181
182 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
183 where
184 E: de::Error,
185 {
186 self.visit_i64(value as i64)
187 }
188 }
189
190 deserializer.deserialize_i64(Visitor)
191 }
192}
193
194#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
196#[reference(expected = "\"parent\", \"self\", or \"#<child-name>\"")]
197pub enum RegistrationRef {
198 Named(Name),
200 Parent,
202 Self_,
204}
205
206#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
207#[serde(deny_unknown_fields)]
208#[reference_doc(fields_as = "list")]
209pub struct RunnerRegistration {
210 pub runner: Name,
212
213 pub from: RegistrationRef,
219
220 #[serde(skip_serializing_if = "Option::is_none")]
223 pub r#as: Option<Name>,
224}
225
226#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
227#[serde(deny_unknown_fields)]
228#[reference_doc(fields_as = "list")]
229pub struct ResolverRegistration {
230 pub resolver: Name,
233
234 pub from: RegistrationRef,
240
241 pub scheme: cm_types::UrlScheme,
244}
245
246impl FromClause for RunnerRegistration {
247 fn from_(&self) -> OneOrMany<AnyRef<'_>> {
248 OneOrMany::One(AnyRef::from(&self.from))
249 }
250}
251
252impl FromClause for ResolverRegistration {
253 fn from_(&self) -> OneOrMany<AnyRef<'_>> {
254 OneOrMany::One(AnyRef::from(&self.from))
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 AsClause for DebugRegistration {
279 fn r#as(&self) -> Option<&BorrowedName> {
280 self.r#as.as_ref().map(Name::as_ref)
281 }
282}
283
284impl PathClause for DebugRegistration {
285 fn path(&self) -> Option<&Path> {
286 None
287 }
288}
289
290impl FromClause for DebugRegistration {
291 fn from_(&self) -> OneOrMany<AnyRef<'_>> {
292 OneOrMany::One(AnyRef::from(&self.from))
293 }
294}
295
296impl CapabilityClause for DebugRegistration {
297 fn service(&self) -> Option<OneOrMany<&BorrowedName>> {
298 None
299 }
300 fn protocol(&self) -> Option<OneOrMany<&BorrowedName>> {
301 option_one_or_many_as_ref(&self.protocol)
302 }
303 fn directory(&self) -> Option<OneOrMany<&BorrowedName>> {
304 None
305 }
306 fn storage(&self) -> Option<OneOrMany<&BorrowedName>> {
307 None
308 }
309 fn runner(&self) -> Option<OneOrMany<&BorrowedName>> {
310 None
311 }
312 fn resolver(&self) -> Option<OneOrMany<&BorrowedName>> {
313 None
314 }
315 fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>> {
316 None
317 }
318 fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>> {
319 None
320 }
321 fn config(&self) -> Option<OneOrMany<&BorrowedName>> {
322 None
323 }
324
325 fn set_service(&mut self, _o: Option<OneOrMany<Name>>) {}
326 fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
327 self.protocol = o;
328 }
329 fn set_directory(&mut self, _o: Option<OneOrMany<Name>>) {}
330 fn set_storage(&mut self, _o: Option<OneOrMany<Name>>) {}
331 fn set_runner(&mut self, _o: Option<OneOrMany<Name>>) {}
332 fn set_resolver(&mut self, _o: Option<OneOrMany<Name>>) {}
333 fn set_event_stream(&mut self, _o: Option<OneOrMany<Name>>) {}
334 fn set_dictionary(&mut self, _o: Option<OneOrMany<Name>>) {}
335 fn set_config(&mut self, _o: Option<OneOrMany<Name>>) {}
336
337 fn availability(&self) -> Option<Availability> {
338 None
339 }
340 fn set_availability(&mut self, _a: Option<Availability>) {}
341
342 fn decl_type(&self) -> &'static str {
343 "debug"
344 }
345 fn supported(&self) -> &[&'static str] {
346 &["service", "protocol"]
347 }
348 fn are_many_names_allowed(&self) -> bool {
349 ["protocol"].contains(&self.capability_type().unwrap())
350 }
351}