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