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::r#use::ContextUse;
9use crate::{AsClauseContext, ContextSpanned, Error, alias_or_name_context};
10pub use cm_types::{
11 Availability, BorrowedName, BoundedName, DeliveryType, DependencyType, HandleType, Name,
12 NamespacePath, OnTerminate, ParseError, Path, RelativePath, StartupMode, StorageId, Url,
13};
14
15use std::fmt;
16use std::path::PathBuf;
17use std::sync::Arc;
18
19#[derive(Debug, PartialEq, Eq, Hash, Clone)]
30pub enum CapabilityId<'a> {
31 Service(&'a BorrowedName),
32 Protocol(&'a BorrowedName),
33 Directory(&'a BorrowedName),
34 UsedService(Path),
36 UsedProtocol(Path),
38 UsedProtocolNumberedHandle(HandleType),
40 UsedDirectory(Path),
42 UsedStorage(Path),
44 UsedEventStream(Path),
46 UsedConfiguration(&'a BorrowedName),
48 UsedRunner(&'a BorrowedName),
49 UsedDictionary(Path),
51 Storage(&'a BorrowedName),
52 Runner(&'a BorrowedName),
53 Resolver(&'a BorrowedName),
54 EventStream(&'a BorrowedName),
55 Dictionary(&'a BorrowedName),
56 Configuration(&'a BorrowedName),
57}
58
59macro_rules! capability_ids_from_context_names {
61 ($name:ident, $variant:expr) => {
62 fn $name(names: Vec<ContextSpanned<&'a BorrowedName>>) -> Vec<(Self, Arc<PathBuf>)> {
63 names
64 .into_iter()
65 .map(|spanned_name| ($variant(spanned_name.value), spanned_name.origin))
66 .collect()
67 }
68 };
69}
70
71macro_rules! capability_ids_from_context_paths {
73 ($name:ident, $variant:expr) => {
74 fn $name(paths: Vec<ContextSpanned<Path>>) -> Vec<(Self, Arc<PathBuf>)> {
75 paths
76 .into_iter()
77 .map(|spanned_path| ($variant(spanned_path.value), spanned_path.origin))
78 .collect()
79 }
80 };
81}
82
83impl<'a> CapabilityId<'a> {
84 pub fn type_str(&self) -> &'static str {
86 match self {
87 CapabilityId::Service(_) => "service",
88 CapabilityId::Protocol(_) => "protocol",
89 CapabilityId::Directory(_) => "directory",
90 CapabilityId::UsedService(_) => "service",
91 CapabilityId::UsedProtocol(_) => "protocol",
92 CapabilityId::UsedProtocolNumberedHandle(_) => "protocol",
93 CapabilityId::UsedDirectory(_) => "directory",
94 CapabilityId::UsedStorage(_) => "storage",
95 CapabilityId::UsedEventStream(_) => "event_stream",
96 CapabilityId::UsedRunner(_) => "runner",
97 CapabilityId::UsedConfiguration(_) => "config",
98 CapabilityId::UsedDictionary(_) => "dictionary",
99 CapabilityId::Storage(_) => "storage",
100 CapabilityId::Runner(_) => "runner",
101 CapabilityId::Resolver(_) => "resolver",
102 CapabilityId::EventStream(_) => "event_stream",
103 CapabilityId::Dictionary(_) => "dictionary",
104 CapabilityId::Configuration(_) => "config",
105 }
106 }
107
108 pub fn get_dir_path(&self) -> Option<NamespacePath> {
110 match self {
111 CapabilityId::UsedService(p)
112 | CapabilityId::UsedProtocol(p)
113 | CapabilityId::UsedEventStream(p) => Some(p.parent()),
114 CapabilityId::UsedDirectory(p)
115 | CapabilityId::UsedStorage(p)
116 | CapabilityId::UsedDictionary(p) => Some(p.clone().into()),
117 _ => None,
118 }
119 }
120
121 pub fn get_target_path(&self) -> Option<NamespacePath> {
123 match self {
124 CapabilityId::UsedService(p)
125 | CapabilityId::UsedProtocol(p)
126 | CapabilityId::UsedEventStream(p)
127 | CapabilityId::UsedDirectory(p)
128 | CapabilityId::UsedStorage(p)
129 | CapabilityId::UsedDictionary(p) => Some(p.clone().into()),
130 _ => None,
131 }
132 }
133
134 pub fn from_context_capability(
135 capability_input: &'a ContextSpanned<ContextCapability>,
136 ) -> Result<Vec<(Self, Arc<PathBuf>)>, Error> {
137 let capability = &capability_input.value;
138 let origin = &capability_input.origin;
139
140 if let Some(n) = capability.service() {
141 if n.value.is_many()
142 && let Some(cs_path) = &capability.path
143 {
144 return Err(Error::validate_context(
145 "\"path\" can only be specified when one `service` is supplied.",
146 Some(cs_path.origin.clone()),
147 ));
148 }
149 return Ok(Self::services_from_context(Self::get_one_or_many_names_context(
150 n,
151 None,
152 capability.capability_type(None).unwrap(),
153 )?));
154 } else if let Some(n) = capability.protocol() {
155 if n.value.is_many()
156 && let Some(cs_path) = &capability.path
157 {
158 return Err(Error::validate_context(
159 "\"path\" can only be specified when one `protocol` is supplied.",
160 Some(cs_path.origin.clone()),
161 ));
162 }
163 return Ok(Self::protocols_from_context(Self::get_one_or_many_names_context(
164 n,
165 None,
166 capability.capability_type(None).unwrap(),
167 )?));
168 } else if let Some(n) = capability.directory() {
169 return Ok(Self::directories_from_context(Self::get_one_or_many_names_context(
170 n,
171 None,
172 capability.capability_type(None).unwrap(),
173 )?));
174 } else if let Some(cs_storage) = capability.storage() {
175 if capability.storage_id.is_none() {
176 return Err(Error::validate_context(
177 "Storage declaration is missing \"storage_id\", but is required.",
178 Some(cs_storage.origin),
179 ));
180 }
181 return Ok(Self::storages_from_context(Self::get_one_or_many_names_context(
182 cs_storage,
183 None,
184 capability.capability_type(None).unwrap(),
185 )?));
186 } else if let Some(n) = capability.runner() {
187 return Ok(Self::runners_from_context(Self::get_one_or_many_names_context(
188 n,
189 None,
190 capability.capability_type(None).unwrap(),
191 )?));
192 } else if let Some(n) = capability.resolver() {
193 return Ok(Self::resolvers_from_context(Self::get_one_or_many_names_context(
194 n,
195 None,
196 capability.capability_type(None).unwrap(),
197 )?));
198 } else if let Some(n) = capability.event_stream() {
199 return Ok(Self::event_streams_from_context(Self::get_one_or_many_names_context(
200 n,
201 None,
202 capability.capability_type(None).unwrap(),
203 )?));
204 } else if let Some(n) = capability.dictionary() {
205 return Ok(Self::dictionaries_from_context(Self::get_one_or_many_names_context(
206 n,
207 None,
208 capability.capability_type(None).unwrap(),
209 )?));
210 } else if let Some(n) = capability.config() {
211 return Ok(Self::configurations_from_context(Self::get_one_or_many_names_context(
212 n,
213 None,
214 capability.capability_type(None).unwrap(),
215 )?));
216 }
217
218 let supported_keywords = capability
220 .supported()
221 .iter()
222 .map(|k| format!("\"{}\"", k))
223 .collect::<Vec<_>>()
224 .join(", ");
225 Err(Error::validate_context(
226 format!(
227 "`{}` declaration is missing a capability keyword, one of: {}",
228 capability.decl_type(),
229 supported_keywords,
230 ),
231 Some(origin.clone()),
232 ))
233 }
234
235 pub fn from_context_offer_expose<T>(
236 clause_input: &'a ContextSpanned<T>,
237 ) -> Result<Vec<(Self, Arc<PathBuf>)>, Error>
238 where
239 T: ContextCapabilityClause + AsClauseContext + fmt::Debug,
240 {
241 let clause = &clause_input.value;
242 let origin = &clause_input.origin;
243
244 let alias = clause.r#as();
245
246 if let Some(n) = clause.service() {
247 return Ok(Self::services_from_context(Self::get_one_or_many_names_context(
248 n,
249 alias,
250 clause.capability_type(Some(origin.clone())).unwrap(),
251 )?));
252 } else if let Some(n) = clause.protocol() {
253 return Ok(Self::protocols_from_context(Self::get_one_or_many_names_context(
254 n,
255 alias,
256 clause.capability_type(Some(origin.clone())).unwrap(),
257 )?));
258 } else if let Some(n) = clause.directory() {
259 return Ok(Self::directories_from_context(Self::get_one_or_many_names_context(
260 n,
261 alias,
262 clause.capability_type(Some(origin.clone())).unwrap(),
263 )?));
264 } else if let Some(n) = clause.storage() {
265 return Ok(Self::storages_from_context(Self::get_one_or_many_names_context(
266 n,
267 alias,
268 clause.capability_type(Some(origin.clone())).unwrap(),
269 )?));
270 } else if let Some(n) = clause.runner() {
271 return Ok(Self::runners_from_context(Self::get_one_or_many_names_context(
272 n,
273 alias,
274 clause.capability_type(Some(origin.clone())).unwrap(),
275 )?));
276 } else if let Some(n) = clause.resolver() {
277 return Ok(Self::resolvers_from_context(Self::get_one_or_many_names_context(
278 n,
279 alias,
280 clause.capability_type(Some(origin.clone())).unwrap(),
281 )?));
282 } else if let Some(event_stream) = clause.event_stream() {
283 return Ok(Self::event_streams_from_context(Self::get_one_or_many_names_context(
284 event_stream,
285 alias,
286 clause.capability_type(Some(origin.clone())).unwrap(),
287 )?));
288 } else if let Some(n) = clause.dictionary() {
289 return Ok(Self::dictionaries_from_context(Self::get_one_or_many_names_context(
290 n,
291 alias,
292 clause.capability_type(Some(origin.clone())).unwrap(),
293 )?));
294 } else if let Some(n) = clause.config() {
295 return Ok(Self::configurations_from_context(Self::get_one_or_many_names_context(
296 n,
297 alias,
298 clause.capability_type(Some(origin.clone())).unwrap(),
299 )?));
300 }
301
302 let supported_keywords =
304 clause.supported().iter().map(|k| format!("\"{}\"", k)).collect::<Vec<_>>().join(", ");
305 Err(Error::validate_context(
306 format!(
307 "`{}` declaration is missing a capability keyword, one of: {}",
308 clause.decl_type(),
309 supported_keywords,
310 ),
311 Some(origin.clone()),
312 ))
313 }
314
315 pub fn from_context_use(
324 use_input: &'a ContextSpanned<ContextUse>,
325 ) -> Result<Vec<(Self, Arc<PathBuf>)>, Error> {
326 let use_ = &use_input.value;
327 let origin = &use_input.origin;
328
329 let alias = use_.path.as_ref();
330
331 if let Some(n) = option_one_or_many_as_ref_context(&use_.service) {
332 return Ok(Self::used_services_from_context(Self::get_one_or_many_svc_paths_context(
333 n,
334 alias,
335 use_input.capability_type(Some(origin.clone())).unwrap(),
336 )?));
337 } else if let Some(n) = option_one_or_many_as_ref_context(&use_.protocol) {
338 if let Some(numbered_handle) = &use_.numbered_handle {
339 return Ok(n
340 .value
341 .iter()
342 .map(|_| {
343 (
344 CapabilityId::UsedProtocolNumberedHandle(numbered_handle.value),
345 n.origin.clone(),
346 )
347 })
348 .collect());
349 }
350
351 return Ok(Self::used_protocols_from_context(Self::get_one_or_many_svc_paths_context(
352 n,
353 alias,
354 use_input.capability_type(Some(origin.clone())).unwrap(),
355 )?));
356 } else if let Some(_) = &use_.directory {
357 if use_.path.is_none() {
358 return Err(Error::validate_context(
359 "\"path\" should be present for `use directory`.",
360 Some(origin.clone()),
361 ));
362 }
363 return Ok(vec![(
364 CapabilityId::UsedDirectory(use_.path.as_ref().unwrap().value.clone()),
365 origin.clone(),
366 )]);
367 } else if let Some(_) = &use_.storage {
368 if use_.path.is_none() {
369 return Err(Error::validate_context(
370 "\"path\" should be present for `use storage`.",
371 Some(origin.clone()),
372 ));
373 }
374 return Ok(vec![(
375 CapabilityId::UsedStorage(use_.path.as_ref().unwrap().value.clone()),
376 origin.clone(),
377 )]);
378 } else if let Some(_) = &use_.event_stream {
379 if let Some(path) = &use_.path {
380 return Ok(vec![(
381 CapabilityId::UsedEventStream(path.value.clone()),
382 origin.clone(),
383 )]);
384 }
385 return Ok(vec![(
386 CapabilityId::UsedEventStream(Path::new("/svc/fuchsia.component.EventStream")?),
387 origin.clone(),
388 )]);
389 } else if let Some(n) = &use_.runner {
390 return Ok(vec![(CapabilityId::UsedRunner(&n.value), n.origin.clone())]);
391 } else if let Some(_) = &use_.config {
392 return match &use_.key {
393 None => Err(Error::validate_context(
394 "\"key\" should be present for `use config`.",
395 Some(origin.clone()),
396 )),
397 Some(name) => {
398 Ok(vec![(CapabilityId::UsedConfiguration(&name.value), origin.clone())])
399 }
400 };
401 } else if let Some(n) = option_one_or_many_as_ref_context(&use_.dictionary) {
402 return Ok(Self::used_dictionaries_from_context(
403 Self::get_one_or_many_svc_paths_context(
404 n,
405 alias,
406 use_input.capability_type(Some(origin.clone())).unwrap(),
407 )?,
408 ));
409 }
410
411 let supported_keywords = use_input
413 .supported()
414 .iter()
415 .map(|k| format!("\"{}\"", k))
416 .collect::<Vec<_>>()
417 .join(", ");
418
419 Err(Error::validate_context(
420 format!(
421 "`{}` declaration is missing a capability keyword, one of: {}",
422 use_input.decl_type(),
423 supported_keywords,
424 ),
425 Some(origin.clone()),
426 ))
427 }
428
429 fn get_one_or_many_names_context<'b>(
431 name_wrapper: ContextSpanned<OneOrMany<&'b BorrowedName>>,
432 alias: Option<ContextSpanned<&'b BorrowedName>>,
433 capability_type: &str,
434 ) -> Result<Vec<ContextSpanned<&'b BorrowedName>>, Error> {
435 let names_origin = name_wrapper.origin;
436 let names_vec: Vec<&'b BorrowedName> = name_wrapper.value.into_iter().collect();
437 let num_names = names_vec.len();
438
439 if num_names > 1 && alias.is_some() {
440 return Err(Error::validate_contexts(
441 format!("\"as\" can only be specified when one `{}` is supplied.", capability_type),
442 vec![alias.map(|s| s.origin).unwrap_or(names_origin)],
443 ));
444 }
445
446 if num_names == 1 {
447 let final_name_span = alias_or_name_context(alias, names_vec[0], names_origin);
448 return Ok(vec![final_name_span]);
449 }
450
451 let final_names = names_vec
452 .into_iter()
453 .map(|name| ContextSpanned { value: name, origin: names_origin.clone() })
454 .collect();
455
456 Ok(final_names)
457 }
458
459 fn get_one_or_many_svc_paths_context(
460 names: ContextSpanned<OneOrMany<&BorrowedName>>,
461 alias: Option<&ContextSpanned<Path>>,
462 capability_type: &str,
463 ) -> Result<Vec<ContextSpanned<Path>>, Error> {
464 let names_origin = &names.origin;
465 let names_vec: Vec<_> = names.value.into_iter().collect();
466
467 match (names_vec.len(), alias) {
468 (_, None) => {
469 let generated_paths = names_vec
470 .into_iter()
471 .map(|n| {
472 let new_path: Path = format!("/svc/{}", n).parse().unwrap();
473 ContextSpanned { value: new_path, origin: names_origin.clone() }
474 })
475 .collect();
476 Ok(generated_paths)
477 }
478
479 (1, Some(spanned_alias)) => Ok(vec![spanned_alias.clone()]),
480
481 (_, Some(spanned_alias)) => Err(Error::validate_contexts(
482 format!(
483 "\"path\" can only be specified when one `{}` is supplied.",
484 capability_type,
485 ),
486 vec![spanned_alias.origin.clone()],
487 )),
488 }
489 }
490
491 capability_ids_from_context_names!(services_from_context, CapabilityId::Service);
492 capability_ids_from_context_names!(protocols_from_context, CapabilityId::Protocol);
493 capability_ids_from_context_names!(directories_from_context, CapabilityId::Directory);
494 capability_ids_from_context_names!(storages_from_context, CapabilityId::Storage);
495 capability_ids_from_context_names!(runners_from_context, CapabilityId::Runner);
496 capability_ids_from_context_names!(resolvers_from_context, CapabilityId::Resolver);
497 capability_ids_from_context_names!(event_streams_from_context, CapabilityId::EventStream);
498 capability_ids_from_context_names!(dictionaries_from_context, CapabilityId::Dictionary);
499 capability_ids_from_context_names!(configurations_from_context, CapabilityId::Configuration);
500
501 capability_ids_from_context_paths!(used_services_from_context, CapabilityId::UsedService);
502 capability_ids_from_context_paths!(used_protocols_from_context, CapabilityId::UsedProtocol);
503 capability_ids_from_context_paths!(
504 used_dictionaries_from_context,
505 CapabilityId::UsedDictionary
506 );
507}
508
509impl fmt::Display for CapabilityId<'_> {
510 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
512 match self {
513 CapabilityId::Service(n)
514 | CapabilityId::Storage(n)
515 | CapabilityId::Runner(n)
516 | CapabilityId::UsedRunner(n)
517 | CapabilityId::Resolver(n)
518 | CapabilityId::EventStream(n)
519 | CapabilityId::Configuration(n)
520 | CapabilityId::UsedConfiguration(n)
521 | CapabilityId::Dictionary(n) => write!(f, "{}", n),
522 CapabilityId::UsedService(p)
523 | CapabilityId::UsedProtocol(p)
524 | CapabilityId::UsedDirectory(p)
525 | CapabilityId::UsedStorage(p)
526 | CapabilityId::UsedEventStream(p)
527 | CapabilityId::UsedDictionary(p) => write!(f, "{}", p),
528 CapabilityId::UsedProtocolNumberedHandle(p) => write!(f, "{}", p),
529 CapabilityId::Protocol(p) | CapabilityId::Directory(p) => write!(f, "{}", p),
530 }
531 }
532}
533
534#[cfg(test)]
535mod tests {
536 use super::*;
537 use crate::types::offer::ContextOffer;
538 use assert_matches::assert_matches;
539 use std::path::PathBuf;
540 use std::sync::Arc;
541
542 #[test]
543 fn test_offer_service() -> Result<(), Error> {
544 let a: Name = "a".parse().unwrap();
545 let b: Name = "b".parse().unwrap();
546
547 let synthetic_origin = Arc::new(PathBuf::from("synthetic"));
548
549 assert_eq!(
550 CapabilityId::from_context_offer_expose(&ContextSpanned {
551 value: ContextOffer {
552 service: Some(ContextSpanned {
553 value: OneOrMany::One(a.clone()),
554 origin: synthetic_origin.clone(),
555 }),
556 ..ContextOffer::default()
557 },
558 origin: synthetic_origin.clone(),
559 })?,
560 vec![(CapabilityId::Service(&a), synthetic_origin.clone())]
561 );
562
563 assert_eq!(
564 CapabilityId::from_context_offer_expose(&ContextSpanned {
565 value: ContextOffer {
566 service: Some(ContextSpanned {
567 value: OneOrMany::Many(vec![a.clone(), b.clone()]),
568 origin: synthetic_origin.clone(),
569 }),
570 ..ContextOffer::default()
571 },
572 origin: synthetic_origin.clone(),
573 })?,
574 vec![
575 (CapabilityId::Service(&a), synthetic_origin.clone()),
576 (CapabilityId::Service(&b), synthetic_origin.clone())
577 ]
578 );
579
580 assert_eq!(
582 CapabilityId::from_context_offer_expose(&ContextSpanned {
583 value: ContextOffer {
584 service: Some(ContextSpanned {
585 value: OneOrMany::One(a.clone()),
586 origin: synthetic_origin.clone(),
587 }),
588 r#as: Some(ContextSpanned {
589 value: b.clone(),
590 origin: synthetic_origin.clone()
591 }),
592 ..ContextOffer::default()
593 },
594 origin: synthetic_origin.clone(),
595 })?,
596 vec![(CapabilityId::Service(&b), synthetic_origin)]
597 );
598
599 Ok(())
600 }
601
602 #[test]
603 fn test_use_service() -> Result<(), Error> {
604 let a: Name = "a".parse().unwrap();
605 let b: Name = "b".parse().unwrap();
606
607 let synthetic_origin = Arc::new(PathBuf::from("synthetic"));
608
609 assert_eq!(
610 CapabilityId::from_context_use(&ContextSpanned {
611 value: ContextUse {
612 service: Some(ContextSpanned {
613 value: OneOrMany::One(a.clone()),
614 origin: synthetic_origin.clone(),
615 }),
616 ..ContextUse::default()
617 },
618 origin: synthetic_origin.clone(),
619 })?,
620 vec![(CapabilityId::UsedService("/svc/a".parse().unwrap()), synthetic_origin.clone())]
621 );
622
623 assert_eq!(
624 CapabilityId::from_context_use(&ContextSpanned {
625 value: ContextUse {
626 service: Some(ContextSpanned {
627 value: OneOrMany::Many(vec![a.clone(), b.clone(),]),
628 origin: synthetic_origin.clone(),
629 }),
630 ..ContextUse::default()
631 },
632 origin: synthetic_origin.clone(),
633 })?,
634 vec![
635 (CapabilityId::UsedService("/svc/a".parse().unwrap()), synthetic_origin.clone()),
636 (CapabilityId::UsedService("/svc/b".parse().unwrap()), synthetic_origin.clone())
637 ]
638 );
639
640 assert_eq!(
641 CapabilityId::from_context_use(&ContextSpanned {
642 value: ContextUse {
643 service: Some(ContextSpanned {
644 value: OneOrMany::One(a.clone()),
645 origin: synthetic_origin.clone(),
646 }),
647 path: Some(ContextSpanned {
648 value: "/b".parse().unwrap(),
649 origin: synthetic_origin.clone(),
650 }),
651 ..ContextUse::default()
652 },
653 origin: synthetic_origin.clone(),
654 })?,
655 vec![(CapabilityId::UsedService("/b".parse().unwrap()), synthetic_origin.clone())]
656 );
657
658 Ok(())
659 }
660
661 #[test]
662 fn test_use_event_stream() -> Result<(), Error> {
663 let synthetic_origin = Arc::new(PathBuf::from("synthetic"));
664
665 assert_eq!(
666 CapabilityId::from_context_use(&ContextSpanned {
667 value: ContextUse {
668 event_stream: Some(ContextSpanned {
669 value: OneOrMany::One(Name::new("test".to_string()).unwrap()),
670 origin: synthetic_origin.clone(),
671 }),
672 path: Some(ContextSpanned {
673 value: cm_types::Path::new("/svc/myevent".to_string()).unwrap(),
674 origin: synthetic_origin.clone(),
675 }),
676 ..ContextUse::default()
677 },
678 origin: synthetic_origin.clone(),
679 })?,
680 vec![(
681 CapabilityId::UsedEventStream("/svc/myevent".parse().unwrap()),
682 synthetic_origin.clone()
683 )]
684 );
685
686 assert_eq!(
687 CapabilityId::from_context_use(&ContextSpanned {
688 value: ContextUse {
689 event_stream: Some(ContextSpanned {
690 value: OneOrMany::One(Name::new("test".to_string()).unwrap()),
691 origin: synthetic_origin.clone(),
692 }),
693 ..ContextUse::default()
694 },
695 origin: synthetic_origin.clone(),
696 })?,
697 vec![(
698 CapabilityId::UsedEventStream(
699 "/svc/fuchsia.component.EventStream".parse().unwrap()
700 ),
701 synthetic_origin.clone()
702 )]
703 );
704
705 Ok(())
706 }
707
708 #[test]
709 fn test_offer_protocol() -> Result<(), Error> {
710 let a: Name = "a".parse().unwrap();
711 let b: Name = "b".parse().unwrap();
712
713 let synthetic_origin = Arc::new(PathBuf::from("synthetic"));
714
715 assert_eq!(
716 CapabilityId::from_context_offer_expose(&ContextSpanned {
717 value: ContextOffer {
718 protocol: Some(ContextSpanned {
719 value: OneOrMany::One(a.clone()),
720 origin: synthetic_origin.clone(),
721 }),
722 ..ContextOffer::default()
723 },
724 origin: synthetic_origin.clone(),
725 })?,
726 vec![(CapabilityId::Protocol(&a), synthetic_origin.clone())]
727 );
728
729 assert_eq!(
730 CapabilityId::from_context_offer_expose(&ContextSpanned {
731 value: ContextOffer {
732 protocol: Some(ContextSpanned {
733 value: OneOrMany::Many(vec![a.clone(), b.clone()]),
734 origin: synthetic_origin.clone(),
735 }),
736 ..ContextOffer::default()
737 },
738 origin: synthetic_origin.clone(),
739 })?,
740 vec![
741 (CapabilityId::Protocol(&a), synthetic_origin.clone()),
742 (CapabilityId::Protocol(&b), synthetic_origin)
743 ]
744 );
745
746 Ok(())
747 }
748
749 #[test]
750 fn test_use_protocol() -> Result<(), Error> {
751 let a: Name = "a".parse().unwrap();
752 let b: Name = "b".parse().unwrap();
753
754 let synthetic_origin = Arc::new(PathBuf::from("synthetic"));
755
756 assert_eq!(
757 CapabilityId::from_context_use(&ContextSpanned {
758 value: ContextUse {
759 protocol: Some(ContextSpanned {
760 value: OneOrMany::One(a.clone()),
761 origin: synthetic_origin.clone(),
762 }),
763 ..ContextUse::default()
764 },
765 origin: synthetic_origin.clone(),
766 })?,
767 vec![(CapabilityId::UsedProtocol("/svc/a".parse().unwrap()), synthetic_origin.clone())]
768 );
769
770 assert_eq!(
771 CapabilityId::from_context_use(&ContextSpanned {
772 value: ContextUse {
773 protocol: Some(ContextSpanned {
774 value: OneOrMany::Many(vec![a.clone(), b.clone(),]),
775 origin: synthetic_origin.clone(),
776 }),
777 ..ContextUse::default()
778 },
779 origin: synthetic_origin.clone(),
780 })?,
781 vec![
782 (CapabilityId::UsedProtocol("/svc/a".parse().unwrap()), synthetic_origin.clone()),
783 (CapabilityId::UsedProtocol("/svc/b".parse().unwrap()), synthetic_origin.clone())
784 ]
785 );
786
787 assert_eq!(
788 CapabilityId::from_context_use(&ContextSpanned {
789 value: ContextUse {
790 protocol: Some(ContextSpanned {
791 value: OneOrMany::One(a.clone()),
792 origin: synthetic_origin.clone(),
793 }),
794 path: Some(ContextSpanned {
795 value: "/b".parse().unwrap(),
796 origin: synthetic_origin.clone(),
797 }),
798 ..ContextUse::default()
799 },
800 origin: synthetic_origin.clone(),
801 })?,
802 vec![(CapabilityId::UsedProtocol("/b".parse().unwrap()), synthetic_origin.clone())]
803 );
804
805 Ok(())
806 }
807
808 #[test]
809 fn test_offer_directory() -> Result<(), Error> {
810 let a: Name = "a".parse().unwrap();
811 let b: Name = "b".parse().unwrap();
812
813 let synthetic_origin = Arc::new(PathBuf::from("synthetic"));
814
815 assert_eq!(
816 CapabilityId::from_context_offer_expose(&ContextSpanned {
817 value: ContextOffer {
818 directory: Some(ContextSpanned {
819 value: OneOrMany::One(a.clone()),
820 origin: synthetic_origin.clone(),
821 }),
822 ..ContextOffer::default()
823 },
824 origin: synthetic_origin.clone(),
825 })?,
826 vec![(CapabilityId::Directory(&a), synthetic_origin.clone())]
827 );
828
829 assert_eq!(
830 CapabilityId::from_context_offer_expose(&ContextSpanned {
831 value: ContextOffer {
832 directory: Some(ContextSpanned {
833 value: OneOrMany::Many(vec![a.clone(), b.clone()]),
834 origin: synthetic_origin.clone(),
835 }),
836 ..ContextOffer::default()
837 },
838 origin: synthetic_origin.clone(),
839 })?,
840 vec![
841 (CapabilityId::Directory(&a), synthetic_origin.clone()),
842 (CapabilityId::Directory(&b), synthetic_origin.clone())
843 ]
844 );
845
846 Ok(())
847 }
848
849 #[test]
850 fn test_use_directory() -> Result<(), Error> {
851 let a: Name = "a".parse().unwrap();
852
853 let synthetic_origin = Arc::new(PathBuf::from("synthetic"));
854
855 assert_eq!(
856 CapabilityId::from_context_use(&ContextSpanned {
857 value: ContextUse {
858 directory: Some(ContextSpanned {
859 value: a.clone(),
860 origin: synthetic_origin.clone(),
861 }),
862 path: Some(ContextSpanned {
863 value: "/b".parse().unwrap(),
864 origin: synthetic_origin.clone(),
865 }),
866 ..ContextUse::default()
867 },
868 origin: synthetic_origin.clone(),
869 })?,
870 vec![(CapabilityId::UsedDirectory("/b".parse().unwrap()), synthetic_origin.clone())]
871 );
872
873 Ok(())
874 }
875
876 #[test]
877 fn test_offer_storage() -> Result<(), Error> {
878 let a: Name = "a".parse().unwrap();
879 let b: Name = "b".parse().unwrap();
880
881 let synthetic_origin = Arc::new(PathBuf::from("synthetic"));
882
883 assert_eq!(
884 CapabilityId::from_context_offer_expose(&ContextSpanned {
885 value: ContextOffer {
886 storage: Some(ContextSpanned {
887 value: OneOrMany::One(a.clone()),
888 origin: synthetic_origin.clone(),
889 }),
890 ..ContextOffer::default()
891 },
892 origin: synthetic_origin.clone(),
893 })?,
894 vec![(CapabilityId::Storage(&a), synthetic_origin.clone())]
895 );
896
897 assert_eq!(
898 CapabilityId::from_context_offer_expose(&ContextSpanned {
899 value: ContextOffer {
900 storage: Some(ContextSpanned {
901 value: OneOrMany::Many(vec![a.clone(), b.clone()]),
902 origin: synthetic_origin.clone(),
903 }),
904 ..ContextOffer::default()
905 },
906 origin: synthetic_origin.clone(),
907 })?,
908 vec![
909 (CapabilityId::Storage(&a), synthetic_origin.clone()),
910 (CapabilityId::Storage(&b), synthetic_origin.clone())
911 ]
912 );
913
914 Ok(())
915 }
916
917 #[test]
918 fn test_use_storage() -> Result<(), Error> {
919 let a: Name = "a".parse().unwrap();
920
921 let synthetic_origin = Arc::new(PathBuf::from("synthetic"));
922
923 assert_eq!(
924 CapabilityId::from_context_use(&ContextSpanned {
925 value: ContextUse {
926 storage: Some(ContextSpanned {
927 value: a.clone(),
928 origin: synthetic_origin.clone(),
929 }),
930 path: Some(ContextSpanned {
931 value: "/b".parse().unwrap(),
932 origin: synthetic_origin.clone(),
933 }),
934 ..ContextUse::default()
935 },
936 origin: synthetic_origin.clone(),
937 })?,
938 vec![(CapabilityId::UsedStorage("/b".parse().unwrap()), synthetic_origin.clone())]
939 );
940
941 Ok(())
942 }
943
944 #[test]
945 fn test_use_runner() -> Result<(), Error> {
946 let synthetic_origin = Arc::new(PathBuf::from("synthetic"));
947
948 assert_eq!(
949 CapabilityId::from_context_use(&ContextSpanned {
950 value: ContextUse {
951 runner: Some(ContextSpanned {
952 value: "elf".parse().unwrap(),
953 origin: synthetic_origin.clone(),
954 }),
955 ..ContextUse::default()
956 },
957 origin: synthetic_origin.clone(),
958 })?,
959 vec![(
960 CapabilityId::UsedRunner(BorrowedName::new("elf").unwrap()),
961 synthetic_origin.clone()
962 )]
963 );
964
965 Ok(())
966 }
967
968 #[test]
969 fn test_offer_dictionary() -> Result<(), Error> {
970 let a: Name = "a".parse().unwrap();
971 let b: Name = "b".parse().unwrap();
972
973 let synthetic_origin = Arc::new(PathBuf::from("synthetic"));
974
975 assert_eq!(
976 CapabilityId::from_context_offer_expose(&ContextSpanned {
977 value: ContextOffer {
978 dictionary: Some(ContextSpanned {
979 value: OneOrMany::One(a.clone()),
980 origin: synthetic_origin.clone(),
981 }),
982 ..ContextOffer::default()
983 },
984 origin: synthetic_origin.clone(),
985 })?,
986 vec![(CapabilityId::Dictionary(&a), synthetic_origin.clone())]
987 );
988
989 assert_eq!(
990 CapabilityId::from_context_offer_expose(&ContextSpanned {
991 value: ContextOffer {
992 dictionary: Some(ContextSpanned {
993 value: OneOrMany::Many(vec![a.clone(), b.clone()]),
994 origin: synthetic_origin.clone(),
995 }),
996 ..ContextOffer::default()
997 },
998 origin: synthetic_origin.clone(),
999 })?,
1000 vec![
1001 (CapabilityId::Dictionary(&a), synthetic_origin.clone()),
1002 (CapabilityId::Dictionary(&b), synthetic_origin.clone())
1003 ]
1004 );
1005
1006 Ok(())
1007 }
1008
1009 #[test]
1010 fn test_use_dictionary() -> Result<(), Error> {
1011 let a: Name = "a".parse().unwrap();
1012 let b: Name = "b".parse().unwrap();
1013
1014 let synthetic_origin = Arc::new(PathBuf::from("synthetic"));
1015
1016 assert_eq!(
1017 CapabilityId::from_context_use(&ContextSpanned {
1018 value: ContextUse {
1019 dictionary: Some(ContextSpanned {
1020 value: OneOrMany::One(a.clone()),
1021 origin: synthetic_origin.clone(),
1022 }),
1023 ..ContextUse::default()
1024 },
1025 origin: synthetic_origin.clone(),
1026 })?,
1027 vec![(
1028 CapabilityId::UsedDictionary("/svc/a".parse().unwrap()),
1029 synthetic_origin.clone()
1030 )]
1031 );
1032
1033 assert_eq!(
1034 CapabilityId::from_context_use(&ContextSpanned {
1035 value: ContextUse {
1036 dictionary: Some(ContextSpanned {
1037 value: OneOrMany::Many(vec![a.clone(), b.clone()]),
1038 origin: synthetic_origin.clone(),
1039 }),
1040 ..ContextUse::default()
1041 },
1042 origin: synthetic_origin.clone(),
1043 })?,
1044 vec![
1045 (CapabilityId::UsedDictionary("/svc/a".parse().unwrap()), synthetic_origin.clone()),
1046 (CapabilityId::UsedDictionary("/svc/b".parse().unwrap()), synthetic_origin.clone())
1047 ]
1048 );
1049
1050 assert_eq!(
1051 CapabilityId::from_context_use(&ContextSpanned {
1052 value: ContextUse {
1053 dictionary: Some(ContextSpanned {
1054 value: OneOrMany::One(a.clone()),
1055 origin: synthetic_origin.clone(),
1056 }),
1057 path: Some(ContextSpanned {
1058 value: "/b".parse().unwrap(),
1059 origin: synthetic_origin.clone()
1060 }),
1061 ..ContextUse::default()
1062 },
1063 origin: synthetic_origin.clone(),
1064 })?,
1065 vec![(CapabilityId::UsedDictionary("/b".parse().unwrap()), synthetic_origin.clone())]
1066 );
1067
1068 Ok(())
1069 }
1070
1071 #[test]
1072 fn test_errors() -> Result<(), Error> {
1073 let synthetic_origin = Arc::new(PathBuf::from("synthetic"));
1074
1075 assert_matches!(
1076 CapabilityId::from_context_offer_expose(&ContextSpanned {
1077 value: ContextOffer::default(),
1078 origin: synthetic_origin
1079 }),
1080 Err(_)
1081 );
1082
1083 Ok(())
1084 }
1085}