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::sync::Arc;
17
18#[derive(Debug, PartialEq, Eq, Hash, Clone)]
29pub enum CapabilityId<'a> {
30 Service(&'a BorrowedName),
31 Protocol(&'a BorrowedName),
32 Directory(&'a BorrowedName),
33 UsedService(Path),
35 UsedProtocol(Path),
37 UsedProtocolNumberedHandle(HandleType),
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_context_names {
60 ($name:ident, $variant:expr) => {
61 fn $name(
62 names: Vec<ContextSpanned<&'a BorrowedName>>,
63 ) -> Vec<(Self, Arc<std::path::Path>)> {
64 names
65 .into_iter()
66 .map(|spanned_name| ($variant(spanned_name.value), spanned_name.origin))
67 .collect()
68 }
69 };
70}
71
72macro_rules! capability_ids_from_context_paths {
74 ($name:ident, $variant:expr) => {
75 fn $name(paths: Vec<ContextSpanned<Path>>) -> Vec<(Self, Arc<std::path::Path>)> {
76 paths
77 .into_iter()
78 .map(|spanned_path| ($variant(spanned_path.value), spanned_path.origin))
79 .collect()
80 }
81 };
82}
83
84impl<'a> CapabilityId<'a> {
85 pub fn type_str(&self) -> &'static str {
87 match self {
88 CapabilityId::Service(_) => "service",
89 CapabilityId::Protocol(_) => "protocol",
90 CapabilityId::Directory(_) => "directory",
91 CapabilityId::UsedService(_) => "service",
92 CapabilityId::UsedProtocol(_) => "protocol",
93 CapabilityId::UsedProtocolNumberedHandle(_) => "protocol",
94 CapabilityId::UsedDirectory(_) => "directory",
95 CapabilityId::UsedStorage(_) => "storage",
96 CapabilityId::UsedEventStream(_) => "event_stream",
97 CapabilityId::UsedRunner(_) => "runner",
98 CapabilityId::UsedConfiguration(_) => "config",
99 CapabilityId::UsedDictionary(_) => "dictionary",
100 CapabilityId::Storage(_) => "storage",
101 CapabilityId::Runner(_) => "runner",
102 CapabilityId::Resolver(_) => "resolver",
103 CapabilityId::EventStream(_) => "event_stream",
104 CapabilityId::Dictionary(_) => "dictionary",
105 CapabilityId::Configuration(_) => "config",
106 }
107 }
108
109 pub fn get_dir_path(&self) -> Option<NamespacePath> {
111 match self {
112 CapabilityId::UsedService(p)
113 | CapabilityId::UsedProtocol(p)
114 | CapabilityId::UsedEventStream(p) => Some(p.parent()),
115 CapabilityId::UsedDirectory(p)
116 | CapabilityId::UsedStorage(p)
117 | CapabilityId::UsedDictionary(p) => Some(p.clone().into()),
118 _ => None,
119 }
120 }
121
122 pub fn get_target_path(&self) -> Option<NamespacePath> {
124 match self {
125 CapabilityId::UsedService(p)
126 | CapabilityId::UsedProtocol(p)
127 | CapabilityId::UsedEventStream(p)
128 | CapabilityId::UsedDirectory(p)
129 | CapabilityId::UsedStorage(p)
130 | CapabilityId::UsedDictionary(p) => Some(p.clone().into()),
131 _ => None,
132 }
133 }
134
135 pub fn from_context_capability(
136 capability_input: &'a ContextSpanned<ContextCapability>,
137 ) -> Result<Vec<(Self, Arc<std::path::Path>)>, Error> {
138 let capability = &capability_input.value;
139 let origin = &capability_input.origin;
140
141 if let Some(n) = capability.service() {
142 if n.value.is_many()
143 && let Some(cs_path) = &capability.path
144 {
145 return Err(Error::validate_context(
146 "\"path\" can only be specified when one `service` is supplied.",
147 Some(cs_path.origin.clone()),
148 ));
149 }
150 return Ok(Self::services_from_context(Self::get_one_or_many_names_context(
151 n,
152 None,
153 capability.capability_type(None).unwrap(),
154 )?));
155 } else if let Some(n) = capability.protocol() {
156 if n.value.is_many()
157 && let Some(cs_path) = &capability.path
158 {
159 return Err(Error::validate_context(
160 "\"path\" can only be specified when one `protocol` is supplied.",
161 Some(cs_path.origin.clone()),
162 ));
163 }
164 return Ok(Self::protocols_from_context(Self::get_one_or_many_names_context(
165 n,
166 None,
167 capability.capability_type(None).unwrap(),
168 )?));
169 } else if let Some(n) = capability.directory() {
170 return Ok(Self::directories_from_context(Self::get_one_or_many_names_context(
171 n,
172 None,
173 capability.capability_type(None).unwrap(),
174 )?));
175 } else if let Some(cs_storage) = capability.storage() {
176 if capability.storage_id.is_none() {
177 return Err(Error::validate_context(
178 "Storage declaration is missing \"storage_id\", but is required.",
179 Some(cs_storage.origin),
180 ));
181 }
182 return Ok(Self::storages_from_context(Self::get_one_or_many_names_context(
183 cs_storage,
184 None,
185 capability.capability_type(None).unwrap(),
186 )?));
187 } else if let Some(n) = capability.runner() {
188 return Ok(Self::runners_from_context(Self::get_one_or_many_names_context(
189 n,
190 None,
191 capability.capability_type(None).unwrap(),
192 )?));
193 } else if let Some(n) = capability.resolver() {
194 return Ok(Self::resolvers_from_context(Self::get_one_or_many_names_context(
195 n,
196 None,
197 capability.capability_type(None).unwrap(),
198 )?));
199 } else if let Some(n) = capability.event_stream() {
200 return Ok(Self::event_streams_from_context(Self::get_one_or_many_names_context(
201 n,
202 None,
203 capability.capability_type(None).unwrap(),
204 )?));
205 } else if let Some(n) = capability.dictionary() {
206 return Ok(Self::dictionaries_from_context(Self::get_one_or_many_names_context(
207 n,
208 None,
209 capability.capability_type(None).unwrap(),
210 )?));
211 } else if let Some(n) = capability.config() {
212 return Ok(Self::configurations_from_context(Self::get_one_or_many_names_context(
213 n,
214 None,
215 capability.capability_type(None).unwrap(),
216 )?));
217 }
218
219 let supported_keywords = capability
221 .supported()
222 .iter()
223 .map(|k| format!("\"{}\"", k))
224 .collect::<Vec<_>>()
225 .join(", ");
226 Err(Error::validate_context(
227 format!(
228 "`{}` declaration is missing a capability keyword, one of: {}",
229 capability.decl_type(),
230 supported_keywords,
231 ),
232 Some(origin.clone()),
233 ))
234 }
235
236 pub fn from_context_offer_expose<T>(
237 clause_input: &'a ContextSpanned<T>,
238 ) -> Result<Vec<(Self, Arc<std::path::Path>)>, Error>
239 where
240 T: ContextCapabilityClause + AsClauseContext + fmt::Debug,
241 {
242 let clause = &clause_input.value;
243 let origin = &clause_input.origin;
244
245 let alias = clause.r#as();
246
247 if let Some(n) = clause.service() {
248 return Ok(Self::services_from_context(Self::get_one_or_many_names_context(
249 n,
250 alias,
251 clause.capability_type(Some(origin.clone())).unwrap(),
252 )?));
253 } else if let Some(n) = clause.protocol() {
254 return Ok(Self::protocols_from_context(Self::get_one_or_many_names_context(
255 n,
256 alias,
257 clause.capability_type(Some(origin.clone())).unwrap(),
258 )?));
259 } else if let Some(n) = clause.directory() {
260 return Ok(Self::directories_from_context(Self::get_one_or_many_names_context(
261 n,
262 alias,
263 clause.capability_type(Some(origin.clone())).unwrap(),
264 )?));
265 } else if let Some(n) = clause.storage() {
266 return Ok(Self::storages_from_context(Self::get_one_or_many_names_context(
267 n,
268 alias,
269 clause.capability_type(Some(origin.clone())).unwrap(),
270 )?));
271 } else if let Some(n) = clause.runner() {
272 return Ok(Self::runners_from_context(Self::get_one_or_many_names_context(
273 n,
274 alias,
275 clause.capability_type(Some(origin.clone())).unwrap(),
276 )?));
277 } else if let Some(n) = clause.resolver() {
278 return Ok(Self::resolvers_from_context(Self::get_one_or_many_names_context(
279 n,
280 alias,
281 clause.capability_type(Some(origin.clone())).unwrap(),
282 )?));
283 } else if let Some(event_stream) = clause.event_stream() {
284 return Ok(Self::event_streams_from_context(Self::get_one_or_many_names_context(
285 event_stream,
286 alias,
287 clause.capability_type(Some(origin.clone())).unwrap(),
288 )?));
289 } else if let Some(n) = clause.dictionary() {
290 return Ok(Self::dictionaries_from_context(Self::get_one_or_many_names_context(
291 n,
292 alias,
293 clause.capability_type(Some(origin.clone())).unwrap(),
294 )?));
295 } else if let Some(n) = clause.config() {
296 return Ok(Self::configurations_from_context(Self::get_one_or_many_names_context(
297 n,
298 alias,
299 clause.capability_type(Some(origin.clone())).unwrap(),
300 )?));
301 }
302
303 let supported_keywords =
305 clause.supported().iter().map(|k| format!("\"{}\"", k)).collect::<Vec<_>>().join(", ");
306 Err(Error::validate_context(
307 format!(
308 "`{}` declaration is missing a capability keyword, one of: {}",
309 clause.decl_type(),
310 supported_keywords,
311 ),
312 Some(origin.clone()),
313 ))
314 }
315
316 pub fn from_context_use(
325 use_input: &'a ContextSpanned<ContextUse>,
326 ) -> Result<Vec<(Self, Arc<std::path::Path>)>, Error> {
327 let use_ = &use_input.value;
328 let origin = &use_input.origin;
329
330 let alias = use_.path.as_ref();
331
332 if let Some(n) = option_one_or_many_as_ref_context(&use_.service) {
333 return Ok(Self::used_services_from_context(Self::get_one_or_many_svc_paths_context(
334 n,
335 alias,
336 use_input.capability_type(Some(origin.clone())).unwrap(),
337 )?));
338 } else if let Some(n) = option_one_or_many_as_ref_context(&use_.protocol) {
339 if let Some(numbered_handle) = &use_.numbered_handle {
340 return Ok(n
341 .value
342 .iter()
343 .map(|_| {
344 (
345 CapabilityId::UsedProtocolNumberedHandle(numbered_handle.value),
346 n.origin.clone(),
347 )
348 })
349 .collect());
350 }
351
352 return Ok(Self::used_protocols_from_context(Self::get_one_or_many_svc_paths_context(
353 n,
354 alias,
355 use_input.capability_type(Some(origin.clone())).unwrap(),
356 )?));
357 } else if let Some(_) = &use_.directory {
358 if use_.path.is_none() {
359 return Err(Error::validate_context(
360 "\"path\" should be present for `use directory`.",
361 Some(origin.clone()),
362 ));
363 }
364 return Ok(vec![(
365 CapabilityId::UsedDirectory(use_.path.as_ref().unwrap().value.clone()),
366 origin.clone(),
367 )]);
368 } else if let Some(_) = &use_.storage {
369 if use_.path.is_none() {
370 return Err(Error::validate_context(
371 "\"path\" should be present for `use storage`.",
372 Some(origin.clone()),
373 ));
374 }
375 return Ok(vec![(
376 CapabilityId::UsedStorage(use_.path.as_ref().unwrap().value.clone()),
377 origin.clone(),
378 )]);
379 } else if let Some(_) = &use_.event_stream {
380 if let Some(path) = &use_.path {
381 return Ok(vec![(
382 CapabilityId::UsedEventStream(path.value.clone()),
383 origin.clone(),
384 )]);
385 }
386 return Ok(vec![(
387 CapabilityId::UsedEventStream(Path::new("/svc/fuchsia.component.EventStream")?),
388 origin.clone(),
389 )]);
390 } else if let Some(n) = &use_.runner {
391 return Ok(vec![(CapabilityId::UsedRunner(&n.value), n.origin.clone())]);
392 } else if let Some(_) = &use_.config {
393 return match &use_.key {
394 None => Err(Error::validate_context(
395 "\"key\" should be present for `use config`.",
396 Some(origin.clone()),
397 )),
398 Some(name) => {
399 Ok(vec![(CapabilityId::UsedConfiguration(&name.value), origin.clone())])
400 }
401 };
402 } else if let Some(n) = option_one_or_many_as_ref_context(&use_.dictionary) {
403 return Ok(Self::used_dictionaries_from_context(
404 Self::get_one_or_many_svc_paths_context(
405 n,
406 alias,
407 use_input.capability_type(Some(origin.clone())).unwrap(),
408 )?,
409 ));
410 }
411
412 let supported_keywords = use_input
414 .supported()
415 .iter()
416 .map(|k| format!("\"{}\"", k))
417 .collect::<Vec<_>>()
418 .join(", ");
419
420 Err(Error::validate_context(
421 format!(
422 "`{}` declaration is missing a capability keyword, one of: {}",
423 use_input.decl_type(),
424 supported_keywords,
425 ),
426 Some(origin.clone()),
427 ))
428 }
429
430 fn get_one_or_many_names_context<'b>(
432 name_wrapper: ContextSpanned<OneOrMany<&'b BorrowedName>>,
433 alias: Option<ContextSpanned<&'b BorrowedName>>,
434 capability_type: &str,
435 ) -> Result<Vec<ContextSpanned<&'b BorrowedName>>, Error> {
436 let names_origin = name_wrapper.origin;
437 let names_vec: Vec<&'b BorrowedName> = name_wrapper.value.into_iter().collect();
438 let num_names = names_vec.len();
439
440 if num_names > 1 && alias.is_some() {
441 return Err(Error::validate_contexts(
442 format!("\"as\" can only be specified when one `{}` is supplied.", capability_type),
443 vec![alias.map(|s| s.origin).unwrap_or(names_origin)],
444 ));
445 }
446
447 if num_names == 1 {
448 let final_name_span = alias_or_name_context(alias, names_vec[0], names_origin);
449 return Ok(vec![final_name_span]);
450 }
451
452 let final_names = names_vec
453 .into_iter()
454 .map(|name| ContextSpanned { value: name, origin: names_origin.clone() })
455 .collect();
456
457 Ok(final_names)
458 }
459
460 fn get_one_or_many_svc_paths_context(
461 names: ContextSpanned<OneOrMany<&BorrowedName>>,
462 alias: Option<&ContextSpanned<Path>>,
463 capability_type: &str,
464 ) -> Result<Vec<ContextSpanned<Path>>, Error> {
465 let names_origin = &names.origin;
466 let names_vec: Vec<_> = names.value.into_iter().collect();
467
468 match (names_vec.len(), alias) {
469 (_, None) => {
470 let generated_paths = names_vec
471 .into_iter()
472 .map(|n| {
473 let new_path: Path = format!("/svc/{}", n).parse().unwrap();
474 ContextSpanned { value: new_path, origin: names_origin.clone() }
475 })
476 .collect();
477 Ok(generated_paths)
478 }
479
480 (1, Some(spanned_alias)) => Ok(vec![spanned_alias.clone()]),
481
482 (_, Some(spanned_alias)) => Err(Error::validate_contexts(
483 format!(
484 "\"path\" can only be specified when one `{}` is supplied.",
485 capability_type,
486 ),
487 vec![spanned_alias.origin.clone()],
488 )),
489 }
490 }
491
492 capability_ids_from_context_names!(services_from_context, CapabilityId::Service);
493 capability_ids_from_context_names!(protocols_from_context, CapabilityId::Protocol);
494 capability_ids_from_context_names!(directories_from_context, CapabilityId::Directory);
495 capability_ids_from_context_names!(storages_from_context, CapabilityId::Storage);
496 capability_ids_from_context_names!(runners_from_context, CapabilityId::Runner);
497 capability_ids_from_context_names!(resolvers_from_context, CapabilityId::Resolver);
498 capability_ids_from_context_names!(event_streams_from_context, CapabilityId::EventStream);
499 capability_ids_from_context_names!(dictionaries_from_context, CapabilityId::Dictionary);
500 capability_ids_from_context_names!(configurations_from_context, CapabilityId::Configuration);
501
502 capability_ids_from_context_paths!(used_services_from_context, CapabilityId::UsedService);
503 capability_ids_from_context_paths!(used_protocols_from_context, CapabilityId::UsedProtocol);
504 capability_ids_from_context_paths!(
505 used_dictionaries_from_context,
506 CapabilityId::UsedDictionary
507 );
508}
509
510impl fmt::Display for CapabilityId<'_> {
511 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
513 match self {
514 CapabilityId::Service(n)
515 | CapabilityId::Storage(n)
516 | CapabilityId::Runner(n)
517 | CapabilityId::UsedRunner(n)
518 | CapabilityId::Resolver(n)
519 | CapabilityId::EventStream(n)
520 | CapabilityId::Configuration(n)
521 | CapabilityId::UsedConfiguration(n)
522 | CapabilityId::Dictionary(n) => write!(f, "{}", n),
523 CapabilityId::UsedService(p)
524 | CapabilityId::UsedProtocol(p)
525 | CapabilityId::UsedDirectory(p)
526 | CapabilityId::UsedStorage(p)
527 | CapabilityId::UsedEventStream(p)
528 | CapabilityId::UsedDictionary(p) => write!(f, "{}", p),
529 CapabilityId::UsedProtocolNumberedHandle(p) => write!(f, "{}", p),
530 CapabilityId::Protocol(p) | CapabilityId::Directory(p) => write!(f, "{}", p),
531 }
532 }
533}
534
535#[cfg(test)]
536mod tests {
537 use super::*;
538 use crate::types::offer::ContextOffer;
539 use assert_matches::assert_matches;
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<std::path::Path> = Arc::from(std::path::Path::new("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<std::path::Path> = Arc::from(std::path::Path::new("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<std::path::Path> = Arc::from(std::path::Path::new("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<std::path::Path> = Arc::from(std::path::Path::new("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<std::path::Path> = Arc::from(std::path::Path::new("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<std::path::Path> = Arc::from(std::path::Path::new("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<std::path::Path> = Arc::from(std::path::Path::new("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<std::path::Path> = Arc::from(std::path::Path::new("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<std::path::Path> = Arc::from(std::path::Path::new("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<std::path::Path> = Arc::from(std::path::Path::new("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<std::path::Path> = Arc::from(std::path::Path::new("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<std::path::Path> = Arc::from(std::path::Path::new("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<std::path::Path> = Arc::from(std::path::Path::new("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}