1use crate::{
6 AsClause, Capability, CapabilityClause, Error, Location, PathClause, SpannedCapability,
7 SpannedCapabilityClause, SpannedExpose, SpannedOffer, SpannedUse, Use, alias_or_name,
8 byte_index_to_location,
9};
10
11use crate::one_or_many::OneOrMany;
12pub use cm_types::{
13 Availability, BorrowedName, BoundedName, DeliveryType, DependencyType, HandleType, Name,
14 NamespacePath, OnTerminate, ParseError, Path, RelativePath, StartupMode, StorageId, Url,
15};
16use json_spanned_value::Spanned;
17
18use std::fmt;
19
20#[derive(Debug, PartialEq, Eq, Hash, Clone)]
31pub enum CapabilityId<'a> {
32 Service(&'a BorrowedName),
33 Protocol(&'a BorrowedName),
34 Directory(&'a BorrowedName),
35 UsedService(Path),
37 UsedProtocol(Path),
39 UsedDirectory(Path),
41 UsedStorage(Path),
43 UsedEventStream(Path),
45 UsedConfiguration(&'a BorrowedName),
47 UsedRunner(&'a BorrowedName),
48 UsedDictionary(Path),
50 Storage(&'a BorrowedName),
51 Runner(&'a BorrowedName),
52 Resolver(&'a BorrowedName),
53 EventStream(&'a BorrowedName),
54 Dictionary(&'a BorrowedName),
55 Configuration(&'a BorrowedName),
56}
57
58macro_rules! capability_ids_from_names {
60 ($name:ident, $variant:expr) => {
61 fn $name(names: Vec<&'a BorrowedName>) -> Vec<Self> {
62 names.into_iter().map(|n| $variant(n)).collect()
63 }
64 };
65}
66
67macro_rules! capability_ids_from_paths {
69 ($name:ident, $variant:expr) => {
70 fn $name(paths: Vec<Path>) -> Vec<Self> {
71 paths.into_iter().map(|p| $variant(p)).collect()
72 }
73 };
74}
75
76impl<'a> CapabilityId<'a> {
77 pub fn type_str(&self) -> &'static str {
79 match self {
80 CapabilityId::Service(_) => "service",
81 CapabilityId::Protocol(_) => "protocol",
82 CapabilityId::Directory(_) => "directory",
83 CapabilityId::UsedService(_) => "service",
84 CapabilityId::UsedProtocol(_) => "protocol",
85 CapabilityId::UsedDirectory(_) => "directory",
86 CapabilityId::UsedStorage(_) => "storage",
87 CapabilityId::UsedEventStream(_) => "event_stream",
88 CapabilityId::UsedRunner(_) => "runner",
89 CapabilityId::UsedConfiguration(_) => "config",
90 CapabilityId::UsedDictionary(_) => "dictionary",
91 CapabilityId::Storage(_) => "storage",
92 CapabilityId::Runner(_) => "runner",
93 CapabilityId::Resolver(_) => "resolver",
94 CapabilityId::EventStream(_) => "event_stream",
95 CapabilityId::Dictionary(_) => "dictionary",
96 CapabilityId::Configuration(_) => "config",
97 }
98 }
99
100 pub fn get_dir_path(&self) -> Option<NamespacePath> {
102 match self {
103 CapabilityId::UsedService(p)
104 | CapabilityId::UsedProtocol(p)
105 | CapabilityId::UsedEventStream(p) => Some(p.parent()),
106 CapabilityId::UsedDirectory(p)
107 | CapabilityId::UsedStorage(p)
108 | CapabilityId::UsedDictionary(p) => Some(p.clone().into()),
109 _ => None,
110 }
111 }
112
113 pub fn get_target_path(&self) -> Option<NamespacePath> {
115 match self {
116 CapabilityId::UsedService(p)
117 | CapabilityId::UsedProtocol(p)
118 | CapabilityId::UsedEventStream(p)
119 | CapabilityId::UsedDirectory(p)
120 | CapabilityId::UsedStorage(p)
121 | CapabilityId::UsedDictionary(p) => Some(p.clone().into()),
122 _ => None,
123 }
124 }
125
126 pub fn from_use(use_: &'a Use) -> Result<Vec<Self>, Error> {
135 let alias = use_.path.as_ref();
137 if let Some(n) = use_.service() {
138 return Ok(Self::used_services_from(Self::get_one_or_many_svc_paths(
139 n,
140 alias,
141 use_.capability_type().unwrap(),
142 )?));
143 } else if let Some(n) = use_.protocol() {
144 return Ok(Self::used_protocols_from(Self::get_one_or_many_svc_paths(
145 n,
146 alias,
147 use_.capability_type().unwrap(),
148 )?));
149 } else if let Some(_) = use_.directory.as_ref() {
150 if use_.path.is_none() {
151 return Err(Error::validate("\"path\" should be present for `use directory`."));
152 }
153 return Ok(vec![CapabilityId::UsedDirectory(use_.path.as_ref().unwrap().clone())]);
154 } else if let Some(_) = use_.storage.as_ref() {
155 if use_.path.is_none() {
156 return Err(Error::validate("\"path\" should be present for `use storage`."));
157 }
158 return Ok(vec![CapabilityId::UsedStorage(use_.path.as_ref().unwrap().clone())]);
159 } else if let Some(_) = use_.event_stream() {
160 if let Some(path) = use_.path() {
161 return Ok(vec![CapabilityId::UsedEventStream(path.clone())]);
162 }
163 return Ok(vec![CapabilityId::UsedEventStream(Path::new(
164 "/svc/fuchsia.component.EventStream",
165 )?)]);
166 } else if let Some(n) = use_.runner() {
167 match n {
168 OneOrMany::One(name) => {
169 return Ok(vec![CapabilityId::UsedRunner(name)]);
170 }
171 OneOrMany::Many(_) => {
172 return Err(Error::validate("`use runner` should occur at most once."));
173 }
174 }
175 } else if let Some(_) = use_.config() {
176 return match &use_.key {
177 None => Err(Error::validate("\"key\" should be present for `use config`.")),
178 Some(name) => Ok(vec![CapabilityId::UsedConfiguration(name)]),
179 };
180 } else if let Some(n) = use_.dictionary() {
181 return Ok(Self::used_dictionaries_from(Self::get_one_or_many_svc_paths(
182 n,
183 alias,
184 use_.capability_type().unwrap(),
185 )?));
186 }
187 let supported_keywords = use_
189 .supported()
190 .into_iter()
191 .map(|k| format!("\"{}\"", k))
192 .collect::<Vec<_>>()
193 .join(", ");
194 Err(Error::validate(format!(
195 "`{}` declaration is missing a capability keyword, one of: {}",
196 use_.decl_type(),
197 supported_keywords,
198 )))
199 }
200
201 pub fn from_spanned_use(
210 use_: &'a Spanned<SpannedUse>,
211 filename: Option<&std::path::Path>,
212 file_source: Option<&String>,
213 ) -> Result<Vec<Self>, Error> {
214 let alias = use_.path.as_ref();
216 if let Some(n) = use_.service() {
217 return Ok(Self::used_services_from(Self::get_one_or_many_svc_paths(
218 n,
219 alias.map(|v| &**v),
220 use_.capability_type().unwrap(),
221 )?));
222 } else if let Some(n) = use_.protocol() {
223 return Ok(Self::used_protocols_from(Self::get_one_or_many_svc_paths(
224 n,
225 alias.map(|v| &**v),
226 use_.capability_type().unwrap(),
227 )?));
228 } else if let Some(_) = use_.directory.as_ref() {
229 if use_.path.is_none() {
230 let location =
231 byte_index_to_location(file_source, use_.directory.as_ref().unwrap().span().0);
232 return Err(Error::validate_with_span(
233 "\"path\" should be present for `use directory`.",
234 location,
235 filename,
236 ));
237 }
238 return Ok(vec![CapabilityId::UsedDirectory(
239 use_.path.as_ref().unwrap().get_ref().clone(),
240 )]);
241 } else if let Some(_) = use_.storage.as_ref() {
242 if use_.path.is_none() {
243 let location =
244 byte_index_to_location(file_source, use_.storage.as_ref().unwrap().span().0);
245 return Err(Error::validate_with_span(
246 "\"path\" should be present for `use storage`.",
247 location,
248 filename,
249 ));
250 }
251 return Ok(vec![CapabilityId::UsedStorage(
252 use_.path.as_ref().unwrap().get_ref().clone(),
253 )]);
254 } else if let Some(_) = use_.event_stream() {
255 if let Some(path) = use_.path() {
256 return Ok(vec![CapabilityId::UsedEventStream(path.clone())]);
257 }
258 return Ok(vec![CapabilityId::UsedEventStream(Path::new(
259 "/svc/fuchsia.component.EventStream",
260 )?)]);
261 } else if let Some(n) = use_.runner() {
262 match n {
263 OneOrMany::One(name) => {
264 return Ok(vec![CapabilityId::UsedRunner(name)]);
265 }
266 OneOrMany::Many(_) => {
267 let location =
268 byte_index_to_location(file_source, use_.runner.as_ref().unwrap().span().0);
269 return Err(Error::validate_with_span(
270 "`use runner` should occur at most once.",
271 location,
272 filename,
273 ));
274 }
275 }
276 } else if let Some(_) = use_.config() {
277 return match &use_.key {
278 None => {
279 let location =
280 byte_index_to_location(file_source, use_.config.as_ref().unwrap().span().0);
281 Err(Error::validate_with_span(
282 "\"key\" should be present for `use config`.",
283 location,
284 filename,
285 ))
286 }
287 Some(name) => Ok(vec![CapabilityId::UsedConfiguration(name)]),
288 };
289 } else if let Some(n) = use_.dictionary() {
290 return Ok(Self::used_dictionaries_from(Self::get_one_or_many_svc_paths(
291 n,
292 alias.map(|v| &**v),
293 use_.capability_type().unwrap(),
294 )?));
295 }
296 let supported_keywords = use_
298 .supported()
299 .into_iter()
300 .map(|k| format!("\"{}\"", k))
301 .collect::<Vec<_>>()
302 .join(", ");
303
304 let location = byte_index_to_location(file_source, use_.span().0);
305
306 Err(Error::validate_with_span(
307 format!(
308 "`{}` declaration is missing a capability keyword, one of: {}",
309 use_.decl_type(),
310 supported_keywords,
311 ),
312 location,
313 filename,
314 ))
315 }
316
317 pub fn from_capability(capability: &'a Capability) -> Result<Vec<Self>, Error> {
318 if let Some(n) = capability.service() {
320 if n.is_many() && capability.path.is_some() {
321 return Err(Error::validate(
322 "\"path\" can only be specified when one `service` is supplied.",
323 ));
324 }
325 return Ok(Self::services_from(Self::get_one_or_many_names_no_span(
326 n,
327 None,
328 capability.capability_type().unwrap(),
329 )?));
330 } else if let Some(n) = capability.protocol() {
331 if n.is_many() && capability.path.is_some() {
332 return Err(Error::validate(
333 "\"path\" can only be specified when one `protocol` is supplied.",
334 ));
335 }
336 return Ok(Self::protocols_from(Self::get_one_or_many_names_no_span(
337 n,
338 None,
339 capability.capability_type().unwrap(),
340 )?));
341 } else if let Some(n) = capability.directory() {
342 return Ok(Self::directories_from(Self::get_one_or_many_names_no_span(
343 n,
344 None,
345 capability.capability_type().unwrap(),
346 )?));
347 } else if let Some(n) = capability.storage() {
348 if capability.storage_id.is_none() {
349 return Err(Error::validate(
350 "Storage declaration is missing \"storage_id\", but is required.",
351 ));
352 }
353 return Ok(Self::storages_from(Self::get_one_or_many_names_no_span(
354 n,
355 None,
356 capability.capability_type().unwrap(),
357 )?));
358 } else if let Some(n) = capability.runner() {
359 return Ok(Self::runners_from(Self::get_one_or_many_names_no_span(
360 n,
361 None,
362 capability.capability_type().unwrap(),
363 )?));
364 } else if let Some(n) = capability.resolver() {
365 return Ok(Self::resolvers_from(Self::get_one_or_many_names_no_span(
366 n,
367 None,
368 capability.capability_type().unwrap(),
369 )?));
370 } else if let Some(n) = capability.event_stream() {
371 return Ok(Self::event_streams_from(Self::get_one_or_many_names_no_span(
372 n,
373 None,
374 capability.capability_type().unwrap(),
375 )?));
376 } else if let Some(n) = capability.dictionary() {
377 return Ok(Self::dictionaries_from(Self::get_one_or_many_names_no_span(
378 n,
379 None,
380 capability.capability_type().unwrap(),
381 )?));
382 } else if let Some(n) = capability.config() {
383 return Ok(Self::configurations_from(Self::get_one_or_many_names_no_span(
384 n,
385 None,
386 capability.capability_type().unwrap(),
387 )?));
388 }
389
390 let supported_keywords = capability
392 .supported()
393 .into_iter()
394 .map(|k| format!("\"{}\"", k))
395 .collect::<Vec<_>>()
396 .join(", ");
397 Err(Error::validate(format!(
398 "`{}` declaration is missing a capability keyword, one of: {}",
399 capability.decl_type(),
400 supported_keywords,
401 )))
402 }
403
404 pub fn from_spanned_capability(
405 capability: &'a Spanned<SpannedCapability>,
406 filename: Option<&std::path::Path>,
407 file_source: Option<&String>,
408 ) -> Result<Vec<Self>, Error> {
409 if let Some(n) = capability.service() {
411 if n.is_many() && capability.path.is_some() {
412 let location =
413 byte_index_to_location(file_source, capability.path.as_ref().unwrap().span().0);
414 return Err(Error::validate_with_span(
415 "\"path\" can only be specified when one `service` is supplied.",
416 location,
417 filename,
418 ));
419 }
420 return Ok(Self::services_from(Self::get_names(n)?));
421 } else if let Some(n) = capability.protocol() {
422 if n.is_many() && capability.path.is_some() {
423 let location =
424 byte_index_to_location(file_source, capability.path.as_ref().unwrap().span().0);
425 return Err(Error::validate_with_span(
426 "\"path\" can only be specified when one `protocol` is supplied.",
427 location,
428 filename,
429 ));
430 }
431 return Ok(Self::protocols_from(Self::get_names(n)?));
432 } else if let Some(n) = capability.directory() {
433 return Ok(Self::directories_from(Self::get_names(n)?));
434 } else if let Some(n) = capability.storage() {
435 if capability.storage_id.is_none() {
436 let location = byte_index_to_location(
437 file_source,
438 capability.storage.as_ref().unwrap().span().0,
439 );
440 return Err(Error::validate_with_span(
441 "Storage declaration is missing \"storage_id\", but is required.",
442 location,
443 filename,
444 ));
445 }
446 return Ok(Self::storages_from(Self::get_names(n)?));
447 } else if let Some(n) = capability.runner() {
448 return Ok(Self::runners_from(Self::get_names(n)?));
449 } else if let Some(n) = capability.resolver() {
450 return Ok(Self::resolvers_from(Self::get_names(n)?));
451 } else if let Some(n) = capability.event_stream() {
452 return Ok(Self::event_streams_from(Self::get_names(n)?));
453 } else if let Some(n) = capability.dictionary() {
454 return Ok(Self::dictionaries_from(Self::get_names(n)?));
455 } else if let Some(n) = capability.config() {
456 return Ok(Self::configurations_from(Self::get_names(n)?));
457 }
458
459 let supported_keywords = capability
461 .supported()
462 .into_iter()
463 .map(|k| format!("\"{}\"", k))
464 .collect::<Vec<_>>()
465 .join(", ");
466 let location = byte_index_to_location(file_source, capability.span().0);
467
468 Err(Error::validate_with_span(
469 format!(
470 "`{}` declaration is missing a capability keyword, one of: {}",
471 capability.decl_type(),
472 supported_keywords,
473 ),
474 location,
475 filename,
476 ))
477 }
478
479 pub fn from_offer_expose<T>(clause: &'a T) -> Result<Vec<Self>, Error>
488 where
489 T: CapabilityClause + AsClause + fmt::Debug,
490 {
491 let alias = clause.r#as();
493 if let Some(n) = clause.service() {
494 return Ok(Self::services_from(Self::get_one_or_many_names_no_span(
495 n,
496 alias,
497 clause.capability_type().unwrap(),
498 )?));
499 } else if let Some(n) = clause.protocol() {
500 return Ok(Self::protocols_from(Self::get_one_or_many_names_no_span(
501 n,
502 alias,
503 clause.capability_type().unwrap(),
504 )?));
505 } else if let Some(n) = clause.directory() {
506 return Ok(Self::directories_from(Self::get_one_or_many_names_no_span(
507 n,
508 alias,
509 clause.capability_type().unwrap(),
510 )?));
511 } else if let Some(n) = clause.storage() {
512 return Ok(Self::storages_from(Self::get_one_or_many_names_no_span(
513 n,
514 alias,
515 clause.capability_type().unwrap(),
516 )?));
517 } else if let Some(n) = clause.runner() {
518 return Ok(Self::runners_from(Self::get_one_or_many_names_no_span(
519 n,
520 alias,
521 clause.capability_type().unwrap(),
522 )?));
523 } else if let Some(n) = clause.resolver() {
524 return Ok(Self::resolvers_from(Self::get_one_or_many_names_no_span(
525 n,
526 alias,
527 clause.capability_type().unwrap(),
528 )?));
529 } else if let Some(event_stream) = clause.event_stream() {
530 return Ok(Self::event_streams_from(Self::get_one_or_many_names_no_span(
531 event_stream,
532 alias,
533 clause.capability_type().unwrap(),
534 )?));
535 } else if let Some(n) = clause.dictionary() {
536 return Ok(Self::dictionaries_from(Self::get_one_or_many_names_no_span(
537 n,
538 alias,
539 clause.capability_type().unwrap(),
540 )?));
541 } else if let Some(n) = clause.config() {
542 return Ok(Self::configurations_from(Self::get_one_or_many_names_no_span(
543 n,
544 alias,
545 clause.capability_type().unwrap(),
546 )?));
547 }
548
549 let supported_keywords = clause
551 .supported()
552 .into_iter()
553 .map(|k| format!("\"{}\"", k))
554 .collect::<Vec<_>>()
555 .join(", ");
556 Err(Error::validate(format!(
557 "`{}` declaration is missing a capability keyword, one of: {}",
558 clause.decl_type(),
559 supported_keywords,
560 )))
561 }
562
563 pub fn from_spanned_expose(
572 expose: &'a Spanned<SpannedExpose>,
573 filename: Option<&std::path::Path>,
574 file_source: Option<&String>,
575 ) -> Result<Vec<Self>, Error> {
576 let alias = expose.r#as();
578 let location = byte_index_to_location(file_source, expose.span().0);
579
580 if let Some(n) = expose.service() {
581 return Ok(Self::services_from(Self::get_one_or_many_names(
582 n,
583 alias,
584 expose.capability_type().unwrap(),
585 location,
586 filename,
587 )?));
588 } else if let Some(n) = expose.protocol() {
589 return Ok(Self::protocols_from(Self::get_one_or_many_names(
590 n,
591 alias,
592 expose.capability_type().unwrap(),
593 location,
594 filename,
595 )?));
596 } else if let Some(n) = expose.directory() {
597 return Ok(Self::directories_from(Self::get_one_or_many_names(
598 n,
599 alias,
600 expose.capability_type().unwrap(),
601 location,
602 filename,
603 )?));
604 } else if let Some(n) = expose.storage() {
605 return Ok(Self::storages_from(Self::get_one_or_many_names(
606 n,
607 alias,
608 expose.capability_type().unwrap(),
609 location,
610 filename,
611 )?));
612 } else if let Some(n) = expose.runner() {
613 return Ok(Self::runners_from(Self::get_one_or_many_names(
614 n,
615 alias,
616 expose.capability_type().unwrap(),
617 location,
618 filename,
619 )?));
620 } else if let Some(n) = expose.resolver() {
621 return Ok(Self::resolvers_from(Self::get_one_or_many_names(
622 n,
623 alias,
624 expose.capability_type().unwrap(),
625 location,
626 filename,
627 )?));
628 } else if let Some(event_stream) = expose.event_stream() {
629 return Ok(Self::event_streams_from(Self::get_one_or_many_names(
630 event_stream,
631 alias,
632 expose.capability_type().unwrap(),
633 location,
634 filename,
635 )?));
636 } else if let Some(n) = expose.dictionary() {
637 return Ok(Self::dictionaries_from(Self::get_one_or_many_names(
638 n,
639 alias,
640 expose.capability_type().unwrap(),
641 location,
642 filename,
643 )?));
644 } else if let Some(n) = expose.config() {
645 return Ok(Self::configurations_from(Self::get_one_or_many_names(
646 n,
647 alias,
648 expose.capability_type().unwrap(),
649 location,
650 filename,
651 )?));
652 }
653
654 let supported_keywords = expose
656 .supported()
657 .into_iter()
658 .map(|k| format!("\"{}\"", k))
659 .collect::<Vec<_>>()
660 .join(", ");
661 Err(Error::validate_with_span(
662 format!(
663 "`{}` declaration is missing a capability keyword, one of: {}",
664 expose.decl_type(),
665 supported_keywords,
666 ),
667 location,
668 filename,
669 ))
670 }
671
672 pub fn from_spanned_offer(
673 offer: &'a Spanned<SpannedOffer>,
674 filename: Option<&std::path::Path>,
675 file_source: Option<&String>,
676 ) -> Result<Vec<Self>, Error> {
677 let alias = offer.r#as();
679 let location = byte_index_to_location(file_source, offer.span().0);
680
681 if let Some(n) = offer.service() {
682 return Ok(Self::services_from(Self::get_one_or_many_names(
683 n,
684 alias,
685 offer.capability_type().unwrap(),
686 location,
687 filename,
688 )?));
689 } else if let Some(n) = offer.protocol() {
690 return Ok(Self::protocols_from(Self::get_one_or_many_names(
691 n,
692 alias,
693 offer.capability_type().unwrap(),
694 location,
695 filename,
696 )?));
697 } else if let Some(n) = offer.directory() {
698 return Ok(Self::directories_from(Self::get_one_or_many_names(
699 n,
700 alias,
701 offer.capability_type().unwrap(),
702 location,
703 filename,
704 )?));
705 } else if let Some(n) = offer.storage() {
706 return Ok(Self::storages_from(Self::get_one_or_many_names(
707 n,
708 alias,
709 offer.capability_type().unwrap(),
710 location,
711 filename,
712 )?));
713 } else if let Some(n) = offer.runner() {
714 return Ok(Self::runners_from(Self::get_one_or_many_names(
715 n,
716 alias,
717 offer.capability_type().unwrap(),
718 location,
719 filename,
720 )?));
721 } else if let Some(n) = offer.resolver() {
722 return Ok(Self::resolvers_from(Self::get_one_or_many_names(
723 n,
724 alias,
725 offer.capability_type().unwrap(),
726 location,
727 filename,
728 )?));
729 } else if let Some(event_stream) = offer.event_stream() {
730 return Ok(Self::event_streams_from(Self::get_one_or_many_names(
731 event_stream,
732 alias,
733 offer.capability_type().unwrap(),
734 location,
735 filename,
736 )?));
737 } else if let Some(n) = offer.dictionary() {
738 return Ok(Self::dictionaries_from(Self::get_one_or_many_names(
739 n,
740 alias,
741 offer.capability_type().unwrap(),
742 location,
743 filename,
744 )?));
745 } else if let Some(n) = offer.config() {
746 return Ok(Self::configurations_from(Self::get_one_or_many_names(
747 n,
748 alias,
749 offer.capability_type().unwrap(),
750 location,
751 filename,
752 )?));
753 }
754
755 let supported_keywords = offer
757 .supported()
758 .into_iter()
759 .map(|k| format!("\"{}\"", k))
760 .collect::<Vec<_>>()
761 .join(", ");
762 Err(Error::validate_with_span(
763 format!(
764 "`{}` declaration is missing a capability keyword, one of: {}",
765 offer.decl_type(),
766 supported_keywords,
767 ),
768 location,
769 filename,
770 ))
771 }
772
773 fn get_one_or_many_names_no_span<'b>(
775 names: OneOrMany<&'b BorrowedName>,
776 alias: Option<&'b BorrowedName>,
777 capability_type: &str,
778 ) -> Result<Vec<&'b BorrowedName>, Error> {
779 let names: Vec<&BorrowedName> = names.into_iter().collect();
780 if names.len() == 1 {
781 Ok(vec![alias_or_name(alias, &names[0])])
782 } else {
783 if alias.is_some() {
784 return Err(Error::validate(format!(
785 "\"as\" can only be specified when one `{}` is supplied.",
786 capability_type,
787 )));
788 }
789 Ok(names)
790 }
791 }
792
793 fn get_names<'b>(names: OneOrMany<&'b BorrowedName>) -> Result<Vec<&'b BorrowedName>, Error> {
795 let names: Vec<&BorrowedName> = names.into_iter().collect();
796 Ok(names)
797 }
798
799 fn get_one_or_many_names<'b>(
801 names: OneOrMany<&'b BorrowedName>,
802 alias: Option<&'b BorrowedName>,
803 capability_type: &str,
804 location: Option<Location>,
805 filepath: Option<&std::path::Path>,
806 ) -> Result<Vec<&'b BorrowedName>, Error> {
807 let names: Vec<&BorrowedName> = names.into_iter().collect();
808 if names.len() == 1 {
809 Ok(vec![alias_or_name(alias, &names[0])])
810 } else {
811 if alias.is_some() {
812 return Err(Error::validate_with_span(
813 format!(
814 "\"as\" can only be specified when one `{}` is supplied.",
815 capability_type,
816 ),
817 location,
818 filepath,
819 ));
820 }
821 Ok(names)
822 }
823 }
824
825 fn get_one_or_many_svc_paths(
827 names: OneOrMany<&BorrowedName>,
828 alias: Option<&Path>,
829 capability_type: &str,
830 ) -> Result<Vec<Path>, Error> {
831 let names: Vec<_> = names.into_iter().collect();
832 match (names.len(), alias) {
833 (_, None) => {
834 Ok(names.into_iter().map(|n| format!("/svc/{}", n).parse().unwrap()).collect())
835 }
836 (1, Some(alias)) => Ok(vec![alias.clone()]),
837 (_, Some(_)) => {
838 return Err(Error::validate(format!(
839 "\"path\" can only be specified when one `{}` is supplied.",
840 capability_type,
841 )));
842 }
843 }
844 }
845
846 capability_ids_from_names!(services_from, CapabilityId::Service);
847 capability_ids_from_names!(protocols_from, CapabilityId::Protocol);
848 capability_ids_from_names!(directories_from, CapabilityId::Directory);
849 capability_ids_from_names!(storages_from, CapabilityId::Storage);
850 capability_ids_from_names!(runners_from, CapabilityId::Runner);
851 capability_ids_from_names!(resolvers_from, CapabilityId::Resolver);
852 capability_ids_from_names!(event_streams_from, CapabilityId::EventStream);
853 capability_ids_from_names!(dictionaries_from, CapabilityId::Dictionary);
854 capability_ids_from_names!(configurations_from, CapabilityId::Configuration);
855 capability_ids_from_paths!(used_services_from, CapabilityId::UsedService);
856 capability_ids_from_paths!(used_protocols_from, CapabilityId::UsedProtocol);
857 capability_ids_from_paths!(used_dictionaries_from, CapabilityId::UsedDictionary);
858}
859
860impl fmt::Display for CapabilityId<'_> {
861 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
863 match self {
864 CapabilityId::Service(n)
865 | CapabilityId::Storage(n)
866 | CapabilityId::Runner(n)
867 | CapabilityId::UsedRunner(n)
868 | CapabilityId::Resolver(n)
869 | CapabilityId::EventStream(n)
870 | CapabilityId::Configuration(n)
871 | CapabilityId::UsedConfiguration(n)
872 | CapabilityId::Dictionary(n) => write!(f, "{}", n),
873 CapabilityId::UsedService(p)
874 | CapabilityId::UsedProtocol(p)
875 | CapabilityId::UsedDirectory(p)
876 | CapabilityId::UsedStorage(p)
877 | CapabilityId::UsedEventStream(p)
878 | CapabilityId::UsedDictionary(p) => write!(f, "{}", p),
879 CapabilityId::Protocol(p) | CapabilityId::Directory(p) => write!(f, "{}", p),
880 }
881 }
882}