1use crate::types::common::*;
6use crate::types::right::{Rights, RightsClause};
7use crate::{
8 AnyRef, AsClause, AsClauseContext, Canonicalize, CanonicalizeContext, CapabilityClause,
9 DictionaryRef, Error, EventScope, FilterClause, FromClause, FromClauseContext, PathClause,
10 SourceAvailability,
11};
12
13use crate::one_or_many::{
14 OneOrMany, one_or_many_from_context, one_or_many_from_impl, option_one_or_many_as_ref,
15};
16pub use cm_types::{
17 Availability, BorrowedName, BoundedName, DependencyType, HandleType, Name, OnTerminate,
18 ParseError, Path, RelativePath, StartupMode, Url,
19};
20use cml_macro::{OneOrMany, Reference};
21use reference_doc::ReferenceDoc;
22use serde::{Deserialize, Serialize};
23use serde_json::{Map, Value};
24
25use std::fmt;
26use std::path::PathBuf;
27use std::sync::Arc;
28
29#[derive(Deserialize, Debug, PartialEq, Clone, ReferenceDoc, Serialize)]
61#[serde(deny_unknown_fields)]
62#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
63pub struct Expose {
64 #[serde(skip_serializing_if = "Option::is_none")]
66 #[reference_doc(skip = true)]
67 pub service: Option<OneOrMany<Name>>,
68
69 #[serde(skip_serializing_if = "Option::is_none")]
71 #[reference_doc(skip = true)]
72 pub protocol: Option<OneOrMany<Name>>,
73
74 #[serde(skip_serializing_if = "Option::is_none")]
76 #[reference_doc(skip = true)]
77 pub directory: Option<OneOrMany<Name>>,
78
79 #[serde(skip_serializing_if = "Option::is_none")]
81 #[reference_doc(skip = true)]
82 pub runner: Option<OneOrMany<Name>>,
83
84 #[serde(skip_serializing_if = "Option::is_none")]
86 #[reference_doc(skip = true)]
87 pub resolver: Option<OneOrMany<Name>>,
88
89 #[serde(skip_serializing_if = "Option::is_none")]
91 #[reference_doc(skip = true)]
92 pub dictionary: Option<OneOrMany<Name>>,
93
94 #[serde(skip_serializing_if = "Option::is_none")]
96 #[reference_doc(skip = true)]
97 pub config: Option<OneOrMany<Name>>,
98
99 pub from: OneOrMany<ExposeFromRef>,
106
107 #[serde(skip_serializing_if = "Option::is_none")]
111 pub r#as: Option<Name>,
112
113 #[serde(skip_serializing_if = "Option::is_none")]
115 pub to: Option<ExposeToRef>,
116
117 #[serde(skip_serializing_if = "Option::is_none")]
120 #[reference_doc(json_type = "array of string")]
121 pub rights: Option<Rights>,
122
123 #[serde(skip_serializing_if = "Option::is_none")]
126 pub subdir: Option<RelativePath>,
127
128 #[serde(skip_serializing_if = "Option::is_none")]
130 pub event_stream: Option<OneOrMany<Name>>,
131
132 #[serde(skip_serializing_if = "Option::is_none")]
136 pub scope: Option<OneOrMany<EventScope>>,
137
138 #[serde(skip_serializing_if = "Option::is_none")]
155 pub availability: Option<Availability>,
156
157 #[serde(skip_serializing_if = "Option::is_none")]
162 pub source_availability: Option<SourceAvailability>,
163}
164
165impl Expose {
166 pub fn new_from(from: OneOrMany<ExposeFromRef>) -> Self {
167 Self {
168 from,
169 service: None,
170 protocol: None,
171 directory: None,
172 config: None,
173 runner: None,
174 resolver: None,
175 dictionary: None,
176 r#as: None,
177 to: None,
178 rights: None,
179 subdir: None,
180 event_stream: None,
181 scope: None,
182 availability: None,
183 source_availability: None,
184 }
185 }
186}
187
188impl FromClause for Expose {
189 fn from_(&self) -> OneOrMany<AnyRef<'_>> {
190 one_or_many_from_impl(&self.from)
191 }
192}
193
194impl AsClause for Expose {
195 fn r#as(&self) -> Option<&BorrowedName> {
196 self.r#as.as_ref().map(Name::as_ref)
197 }
198}
199
200impl PathClause for Expose {
201 fn path(&self) -> Option<&Path> {
202 None
203 }
204}
205
206impl FilterClause for Expose {
207 fn filter(&self) -> Option<&Map<String, Value>> {
208 None
209 }
210}
211
212impl RightsClause for Expose {
213 fn rights(&self) -> Option<&Rights> {
214 self.rights.as_ref()
215 }
216}
217
218impl Canonicalize for Expose {
219 fn canonicalize(&mut self) {
220 if let Some(service) = &mut self.service {
222 service.canonicalize();
223 } else if let Some(protocol) = &mut self.protocol {
224 protocol.canonicalize();
225 } else if let Some(directory) = &mut self.directory {
226 directory.canonicalize();
227 } else if let Some(runner) = &mut self.runner {
228 runner.canonicalize();
229 } else if let Some(resolver) = &mut self.resolver {
230 resolver.canonicalize();
231 } else if let Some(event_stream) = &mut self.event_stream {
232 event_stream.canonicalize();
233 if let Some(scope) = &mut self.scope {
234 scope.canonicalize();
235 }
236 }
237 }
239}
240
241impl CapabilityClause for Expose {
242 fn service(&self) -> Option<OneOrMany<&BorrowedName>> {
243 option_one_or_many_as_ref(&self.service)
244 }
245 fn protocol(&self) -> Option<OneOrMany<&BorrowedName>> {
246 option_one_or_many_as_ref(&self.protocol)
247 }
248 fn directory(&self) -> Option<OneOrMany<&BorrowedName>> {
249 option_one_or_many_as_ref(&self.directory)
250 }
251 fn storage(&self) -> Option<OneOrMany<&BorrowedName>> {
252 None
253 }
254 fn runner(&self) -> Option<OneOrMany<&BorrowedName>> {
255 option_one_or_many_as_ref(&self.runner)
256 }
257 fn resolver(&self) -> Option<OneOrMany<&BorrowedName>> {
258 option_one_or_many_as_ref(&self.resolver)
259 }
260 fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>> {
261 option_one_or_many_as_ref(&self.event_stream)
262 }
263 fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>> {
264 option_one_or_many_as_ref(&self.dictionary)
265 }
266 fn config(&self) -> Option<OneOrMany<&BorrowedName>> {
267 option_one_or_many_as_ref(&self.config)
268 }
269
270 fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
271 self.service = o;
272 }
273 fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
274 self.protocol = o;
275 }
276 fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
277 self.directory = o;
278 }
279 fn set_storage(&mut self, _o: Option<OneOrMany<Name>>) {}
280 fn set_runner(&mut self, o: Option<OneOrMany<Name>>) {
281 self.runner = o;
282 }
283 fn set_resolver(&mut self, o: Option<OneOrMany<Name>>) {
284 self.resolver = o;
285 }
286 fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
287 self.event_stream = o;
288 }
289 fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>) {
290 self.dictionary = o;
291 }
292 fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
293 self.config = o;
294 }
295
296 fn availability(&self) -> Option<Availability> {
297 None
298 }
299 fn set_availability(&mut self, _a: Option<Availability>) {}
300
301 fn decl_type(&self) -> &'static str {
302 "expose"
303 }
304 fn supported(&self) -> &[&'static str] {
305 &[
306 "service",
307 "protocol",
308 "directory",
309 "runner",
310 "resolver",
311 "event_stream",
312 "dictionary",
313 "config",
314 ]
315 }
316 fn are_many_names_allowed(&self) -> bool {
317 [
318 "service",
319 "protocol",
320 "directory",
321 "runner",
322 "resolver",
323 "event_stream",
324 "dictionary",
325 "config",
326 ]
327 .contains(&self.capability_type().unwrap())
328 }
329}
330
331#[derive(OneOrMany, Debug, Clone)]
333#[one_or_many(
334 expected = "one or an array of \"framework\", \"self\", \"#<child-name>\", or a dictionary path",
335 inner_type = "ExposeFromRef",
336 min_length = 1,
337 unique_items = true
338)]
339pub struct OneOrManyExposeFromRefs;
340
341#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
343#[reference(expected = "\"framework\", \"self\", \"void\", or \"#<child-name>\"")]
344pub enum ExposeFromRef {
345 Named(Name),
347 Framework,
349 Self_,
351 Void,
353 Dictionary(DictionaryRef),
355}
356
357#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
359#[reference(expected = "\"parent\", \"framework\", or none")]
360pub enum ExposeToRef {
361 Parent,
363 Framework,
365}
366
367#[derive(Debug, Clone, Serialize)]
368pub struct ContextExpose {
369 #[serde(skip)]
370 pub origin: Arc<PathBuf>,
371 #[serde(skip_serializing_if = "Option::is_none")]
372 pub service: Option<ContextSpanned<OneOrMany<Name>>>,
373 #[serde(skip_serializing_if = "Option::is_none")]
374 pub protocol: Option<ContextSpanned<OneOrMany<Name>>>,
375 #[serde(skip_serializing_if = "Option::is_none")]
376 pub directory: Option<ContextSpanned<OneOrMany<Name>>>,
377 #[serde(skip_serializing_if = "Option::is_none")]
378 pub runner: Option<ContextSpanned<OneOrMany<Name>>>,
379 #[serde(skip_serializing_if = "Option::is_none")]
380 pub resolver: Option<ContextSpanned<OneOrMany<Name>>>,
381 #[serde(skip_serializing_if = "Option::is_none")]
382 pub dictionary: Option<ContextSpanned<OneOrMany<Name>>>,
383 #[serde(skip_serializing_if = "Option::is_none")]
384 pub config: Option<ContextSpanned<OneOrMany<Name>>>,
385 pub from: ContextSpanned<OneOrMany<ExposeFromRef>>,
386 #[serde(skip_serializing_if = "Option::is_none")]
387 pub to: Option<ContextSpanned<ExposeToRef>>,
388 #[serde(skip_serializing_if = "Option::is_none")]
389 pub r#as: Option<ContextSpanned<Name>>,
390 #[serde(skip_serializing_if = "Option::is_none")]
391 pub rights: Option<ContextSpanned<Rights>>,
392 #[serde(skip_serializing_if = "Option::is_none")]
393 pub subdir: Option<ContextSpanned<RelativePath>>,
394 #[serde(skip_serializing_if = "Option::is_none")]
395 pub event_stream: Option<ContextSpanned<OneOrMany<Name>>>,
396 #[serde(skip_serializing_if = "Option::is_none")]
397 pub scope: Option<ContextSpanned<OneOrMany<EventScope>>>,
398 #[serde(skip_serializing_if = "Option::is_none")]
399 pub availability: Option<ContextSpanned<Availability>>,
400 #[serde(skip_serializing_if = "Option::is_none")]
401 pub source_availability: Option<ContextSpanned<SourceAvailability>>,
402}
403
404impl ContextCapabilityClause for ContextExpose {
405 fn service(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
406 option_one_or_many_as_ref_context(&self.service)
407 }
408 fn protocol(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
409 option_one_or_many_as_ref_context(&self.protocol)
410 }
411 fn directory(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
412 option_one_or_many_as_ref_context(&self.directory)
413 }
414 fn storage(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
415 None
416 }
417 fn runner(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
418 option_one_or_many_as_ref_context(&self.runner)
419 }
420 fn resolver(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
421 option_one_or_many_as_ref_context(&self.resolver)
422 }
423 fn event_stream(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
424 option_one_or_many_as_ref_context(&self.event_stream)
425 }
426 fn dictionary(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
427 option_one_or_many_as_ref_context(&self.dictionary)
428 }
429 fn config(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
430 option_one_or_many_as_ref_context(&self.config)
431 }
432
433 fn decl_type(&self) -> &'static str {
434 "expose"
435 }
436 fn supported(&self) -> &[&'static str] {
437 &[
438 "service",
439 "protocol",
440 "directory",
441 "event_stream",
442 "runner",
443 "resolver",
444 "config",
445 "dicitionary",
446 ]
447 }
448 fn are_many_names_allowed(&self) -> bool {
449 [
450 "service",
451 "protocol",
452 "directory",
453 "runner",
454 "resolver",
455 "event_stream",
456 "config",
457 "dicitionary",
458 ]
459 .contains(&self.capability_type(None).unwrap())
460 }
461
462 fn set_service(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
463 self.service = o;
464 }
465 fn set_protocol(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
466 self.protocol = o;
467 }
468 fn set_directory(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
469 self.directory = o;
470 }
471 fn set_storage(&mut self, _o: Option<ContextSpanned<OneOrMany<Name>>>) {}
472 fn set_runner(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
473 self.runner = o;
474 }
475 fn set_resolver(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
476 self.resolver = o;
477 }
478 fn set_event_stream(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
479 self.event_stream = o;
480 }
481 fn set_dictionary(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
482 self.dictionary = o;
483 }
484 fn set_config(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
485 self.config = o;
486 }
487
488 fn origin(&self) -> &Arc<PathBuf> {
489 &self.origin
490 }
491
492 fn availability(&self) -> Option<ContextSpanned<Availability>> {
493 None
494 }
495 fn set_availability(&mut self, _a: Option<ContextSpanned<Availability>>) {}
496}
497
498impl CanonicalizeContext for ContextExpose {
499 fn canonicalize_context(&mut self) {
500 if let Some(service) = &mut self.service {
502 service.value.canonicalize_context();
503 } else if let Some(protocol) = &mut self.protocol {
504 protocol.value.canonicalize_context();
505 } else if let Some(directory) = &mut self.directory {
506 directory.value.canonicalize_context();
507 } else if let Some(runner) = &mut self.runner {
508 runner.value.canonicalize_context();
509 } else if let Some(resolver) = &mut self.resolver {
510 resolver.value.canonicalize_context();
511 } else if let Some(event_stream) = &mut self.event_stream {
512 event_stream.value.canonicalize_context();
513 if let Some(scope) = &mut self.scope {
514 scope.value.canonicalize_context();
515 }
516 }
517 }
519}
520
521impl PartialEq for ContextExpose {
522 fn eq(&self, other: &Self) -> bool {
523 macro_rules! cmp {
524 ($field:ident) => {
525 match (&self.$field, &other.$field) {
526 (Some(a), Some(b)) => a.value == b.value,
527 (None, None) => true,
528 _ => false,
529 }
530 };
531 }
532
533 cmp!(service)
534 && cmp!(protocol)
535 && cmp!(directory)
536 && cmp!(runner)
537 && cmp!(resolver)
538 && cmp!(dictionary)
539 && cmp!(config)
540 && self.from.value == other.from.value
541 && cmp!(to)
542 && cmp!(r#as)
543 && cmp!(rights)
544 && cmp!(subdir)
545 && cmp!(event_stream)
546 && cmp!(scope)
547 && cmp!(availability)
548 && cmp!(source_availability)
549 }
550}
551
552impl Eq for ContextExpose {}
553
554impl ContextPathClause for ContextExpose {
555 fn path(&self) -> Option<&ContextSpanned<Path>> {
556 None
557 }
558}
559
560impl AsClauseContext for ContextExpose {
561 fn r#as(&self) -> Option<ContextSpanned<&BorrowedName>> {
562 self.r#as.as_ref().map(|spanned_name| ContextSpanned {
563 value: spanned_name.value.as_ref(),
564 origin: spanned_name.origin.clone(),
565 })
566 }
567}
568
569impl FromClauseContext for ContextExpose {
570 fn from_(&self) -> ContextSpanned<OneOrMany<AnyRef<'_>>> {
571 one_or_many_from_context(&self.from)
572 }
573}
574
575impl Hydrate for Expose {
576 type Output = ContextExpose;
577
578 fn hydrate(self, file: &Arc<PathBuf>) -> Result<Self::Output, Error> {
579 Ok(ContextExpose {
580 origin: file.clone(),
581 service: hydrate_opt_simple(self.service, file),
582 protocol: hydrate_opt_simple(self.protocol, file),
583 directory: hydrate_opt_simple(self.directory, file),
584 runner: hydrate_opt_simple(self.runner, file),
585 resolver: hydrate_opt_simple(self.resolver, file),
586 dictionary: hydrate_opt_simple(self.dictionary, file),
587 config: hydrate_opt_simple(self.config, file),
588 from: hydrate_simple(self.from, file),
589 to: hydrate_opt_simple(self.to, file),
590 r#as: hydrate_opt_simple(self.r#as, file),
591 rights: hydrate_opt_simple(self.rights, file),
592 subdir: hydrate_opt_simple(self.subdir, file),
593 event_stream: hydrate_opt_simple(self.event_stream, file),
594 scope: hydrate_opt_simple(self.scope, file),
595 availability: hydrate_opt_simple(self.availability, file),
596 source_availability: hydrate_opt_simple(self.source_availability, file),
597 })
598 }
599}