Skip to main content

routing/
capability_source.rs

1// Copyright 2021 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::error::RoutingError;
6use crate::legacy_router::Sources;
7use cm_rust::{
8    CapabilityDecl, CapabilityTypeName, ChildRef, ConfigurationDecl, DictionaryDecl, DirectoryDecl,
9    EventStreamDecl, ExposeConfigurationDecl, ExposeDecl, ExposeDeclCommon, ExposeDictionaryDecl,
10    ExposeDirectoryDecl, ExposeProtocolDecl, ExposeResolverDecl, ExposeRunnerDecl,
11    ExposeServiceDecl, ExposeSource, FidlIntoNative, NameMapping, NativeIntoFidl,
12    OfferConfigurationDecl, OfferDecl, OfferDeclCommon, OfferDictionaryDecl, OfferDirectoryDecl,
13    OfferEventStreamDecl, OfferProtocolDecl, OfferResolverDecl, OfferRunnerDecl, OfferServiceDecl,
14    OfferSource, OfferStorageDecl, ProtocolDecl, RegistrationSource, ResolverDecl, RunnerDecl,
15    ServiceDecl, StorageDecl, UseDecl, UseDeclCommon, UseDirectoryDecl, UseProtocolDecl,
16    UseServiceDecl, UseSource, UseStorageDecl,
17};
18use cm_rust_derive::FidlDecl;
19use cm_types::{Name, Path, RelativePath};
20use derivative::Derivative;
21use fidl::{persist, unpersist};
22use from_enum::FromEnum;
23use futures::future::BoxFuture;
24use moniker::{ChildName, ExtendedMoniker, Moniker};
25use sandbox::{Capability, Data};
26use std::fmt;
27use thiserror::Error;
28use {
29    fidl_fuchsia_component_decl as fdecl, fidl_fuchsia_component_internal as finternal,
30    fidl_fuchsia_sys2 as fsys,
31};
32
33#[cfg(feature = "serde")]
34use serde::{Deserialize, Serialize};
35
36#[derive(Debug, Error)]
37pub enum Error {
38    #[error("Invalid framework capability.")]
39    InvalidFrameworkCapability {},
40    #[error("Invalid builtin capability.")]
41    InvalidBuiltinCapability {},
42}
43
44#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
45#[derive(Debug, Hash, PartialEq, Eq, Clone)]
46pub enum AggregateMember {
47    Child(ChildRef),
48    Collection(Name),
49    Parent,
50    Self_,
51}
52
53impl TryFrom<&cm_rust::OfferDecl> for AggregateMember {
54    type Error = ();
55
56    fn try_from(offer: &cm_rust::OfferDecl) -> Result<AggregateMember, ()> {
57        match offer.source() {
58            // TODO: should we panic instead of filtering when we find something we don't expect?
59            cm_rust::OfferSource::Framework => Err(()),
60            cm_rust::OfferSource::Parent => Ok(AggregateMember::Parent),
61            cm_rust::OfferSource::Child(child) => Ok(AggregateMember::Child(child.clone())),
62            cm_rust::OfferSource::Collection(name) => Ok(AggregateMember::Collection(name.clone())),
63            cm_rust::OfferSource::Self_ => Ok(AggregateMember::Self_),
64            cm_rust::OfferSource::Capability(_name) => Err(()),
65            cm_rust::OfferSource::Void => Err(()),
66        }
67    }
68}
69
70impl TryFrom<&cm_rust::ExposeDecl> for AggregateMember {
71    type Error = ();
72
73    fn try_from(expose: &cm_rust::ExposeDecl) -> Result<AggregateMember, ()> {
74        match expose.source() {
75            // TODO: should we panic instead of filtering when we find something we don't expect?
76            cm_rust::ExposeSource::Framework => Err(()),
77            cm_rust::ExposeSource::Child(child) => Ok(AggregateMember::Child(cm_rust::ChildRef {
78                name: child.clone().into(),
79                collection: None,
80            })),
81            cm_rust::ExposeSource::Collection(name) => {
82                Ok(AggregateMember::Collection(name.clone()))
83            }
84            cm_rust::ExposeSource::Self_ => Ok(AggregateMember::Self_),
85            cm_rust::ExposeSource::Capability(_name) => Err(()),
86            cm_rust::ExposeSource::Void => Err(()),
87        }
88    }
89}
90
91impl TryFrom<&cm_rust::UseDecl> for AggregateMember {
92    type Error = ();
93
94    fn try_from(use_: &cm_rust::UseDecl) -> Result<AggregateMember, ()> {
95        match use_.source() {
96            cm_rust::UseSource::Parent => Ok(AggregateMember::Parent),
97            cm_rust::UseSource::Framework => Err(()),
98            cm_rust::UseSource::Debug => Err(()),
99            cm_rust::UseSource::Self_ => Ok(AggregateMember::Self_),
100            cm_rust::UseSource::Capability(_) => Err(()),
101            cm_rust::UseSource::Child(name) => {
102                Ok(AggregateMember::Child(ChildRef { name: name.clone().into(), collection: None }))
103            }
104            cm_rust::UseSource::Collection(name) => Ok(AggregateMember::Collection(name.clone())),
105            cm_rust::UseSource::Environment => Err(()),
106        }
107    }
108}
109
110impl fmt::Display for AggregateMember {
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        match self {
113            Self::Child(n) => {
114                write!(f, "child `{n}`")
115            }
116            Self::Collection(n) => {
117                write!(f, "collection `{n}`")
118            }
119            Self::Parent => {
120                write!(f, "parent")
121            }
122            Self::Self_ => {
123                write!(f, "self")
124            }
125        }
126    }
127}
128
129impl FidlIntoNative<AggregateMember> for finternal::AggregateMember {
130    fn fidl_into_native(self) -> AggregateMember {
131        match self {
132            finternal::AggregateMember::Self_(_) => AggregateMember::Self_,
133            finternal::AggregateMember::Parent(_) => AggregateMember::Parent,
134            finternal::AggregateMember::Collection(name) => {
135                AggregateMember::Collection(Name::new(name).unwrap())
136            }
137            finternal::AggregateMember::Child(child_ref) => {
138                AggregateMember::Child(child_ref.fidl_into_native())
139            }
140        }
141    }
142}
143
144impl NativeIntoFidl<finternal::AggregateMember> for AggregateMember {
145    fn native_into_fidl(self) -> finternal::AggregateMember {
146        match self {
147            AggregateMember::Self_ => finternal::AggregateMember::Self_(fdecl::SelfRef {}),
148            AggregateMember::Parent => finternal::AggregateMember::Parent(fdecl::ParentRef {}),
149            AggregateMember::Collection(name) => {
150                finternal::AggregateMember::Collection(name.to_string())
151            }
152            AggregateMember::Child(child_ref) => {
153                finternal::AggregateMember::Child(child_ref.native_into_fidl())
154            }
155        }
156    }
157}
158
159/// Describes the source of a capability, as determined by `find_capability_source`
160#[cfg_attr(
161    feature = "serde",
162    derive(Deserialize, Serialize),
163    serde(tag = "type", rename_all = "snake_case")
164)]
165#[derive(FidlDecl, Debug, Derivative)]
166#[derivative(Clone(bound = ""), PartialEq)]
167#[fidl_decl(fidl_union = "finternal::CapabilitySource")]
168pub enum CapabilitySource {
169    /// This capability originates from the component instance for the given Realm.
170    /// point.
171    Component(ComponentSource),
172    /// This capability originates from "framework". It's implemented by component manager and is
173    /// scoped to the realm of the source.
174    Framework(FrameworkSource),
175    /// This capability originates from the parent of the root component, and is built in to
176    /// component manager. `top_instance` is the instance at the top of the tree, i.e.  the
177    /// instance representing component manager.
178    Builtin(BuiltinSource),
179    /// This capability originates from the parent of the root component, and is offered from
180    /// component manager's namespace. `top_instance` is the instance at the top of the tree, i.e.
181    /// the instance representing component manager.
182    Namespace(NamespaceSource),
183    /// This capability is provided by the framework based on some other capability.
184    Capability(CapabilityToCapabilitySource),
185    /// This capability is an aggregate of capabilities over a set of collections and static
186    /// children. The instance names in the aggregate service will be anonymized.
187    AnonymizedAggregate(AnonymizedAggregateSource),
188    /// This capability is a filtered service capability from a single source, such as self or a
189    /// child.
190    FilteredProvider(FilteredProviderSource),
191    /// This capability is a filtered service capability with multiple sources, such as all of the
192    /// dynamic children in a collection. The instances in the aggregate service are the union of
193    /// the filters.
194    FilteredAggregateProvider(FilteredAggregateProviderSource),
195    /// This capability originates from "environment". It's implemented by a component instance.
196    Environment(EnvironmentSource),
197    /// This capability originates from "void". This is only a valid origination for optional
198    /// capabilities.
199    Void(VoidSource),
200    /// The route for this capability extended outside of component manager at the given moniker,
201    /// and we thus don't know where the ultimate terminus of it is.
202    RemotedAt(Moniker),
203    /// This capability is a storage capability backed by a directory capability
204    /// originating in some component.
205    StorageBackingDirectory(StorageBackingDirectorySource),
206}
207
208#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
209#[derive(FidlDecl, Debug, PartialEq, Clone)]
210#[fidl_decl(fidl_table = "finternal::Component")]
211pub struct ComponentSource {
212    pub capability: ComponentCapability,
213    pub moniker: Moniker,
214}
215#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
216#[derive(FidlDecl, Debug, PartialEq, Clone)]
217#[fidl_decl(fidl_table = "finternal::Framework")]
218pub struct FrameworkSource {
219    pub capability: InternalCapability,
220    pub moniker: Moniker,
221}
222#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
223#[derive(FidlDecl, Debug, PartialEq, Clone)]
224#[fidl_decl(fidl_table = "finternal::Builtin")]
225pub struct BuiltinSource {
226    pub capability: InternalCapability,
227}
228#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
229#[derive(FidlDecl, Debug, PartialEq, Clone)]
230#[fidl_decl(fidl_table = "finternal::Namespace")]
231pub struct NamespaceSource {
232    pub capability: ComponentCapability,
233}
234#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
235#[derive(FidlDecl, Debug, PartialEq, Clone)]
236#[fidl_decl(fidl_table = "finternal::Capability")]
237pub struct CapabilityToCapabilitySource {
238    pub source_capability: ComponentCapability,
239    pub moniker: Moniker,
240}
241#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
242#[derive(FidlDecl, Debug, PartialEq, Clone)]
243#[fidl_decl(fidl_table = "finternal::AnonymizedAggregate")]
244pub struct AnonymizedAggregateSource {
245    pub capability: AggregateCapability,
246    pub moniker: Moniker,
247    pub members: Vec<AggregateMember>,
248    pub sources: Sources,
249    pub instances: Vec<ServiceInstance>,
250}
251#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
252#[derive(FidlDecl, Debug, PartialEq, Clone)]
253#[fidl_decl(fidl_table = "fsys::ServiceInstance")]
254pub struct ServiceInstance {
255    pub instance_name: Name,
256    pub child_name: String,
257    pub child_instance_name: Name,
258}
259#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
260#[derive(FidlDecl, Debug, PartialEq, Clone)]
261#[fidl_decl(fidl_table = "finternal::FilteredProvider")]
262pub struct FilteredProviderSource {
263    pub capability: AggregateCapability,
264    pub moniker: Moniker,
265    pub service_capability: ComponentCapability,
266    pub offer_service_decl: OfferServiceDecl,
267}
268#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
269#[derive(FidlDecl, Debug, PartialEq, Clone)]
270#[fidl_decl(fidl_table = "finternal::FilteredAggregateProvider")]
271pub struct FilteredAggregateProviderSource {
272    pub capability: AggregateCapability,
273    pub moniker: Moniker,
274    pub offer_service_decls: Vec<OfferServiceDecl>,
275    pub sources: Sources,
276}
277#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
278#[derive(FidlDecl, Debug, PartialEq, Clone)]
279#[fidl_decl(fidl_table = "finternal::Environment")]
280pub struct EnvironmentSource {
281    pub capability: ComponentCapability,
282    pub moniker: Moniker,
283}
284#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
285#[derive(FidlDecl, Debug, PartialEq, Clone)]
286#[fidl_decl(fidl_table = "finternal::Void")]
287pub struct VoidSource {
288    pub capability: InternalCapability,
289    pub moniker: Moniker,
290}
291
292#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
293#[derive(FidlDecl, Debug, PartialEq, Clone)]
294#[fidl_decl(fidl_table = "finternal::StorageBackingDirectory")]
295pub struct StorageBackingDirectorySource {
296    pub capability: ComponentCapability,
297    pub moniker: Moniker,
298    pub backing_dir_subdir: RelativePath,
299    pub storage_subdir: RelativePath,
300    pub storage_source_moniker: Moniker,
301}
302
303impl CapabilitySource {
304    pub fn source_name(&self) -> Option<&Name> {
305        match self {
306            Self::Component(ComponentSource { capability, .. }) => capability.source_name(),
307            Self::Framework(FrameworkSource { capability, .. }) => Some(capability.source_name()),
308            Self::Builtin(BuiltinSource { capability }) => Some(capability.source_name()),
309            Self::Namespace(NamespaceSource { capability }) => capability.source_name(),
310            Self::Capability(CapabilityToCapabilitySource { .. }) => None,
311            Self::AnonymizedAggregate(AnonymizedAggregateSource { capability, .. }) => {
312                Some(capability.source_name())
313            }
314            Self::FilteredProvider(FilteredProviderSource { capability, .. })
315            | Self::FilteredAggregateProvider(FilteredAggregateProviderSource {
316                capability, ..
317            }) => Some(capability.source_name()),
318            Self::Environment(EnvironmentSource { capability, .. }) => capability.source_name(),
319            Self::Void(VoidSource { capability, .. }) => Some(capability.source_name()),
320            Self::RemotedAt(_) => None,
321            Self::StorageBackingDirectory(StorageBackingDirectorySource { capability, .. }) => {
322                capability.source_name()
323            }
324        }
325    }
326
327    pub fn type_name(&self) -> CapabilityTypeName {
328        match self {
329            Self::Component(ComponentSource { capability, .. }) => capability.type_name(),
330            Self::Framework(FrameworkSource { capability, .. }) => capability.type_name(),
331            Self::Builtin(BuiltinSource { capability }) => capability.type_name(),
332            Self::Namespace(NamespaceSource { capability }) => capability.type_name(),
333            Self::Capability(CapabilityToCapabilitySource { source_capability, .. }) => {
334                source_capability.type_name()
335            }
336            Self::AnonymizedAggregate(AnonymizedAggregateSource { capability, .. }) => {
337                capability.type_name()
338            }
339            Self::FilteredProvider(FilteredProviderSource { capability, .. })
340            | Self::FilteredAggregateProvider(FilteredAggregateProviderSource {
341                capability, ..
342            }) => capability.type_name(),
343            Self::Environment(EnvironmentSource { capability, .. }) => capability.type_name(),
344            Self::Void(VoidSource { capability, .. }) => capability.type_name(),
345            Self::RemotedAt(_) => unimplemented!(),
346            Self::StorageBackingDirectory(StorageBackingDirectorySource { capability, .. }) => {
347                capability.type_name()
348            }
349        }
350    }
351
352    pub fn source_moniker(&self) -> ExtendedMoniker {
353        match self {
354            Self::Component(ComponentSource { moniker, .. })
355            | Self::Framework(FrameworkSource { moniker, .. })
356            | Self::Capability(CapabilityToCapabilitySource { moniker, .. })
357            | Self::Environment(EnvironmentSource { moniker, .. })
358            | Self::Void(VoidSource { moniker, .. })
359            | Self::StorageBackingDirectory(StorageBackingDirectorySource { moniker, .. })
360            | Self::AnonymizedAggregate(AnonymizedAggregateSource { moniker, .. })
361            | Self::FilteredProvider(FilteredProviderSource { moniker, .. })
362            | Self::FilteredAggregateProvider(FilteredAggregateProviderSource {
363                moniker, ..
364            })
365            | Self::RemotedAt(moniker) => ExtendedMoniker::ComponentInstance(moniker.clone()),
366            Self::Builtin(_) | Self::Namespace(_) => ExtendedMoniker::ComponentManager,
367        }
368    }
369}
370
371impl fmt::Display for CapabilitySource {
372    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
373        write!(
374            f,
375            "{}",
376            match self {
377                Self::Component(ComponentSource { capability, moniker })
378                | Self::StorageBackingDirectory(StorageBackingDirectorySource {
379                    capability,
380                    moniker,
381                    ..
382                }) => {
383                    format!("{} '{}'", capability, moniker)
384                }
385                Self::Framework(FrameworkSource { capability, .. }) => capability.to_string(),
386                Self::Builtin(BuiltinSource { capability }) => capability.to_string(),
387                Self::Namespace(NamespaceSource { capability }) => capability.to_string(),
388                Self::FilteredProvider(FilteredProviderSource { capability, .. })
389                | Self::FilteredAggregateProvider(FilteredAggregateProviderSource {
390                    capability,
391                    ..
392                }) => capability.to_string(),
393                Self::Capability(CapabilityToCapabilitySource { source_capability, .. }) =>
394                    format!("{}", source_capability),
395                Self::AnonymizedAggregate(AnonymizedAggregateSource {
396                    capability,
397                    members,
398                    moniker,
399                    ..
400                }) => {
401                    format!(
402                        "{} from component '{}' aggregated from {}",
403                        capability,
404                        moniker,
405                        members.iter().map(|s| format!("{s}")).collect::<Vec<_>>().join(","),
406                    )
407                }
408                Self::Environment(EnvironmentSource { capability, .. }) => capability.to_string(),
409                Self::Void(VoidSource { capability, .. }) => capability.to_string(),
410                Self::RemotedAt(moniker) => format!("route left component manager at {}", moniker),
411            }
412        )
413    }
414}
415
416impl TryFrom<CapabilitySource> for Capability {
417    type Error = fidl::Error;
418
419    fn try_from(capability_source: CapabilitySource) -> Result<Self, Self::Error> {
420        Ok(Data::try_from(capability_source)?.into())
421    }
422}
423
424impl TryFrom<CapabilitySource> for Data {
425    type Error = fidl::Error;
426
427    fn try_from(capability_source: CapabilitySource) -> Result<Self, Self::Error> {
428        Ok(Data::Bytes(persist(&capability_source.native_into_fidl())?.into()))
429    }
430}
431
432impl TryFrom<Capability> for CapabilitySource {
433    type Error = fidl::Error;
434
435    fn try_from(capability: Capability) -> Result<Self, Self::Error> {
436        let Capability::Data(data) = capability else {
437            return Err(fidl::Error::InvalidEnumValue);
438        };
439        Self::try_from(data)
440    }
441}
442
443impl TryFrom<Data> for CapabilitySource {
444    type Error = fidl::Error;
445
446    fn try_from(data: Data) -> Result<Self, Self::Error> {
447        let Data::Bytes(bytes) = data else {
448            return Err(fidl::Error::InvalidEnumValue);
449        };
450        Ok(unpersist::<finternal::CapabilitySource>(&bytes)?.fidl_into_native())
451    }
452}
453
454/// An individual instance in an aggregate.
455#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
456pub enum AggregateInstance {
457    Child(ChildName),
458    Parent,
459    Self_,
460}
461
462impl fmt::Display for AggregateInstance {
463    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
464        match self {
465            Self::Child(n) => {
466                write!(f, "child `{n}`")
467            }
468            Self::Parent => {
469                write!(f, "parent")
470            }
471            Self::Self_ => {
472                write!(f, "self")
473            }
474        }
475    }
476}
477
478/// The return value of the routing future returned by
479/// `FilteredAggregateCapabilityProvider::route_instances`, which contains information about the
480/// source of the route.
481#[derive(Debug)]
482pub struct FilteredAggregateCapabilityRouteData {
483    /// The source of the capability.
484    pub capability_source: CapabilitySource,
485    /// The filter to apply to service instances, as defined by
486    /// [`fuchsia.component.decl/OfferService.renamed_instances`](https://fuchsia.dev/reference/fidl/fuchsia.component.decl#OfferService).
487    pub instance_filter: Vec<NameMapping>,
488}
489
490/// A provider of a capability from an aggregation of zero or more offered instances of a
491/// capability, with filters.
492///
493/// This trait type-erases the capability type, so it can be handled and hosted generically.
494pub trait FilteredAggregateCapabilityProvider: Send + Sync {
495    /// Return a list of futures to route every instance in the aggregate to its source. Each
496    /// result is paired with the list of instances to include in the source.
497    fn route_instances(
498        &self,
499    ) -> Vec<BoxFuture<'_, Result<FilteredAggregateCapabilityRouteData, RoutingError>>>;
500
501    /// Trait-object compatible clone.
502    fn clone_boxed(&self) -> Box<dyn FilteredAggregateCapabilityProvider>;
503}
504
505impl Clone for Box<dyn FilteredAggregateCapabilityProvider> {
506    fn clone(&self) -> Self {
507        self.clone_boxed()
508    }
509}
510
511impl fmt::Debug for Box<dyn FilteredAggregateCapabilityProvider> {
512    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
513        f.debug_struct("Box<dyn FilteredAggregateCapabilityProvider>").finish()
514    }
515}
516
517/// Describes a capability provided by the component manager which could be a framework capability
518/// scoped to a realm, a built-in global capability, or a capability from component manager's own
519/// namespace.
520#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
521#[derive(FidlDecl, Clone, Debug, PartialEq, Eq)]
522#[fidl_decl(fidl_union = "finternal::InternalCapability")]
523pub enum InternalCapability {
524    Service(Name),
525    Protocol(Name),
526    Directory(Name),
527    Runner(Name),
528    Config(Name),
529    EventStream(Name),
530    Resolver(Name),
531    Storage(Name),
532    Dictionary(Name),
533}
534
535impl InternalCapability {
536    pub fn new(type_name: CapabilityTypeName, name: Name) -> Self {
537        match type_name {
538            CapabilityTypeName::Directory => InternalCapability::Directory(name),
539            CapabilityTypeName::EventStream => InternalCapability::Directory(name),
540            CapabilityTypeName::Protocol => InternalCapability::Protocol(name),
541            CapabilityTypeName::Resolver => InternalCapability::Resolver(name),
542            CapabilityTypeName::Runner => InternalCapability::Runner(name),
543            CapabilityTypeName::Service => InternalCapability::Service(name),
544            CapabilityTypeName::Storage => InternalCapability::Storage(name),
545            CapabilityTypeName::Dictionary => InternalCapability::Dictionary(name),
546            CapabilityTypeName::Config => InternalCapability::Config(name),
547        }
548    }
549
550    /// Returns a name for the capability type.
551    pub fn type_name(&self) -> CapabilityTypeName {
552        match self {
553            InternalCapability::Service(_) => CapabilityTypeName::Service,
554            InternalCapability::Protocol(_) => CapabilityTypeName::Protocol,
555            InternalCapability::Directory(_) => CapabilityTypeName::Directory,
556            InternalCapability::Runner(_) => CapabilityTypeName::Runner,
557            InternalCapability::Config(_) => CapabilityTypeName::Config,
558            InternalCapability::EventStream(_) => CapabilityTypeName::EventStream,
559            InternalCapability::Resolver(_) => CapabilityTypeName::Resolver,
560            InternalCapability::Storage(_) => CapabilityTypeName::Storage,
561            InternalCapability::Dictionary(_) => CapabilityTypeName::Dictionary,
562        }
563    }
564
565    pub fn source_name(&self) -> &Name {
566        match self {
567            InternalCapability::Service(name) => &name,
568            InternalCapability::Protocol(name) => &name,
569            InternalCapability::Directory(name) => &name,
570            InternalCapability::Runner(name) => &name,
571            InternalCapability::Config(name) => &name,
572            InternalCapability::EventStream(name) => &name,
573            InternalCapability::Resolver(name) => &name,
574            InternalCapability::Storage(name) => &name,
575            InternalCapability::Dictionary(name) => &name,
576        }
577    }
578
579    /// Returns true if this is a protocol with name that matches `name`.
580    pub fn matches_protocol(&self, name: &Name) -> bool {
581        match self {
582            Self::Protocol(source_name) => source_name == name,
583            _ => false,
584        }
585    }
586}
587
588impl fmt::Display for InternalCapability {
589    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
590        write!(f, "{} '{}' from component manager", self.type_name(), self.source_name())
591    }
592}
593
594impl From<CapabilityDecl> for InternalCapability {
595    fn from(capability: CapabilityDecl) -> Self {
596        match capability {
597            CapabilityDecl::Service(c) => InternalCapability::Service(c.name),
598            CapabilityDecl::Protocol(c) => InternalCapability::Protocol(c.name),
599            CapabilityDecl::Directory(c) => InternalCapability::Directory(c.name),
600            CapabilityDecl::Storage(c) => InternalCapability::Storage(c.name),
601            CapabilityDecl::Runner(c) => InternalCapability::Runner(c.name),
602            CapabilityDecl::Resolver(c) => InternalCapability::Resolver(c.name),
603            CapabilityDecl::EventStream(c) => InternalCapability::EventStream(c.name),
604            CapabilityDecl::Dictionary(c) => InternalCapability::Dictionary(c.name),
605            CapabilityDecl::Config(c) => InternalCapability::Config(c.name),
606        }
607    }
608}
609
610impl From<ServiceDecl> for InternalCapability {
611    fn from(service: ServiceDecl) -> Self {
612        Self::Service(service.name)
613    }
614}
615
616impl From<ProtocolDecl> for InternalCapability {
617    fn from(protocol: ProtocolDecl) -> Self {
618        Self::Protocol(protocol.name)
619    }
620}
621
622impl From<DirectoryDecl> for InternalCapability {
623    fn from(directory: DirectoryDecl) -> Self {
624        Self::Directory(directory.name)
625    }
626}
627
628impl From<RunnerDecl> for InternalCapability {
629    fn from(runner: RunnerDecl) -> Self {
630        Self::Runner(runner.name)
631    }
632}
633
634impl From<ResolverDecl> for InternalCapability {
635    fn from(resolver: ResolverDecl) -> Self {
636        Self::Resolver(resolver.name)
637    }
638}
639
640impl From<EventStreamDecl> for InternalCapability {
641    fn from(event: EventStreamDecl) -> Self {
642        Self::EventStream(event.name)
643    }
644}
645
646impl From<StorageDecl> for InternalCapability {
647    fn from(storage: StorageDecl) -> Self {
648        Self::Storage(storage.name)
649    }
650}
651
652impl From<cm_rust::ConfigurationDecl> for InternalCapability {
653    fn from(config: cm_rust::ConfigurationDecl) -> Self {
654        Self::Config(config.name)
655    }
656}
657
658/// A capability being routed from a component.
659#[cfg_attr(
660    feature = "serde",
661    derive(Deserialize, Serialize),
662    serde(tag = "type", rename_all = "snake_case")
663)]
664#[derive(FidlDecl, FromEnum, Clone, Debug, PartialEq, Eq)]
665#[fidl_decl(fidl_union = "finternal::ComponentCapability")]
666pub enum ComponentCapability {
667    Use_(UseDecl),
668    /// Models a capability used from the environment.
669    Environment(EnvironmentCapability),
670    Expose(ExposeDecl),
671    Offer(OfferDecl),
672    Protocol(ProtocolDecl),
673    Directory(DirectoryDecl),
674    Storage(StorageDecl),
675    Runner(RunnerDecl),
676    Resolver(ResolverDecl),
677    Service(ServiceDecl),
678    EventStream(EventStreamDecl),
679    Dictionary(DictionaryDecl),
680    Config(ConfigurationDecl),
681}
682
683impl ComponentCapability {
684    /// Returns a name for the capability type.
685    pub fn type_name(&self) -> CapabilityTypeName {
686        match self {
687            ComponentCapability::Use_(use_) => use_.into(),
688            ComponentCapability::Environment(env) => match env {
689                EnvironmentCapability::Runner(_) => CapabilityTypeName::Runner,
690                EnvironmentCapability::Resolver(_) => CapabilityTypeName::Resolver,
691                EnvironmentCapability::Debug(_) => CapabilityTypeName::Protocol,
692            },
693            ComponentCapability::Expose(expose) => expose.into(),
694            ComponentCapability::Offer(offer) => offer.into(),
695            ComponentCapability::Protocol(_) => CapabilityTypeName::Protocol,
696            ComponentCapability::Directory(_) => CapabilityTypeName::Directory,
697            ComponentCapability::Storage(_) => CapabilityTypeName::Storage,
698            ComponentCapability::Runner(_) => CapabilityTypeName::Runner,
699            ComponentCapability::Config(_) => CapabilityTypeName::Config,
700            ComponentCapability::Resolver(_) => CapabilityTypeName::Resolver,
701            ComponentCapability::Service(_) => CapabilityTypeName::Service,
702            ComponentCapability::EventStream(_) => CapabilityTypeName::EventStream,
703            ComponentCapability::Dictionary(_) => CapabilityTypeName::Dictionary,
704        }
705    }
706
707    /// Return the source path of the capability, if one exists.
708    pub fn source_path(&self) -> Option<&Path> {
709        match self {
710            ComponentCapability::Storage(_) => None,
711            ComponentCapability::Protocol(protocol) => protocol.source_path.as_ref(),
712            ComponentCapability::Directory(directory) => directory.source_path.as_ref(),
713            ComponentCapability::Runner(runner) => runner.source_path.as_ref(),
714            ComponentCapability::Resolver(resolver) => resolver.source_path.as_ref(),
715            ComponentCapability::Service(service) => service.source_path.as_ref(),
716            _ => None,
717        }
718    }
719
720    /// Return the name of the capability, if this is a capability declaration.
721    pub fn source_name(&self) -> Option<&Name> {
722        match self {
723            ComponentCapability::Storage(storage) => Some(&storage.name),
724            ComponentCapability::Protocol(protocol) => Some(&protocol.name),
725            ComponentCapability::Directory(directory) => Some(&directory.name),
726            ComponentCapability::Runner(runner) => Some(&runner.name),
727            ComponentCapability::Config(config) => Some(&config.name),
728            ComponentCapability::Resolver(resolver) => Some(&resolver.name),
729            ComponentCapability::Service(service) => Some(&service.name),
730            ComponentCapability::EventStream(event) => Some(&event.name),
731            ComponentCapability::Dictionary(dictionary) => Some(&dictionary.name),
732            ComponentCapability::Use_(use_) => match use_ {
733                UseDecl::Protocol(UseProtocolDecl { source_name, .. }) => Some(source_name),
734                UseDecl::Directory(UseDirectoryDecl { source_name, .. }) => Some(source_name),
735                UseDecl::Storage(UseStorageDecl { source_name, .. }) => Some(source_name),
736                UseDecl::Service(UseServiceDecl { source_name, .. }) => Some(source_name),
737                UseDecl::Config(cm_rust::UseConfigurationDecl { source_name, .. }) => {
738                    Some(source_name)
739                }
740                _ => None,
741            },
742            ComponentCapability::Environment(env_cap) => match env_cap {
743                EnvironmentCapability::Runner(EnvironmentCapabilityData {
744                    source_name, ..
745                }) => Some(source_name),
746                EnvironmentCapability::Resolver(EnvironmentCapabilityData {
747                    source_name, ..
748                }) => Some(source_name),
749                EnvironmentCapability::Debug(EnvironmentCapabilityData { source_name, .. }) => {
750                    Some(source_name)
751                }
752            },
753            ComponentCapability::Expose(expose) => match expose {
754                ExposeDecl::Protocol(ExposeProtocolDecl { source_name, .. }) => Some(source_name),
755                ExposeDecl::Directory(ExposeDirectoryDecl { source_name, .. }) => Some(source_name),
756                ExposeDecl::Runner(ExposeRunnerDecl { source_name, .. }) => Some(source_name),
757                ExposeDecl::Resolver(ExposeResolverDecl { source_name, .. }) => Some(source_name),
758                ExposeDecl::Service(ExposeServiceDecl { source_name, .. }) => Some(source_name),
759                ExposeDecl::Config(ExposeConfigurationDecl { source_name, .. }) => {
760                    Some(source_name)
761                }
762                ExposeDecl::Dictionary(ExposeDictionaryDecl { source_name, .. }) => {
763                    Some(source_name)
764                }
765            },
766            ComponentCapability::Offer(offer) => match offer {
767                OfferDecl::Protocol(OfferProtocolDecl { source_name, .. }) => Some(source_name),
768                OfferDecl::Directory(OfferDirectoryDecl { source_name, .. }) => Some(source_name),
769                OfferDecl::Runner(OfferRunnerDecl { source_name, .. }) => Some(source_name),
770                OfferDecl::Storage(OfferStorageDecl { source_name, .. }) => Some(source_name),
771                OfferDecl::Resolver(OfferResolverDecl { source_name, .. }) => Some(source_name),
772                OfferDecl::Service(OfferServiceDecl { source_name, .. }) => Some(source_name),
773                OfferDecl::Config(OfferConfigurationDecl { source_name, .. }) => Some(source_name),
774                OfferDecl::EventStream(OfferEventStreamDecl { source_name, .. }) => {
775                    Some(source_name)
776                }
777                OfferDecl::Dictionary(OfferDictionaryDecl { source_name, .. }) => Some(source_name),
778            },
779        }
780    }
781
782    pub fn source_capability_name(&self) -> Option<&Name> {
783        match self {
784            ComponentCapability::Offer(OfferDecl::Protocol(OfferProtocolDecl {
785                source: OfferSource::Capability(name),
786                ..
787            })) => Some(name),
788            ComponentCapability::Expose(ExposeDecl::Protocol(ExposeProtocolDecl {
789                source: ExposeSource::Capability(name),
790                ..
791            })) => Some(name),
792            ComponentCapability::Use_(UseDecl::Protocol(UseProtocolDecl {
793                source: UseSource::Capability(name),
794                ..
795            })) => Some(name),
796            _ => None,
797        }
798    }
799
800    /// Returns the path or name of the capability as a string, useful for debugging.
801    pub fn source_id(&self) -> String {
802        self.source_name()
803            .map(|p| format!("{}", p))
804            .or_else(|| self.source_path().map(|p| format!("{}", p)))
805            .unwrap_or_default()
806    }
807}
808
809impl From<CapabilityDecl> for ComponentCapability {
810    fn from(capability: CapabilityDecl) -> Self {
811        match capability {
812            CapabilityDecl::Service(c) => ComponentCapability::Service(c),
813            CapabilityDecl::Protocol(c) => ComponentCapability::Protocol(c),
814            CapabilityDecl::Directory(c) => ComponentCapability::Directory(c),
815            CapabilityDecl::Storage(c) => ComponentCapability::Storage(c),
816            CapabilityDecl::Runner(c) => ComponentCapability::Runner(c),
817            CapabilityDecl::Resolver(c) => ComponentCapability::Resolver(c),
818            CapabilityDecl::EventStream(c) => ComponentCapability::EventStream(c),
819            CapabilityDecl::Dictionary(c) => ComponentCapability::Dictionary(c),
820            CapabilityDecl::Config(c) => ComponentCapability::Config(c),
821        }
822    }
823}
824
825impl TryInto<CapabilityDecl> for ComponentCapability {
826    type Error = ();
827
828    fn try_into(self) -> Result<CapabilityDecl, Self::Error> {
829        match self {
830            Self::Service(c) => Ok(CapabilityDecl::Service(c)),
831            Self::Protocol(c) => Ok(CapabilityDecl::Protocol(c)),
832            Self::Directory(c) => Ok(CapabilityDecl::Directory(c)),
833            Self::Storage(c) => Ok(CapabilityDecl::Storage(c)),
834            Self::Runner(c) => Ok(CapabilityDecl::Runner(c)),
835            Self::Resolver(c) => Ok(CapabilityDecl::Resolver(c)),
836            Self::EventStream(c) => Ok(CapabilityDecl::EventStream(c)),
837            Self::Dictionary(c) => Ok(CapabilityDecl::Dictionary(c)),
838            Self::Config(c) => Ok(CapabilityDecl::Config(c)),
839            _ => Err(()),
840        }
841    }
842}
843
844impl fmt::Display for ComponentCapability {
845    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
846        write!(f, "{} '{}' from component", self.type_name(), self.source_id())
847    }
848}
849
850#[cfg_attr(
851    feature = "serde",
852    derive(Deserialize, Serialize),
853    serde(tag = "type", rename_all = "snake_case")
854)]
855#[derive(FidlDecl, Clone, Debug, PartialEq, Eq)]
856#[fidl_decl(fidl_union = "finternal::EnvironmentCapability")]
857pub enum EnvironmentCapability {
858    Runner(EnvironmentCapabilityData),
859    Resolver(EnvironmentCapabilityData),
860    Debug(EnvironmentCapabilityData),
861}
862
863impl EnvironmentCapability {
864    pub fn registration_source(&self) -> &RegistrationSource {
865        match self {
866            Self::Runner(EnvironmentCapabilityData { source, .. })
867            | Self::Resolver(EnvironmentCapabilityData { source, .. })
868            | Self::Debug(EnvironmentCapabilityData { source, .. }) => &source,
869        }
870    }
871}
872
873#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
874#[derive(FidlDecl, Clone, Debug, PartialEq, Eq)]
875#[fidl_decl(fidl_table = "finternal::EnvironmentSource")]
876pub struct EnvironmentCapabilityData {
877    source_name: Name,
878    source: RegistrationSource,
879}
880
881/// Describes a capability provided by component manager that is an aggregation
882/// of multiple instances of a capability.
883#[cfg_attr(
884    feature = "serde",
885    derive(Deserialize, Serialize),
886    serde(tag = "type", rename_all = "snake_case")
887)]
888#[derive(FidlDecl, Debug, Clone, PartialEq, Eq, Hash)]
889#[fidl_decl(fidl_union = "finternal::AggregateCapability")]
890pub enum AggregateCapability {
891    Service(Name),
892}
893
894impl AggregateCapability {
895    /// Returns a name for the capability type.
896    pub fn type_name(&self) -> CapabilityTypeName {
897        match self {
898            AggregateCapability::Service(_) => CapabilityTypeName::Service,
899        }
900    }
901
902    pub fn source_name(&self) -> &Name {
903        match self {
904            AggregateCapability::Service(name) => &name,
905        }
906    }
907}
908
909impl fmt::Display for AggregateCapability {
910    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
911        write!(f, "aggregate {} '{}'", self.type_name(), self.source_name())
912    }
913}
914
915impl From<ServiceDecl> for AggregateCapability {
916    fn from(service: ServiceDecl) -> Self {
917        Self::Service(service.name)
918    }
919}
920
921/// The list of declarations for capabilities from component manager's namespace.
922pub type NamespaceCapabilities = Vec<CapabilityDecl>;
923
924/// The list of declarations for capabilities offered by component manager as built-in capabilities.
925pub type BuiltinCapabilities = Vec<CapabilityDecl>;
926
927#[cfg(test)]
928mod tests {
929    use super::*;
930    use cm_rust::StorageDirectorySource;
931
932    #[test]
933    fn capability_type_name() {
934        let storage_capability = ComponentCapability::Storage(StorageDecl {
935            name: "foo".parse().unwrap(),
936            source: StorageDirectorySource::Parent,
937            backing_dir: "bar".parse().unwrap(),
938            subdir: Default::default(),
939            storage_id: fdecl::StorageId::StaticInstanceIdOrMoniker,
940        });
941        assert_eq!(storage_capability.type_name(), CapabilityTypeName::Storage);
942    }
943}