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