1use crate::types::common::*;
6use crate::types::right::Rights;
7use crate::{
8 AnyRef, AsClauseContext, CanonicalizeContext, DictionaryRef, Error, EventScope,
9 FromClauseContext, SourceAvailability,
10};
11
12use crate::one_or_many::{OneOrMany, one_or_many_from_context};
13pub use cm_types::{
14 Availability, BorrowedName, BoundedName, DependencyType, HandleType, Name, OnTerminate,
15 ParseError, Path, RelativePath, StartupMode, Url,
16};
17use cml_macro::{OneOrMany, Reference};
18use reference_doc::ReferenceDoc;
19use serde::{Deserialize, Serialize};
20
21use std::fmt;
22use std::sync::Arc;
23
24#[derive(Deserialize, Debug, PartialEq, Clone, ReferenceDoc, Serialize)]
56#[serde(deny_unknown_fields)]
57#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
58pub struct Expose {
59 #[serde(skip_serializing_if = "Option::is_none")]
61 #[reference_doc(skip = true)]
62 pub service: Option<OneOrMany<Name>>,
63
64 #[serde(skip_serializing_if = "Option::is_none")]
66 #[reference_doc(skip = true)]
67 pub protocol: Option<OneOrMany<Name>>,
68
69 #[serde(skip_serializing_if = "Option::is_none")]
71 #[reference_doc(skip = true)]
72 pub directory: Option<OneOrMany<Name>>,
73
74 #[serde(skip_serializing_if = "Option::is_none")]
76 #[reference_doc(skip = true)]
77 pub runner: Option<OneOrMany<Name>>,
78
79 #[serde(skip_serializing_if = "Option::is_none")]
81 #[reference_doc(skip = true)]
82 pub resolver: Option<OneOrMany<Name>>,
83
84 #[serde(skip_serializing_if = "Option::is_none")]
86 #[reference_doc(skip = true)]
87 pub dictionary: Option<OneOrMany<Name>>,
88
89 #[serde(skip_serializing_if = "Option::is_none")]
91 #[reference_doc(skip = true)]
92 pub config: Option<OneOrMany<Name>>,
93
94 pub from: OneOrMany<ExposeFromRef>,
101
102 #[serde(skip_serializing_if = "Option::is_none")]
106 pub r#as: Option<Name>,
107
108 #[serde(skip_serializing_if = "Option::is_none")]
110 pub to: Option<ExposeToRef>,
111
112 #[serde(skip_serializing_if = "Option::is_none")]
115 #[reference_doc(json_type = "array of string")]
116 pub rights: Option<Rights>,
117
118 #[serde(skip_serializing_if = "Option::is_none")]
121 pub subdir: Option<RelativePath>,
122
123 #[serde(skip_serializing_if = "Option::is_none")]
125 pub event_stream: Option<OneOrMany<Name>>,
126
127 #[serde(skip_serializing_if = "Option::is_none")]
131 pub scope: Option<OneOrMany<EventScope>>,
132
133 #[serde(skip_serializing_if = "Option::is_none")]
150 pub availability: Option<Availability>,
151
152 #[serde(skip_serializing_if = "Option::is_none")]
157 pub source_availability: Option<SourceAvailability>,
158}
159
160impl Expose {
161 pub fn new_from(from: OneOrMany<ExposeFromRef>) -> Self {
162 Self {
163 from,
164 service: None,
165 protocol: None,
166 directory: None,
167 config: None,
168 runner: None,
169 resolver: None,
170 dictionary: None,
171 r#as: None,
172 to: None,
173 rights: None,
174 subdir: None,
175 event_stream: None,
176 scope: None,
177 availability: None,
178 source_availability: None,
179 }
180 }
181}
182
183#[derive(OneOrMany, Debug, Clone)]
185#[one_or_many(
186 expected = "one or an array of \"framework\", \"self\", \"#<child-name>\", or a dictionary path",
187 inner_type = "ExposeFromRef",
188 min_length = 1,
189 unique_items = true
190)]
191pub struct OneOrManyExposeFromRefs;
192
193#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
195#[reference(expected = "\"framework\", \"self\", \"void\", or \"#<child-name>\"")]
196pub enum ExposeFromRef {
197 Named(Name),
199 Framework,
201 Self_,
203 Void,
205 Dictionary(DictionaryRef),
207}
208
209#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
211#[reference(expected = "\"parent\", \"framework\", or none")]
212pub enum ExposeToRef {
213 Parent,
215 Framework,
217}
218
219#[derive(Debug, Clone, Serialize)]
220pub struct ContextExpose {
221 #[serde(skip)]
222 pub origin: Arc<std::path::Path>,
223 #[serde(skip_serializing_if = "Option::is_none")]
224 pub service: Option<ContextSpanned<OneOrMany<Name>>>,
225 #[serde(skip_serializing_if = "Option::is_none")]
226 pub protocol: Option<ContextSpanned<OneOrMany<Name>>>,
227 #[serde(skip_serializing_if = "Option::is_none")]
228 pub directory: Option<ContextSpanned<OneOrMany<Name>>>,
229 #[serde(skip_serializing_if = "Option::is_none")]
230 pub runner: Option<ContextSpanned<OneOrMany<Name>>>,
231 #[serde(skip_serializing_if = "Option::is_none")]
232 pub resolver: Option<ContextSpanned<OneOrMany<Name>>>,
233 #[serde(skip_serializing_if = "Option::is_none")]
234 pub dictionary: Option<ContextSpanned<OneOrMany<Name>>>,
235 #[serde(skip_serializing_if = "Option::is_none")]
236 pub config: Option<ContextSpanned<OneOrMany<Name>>>,
237 pub from: ContextSpanned<OneOrMany<ExposeFromRef>>,
238 #[serde(skip_serializing_if = "Option::is_none")]
239 pub to: Option<ContextSpanned<ExposeToRef>>,
240 #[serde(skip_serializing_if = "Option::is_none")]
241 pub r#as: Option<ContextSpanned<Name>>,
242 #[serde(skip_serializing_if = "Option::is_none")]
243 pub rights: Option<ContextSpanned<Rights>>,
244 #[serde(skip_serializing_if = "Option::is_none")]
245 pub subdir: Option<ContextSpanned<RelativePath>>,
246 #[serde(skip_serializing_if = "Option::is_none")]
247 pub event_stream: Option<ContextSpanned<OneOrMany<Name>>>,
248 #[serde(skip_serializing_if = "Option::is_none")]
249 pub scope: Option<ContextSpanned<OneOrMany<EventScope>>>,
250 #[serde(skip_serializing_if = "Option::is_none")]
251 pub availability: Option<ContextSpanned<Availability>>,
252 #[serde(skip_serializing_if = "Option::is_none")]
253 pub source_availability: Option<ContextSpanned<SourceAvailability>>,
254}
255
256impl Default for ContextExpose {
257 fn default() -> Self {
258 Self {
259 origin: Arc::from(std::path::Path::new("")),
260
261 from: ContextSpanned {
262 value: OneOrMany::One(ExposeFromRef::Self_),
263 origin: Arc::from(std::path::Path::new("")),
264 },
265
266 service: None,
267 protocol: None,
268 directory: None,
269 runner: None,
270 resolver: None,
271 dictionary: None,
272 config: None,
273 to: None,
274 r#as: None,
275 rights: None,
276 subdir: None,
277 event_stream: None,
278 scope: None,
279 availability: None,
280 source_availability: None,
281 }
282 }
283}
284
285impl ContextCapabilityClause for ContextExpose {
286 fn service(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
287 option_one_or_many_as_ref_context(&self.service)
288 }
289 fn protocol(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
290 option_one_or_many_as_ref_context(&self.protocol)
291 }
292 fn directory(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
293 option_one_or_many_as_ref_context(&self.directory)
294 }
295 fn storage(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
296 None
297 }
298 fn runner(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
299 option_one_or_many_as_ref_context(&self.runner)
300 }
301 fn resolver(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
302 option_one_or_many_as_ref_context(&self.resolver)
303 }
304 fn event_stream(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
305 option_one_or_many_as_ref_context(&self.event_stream)
306 }
307 fn dictionary(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
308 option_one_or_many_as_ref_context(&self.dictionary)
309 }
310 fn config(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
311 option_one_or_many_as_ref_context(&self.config)
312 }
313
314 fn decl_type(&self) -> &'static str {
315 "expose"
316 }
317 fn supported(&self) -> &[&'static str] {
318 &[
319 "service",
320 "protocol",
321 "directory",
322 "event_stream",
323 "runner",
324 "resolver",
325 "config",
326 "dictionary",
327 ]
328 }
329 fn are_many_names_allowed(&self) -> bool {
330 [
331 "service",
332 "protocol",
333 "directory",
334 "runner",
335 "resolver",
336 "event_stream",
337 "config",
338 "dictionary",
339 ]
340 .contains(&self.capability_type(None).unwrap())
341 }
342
343 fn set_service(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
344 self.service = o;
345 }
346 fn set_protocol(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
347 self.protocol = o;
348 }
349 fn set_directory(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
350 self.directory = o;
351 }
352 fn set_storage(&mut self, _o: Option<ContextSpanned<OneOrMany<Name>>>) {}
353 fn set_runner(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
354 self.runner = o;
355 }
356 fn set_resolver(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
357 self.resolver = o;
358 }
359 fn set_event_stream(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
360 self.event_stream = o;
361 }
362 fn set_dictionary(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
363 self.dictionary = o;
364 }
365 fn set_config(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
366 self.config = o;
367 }
368
369 fn origin(&self) -> &Arc<std::path::Path> {
370 &self.origin
371 }
372
373 fn availability(&self) -> Option<ContextSpanned<Availability>> {
374 None
375 }
376 fn set_availability(&mut self, _a: Option<ContextSpanned<Availability>>) {}
377}
378
379impl CanonicalizeContext for ContextExpose {
380 fn canonicalize_context(&mut self) {
381 if let Some(service) = &mut self.service {
383 service.value.canonicalize_context();
384 } else if let Some(protocol) = &mut self.protocol {
385 protocol.value.canonicalize_context();
386 } else if let Some(directory) = &mut self.directory {
387 directory.value.canonicalize_context();
388 } else if let Some(runner) = &mut self.runner {
389 runner.value.canonicalize_context();
390 } else if let Some(resolver) = &mut self.resolver {
391 resolver.value.canonicalize_context();
392 } else if let Some(event_stream) = &mut self.event_stream {
393 event_stream.value.canonicalize_context();
394 if let Some(scope) = &mut self.scope {
395 scope.value.canonicalize_context();
396 }
397 }
398 }
400}
401
402impl PartialEq for ContextExpose {
403 fn eq(&self, other: &Self) -> bool {
404 macro_rules! cmp {
405 ($field:ident) => {
406 match (&self.$field, &other.$field) {
407 (Some(a), Some(b)) => a.value == b.value,
408 (None, None) => true,
409 _ => false,
410 }
411 };
412 }
413
414 cmp!(service)
415 && cmp!(protocol)
416 && cmp!(directory)
417 && cmp!(runner)
418 && cmp!(resolver)
419 && cmp!(dictionary)
420 && cmp!(config)
421 && self.from.value == other.from.value
422 && cmp!(to)
423 && cmp!(r#as)
424 && cmp!(rights)
425 && cmp!(subdir)
426 && cmp!(event_stream)
427 && cmp!(scope)
428 && cmp!(availability)
429 && cmp!(source_availability)
430 }
431}
432
433impl Eq for ContextExpose {}
434
435impl ContextPathClause for ContextExpose {
436 fn path(&self) -> Option<&ContextSpanned<Path>> {
437 None
438 }
439}
440
441impl AsClauseContext for ContextExpose {
442 fn r#as(&self) -> Option<ContextSpanned<&BorrowedName>> {
443 self.r#as.as_ref().map(|spanned_name| ContextSpanned {
444 value: spanned_name.value.as_ref(),
445 origin: spanned_name.origin.clone(),
446 })
447 }
448}
449
450impl FromClauseContext for ContextExpose {
451 fn from_(&self) -> ContextSpanned<OneOrMany<AnyRef<'_>>> {
452 one_or_many_from_context(&self.from)
453 }
454}
455
456impl Hydrate for Expose {
457 type Output = ContextExpose;
458
459 fn hydrate(self, file: &Arc<std::path::Path>) -> Result<Self::Output, Error> {
460 Ok(ContextExpose {
461 origin: file.clone(),
462 service: hydrate_opt_simple(self.service, file),
463 protocol: hydrate_opt_simple(self.protocol, file),
464 directory: hydrate_opt_simple(self.directory, file),
465 runner: hydrate_opt_simple(self.runner, file),
466 resolver: hydrate_opt_simple(self.resolver, file),
467 dictionary: hydrate_opt_simple(self.dictionary, file),
468 config: hydrate_opt_simple(self.config, file),
469 from: hydrate_simple(self.from, file),
470 to: hydrate_opt_simple(self.to, file),
471 r#as: hydrate_opt_simple(self.r#as, file),
472 rights: hydrate_opt_simple(self.rights, file),
473 subdir: hydrate_opt_simple(self.subdir, file),
474 event_stream: hydrate_opt_simple(self.event_stream, file),
475 scope: hydrate_opt_simple(self.scope, file),
476 availability: hydrate_opt_simple(self.availability, file),
477 source_availability: hydrate_opt_simple(self.source_availability, file),
478 })
479 }
480}