1use crate::one_or_many::OneOrMany;
6use crate::types::capability::ContextCapability;
7use crate::types::common::{ContextCapabilityClause, option_one_or_many_as_ref_context};
8use crate::types::offer::ContextOffer;
9use crate::types::r#use::ContextUse;
10use crate::{
11 AsClause, AsClauseContext, Capability, CapabilityClause, ContextExpose, ContextSpanned, Error,
12 Origin, PathClause, Use, alias_or_name, alias_or_name_context,
13};
14pub use cm_types::{
15 Availability, BorrowedName, BoundedName, DeliveryType, DependencyType, HandleType, Name,
16 NamespacePath, OnTerminate, ParseError, Path, RelativePath, StartupMode, StorageId, Url,
17};
18
19use std::fmt;
20
21#[derive(Debug, PartialEq, Eq, Hash, Clone)]
32pub enum CapabilityId<'a> {
33 Service(&'a BorrowedName),
34 Protocol(&'a BorrowedName),
35 Directory(&'a BorrowedName),
36 UsedService(Path),
38 UsedProtocol(Path),
40 UsedProtocolNumberedHandle(HandleType),
42 UsedDirectory(Path),
44 UsedStorage(Path),
46 UsedEventStream(Path),
48 UsedConfiguration(&'a BorrowedName),
50 UsedRunner(&'a BorrowedName),
51 UsedDictionary(Path),
53 Storage(&'a BorrowedName),
54 Runner(&'a BorrowedName),
55 Resolver(&'a BorrowedName),
56 EventStream(&'a BorrowedName),
57 Dictionary(&'a BorrowedName),
58 Configuration(&'a BorrowedName),
59}
60
61macro_rules! capability_ids_from_names {
63 ($name:ident, $variant:expr) => {
64 fn $name(names: Vec<&'a BorrowedName>) -> Vec<Self> {
65 names.into_iter().map(|n| $variant(n)).collect()
66 }
67 };
68}
69
70macro_rules! capability_ids_from_context_names {
72 ($name:ident, $variant:expr) => {
73 fn $name(names: Vec<ContextSpanned<&'a BorrowedName>>) -> Vec<(Self, Origin)> {
74 names
75 .into_iter()
76 .map(|spanned_name| ($variant(spanned_name.value), spanned_name.origin))
77 .collect()
78 }
79 };
80}
81
82macro_rules! capability_ids_from_paths {
84 ($name:ident, $variant:expr) => {
85 fn $name(paths: Vec<Path>) -> Vec<Self> {
86 paths.into_iter().map(|p| $variant(p)).collect()
87 }
88 };
89}
90
91macro_rules! capability_ids_from_context_paths {
93 ($name:ident, $variant:expr) => {
94 fn $name(paths: Vec<ContextSpanned<Path>>) -> Vec<(Self, Origin)> {
95 paths
96 .into_iter()
97 .map(|spanned_path| ($variant(spanned_path.value), spanned_path.origin))
98 .collect()
99 }
100 };
101}
102
103impl<'a> CapabilityId<'a> {
104 pub fn type_str(&self) -> &'static str {
106 match self {
107 CapabilityId::Service(_) => "service",
108 CapabilityId::Protocol(_) => "protocol",
109 CapabilityId::Directory(_) => "directory",
110 CapabilityId::UsedService(_) => "service",
111 CapabilityId::UsedProtocol(_) => "protocol",
112 CapabilityId::UsedProtocolNumberedHandle(_) => "protocol",
113 CapabilityId::UsedDirectory(_) => "directory",
114 CapabilityId::UsedStorage(_) => "storage",
115 CapabilityId::UsedEventStream(_) => "event_stream",
116 CapabilityId::UsedRunner(_) => "runner",
117 CapabilityId::UsedConfiguration(_) => "config",
118 CapabilityId::UsedDictionary(_) => "dictionary",
119 CapabilityId::Storage(_) => "storage",
120 CapabilityId::Runner(_) => "runner",
121 CapabilityId::Resolver(_) => "resolver",
122 CapabilityId::EventStream(_) => "event_stream",
123 CapabilityId::Dictionary(_) => "dictionary",
124 CapabilityId::Configuration(_) => "config",
125 }
126 }
127
128 pub fn get_dir_path(&self) -> Option<NamespacePath> {
130 match self {
131 CapabilityId::UsedService(p)
132 | CapabilityId::UsedProtocol(p)
133 | CapabilityId::UsedEventStream(p) => Some(p.parent()),
134 CapabilityId::UsedDirectory(p)
135 | CapabilityId::UsedStorage(p)
136 | CapabilityId::UsedDictionary(p) => Some(p.clone().into()),
137 _ => None,
138 }
139 }
140
141 pub fn get_target_path(&self) -> Option<NamespacePath> {
143 match self {
144 CapabilityId::UsedService(p)
145 | CapabilityId::UsedProtocol(p)
146 | CapabilityId::UsedEventStream(p)
147 | CapabilityId::UsedDirectory(p)
148 | CapabilityId::UsedStorage(p)
149 | CapabilityId::UsedDictionary(p) => Some(p.clone().into()),
150 _ => None,
151 }
152 }
153
154 pub fn from_use(use_: &'a Use) -> Result<Vec<Self>, Error> {
163 let alias = use_.path.as_ref();
165 if let Some(n) = use_.service() {
166 return Ok(Self::used_services_from(Self::get_one_or_many_svc_paths(
167 n,
168 alias,
169 use_.capability_type().unwrap(),
170 )?));
171 } else if let Some(n) = use_.protocol() {
172 if let Some(numbered_handle) = use_.numbered_handle {
173 return Ok(n
174 .iter()
175 .map(|_| CapabilityId::UsedProtocolNumberedHandle(numbered_handle))
176 .collect());
177 }
178 return Ok(Self::used_protocols_from(Self::get_one_or_many_svc_paths(
179 n,
180 alias,
181 use_.capability_type().unwrap(),
182 )?));
183 } else if let Some(_) = use_.directory.as_ref() {
184 if use_.path.is_none() {
185 return Err(Error::validate("\"path\" should be present for `use directory`."));
186 }
187 return Ok(vec![CapabilityId::UsedDirectory(use_.path.as_ref().unwrap().clone())]);
188 } else if let Some(_) = use_.storage.as_ref() {
189 if use_.path.is_none() {
190 return Err(Error::validate("\"path\" should be present for `use storage`."));
191 }
192 return Ok(vec![CapabilityId::UsedStorage(use_.path.as_ref().unwrap().clone())]);
193 } else if let Some(_) = use_.event_stream() {
194 if let Some(path) = use_.path() {
195 return Ok(vec![CapabilityId::UsedEventStream(path.clone())]);
196 }
197 return Ok(vec![CapabilityId::UsedEventStream(Path::new(
198 "/svc/fuchsia.component.EventStream",
199 )?)]);
200 } else if let Some(n) = use_.runner() {
201 match n {
202 OneOrMany::One(name) => {
203 return Ok(vec![CapabilityId::UsedRunner(name)]);
204 }
205 OneOrMany::Many(_) => {
206 return Err(Error::validate("`use runner` should occur at most once."));
207 }
208 }
209 } else if let Some(_) = use_.config() {
210 return match &use_.key {
211 None => Err(Error::validate("\"key\" should be present for `use config`.")),
212 Some(name) => Ok(vec![CapabilityId::UsedConfiguration(name)]),
213 };
214 } else if let Some(n) = use_.dictionary() {
215 return Ok(Self::used_dictionaries_from(Self::get_one_or_many_svc_paths(
216 n,
217 alias,
218 use_.capability_type().unwrap(),
219 )?));
220 }
221 let supported_keywords = use_
223 .supported()
224 .into_iter()
225 .map(|k| format!("\"{}\"", k))
226 .collect::<Vec<_>>()
227 .join(", ");
228 Err(Error::validate(format!(
229 "`{}` declaration is missing a capability keyword, one of: {}",
230 use_.decl_type(),
231 supported_keywords,
232 )))
233 }
234
235 pub fn from_capability(capability: &'a Capability) -> Result<Vec<Self>, Error> {
236 if let Some(n) = capability.service() {
238 if n.is_many() && capability.path.is_some() {
239 return Err(Error::validate(
240 "\"path\" can only be specified when one `service` is supplied.",
241 ));
242 }
243 return Ok(Self::services_from(Self::get_one_or_many_names_no_span(
244 n,
245 None,
246 capability.capability_type().unwrap(),
247 )?));
248 } else if let Some(n) = capability.protocol() {
249 if n.is_many() && capability.path.is_some() {
250 return Err(Error::validate(
251 "\"path\" can only be specified when one `protocol` is supplied.",
252 ));
253 }
254 return Ok(Self::protocols_from(Self::get_one_or_many_names_no_span(
255 n,
256 None,
257 capability.capability_type().unwrap(),
258 )?));
259 } else if let Some(n) = capability.directory() {
260 return Ok(Self::directories_from(Self::get_one_or_many_names_no_span(
261 n,
262 None,
263 capability.capability_type().unwrap(),
264 )?));
265 } else if let Some(n) = capability.storage() {
266 if capability.storage_id.is_none() {
267 return Err(Error::validate(
268 "Storage declaration is missing \"storage_id\", but is required.",
269 ));
270 }
271 return Ok(Self::storages_from(Self::get_one_or_many_names_no_span(
272 n,
273 None,
274 capability.capability_type().unwrap(),
275 )?));
276 } else if let Some(n) = capability.runner() {
277 return Ok(Self::runners_from(Self::get_one_or_many_names_no_span(
278 n,
279 None,
280 capability.capability_type().unwrap(),
281 )?));
282 } else if let Some(n) = capability.resolver() {
283 return Ok(Self::resolvers_from(Self::get_one_or_many_names_no_span(
284 n,
285 None,
286 capability.capability_type().unwrap(),
287 )?));
288 } else if let Some(n) = capability.event_stream() {
289 return Ok(Self::event_streams_from(Self::get_one_or_many_names_no_span(
290 n,
291 None,
292 capability.capability_type().unwrap(),
293 )?));
294 } else if let Some(n) = capability.dictionary() {
295 return Ok(Self::dictionaries_from(Self::get_one_or_many_names_no_span(
296 n,
297 None,
298 capability.capability_type().unwrap(),
299 )?));
300 } else if let Some(n) = capability.config() {
301 return Ok(Self::configurations_from(Self::get_one_or_many_names_no_span(
302 n,
303 None,
304 capability.capability_type().unwrap(),
305 )?));
306 }
307
308 let supported_keywords = capability
310 .supported()
311 .into_iter()
312 .map(|k| format!("\"{}\"", k))
313 .collect::<Vec<_>>()
314 .join(", ");
315 Err(Error::validate(format!(
316 "`{}` declaration is missing a capability keyword, one of: {}",
317 capability.decl_type(),
318 supported_keywords,
319 )))
320 }
321
322 pub fn from_offer_expose<T>(clause: &'a T) -> Result<Vec<Self>, Error>
331 where
332 T: CapabilityClause + AsClause + fmt::Debug,
333 {
334 let alias = clause.r#as();
336 if let Some(n) = clause.service() {
337 return Ok(Self::services_from(Self::get_one_or_many_names_no_span(
338 n,
339 alias,
340 clause.capability_type().unwrap(),
341 )?));
342 } else if let Some(n) = clause.protocol() {
343 return Ok(Self::protocols_from(Self::get_one_or_many_names_no_span(
344 n,
345 alias,
346 clause.capability_type().unwrap(),
347 )?));
348 } else if let Some(n) = clause.directory() {
349 return Ok(Self::directories_from(Self::get_one_or_many_names_no_span(
350 n,
351 alias,
352 clause.capability_type().unwrap(),
353 )?));
354 } else if let Some(n) = clause.storage() {
355 return Ok(Self::storages_from(Self::get_one_or_many_names_no_span(
356 n,
357 alias,
358 clause.capability_type().unwrap(),
359 )?));
360 } else if let Some(n) = clause.runner() {
361 return Ok(Self::runners_from(Self::get_one_or_many_names_no_span(
362 n,
363 alias,
364 clause.capability_type().unwrap(),
365 )?));
366 } else if let Some(n) = clause.resolver() {
367 return Ok(Self::resolvers_from(Self::get_one_or_many_names_no_span(
368 n,
369 alias,
370 clause.capability_type().unwrap(),
371 )?));
372 } else if let Some(event_stream) = clause.event_stream() {
373 return Ok(Self::event_streams_from(Self::get_one_or_many_names_no_span(
374 event_stream,
375 alias,
376 clause.capability_type().unwrap(),
377 )?));
378 } else if let Some(n) = clause.dictionary() {
379 return Ok(Self::dictionaries_from(Self::get_one_or_many_names_no_span(
380 n,
381 alias,
382 clause.capability_type().unwrap(),
383 )?));
384 } else if let Some(n) = clause.config() {
385 return Ok(Self::configurations_from(Self::get_one_or_many_names_no_span(
386 n,
387 alias,
388 clause.capability_type().unwrap(),
389 )?));
390 }
391
392 let supported_keywords = clause
394 .supported()
395 .into_iter()
396 .map(|k| format!("\"{}\"", k))
397 .collect::<Vec<_>>()
398 .join(", ");
399 Err(Error::validate(format!(
400 "`{}` declaration is missing a capability keyword, one of: {}",
401 clause.decl_type(),
402 supported_keywords,
403 )))
404 }
405
406 pub fn from_context_capability(
407 capability_input: &'a ContextSpanned<ContextCapability>,
408 ) -> Result<Vec<(Self, Origin)>, Error> {
409 let capability = &capability_input.value;
410 let origin = &capability_input.origin;
411
412 if let Some(n) = capability.service() {
413 if n.value.is_many()
414 && let Some(cs_path) = &capability.path
415 {
416 return Err(Error::validate_context(
417 "\"path\" can only be specified when one `service` is supplied.",
418 Some(cs_path.origin.clone()),
419 ));
420 }
421 return Ok(Self::services_from_context(Self::get_one_or_many_names_context(
422 n,
423 None,
424 capability.capability_type(None).unwrap(),
425 )?));
426 } else if let Some(n) = capability.protocol() {
427 if n.value.is_many()
428 && let Some(cs_path) = &capability.path
429 {
430 return Err(Error::validate_context(
431 "\"path\" can only be specified when one `protocol` is supplied.",
432 Some(cs_path.origin.clone()),
433 ));
434 }
435 return Ok(Self::protocols_from_context(Self::get_one_or_many_names_context(
436 n,
437 None,
438 capability.capability_type(None).unwrap(),
439 )?));
440 } else if let Some(n) = capability.directory() {
441 return Ok(Self::directories_from_context(Self::get_one_or_many_names_context(
442 n,
443 None,
444 capability.capability_type(None).unwrap(),
445 )?));
446 } else if let Some(cs_storage) = capability.storage() {
447 if capability.storage_id.is_none() {
448 return Err(Error::validate_context(
449 "Storage declaration is missing \"storage_id\", but is required.",
450 Some(cs_storage.origin),
451 ));
452 }
453 return Ok(Self::storages_from_context(Self::get_one_or_many_names_context(
454 cs_storage,
455 None,
456 capability.capability_type(None).unwrap(),
457 )?));
458 } else if let Some(n) = capability.runner() {
459 return Ok(Self::runners_from_context(Self::get_one_or_many_names_context(
460 n,
461 None,
462 capability.capability_type(None).unwrap(),
463 )?));
464 } else if let Some(n) = capability.resolver() {
465 return Ok(Self::resolvers_from_context(Self::get_one_or_many_names_context(
466 n,
467 None,
468 capability.capability_type(None).unwrap(),
469 )?));
470 } else if let Some(n) = capability.event_stream() {
471 return Ok(Self::event_streams_from_context(Self::get_one_or_many_names_context(
472 n,
473 None,
474 capability.capability_type(None).unwrap(),
475 )?));
476 } else if let Some(n) = capability.dictionary() {
477 return Ok(Self::dictionaries_from_context(Self::get_one_or_many_names_context(
478 n,
479 None,
480 capability.capability_type(None).unwrap(),
481 )?));
482 } else if let Some(n) = capability.config() {
483 return Ok(Self::configurations_from_context(Self::get_one_or_many_names_context(
484 n,
485 None,
486 capability.capability_type(None).unwrap(),
487 )?));
488 }
489
490 let supported_keywords = capability
492 .supported()
493 .into_iter()
494 .map(|k| format!("\"{}\"", k))
495 .collect::<Vec<_>>()
496 .join(", ");
497 Err(Error::validate_context(
498 format!(
499 "`{}` declaration is missing a capability keyword, one of: {}",
500 capability.decl_type(),
501 supported_keywords,
502 ),
503 Some(origin.clone()),
504 ))
505 }
506
507 pub fn from_context_offer(
508 offer_input: &'a ContextSpanned<ContextOffer>,
509 ) -> Result<Vec<(Self, Origin)>, Error> {
510 let offer = &offer_input.value;
511 let origin = &offer_input.origin;
512
513 let alias = offer.r#as();
514
515 if let Some(n) = offer.service() {
516 return Ok(Self::services_from_context(Self::get_one_or_many_names_context(
517 n,
518 alias,
519 offer.capability_type(Some(origin.clone())).unwrap(),
520 )?));
521 } else if let Some(n) = offer.protocol() {
522 return Ok(Self::protocols_from_context(Self::get_one_or_many_names_context(
523 n,
524 alias,
525 offer.capability_type(Some(origin.clone())).unwrap(),
526 )?));
527 } else if let Some(n) = offer.directory() {
528 return Ok(Self::directories_from_context(Self::get_one_or_many_names_context(
529 n,
530 alias,
531 offer.capability_type(Some(origin.clone())).unwrap(),
532 )?));
533 } else if let Some(n) = offer.storage() {
534 return Ok(Self::storages_from_context(Self::get_one_or_many_names_context(
535 n,
536 alias,
537 offer.capability_type(Some(origin.clone())).unwrap(),
538 )?));
539 } else if let Some(n) = offer.runner() {
540 return Ok(Self::runners_from_context(Self::get_one_or_many_names_context(
541 n,
542 alias,
543 offer.capability_type(Some(origin.clone())).unwrap(),
544 )?));
545 } else if let Some(n) = offer.resolver() {
546 return Ok(Self::resolvers_from_context(Self::get_one_or_many_names_context(
547 n,
548 alias,
549 offer.capability_type(Some(origin.clone())).unwrap(),
550 )?));
551 } else if let Some(event_stream) = offer.event_stream() {
552 return Ok(Self::event_streams_from_context(Self::get_one_or_many_names_context(
553 event_stream,
554 alias,
555 offer.capability_type(Some(origin.clone())).unwrap(),
556 )?));
557 } else if let Some(n) = offer.dictionary() {
558 return Ok(Self::dictionaries_from_context(Self::get_one_or_many_names_context(
559 n,
560 alias,
561 offer.capability_type(Some(origin.clone())).unwrap(),
562 )?));
563 } else if let Some(n) = offer.config() {
564 return Ok(Self::configurations_from_context(Self::get_one_or_many_names_context(
565 n,
566 alias,
567 offer.capability_type(Some(origin.clone())).unwrap(),
568 )?));
569 }
570
571 let supported_keywords = offer
573 .supported()
574 .into_iter()
575 .map(|k| format!("\"{}\"", k))
576 .collect::<Vec<_>>()
577 .join(", ");
578 Err(Error::validate_context(
579 format!(
580 "`{}` declaration is missing a capability keyword, one of: {}",
581 offer.decl_type(),
582 supported_keywords,
583 ),
584 Some(origin.clone()),
585 ))
586 }
587
588 pub fn from_context_expose(
589 expose_input: &'a ContextSpanned<ContextExpose>,
590 ) -> Result<Vec<(Self, Origin)>, Error> {
591 let expose = &expose_input.value;
592 let origin = &expose_input.origin;
593
594 let alias = expose.r#as();
595
596 if let Some(n) = expose.service() {
597 return Ok(Self::services_from_context(Self::get_one_or_many_names_context(
598 n,
599 alias,
600 expose.capability_type(Some(origin.clone())).unwrap(),
601 )?));
602 } else if let Some(n) = expose.protocol() {
603 return Ok(Self::protocols_from_context(Self::get_one_or_many_names_context(
604 n,
605 alias,
606 expose.capability_type(Some(origin.clone())).unwrap(),
607 )?));
608 } else if let Some(n) = expose.directory() {
609 return Ok(Self::directories_from_context(Self::get_one_or_many_names_context(
610 n,
611 alias,
612 expose.capability_type(Some(origin.clone())).unwrap(),
613 )?));
614 } else if let Some(n) = expose.storage() {
615 return Ok(Self::storages_from_context(Self::get_one_or_many_names_context(
616 n,
617 alias,
618 expose.capability_type(Some(origin.clone())).unwrap(),
619 )?));
620 } else if let Some(n) = expose.runner() {
621 return Ok(Self::runners_from_context(Self::get_one_or_many_names_context(
622 n,
623 alias,
624 expose.capability_type(Some(origin.clone())).unwrap(),
625 )?));
626 } else if let Some(n) = expose.resolver() {
627 return Ok(Self::resolvers_from_context(Self::get_one_or_many_names_context(
628 n,
629 alias,
630 expose.capability_type(Some(origin.clone())).unwrap(),
631 )?));
632 } else if let Some(event_stream) = expose.event_stream() {
633 return Ok(Self::event_streams_from_context(Self::get_one_or_many_names_context(
634 event_stream,
635 alias,
636 expose.capability_type(Some(origin.clone())).unwrap(),
637 )?));
638 } else if let Some(n) = expose.dictionary() {
639 return Ok(Self::dictionaries_from_context(Self::get_one_or_many_names_context(
640 n,
641 alias,
642 expose.capability_type(Some(origin.clone())).unwrap(),
643 )?));
644 } else if let Some(n) = expose.config() {
645 return Ok(Self::configurations_from_context(Self::get_one_or_many_names_context(
646 n,
647 alias,
648 expose.capability_type(Some(origin.clone())).unwrap(),
649 )?));
650 }
651
652 let supported_keywords = expose
654 .supported()
655 .into_iter()
656 .map(|k| format!("\"{}\"", k))
657 .collect::<Vec<_>>()
658 .join(", ");
659 Err(Error::validate_context(
660 format!(
661 "`{}` declaration is missing a capability keyword, one of: {}",
662 expose.decl_type(),
663 supported_keywords,
664 ),
665 Some(origin.clone()),
666 ))
667 }
668
669 pub fn from_context_use(
678 use_input: &'a ContextSpanned<ContextUse>,
679 ) -> Result<Vec<(Self, Origin)>, Error> {
680 let use_ = &use_input.value;
681 let origin = &use_input.origin;
682
683 let alias = use_.path.as_ref();
684
685 if let Some(n) = option_one_or_many_as_ref_context(&use_.service) {
686 return Ok(Self::used_services_from_context(Self::get_one_or_many_svc_paths_context(
687 n,
688 alias,
689 use_input.capability_type(Some(origin.clone())).unwrap(),
690 )?));
691 } else if let Some(n) = option_one_or_many_as_ref_context(&use_.protocol) {
692 return Ok(Self::used_protocols_from_context(Self::get_one_or_many_svc_paths_context(
693 n,
694 alias,
695 use_input.capability_type(Some(origin.clone())).unwrap(),
696 )?));
697 } else if let Some(_) = &use_.directory {
698 if use_.path.is_none() {
699 return Err(Error::validate_context(
700 "\"path\" should be present for `use directory`.",
701 Some(origin.clone()),
702 ));
703 }
704 return Ok(vec![(
705 CapabilityId::UsedDirectory(use_.path.as_ref().unwrap().value.clone()),
706 origin.clone(),
707 )]);
708 } else if let Some(_) = &use_.storage {
709 if use_.path.is_none() {
710 return Err(Error::validate_context(
711 "\"path\" should be present for `use storage`.",
712 Some(origin.clone()),
713 ));
714 }
715 return Ok(vec![(
716 CapabilityId::UsedStorage(use_.path.as_ref().unwrap().value.clone()),
717 origin.clone(),
718 )]);
719 } else if let Some(_) = &use_.event_stream {
720 if let Some(path) = &use_.path {
721 return Ok(vec![(
722 CapabilityId::UsedEventStream(path.value.clone()),
723 origin.clone(),
724 )]);
725 }
726 return Ok(vec![(
727 CapabilityId::UsedEventStream(Path::new("/svc/fuchsia.component.EventStream")?),
728 origin.clone(),
729 )]);
730 } else if let Some(n) = &use_.runner {
731 return Ok(vec![(CapabilityId::UsedRunner(&n.value), n.origin.clone())]);
732 } else if let Some(_) = &use_.config {
733 return match &use_.key {
734 None => Err(Error::validate_context(
735 "\"key\" should be present for `use config`.",
736 Some(origin.clone()),
737 )),
738 Some(name) => {
739 Ok(vec![(CapabilityId::UsedConfiguration(&name.value), origin.clone())])
740 }
741 };
742 } else if let Some(n) = option_one_or_many_as_ref_context(&use_.dictionary) {
743 return Ok(Self::used_dictionaries_from_context(
744 Self::get_one_or_many_svc_paths_context(
745 n,
746 alias,
747 use_input.capability_type(Some(origin.clone())).unwrap(),
748 )?,
749 ));
750 }
751
752 let supported_keywords = use_input
754 .supported()
755 .into_iter()
756 .map(|k| format!("\"{}\"", k))
757 .collect::<Vec<_>>()
758 .join(", ");
759
760 Err(Error::validate_context(
761 format!(
762 "`{}` declaration is missing a capability keyword, one of: {}",
763 use_input.decl_type(),
764 supported_keywords,
765 ),
766 Some(origin.clone()),
767 ))
768 }
769
770 fn get_one_or_many_names_no_span<'b>(
772 names: OneOrMany<&'b BorrowedName>,
773 alias: Option<&'b BorrowedName>,
774 capability_type: &str,
775 ) -> Result<Vec<&'b BorrowedName>, Error> {
776 let names: Vec<&BorrowedName> = names.into_iter().collect();
777 if names.len() == 1 {
778 Ok(vec![alias_or_name(alias, &names[0])])
779 } else {
780 if alias.is_some() {
781 return Err(Error::validate(format!(
782 "\"as\" can only be specified when one `{}` is supplied.",
783 capability_type,
784 )));
785 }
786 Ok(names)
787 }
788 }
789
790 fn get_one_or_many_names_context<'b>(
792 name_wrapper: ContextSpanned<OneOrMany<&'b BorrowedName>>,
793 alias: Option<ContextSpanned<&'b BorrowedName>>,
794 capability_type: &str,
795 ) -> Result<Vec<ContextSpanned<&'b BorrowedName>>, Error> {
796 let names_origin = name_wrapper.origin;
797 let names_vec: Vec<&'b BorrowedName> = name_wrapper.value.into_iter().collect();
798 let num_names = names_vec.len();
799
800 if num_names > 1 && alias.is_some() {
801 return Err(Error::validate_contexts(
802 format!("\"as\" can only be specified when one `{}` is supplied.", capability_type),
803 vec![alias.map(|s| s.origin).unwrap_or(names_origin)],
804 ));
805 }
806
807 if num_names == 1 {
808 let final_name_span = alias_or_name_context(alias, names_vec[0], names_origin);
809 return Ok(vec![final_name_span]);
810 }
811
812 let final_names = names_vec
813 .into_iter()
814 .map(|name| ContextSpanned { value: name, origin: names_origin.clone() })
815 .collect();
816
817 Ok(final_names)
818 }
819
820 fn get_one_or_many_svc_paths(
822 names: OneOrMany<&BorrowedName>,
823 alias: Option<&Path>,
824 capability_type: &str,
825 ) -> Result<Vec<Path>, Error> {
826 let names: Vec<_> = names.into_iter().collect();
827 match (names.len(), alias) {
828 (_, None) => {
829 Ok(names.into_iter().map(|n| format!("/svc/{}", n).parse().unwrap()).collect())
830 }
831 (1, Some(alias)) => Ok(vec![alias.clone()]),
832 (_, Some(_)) => {
833 return Err(Error::validate(format!(
834 "\"path\" can only be specified when one `{}` is supplied.",
835 capability_type,
836 )));
837 }
838 }
839 }
840
841 fn get_one_or_many_svc_paths_context(
842 names: ContextSpanned<OneOrMany<&BorrowedName>>,
843 alias: Option<&ContextSpanned<Path>>,
844 capability_type: &str,
845 ) -> Result<Vec<ContextSpanned<Path>>, Error> {
846 let names_origin = &names.origin;
847 let names_vec: Vec<_> = names.value.into_iter().collect();
848
849 match (names_vec.len(), alias) {
850 (_, None) => {
851 let generated_paths = names_vec
852 .into_iter()
853 .map(|n| {
854 let new_path: Path = format!("/svc/{}", n).parse().unwrap();
855 ContextSpanned { value: new_path, origin: names_origin.clone() }
856 })
857 .collect();
858 Ok(generated_paths)
859 }
860
861 (1, Some(spanned_alias)) => Ok(vec![spanned_alias.clone()]),
862
863 (_, Some(spanned_alias)) => Err(Error::validate_contexts(
864 format!(
865 "\"path\" can only be specified when one `{}` is supplied.",
866 capability_type,
867 ),
868 vec![spanned_alias.origin.clone()],
869 )),
870 }
871 }
872
873 capability_ids_from_names!(services_from, CapabilityId::Service);
874 capability_ids_from_names!(protocols_from, CapabilityId::Protocol);
875 capability_ids_from_names!(directories_from, CapabilityId::Directory);
876 capability_ids_from_names!(storages_from, CapabilityId::Storage);
877 capability_ids_from_names!(runners_from, CapabilityId::Runner);
878 capability_ids_from_names!(resolvers_from, CapabilityId::Resolver);
879 capability_ids_from_names!(event_streams_from, CapabilityId::EventStream);
880 capability_ids_from_names!(dictionaries_from, CapabilityId::Dictionary);
881 capability_ids_from_names!(configurations_from, CapabilityId::Configuration);
882
883 capability_ids_from_paths!(used_services_from, CapabilityId::UsedService);
884 capability_ids_from_paths!(used_protocols_from, CapabilityId::UsedProtocol);
885 capability_ids_from_paths!(used_dictionaries_from, CapabilityId::UsedDictionary);
886
887 capability_ids_from_context_names!(services_from_context, CapabilityId::Service);
888 capability_ids_from_context_names!(protocols_from_context, CapabilityId::Protocol);
889 capability_ids_from_context_names!(directories_from_context, CapabilityId::Directory);
890 capability_ids_from_context_names!(storages_from_context, CapabilityId::Storage);
891 capability_ids_from_context_names!(runners_from_context, CapabilityId::Runner);
892 capability_ids_from_context_names!(resolvers_from_context, CapabilityId::Resolver);
893 capability_ids_from_context_names!(event_streams_from_context, CapabilityId::EventStream);
894 capability_ids_from_context_names!(dictionaries_from_context, CapabilityId::Dictionary);
895 capability_ids_from_context_names!(configurations_from_context, CapabilityId::Configuration);
896
897 capability_ids_from_context_paths!(used_services_from_context, CapabilityId::UsedService);
898 capability_ids_from_context_paths!(used_protocols_from_context, CapabilityId::UsedProtocol);
899 capability_ids_from_context_paths!(
900 used_dictionaries_from_context,
901 CapabilityId::UsedDictionary
902 );
903}
904
905impl fmt::Display for CapabilityId<'_> {
906 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
908 match self {
909 CapabilityId::Service(n)
910 | CapabilityId::Storage(n)
911 | CapabilityId::Runner(n)
912 | CapabilityId::UsedRunner(n)
913 | CapabilityId::Resolver(n)
914 | CapabilityId::EventStream(n)
915 | CapabilityId::Configuration(n)
916 | CapabilityId::UsedConfiguration(n)
917 | CapabilityId::Dictionary(n) => write!(f, "{}", n),
918 CapabilityId::UsedService(p)
919 | CapabilityId::UsedProtocol(p)
920 | CapabilityId::UsedDirectory(p)
921 | CapabilityId::UsedStorage(p)
922 | CapabilityId::UsedEventStream(p)
923 | CapabilityId::UsedDictionary(p) => write!(f, "{}", p),
924 CapabilityId::UsedProtocolNumberedHandle(p) => write!(f, "{}", p),
925 CapabilityId::Protocol(p) | CapabilityId::Directory(p) => write!(f, "{}", p),
926 }
927 }
928}
929
930#[cfg(test)]
931mod tests {
932 use super::*;
933 use crate::error::Location;
934 use crate::types::offer::Offer;
935 use crate::types::r#use::Use;
936 use assert_matches::assert_matches;
937 use std::path::PathBuf;
938 use std::sync::Arc;
939
940 #[test]
941 fn test_offer_service() -> Result<(), Error> {
942 let a: Name = "a".parse().unwrap();
943 let b: Name = "b".parse().unwrap();
944 assert_eq!(
945 CapabilityId::from_offer_expose(&Offer {
946 service: Some(OneOrMany::One(a.clone())),
947 ..Offer::default()
948 },)?,
949 vec![CapabilityId::Service(&a)]
950 );
951
952 let synthetic_origin = Origin {
953 file: Arc::new(PathBuf::from("synthetic")),
954 location: Location { line: 0, column: 0 },
955 };
956
957 assert_eq!(
958 CapabilityId::from_context_offer(&ContextSpanned {
959 value: ContextOffer {
960 service: Some(ContextSpanned {
961 value: OneOrMany::One(a.clone()),
962 origin: synthetic_origin.clone(),
963 }),
964 ..ContextOffer::default()
965 },
966 origin: synthetic_origin.clone(),
967 })?,
968 vec![(CapabilityId::Service(&a), synthetic_origin.clone())]
969 );
970
971 assert_eq!(
972 CapabilityId::from_offer_expose(&Offer {
973 service: Some(OneOrMany::Many(vec![a.clone(), b.clone()],)),
974 ..Offer::default()
975 },)?,
976 vec![CapabilityId::Service(&a), CapabilityId::Service(&b)]
977 );
978
979 assert_eq!(
980 CapabilityId::from_context_offer(&ContextSpanned {
981 value: ContextOffer {
982 service: Some(ContextSpanned {
983 value: OneOrMany::Many(vec![a.clone(), b.clone()]),
984 origin: synthetic_origin.clone(),
985 }),
986 ..ContextOffer::default()
987 },
988 origin: synthetic_origin.clone(),
989 })?,
990 vec![
991 (CapabilityId::Service(&a), synthetic_origin.clone()),
992 (CapabilityId::Service(&b), synthetic_origin.clone())
993 ]
994 );
995
996 assert_eq!(
998 CapabilityId::from_offer_expose(&Offer {
999 service: Some(OneOrMany::One(a.clone())),
1000 r#as: Some(b.clone()),
1001 ..Offer::default()
1002 },)?,
1003 vec![CapabilityId::Service(&b)]
1004 );
1005
1006 assert_eq!(
1007 CapabilityId::from_context_offer(&ContextSpanned {
1008 value: ContextOffer {
1009 service: Some(ContextSpanned {
1010 value: OneOrMany::One(a.clone()),
1011 origin: synthetic_origin.clone(),
1012 }),
1013 r#as: Some(ContextSpanned {
1014 value: b.clone(),
1015 origin: synthetic_origin.clone()
1016 }),
1017 ..ContextOffer::default()
1018 },
1019 origin: synthetic_origin.clone(),
1020 })?,
1021 vec![(CapabilityId::Service(&b), synthetic_origin)]
1022 );
1023
1024 Ok(())
1025 }
1026
1027 #[test]
1028 fn test_use_service() -> Result<(), Error> {
1029 let a: Name = "a".parse().unwrap();
1030 let b: Name = "b".parse().unwrap();
1031
1032 let synthetic_origin = Origin {
1033 file: Arc::new(PathBuf::from("synthetic")),
1034 location: Location { line: 0, column: 0 },
1035 };
1036
1037 assert_eq!(
1038 CapabilityId::from_use(&Use {
1039 service: Some(OneOrMany::One(a.clone())),
1040 ..Use::default()
1041 },)?,
1042 vec![CapabilityId::UsedService("/svc/a".parse().unwrap())]
1043 );
1044
1045 assert_eq!(
1046 CapabilityId::from_context_use(&ContextSpanned {
1047 value: ContextUse {
1048 service: Some(ContextSpanned {
1049 value: OneOrMany::One(a.clone()),
1050 origin: synthetic_origin.clone(),
1051 }),
1052 ..ContextUse::default()
1053 },
1054 origin: synthetic_origin.clone(),
1055 })?,
1056 vec![(CapabilityId::UsedService("/svc/a".parse().unwrap()), synthetic_origin.clone())]
1057 );
1058
1059 assert_eq!(
1060 CapabilityId::from_use(&Use {
1061 service: Some(OneOrMany::Many(vec![a.clone(), b.clone(),],)),
1062 ..Use::default()
1063 },)?,
1064 vec![
1065 CapabilityId::UsedService("/svc/a".parse().unwrap()),
1066 CapabilityId::UsedService("/svc/b".parse().unwrap())
1067 ]
1068 );
1069
1070 assert_eq!(
1071 CapabilityId::from_context_use(&ContextSpanned {
1072 value: ContextUse {
1073 service: Some(ContextSpanned {
1074 value: OneOrMany::Many(vec![a.clone(), b.clone(),]),
1075 origin: synthetic_origin.clone(),
1076 }),
1077 ..ContextUse::default()
1078 },
1079 origin: synthetic_origin.clone(),
1080 })?,
1081 vec![
1082 (CapabilityId::UsedService("/svc/a".parse().unwrap()), synthetic_origin.clone()),
1083 (CapabilityId::UsedService("/svc/b".parse().unwrap()), synthetic_origin.clone())
1084 ]
1085 );
1086
1087 assert_eq!(
1088 CapabilityId::from_use(&Use {
1089 service: Some(OneOrMany::One(a.clone())),
1090 path: Some("/b".parse().unwrap()),
1091 ..Use::default()
1092 },)?,
1093 vec![CapabilityId::UsedService("/b".parse().unwrap())]
1094 );
1095
1096 assert_eq!(
1097 CapabilityId::from_context_use(&ContextSpanned {
1098 value: ContextUse {
1099 service: Some(ContextSpanned {
1100 value: OneOrMany::One(a.clone()),
1101 origin: synthetic_origin.clone(),
1102 }),
1103 path: Some(ContextSpanned {
1104 value: "/b".parse().unwrap(),
1105 origin: synthetic_origin.clone(),
1106 }),
1107 ..ContextUse::default()
1108 },
1109 origin: synthetic_origin.clone(),
1110 })?,
1111 vec![(CapabilityId::UsedService("/b".parse().unwrap()), synthetic_origin.clone())]
1112 );
1113
1114 Ok(())
1115 }
1116
1117 #[test]
1118 fn test_use_event_stream() -> Result<(), Error> {
1119 let synthetic_origin = Origin {
1120 file: Arc::new(PathBuf::from("synthetic")),
1121 location: Location { line: 0, column: 0 },
1122 };
1123
1124 assert_eq!(
1125 CapabilityId::from_use(&Use {
1126 event_stream: Some(OneOrMany::One(Name::new("test".to_string()).unwrap())),
1127 path: Some(cm_types::Path::new("/svc/myevent".to_string()).unwrap()),
1128 ..Use::default()
1129 },)?,
1130 vec![CapabilityId::UsedEventStream("/svc/myevent".parse().unwrap()),]
1131 );
1132
1133 assert_eq!(
1134 CapabilityId::from_context_use(&ContextSpanned {
1135 value: ContextUse {
1136 event_stream: Some(ContextSpanned {
1137 value: OneOrMany::One(Name::new("test".to_string()).unwrap()),
1138 origin: synthetic_origin.clone(),
1139 }),
1140 path: Some(ContextSpanned {
1141 value: cm_types::Path::new("/svc/myevent".to_string()).unwrap(),
1142 origin: synthetic_origin.clone(),
1143 }),
1144 ..ContextUse::default()
1145 },
1146 origin: synthetic_origin.clone(),
1147 })?,
1148 vec![(
1149 CapabilityId::UsedEventStream("/svc/myevent".parse().unwrap()),
1150 synthetic_origin.clone()
1151 )]
1152 );
1153
1154 assert_eq!(
1155 CapabilityId::from_use(&Use {
1156 event_stream: Some(OneOrMany::One(Name::new("test".to_string()).unwrap())),
1157 ..Use::default()
1158 },)?,
1159 vec![CapabilityId::UsedEventStream(
1160 "/svc/fuchsia.component.EventStream".parse().unwrap()
1161 ),]
1162 );
1163
1164 assert_eq!(
1165 CapabilityId::from_context_use(&ContextSpanned {
1166 value: ContextUse {
1167 event_stream: Some(ContextSpanned {
1168 value: OneOrMany::One(Name::new("test".to_string()).unwrap()),
1169 origin: synthetic_origin.clone(),
1170 }),
1171 ..ContextUse::default()
1172 },
1173 origin: synthetic_origin.clone(),
1174 })?,
1175 vec![(
1176 CapabilityId::UsedEventStream(
1177 "/svc/fuchsia.component.EventStream".parse().unwrap()
1178 ),
1179 synthetic_origin.clone()
1180 )]
1181 );
1182
1183 Ok(())
1184 }
1185
1186 #[test]
1187 fn test_offer_protocol() -> Result<(), Error> {
1188 let a: Name = "a".parse().unwrap();
1189 let b: Name = "b".parse().unwrap();
1190
1191 let synthetic_origin = Origin {
1192 file: Arc::new(PathBuf::from("synthetic")),
1193 location: Location { line: 0, column: 0 },
1194 };
1195
1196 assert_eq!(
1197 CapabilityId::from_offer_expose(&Offer {
1198 protocol: Some(OneOrMany::One(a.clone())),
1199 ..Offer::default()
1200 },)?,
1201 vec![CapabilityId::Protocol(&a)]
1202 );
1203
1204 assert_eq!(
1205 CapabilityId::from_context_offer(&ContextSpanned {
1206 value: ContextOffer {
1207 protocol: Some(ContextSpanned {
1208 value: OneOrMany::One(a.clone()),
1209 origin: synthetic_origin.clone(),
1210 }),
1211 ..ContextOffer::default()
1212 },
1213 origin: synthetic_origin.clone(),
1214 })?,
1215 vec![(CapabilityId::Protocol(&a), synthetic_origin.clone())]
1216 );
1217
1218 assert_eq!(
1219 CapabilityId::from_offer_expose(&Offer {
1220 protocol: Some(OneOrMany::Many(vec![a.clone(), b.clone()],)),
1221 ..Offer::default()
1222 },)?,
1223 vec![CapabilityId::Protocol(&a), CapabilityId::Protocol(&b)]
1224 );
1225
1226 assert_eq!(
1227 CapabilityId::from_context_offer(&ContextSpanned {
1228 value: ContextOffer {
1229 protocol: Some(ContextSpanned {
1230 value: OneOrMany::Many(vec![a.clone(), b.clone()]),
1231 origin: synthetic_origin.clone(),
1232 }),
1233 ..ContextOffer::default()
1234 },
1235 origin: synthetic_origin.clone(),
1236 })?,
1237 vec![
1238 (CapabilityId::Protocol(&a), synthetic_origin.clone()),
1239 (CapabilityId::Protocol(&b), synthetic_origin)
1240 ]
1241 );
1242
1243 Ok(())
1244 }
1245
1246 #[test]
1247 fn test_use_protocol() -> Result<(), Error> {
1248 let a: Name = "a".parse().unwrap();
1249 let b: Name = "b".parse().unwrap();
1250
1251 let synthetic_origin = Origin {
1252 file: Arc::new(PathBuf::from("synthetic")),
1253 location: Location { line: 0, column: 0 },
1254 };
1255
1256 assert_eq!(
1257 CapabilityId::from_use(&Use {
1258 protocol: Some(OneOrMany::One(a.clone())),
1259 ..Use::default()
1260 },)?,
1261 vec![CapabilityId::UsedProtocol("/svc/a".parse().unwrap())]
1262 );
1263
1264 assert_eq!(
1265 CapabilityId::from_context_use(&ContextSpanned {
1266 value: ContextUse {
1267 protocol: Some(ContextSpanned {
1268 value: OneOrMany::One(a.clone()),
1269 origin: synthetic_origin.clone(),
1270 }),
1271 ..ContextUse::default()
1272 },
1273 origin: synthetic_origin.clone(),
1274 })?,
1275 vec![(CapabilityId::UsedProtocol("/svc/a".parse().unwrap()), synthetic_origin.clone())]
1276 );
1277 assert_eq!(
1278 CapabilityId::from_use(&Use {
1279 protocol: Some(OneOrMany::Many(vec![a.clone(), b.clone(),],)),
1280 ..Use::default()
1281 },)?,
1282 vec![
1283 CapabilityId::UsedProtocol("/svc/a".parse().unwrap()),
1284 CapabilityId::UsedProtocol("/svc/b".parse().unwrap())
1285 ]
1286 );
1287
1288 assert_eq!(
1289 CapabilityId::from_context_use(&ContextSpanned {
1290 value: ContextUse {
1291 protocol: Some(ContextSpanned {
1292 value: OneOrMany::Many(vec![a.clone(), b.clone(),]),
1293 origin: synthetic_origin.clone(),
1294 }),
1295 ..ContextUse::default()
1296 },
1297 origin: synthetic_origin.clone(),
1298 })?,
1299 vec![
1300 (CapabilityId::UsedProtocol("/svc/a".parse().unwrap()), synthetic_origin.clone()),
1301 (CapabilityId::UsedProtocol("/svc/b".parse().unwrap()), synthetic_origin.clone())
1302 ]
1303 );
1304
1305 assert_eq!(
1306 CapabilityId::from_use(&Use {
1307 protocol: Some(OneOrMany::One(a.clone())),
1308 path: Some("/b".parse().unwrap()),
1309 ..Use::default()
1310 },)?,
1311 vec![CapabilityId::UsedProtocol("/b".parse().unwrap())]
1312 );
1313
1314 assert_eq!(
1315 CapabilityId::from_context_use(&ContextSpanned {
1316 value: ContextUse {
1317 protocol: Some(ContextSpanned {
1318 value: OneOrMany::One(a.clone()),
1319 origin: synthetic_origin.clone(),
1320 }),
1321 path: Some(ContextSpanned {
1322 value: "/b".parse().unwrap(),
1323 origin: synthetic_origin.clone(),
1324 }),
1325 ..ContextUse::default()
1326 },
1327 origin: synthetic_origin.clone(),
1328 })?,
1329 vec![(CapabilityId::UsedProtocol("/b".parse().unwrap()), synthetic_origin.clone())]
1330 );
1331
1332 Ok(())
1333 }
1334
1335 #[test]
1336 fn test_offer_directory() -> Result<(), Error> {
1337 let a: Name = "a".parse().unwrap();
1338 let b: Name = "b".parse().unwrap();
1339
1340 let synthetic_origin = Origin {
1341 file: Arc::new(PathBuf::from("synthetic")),
1342 location: Location { line: 0, column: 0 },
1343 };
1344
1345 assert_eq!(
1346 CapabilityId::from_offer_expose(&Offer {
1347 directory: Some(OneOrMany::One(a.clone())),
1348 ..Offer::default()
1349 },)?,
1350 vec![CapabilityId::Directory(&a)]
1351 );
1352
1353 assert_eq!(
1354 CapabilityId::from_context_offer(&ContextSpanned {
1355 value: ContextOffer {
1356 directory: Some(ContextSpanned {
1357 value: OneOrMany::One(a.clone()),
1358 origin: synthetic_origin.clone(),
1359 }),
1360 ..ContextOffer::default()
1361 },
1362 origin: synthetic_origin.clone(),
1363 })?,
1364 vec![(CapabilityId::Directory(&a), synthetic_origin.clone())]
1365 );
1366
1367 assert_eq!(
1368 CapabilityId::from_offer_expose(&Offer {
1369 directory: Some(OneOrMany::Many(vec![a.clone(), b.clone()])),
1370 ..Offer::default()
1371 },)?,
1372 vec![CapabilityId::Directory(&a), CapabilityId::Directory(&b),]
1373 );
1374
1375 assert_eq!(
1376 CapabilityId::from_context_offer(&ContextSpanned {
1377 value: ContextOffer {
1378 directory: Some(ContextSpanned {
1379 value: OneOrMany::Many(vec![a.clone(), b.clone()]),
1380 origin: synthetic_origin.clone(),
1381 }),
1382 ..ContextOffer::default()
1383 },
1384 origin: synthetic_origin.clone(),
1385 })?,
1386 vec![
1387 (CapabilityId::Directory(&a), synthetic_origin.clone()),
1388 (CapabilityId::Directory(&b), synthetic_origin.clone())
1389 ]
1390 );
1391
1392 Ok(())
1393 }
1394
1395 #[test]
1396 fn test_use_directory() -> Result<(), Error> {
1397 let a: Name = "a".parse().unwrap();
1398
1399 let synthetic_origin = Origin {
1400 file: Arc::new(PathBuf::from("synthetic")),
1401 location: Location { line: 0, column: 0 },
1402 };
1403
1404 assert_eq!(
1405 CapabilityId::from_use(&Use {
1406 directory: Some(a.clone()),
1407 path: Some("/b".parse().unwrap()),
1408 ..Use::default()
1409 },)?,
1410 vec![CapabilityId::UsedDirectory("/b".parse().unwrap())]
1411 );
1412
1413 assert_eq!(
1414 CapabilityId::from_context_use(&ContextSpanned {
1415 value: ContextUse {
1416 directory: Some(ContextSpanned {
1417 value: a.clone(),
1418 origin: synthetic_origin.clone(),
1419 }),
1420 path: Some(ContextSpanned {
1421 value: "/b".parse().unwrap(),
1422 origin: synthetic_origin.clone(),
1423 }),
1424 ..ContextUse::default()
1425 },
1426 origin: synthetic_origin.clone(),
1427 })?,
1428 vec![(CapabilityId::UsedDirectory("/b".parse().unwrap()), synthetic_origin.clone())]
1429 );
1430
1431 Ok(())
1432 }
1433
1434 #[test]
1435 fn test_offer_storage() -> Result<(), Error> {
1436 let a: Name = "a".parse().unwrap();
1437 let b: Name = "b".parse().unwrap();
1438
1439 let synthetic_origin = Origin {
1440 file: Arc::new(PathBuf::from("synthetic")),
1441 location: Location { line: 0, column: 0 },
1442 };
1443
1444 assert_eq!(
1445 CapabilityId::from_offer_expose(&Offer {
1446 storage: Some(OneOrMany::One(a.clone())),
1447 ..Offer::default()
1448 },)?,
1449 vec![CapabilityId::Storage(&a)]
1450 );
1451
1452 assert_eq!(
1453 CapabilityId::from_context_offer(&ContextSpanned {
1454 value: ContextOffer {
1455 storage: Some(ContextSpanned {
1456 value: OneOrMany::One(a.clone()),
1457 origin: synthetic_origin.clone(),
1458 }),
1459 ..ContextOffer::default()
1460 },
1461 origin: synthetic_origin.clone(),
1462 })?,
1463 vec![(CapabilityId::Storage(&a), synthetic_origin.clone())]
1464 );
1465
1466 assert_eq!(
1467 CapabilityId::from_offer_expose(&Offer {
1468 storage: Some(OneOrMany::Many(vec![a.clone(), b.clone()])),
1469 ..Offer::default()
1470 },)?,
1471 vec![CapabilityId::Storage(&a), CapabilityId::Storage(&b),]
1472 );
1473
1474 assert_eq!(
1475 CapabilityId::from_context_offer(&ContextSpanned {
1476 value: ContextOffer {
1477 storage: Some(ContextSpanned {
1478 value: OneOrMany::Many(vec![a.clone(), b.clone()]),
1479 origin: synthetic_origin.clone(),
1480 }),
1481 ..ContextOffer::default()
1482 },
1483 origin: synthetic_origin.clone(),
1484 })?,
1485 vec![
1486 (CapabilityId::Storage(&a), synthetic_origin.clone()),
1487 (CapabilityId::Storage(&b), synthetic_origin.clone())
1488 ]
1489 );
1490
1491 Ok(())
1492 }
1493
1494 #[test]
1495 fn test_use_storage() -> Result<(), Error> {
1496 let a: Name = "a".parse().unwrap();
1497
1498 let synthetic_origin = Origin {
1499 file: Arc::new(PathBuf::from("synthetic")),
1500 location: Location { line: 0, column: 0 },
1501 };
1502
1503 assert_eq!(
1504 CapabilityId::from_use(&Use {
1505 storage: Some(a.clone()),
1506 path: Some("/b".parse().unwrap()),
1507 ..Use::default()
1508 },)?,
1509 vec![CapabilityId::UsedStorage("/b".parse().unwrap())]
1510 );
1511
1512 assert_eq!(
1513 CapabilityId::from_context_use(&ContextSpanned {
1514 value: ContextUse {
1515 storage: Some(ContextSpanned {
1516 value: a.clone(),
1517 origin: synthetic_origin.clone(),
1518 }),
1519 path: Some(ContextSpanned {
1520 value: "/b".parse().unwrap(),
1521 origin: synthetic_origin.clone(),
1522 }),
1523 ..ContextUse::default()
1524 },
1525 origin: synthetic_origin.clone(),
1526 })?,
1527 vec![(CapabilityId::UsedStorage("/b".parse().unwrap()), synthetic_origin.clone())]
1528 );
1529
1530 Ok(())
1531 }
1532
1533 #[test]
1534 fn test_use_runner() -> Result<(), Error> {
1535 let synthetic_origin = Origin {
1536 file: Arc::new(PathBuf::from("synthetic")),
1537 location: Location { line: 0, column: 0 },
1538 };
1539
1540 assert_eq!(
1541 CapabilityId::from_use(&Use {
1542 runner: Some("elf".parse().unwrap()),
1543 ..Use::default()
1544 })?,
1545 vec![CapabilityId::UsedRunner(BorrowedName::new("elf").unwrap())]
1546 );
1547
1548 assert_eq!(
1549 CapabilityId::from_context_use(&ContextSpanned {
1550 value: ContextUse {
1551 runner: Some(ContextSpanned {
1552 value: "elf".parse().unwrap(),
1553 origin: synthetic_origin.clone(),
1554 }),
1555 ..ContextUse::default()
1556 },
1557 origin: synthetic_origin.clone(),
1558 })?,
1559 vec![(
1560 CapabilityId::UsedRunner(BorrowedName::new("elf").unwrap()),
1561 synthetic_origin.clone()
1562 )]
1563 );
1564
1565 Ok(())
1566 }
1567
1568 #[test]
1569 fn test_offer_dictionary() -> Result<(), Error> {
1570 let a: Name = "a".parse().unwrap();
1571 let b: Name = "b".parse().unwrap();
1572
1573 let synthetic_origin = Origin {
1574 file: Arc::new(PathBuf::from("synthetic")),
1575 location: Location { line: 0, column: 0 },
1576 };
1577
1578 assert_eq!(
1579 CapabilityId::from_offer_expose(&Offer {
1580 dictionary: Some(OneOrMany::One(a.clone())),
1581 ..Offer::default()
1582 },)?,
1583 vec![CapabilityId::Dictionary(&a)]
1584 );
1585
1586 assert_eq!(
1587 CapabilityId::from_context_offer(&ContextSpanned {
1588 value: ContextOffer {
1589 dictionary: Some(ContextSpanned {
1590 value: OneOrMany::One(a.clone()),
1591 origin: synthetic_origin.clone(),
1592 }),
1593 ..ContextOffer::default()
1594 },
1595 origin: synthetic_origin.clone(),
1596 })?,
1597 vec![(CapabilityId::Dictionary(&a), synthetic_origin.clone())]
1598 );
1599
1600 assert_eq!(
1601 CapabilityId::from_offer_expose(&Offer {
1602 dictionary: Some(OneOrMany::Many(vec![a.clone(), b.clone()],)),
1603 ..Offer::default()
1604 },)?,
1605 vec![CapabilityId::Dictionary(&a), CapabilityId::Dictionary(&b)]
1606 );
1607
1608 assert_eq!(
1609 CapabilityId::from_context_offer(&ContextSpanned {
1610 value: ContextOffer {
1611 dictionary: Some(ContextSpanned {
1612 value: OneOrMany::Many(vec![a.clone(), b.clone()]),
1613 origin: synthetic_origin.clone(),
1614 }),
1615 ..ContextOffer::default()
1616 },
1617 origin: synthetic_origin.clone(),
1618 })?,
1619 vec![
1620 (CapabilityId::Dictionary(&a), synthetic_origin.clone()),
1621 (CapabilityId::Dictionary(&b), synthetic_origin.clone())
1622 ]
1623 );
1624
1625 Ok(())
1626 }
1627
1628 #[test]
1629 fn test_use_dictionary() -> Result<(), Error> {
1630 let a: Name = "a".parse().unwrap();
1631 let b: Name = "b".parse().unwrap();
1632
1633 let synthetic_origin = Origin {
1634 file: Arc::new(PathBuf::from("synthetic")),
1635 location: Location { line: 0, column: 0 },
1636 };
1637
1638 assert_eq!(
1639 CapabilityId::from_use(&Use {
1640 dictionary: Some(OneOrMany::One(a.clone())),
1641 ..Use::default()
1642 },)?,
1643 vec![CapabilityId::UsedDictionary("/svc/a".parse().unwrap())]
1644 );
1645
1646 assert_eq!(
1647 CapabilityId::from_context_use(&ContextSpanned {
1648 value: ContextUse {
1649 dictionary: Some(ContextSpanned {
1650 value: OneOrMany::One(a.clone()),
1651 origin: synthetic_origin.clone(),
1652 }),
1653 ..ContextUse::default()
1654 },
1655 origin: synthetic_origin.clone(),
1656 })?,
1657 vec![(
1658 CapabilityId::UsedDictionary("/svc/a".parse().unwrap()),
1659 synthetic_origin.clone()
1660 )]
1661 );
1662
1663 assert_eq!(
1664 CapabilityId::from_use(&Use {
1665 dictionary: Some(OneOrMany::Many(vec![a.clone(), b.clone(),],)),
1666 ..Use::default()
1667 },)?,
1668 vec![
1669 CapabilityId::UsedDictionary("/svc/a".parse().unwrap()),
1670 CapabilityId::UsedDictionary("/svc/b".parse().unwrap())
1671 ]
1672 );
1673
1674 assert_eq!(
1675 CapabilityId::from_context_use(&ContextSpanned {
1676 value: ContextUse {
1677 dictionary: Some(ContextSpanned {
1678 value: OneOrMany::Many(vec![a.clone(), b.clone()]),
1679 origin: synthetic_origin.clone(),
1680 }),
1681 ..ContextUse::default()
1682 },
1683 origin: synthetic_origin.clone(),
1684 })?,
1685 vec![
1686 (CapabilityId::UsedDictionary("/svc/a".parse().unwrap()), synthetic_origin.clone()),
1687 (CapabilityId::UsedDictionary("/svc/b".parse().unwrap()), synthetic_origin.clone())
1688 ]
1689 );
1690
1691 assert_eq!(
1692 CapabilityId::from_use(&Use {
1693 dictionary: Some(OneOrMany::One(a.clone())),
1694 path: Some("/b".parse().unwrap()),
1695 ..Use::default()
1696 },)?,
1697 vec![CapabilityId::UsedDictionary("/b".parse().unwrap())]
1698 );
1699
1700 assert_eq!(
1701 CapabilityId::from_context_use(&ContextSpanned {
1702 value: ContextUse {
1703 dictionary: Some(ContextSpanned {
1704 value: OneOrMany::One(a.clone()),
1705 origin: synthetic_origin.clone(),
1706 }),
1707 path: Some(ContextSpanned {
1708 value: "/b".parse().unwrap(),
1709 origin: synthetic_origin.clone()
1710 }),
1711 ..ContextUse::default()
1712 },
1713 origin: synthetic_origin.clone(),
1714 })?,
1715 vec![(CapabilityId::UsedDictionary("/b".parse().unwrap()), synthetic_origin.clone())]
1716 );
1717
1718 Ok(())
1719 }
1720
1721 #[test]
1722 fn test_errors() -> Result<(), Error> {
1723 assert_matches!(CapabilityId::from_offer_expose(&Offer::default()), Err(_));
1724
1725 let synthetic_origin = Origin {
1726 file: Arc::new(PathBuf::from("synthetic")),
1727 location: Location { line: 0, column: 0 },
1728 };
1729
1730 assert_matches!(
1731 CapabilityId::from_context_offer(&ContextSpanned {
1732 value: ContextOffer::default(),
1733 origin: synthetic_origin
1734 }),
1735 Err(_)
1736 );
1737
1738 Ok(())
1739 }
1740}