Skip to main content

cml/types/
capability_id.rs

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