1use crate::{
6 AnyRef, AsClauseContext, CanonicalizeContext, ConfigNestedValueType, ConfigType, Error,
7};
8
9use crate::one_or_many::{OneOrMany, always_one_context};
10use crate::types::common::*;
11use crate::types::right::{Rights, RightsClause};
12pub use cm_types::{
13 Availability, BorrowedName, BoundedName, DeliveryType, DependencyType, HandleType, Name,
14 OnTerminate, ParseError, Path, RelativePath, StartupMode, StorageId, Url,
15};
16use cml_macro::Reference;
17use reference_doc::ReferenceDoc;
18use serde::{Deserialize, Serialize};
19use std::num::NonZeroU32;
20
21use std::fmt;
22use std::path::PathBuf;
23use std::sync::Arc;
24
25#[derive(Deserialize, Debug, PartialEq, Clone, ReferenceDoc, Serialize, Default)]
26#[serde(deny_unknown_fields)]
27#[reference_doc(fields_as = "list")]
28pub struct Capability {
29 #[serde(skip_serializing_if = "Option::is_none")]
32 #[reference_doc(skip = true)]
33 pub service: Option<OneOrMany<Name>>,
34
35 #[serde(skip_serializing_if = "Option::is_none")]
38 #[reference_doc(skip = true)]
39 pub protocol: Option<OneOrMany<Name>>,
40
41 #[serde(skip_serializing_if = "Option::is_none")]
43 #[reference_doc(skip = true)]
44 pub directory: Option<Name>,
45
46 #[serde(skip_serializing_if = "Option::is_none")]
48 #[reference_doc(skip = true)]
49 pub storage: Option<Name>,
50
51 #[serde(skip_serializing_if = "Option::is_none")]
53 #[reference_doc(skip = true)]
54 pub runner: Option<Name>,
55
56 #[serde(skip_serializing_if = "Option::is_none")]
58 #[reference_doc(skip = true)]
59 pub resolver: Option<Name>,
60
61 #[serde(skip_serializing_if = "Option::is_none")]
63 #[reference_doc(skip = true)]
64 pub event_stream: Option<OneOrMany<Name>>,
65
66 #[serde(skip_serializing_if = "Option::is_none")]
68 #[reference_doc(skip = true)]
69 pub dictionary: Option<Name>,
70
71 #[serde(skip_serializing_if = "Option::is_none")]
73 #[reference_doc(skip = true)]
74 pub config: Option<Name>,
75
76 #[serde(skip_serializing_if = "Option::is_none")]
98 pub path: Option<Path>,
99
100 #[serde(skip_serializing_if = "Option::is_none")]
103 #[reference_doc(json_type = "array of string")]
104 pub rights: Option<Rights>,
105
106 #[serde(skip_serializing_if = "Option::is_none")]
113 pub from: Option<CapabilityFromRef>,
114
115 #[serde(skip_serializing_if = "Option::is_none")]
118 pub backing_dir: Option<Name>,
119
120 #[serde(skip_serializing_if = "Option::is_none")]
123 pub subdir: Option<RelativePath>,
124
125 #[serde(skip_serializing_if = "Option::is_none")]
134 pub storage_id: Option<StorageId>,
135
136 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
149 #[reference_doc(rename = "type")]
150 pub config_type: Option<ConfigType>,
151
152 #[serde(rename = "max_size", skip_serializing_if = "Option::is_none")]
155 #[reference_doc(rename = "max_size")]
156 pub config_max_size: Option<NonZeroU32>,
157
158 #[serde(rename = "max_count", skip_serializing_if = "Option::is_none")]
161 #[reference_doc(rename = "max_count")]
162 pub config_max_count: Option<NonZeroU32>,
163
164 #[serde(rename = "element", skip_serializing_if = "Option::is_none")]
182 #[reference_doc(rename = "element", json_type = "object")]
183 pub config_element_type: Option<ConfigNestedValueType>,
184
185 #[serde(skip_serializing_if = "Option::is_none")]
187 pub value: Option<serde_json::Value>,
188
189 #[serde(skip_serializing_if = "Option::is_none")]
199 pub delivery: Option<DeliveryType>,
200}
201
202#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
204#[reference(expected = "\"parent\", \"self\", or \"#<child-name>\"")]
205pub enum CapabilityFromRef {
206 Named(Name),
208 Parent,
210 Self_,
212}
213
214#[derive(Debug, Clone, Serialize)]
215pub struct ContextCapability {
216 #[serde(skip)]
217 pub origin: Arc<PathBuf>,
218
219 #[serde(skip_serializing_if = "Option::is_none")]
220 pub service: Option<ContextSpanned<OneOrMany<Name>>>,
221
222 #[serde(skip_serializing_if = "Option::is_none")]
223 pub protocol: Option<ContextSpanned<OneOrMany<Name>>>,
224
225 #[serde(skip_serializing_if = "Option::is_none")]
226 pub directory: Option<ContextSpanned<Name>>,
227
228 #[serde(skip_serializing_if = "Option::is_none")]
229 pub storage: Option<ContextSpanned<Name>>,
230
231 #[serde(skip_serializing_if = "Option::is_none")]
232 pub runner: Option<ContextSpanned<Name>>,
233
234 #[serde(skip_serializing_if = "Option::is_none")]
235 pub resolver: Option<ContextSpanned<Name>>,
236
237 #[serde(skip_serializing_if = "Option::is_none")]
238 pub event_stream: Option<ContextSpanned<OneOrMany<Name>>>,
239
240 #[serde(skip_serializing_if = "Option::is_none")]
241 pub dictionary: Option<ContextSpanned<Name>>,
242
243 #[serde(skip_serializing_if = "Option::is_none")]
244 pub config: Option<ContextSpanned<Name>>,
245
246 #[serde(skip_serializing_if = "Option::is_none")]
247 pub path: Option<ContextSpanned<Path>>,
248
249 #[serde(skip_serializing_if = "Option::is_none")]
250 pub rights: Option<ContextSpanned<Rights>>,
251
252 #[serde(skip_serializing_if = "Option::is_none")]
253 pub from: Option<ContextSpanned<CapabilityFromRef>>,
254
255 #[serde(skip_serializing_if = "Option::is_none")]
256 pub backing_dir: Option<ContextSpanned<Name>>,
257
258 #[serde(skip_serializing_if = "Option::is_none")]
259 pub subdir: Option<ContextSpanned<RelativePath>>,
260
261 #[serde(skip_serializing_if = "Option::is_none")]
262 pub storage_id: Option<ContextSpanned<StorageId>>,
263
264 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
265 pub config_type: Option<ContextSpanned<ConfigType>>,
266
267 #[serde(rename = "max_size", skip_serializing_if = "Option::is_none")]
268 pub config_max_size: Option<ContextSpanned<NonZeroU32>>,
269
270 #[serde(rename = "max_count", skip_serializing_if = "Option::is_none")]
271 pub config_max_count: Option<ContextSpanned<NonZeroU32>>,
272
273 #[serde(rename = "element", skip_serializing_if = "Option::is_none")]
274 pub config_element_type: Option<ContextSpanned<ConfigNestedValueType>>,
275
276 #[serde(skip_serializing_if = "Option::is_none")]
277 pub value: Option<ContextSpanned<serde_json::Value>>,
278
279 #[serde(skip_serializing_if = "Option::is_none")]
280 pub delivery: Option<ContextSpanned<DeliveryType>>,
281}
282
283impl Default for ContextCapability {
284 fn default() -> Self {
285 Self {
286 origin: Arc::new(PathBuf::new()),
287 service: None,
288 protocol: None,
289 directory: None,
290 storage: None,
291 runner: None,
292 resolver: None,
293 event_stream: None,
294 dictionary: None,
295 config: None,
296 path: None,
297 rights: None,
298 from: None,
299 backing_dir: None,
300 subdir: None,
301 storage_id: None,
302 config_type: None,
303 config_max_size: None,
304 config_max_count: None,
305 config_element_type: None,
306 value: None,
307 delivery: None,
308 }
309 }
310}
311
312impl CanonicalizeContext for ContextCapability {
313 fn canonicalize_context(&mut self) {
314 if let Some(service) = &mut self.service {
316 service.value.canonicalize_context()
317 } else if let Some(protocol) = &mut self.protocol {
318 protocol.value.canonicalize_context()
319 } else if let Some(event_stream) = &mut self.event_stream {
320 event_stream.value.canonicalize_context()
321 }
322 }
323}
324
325impl RightsClause for ContextCapability {
326 fn rights(&self) -> Option<&Rights> {
327 self.rights.as_ref().map(|r| &r.value)
328 }
329}
330
331impl ContextCapabilityClause for ContextCapability {
332 fn service(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
333 option_one_or_many_as_ref_context(&self.service)
334 }
335 fn protocol(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
336 option_one_or_many_as_ref_context(&self.protocol)
337 }
338 fn directory(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
339 self.directory.as_ref().map(|s| ContextSpanned {
340 value: OneOrMany::One((s.value).as_ref()),
341 origin: s.origin.clone(),
342 })
343 }
344 fn storage(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
345 self.storage.as_ref().map(|s| ContextSpanned {
346 value: OneOrMany::One((s.value).as_ref()),
347 origin: s.origin.clone(),
348 })
349 }
350 fn runner(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
351 self.runner.as_ref().map(|s| ContextSpanned {
352 value: OneOrMany::One((s.value).as_ref()),
353 origin: s.origin.clone(),
354 })
355 }
356 fn resolver(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
357 self.resolver.as_ref().map(|s| ContextSpanned {
358 value: OneOrMany::One((s.value).as_ref()),
359 origin: s.origin.clone(),
360 })
361 }
362 fn event_stream(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
363 option_one_or_many_as_ref_context(&self.event_stream)
364 }
365 fn dictionary(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
366 self.dictionary.as_ref().map(|s| ContextSpanned {
367 value: OneOrMany::One((s.value).as_ref()),
368 origin: s.origin.clone(),
369 })
370 }
371 fn config(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
372 self.config.as_ref().map(|s| ContextSpanned {
373 value: OneOrMany::One((s.value).as_ref()),
374 origin: s.origin.clone(),
375 })
376 }
377
378 fn decl_type(&self) -> &'static str {
379 "capability"
380 }
381 fn supported(&self) -> &[&'static str] {
382 &[
383 "service",
384 "protocol",
385 "directory",
386 "storage",
387 "event_stream",
388 "runner",
389 "resolver",
390 "config",
391 "dictionary",
392 ]
393 }
394 fn are_many_names_allowed(&self) -> bool {
395 ["service", "protocol", "event_stream"].contains(&self.capability_type(None).unwrap())
396 }
397
398 fn set_service(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
399 self.service = o;
400 }
401 fn set_protocol(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
402 self.protocol = o;
403 }
404 fn set_directory(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
405 self.directory = always_one_context(o);
406 }
407 fn set_storage(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
408 self.storage = always_one_context(o);
409 }
410 fn set_runner(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
411 self.runner = always_one_context(o);
412 }
413 fn set_resolver(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
414 self.resolver = always_one_context(o);
415 }
416 fn set_event_stream(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
417 self.event_stream = o;
418 }
419 fn set_dictionary(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
420 self.dictionary = always_one_context(o);
421 }
422 fn set_config(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
423 self.config = always_one_context(o);
424 }
425
426 fn origin(&self) -> &Arc<PathBuf> {
428 &self.origin
429 }
430
431 fn availability(&self) -> Option<ContextSpanned<Availability>> {
432 None
433 }
434 fn set_availability(&mut self, _a: Option<ContextSpanned<Availability>>) {}
435}
436
437impl PartialEq for ContextCapability {
438 fn eq(&self, other: &Self) -> bool {
439 macro_rules! cmp {
440 ($field:ident) => {
441 match (&self.$field, &other.$field) {
442 (Some(a), Some(b)) => a.value == b.value,
443 (None, None) => true,
444 _ => false,
445 }
446 };
447 }
448
449 cmp!(service)
450 && cmp!(protocol)
451 && cmp!(directory)
452 && cmp!(storage)
453 && cmp!(runner)
454 && cmp!(resolver)
455 && cmp!(dictionary)
456 && cmp!(config)
457 && cmp!(path)
458 && cmp!(rights)
459 && cmp!(from)
460 && cmp!(event_stream)
461 && cmp!(backing_dir)
462 && cmp!(subdir)
463 && cmp!(storage_id)
464 && cmp!(config_type)
465 && cmp!(config_max_size)
466 && cmp!(config_max_count)
467 && cmp!(config_element_type)
468 && cmp!(value)
469 && cmp!(delivery)
470 }
471}
472
473impl Eq for ContextCapability {}
474
475impl ContextPathClause for ContextCapability {
476 fn path(&self) -> Option<&ContextSpanned<Path>> {
477 self.path.as_ref()
478 }
479}
480
481impl AsClauseContext for ContextCapability {
482 fn r#as(&self) -> Option<ContextSpanned<&BorrowedName>> {
483 None
484 }
485}
486
487impl Hydrate for Capability {
488 type Output = ContextCapability;
489
490 fn hydrate(self, file: &Arc<PathBuf>) -> Result<Self::Output, Error> {
491 Ok(ContextCapability {
492 origin: file.clone(),
493 service: hydrate_opt_simple(self.service, file),
494 protocol: hydrate_opt_simple(self.protocol, file),
495 directory: hydrate_opt_simple(self.directory, file),
496 storage: hydrate_opt_simple(self.storage, file),
497 runner: hydrate_opt_simple(self.runner, file),
498 resolver: hydrate_opt_simple(self.resolver, file),
499 dictionary: hydrate_opt_simple(self.dictionary, file),
500 config: hydrate_opt_simple(self.config, file),
501 path: hydrate_opt_simple(self.path, file),
502 rights: hydrate_opt_simple(self.rights, file),
503 from: hydrate_opt_simple(self.from, file),
504 event_stream: hydrate_opt_simple(self.event_stream, file),
505 backing_dir: hydrate_opt_simple(self.backing_dir, file),
506 subdir: hydrate_opt_simple(self.subdir, file),
507 storage_id: hydrate_opt_simple(self.storage_id, file),
508 config_type: hydrate_opt_simple(self.config_type, file),
509 config_max_size: hydrate_opt_simple(self.config_max_size, file),
510 config_max_count: hydrate_opt_simple(self.config_max_count, file),
511 config_element_type: hydrate_opt_simple(self.config_element_type, file),
512 value: hydrate_opt_simple(self.value, file),
513 delivery: hydrate_opt_simple(self.delivery, file),
514 })
515 }
516}
517
518pub fn span_capability(cap: Capability) -> ContextSpanned<ContextCapability> {
520 let context_cap = ContextCapability {
521 origin: Arc::new(PathBuf::from("programmatic_manifest.cml")),
522 service: cap.service.map(synthetic_span),
523 protocol: cap.protocol.map(synthetic_span),
524 directory: cap.directory.map(synthetic_span),
525 storage: cap.storage.map(synthetic_span),
526 runner: cap.runner.map(synthetic_span),
527 resolver: cap.resolver.map(synthetic_span),
528 event_stream: cap.event_stream.map(synthetic_span),
529 dictionary: cap.dictionary.map(synthetic_span),
530 config: cap.config.map(synthetic_span),
531 path: cap.path.map(synthetic_span),
532 rights: cap.rights.map(synthetic_span),
533 from: cap.from.map(synthetic_span),
534 backing_dir: cap.backing_dir.map(synthetic_span),
535 subdir: cap.subdir.map(synthetic_span),
536 storage_id: cap.storage_id.map(synthetic_span),
537 config_type: cap.config_type.map(synthetic_span),
538 config_max_size: cap.config_max_size.map(synthetic_span),
539 config_max_count: cap.config_max_count.map(synthetic_span),
540 config_element_type: cap.config_element_type.map(synthetic_span),
541 value: cap.value.map(synthetic_span),
542 delivery: cap.delivery.map(synthetic_span),
543 };
544
545 synthetic_span(context_cap)
546}