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