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};
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}
204
205#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
206#[derive(FidlDecl, Debug, PartialEq, Clone)]
207#[fidl_decl(fidl_table = "finternal::Component")]
208pub struct ComponentSource {
209    pub capability: ComponentCapability,
210    pub moniker: Moniker,
211}
212#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
213#[derive(FidlDecl, Debug, PartialEq, Clone)]
214#[fidl_decl(fidl_table = "finternal::Framework")]
215pub struct FrameworkSource {
216    pub capability: InternalCapability,
217    pub moniker: Moniker,
218}
219#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
220#[derive(FidlDecl, Debug, PartialEq, Clone)]
221#[fidl_decl(fidl_table = "finternal::Builtin")]
222pub struct BuiltinSource {
223    pub capability: InternalCapability,
224}
225#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
226#[derive(FidlDecl, Debug, PartialEq, Clone)]
227#[fidl_decl(fidl_table = "finternal::Namespace")]
228pub struct NamespaceSource {
229    pub capability: ComponentCapability,
230}
231#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
232#[derive(FidlDecl, Debug, PartialEq, Clone)]
233#[fidl_decl(fidl_table = "finternal::Capability")]
234pub struct CapabilityToCapabilitySource {
235    pub source_capability: ComponentCapability,
236    pub moniker: Moniker,
237}
238#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
239#[derive(FidlDecl, Debug, PartialEq, Clone)]
240#[fidl_decl(fidl_table = "finternal::AnonymizedAggregate")]
241pub struct AnonymizedAggregateSource {
242    pub capability: AggregateCapability,
243    pub moniker: Moniker,
244    pub members: Vec<AggregateMember>,
245    pub sources: Sources,
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    pub sources: Sources,
273}
274#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
275#[derive(FidlDecl, Debug, PartialEq, Clone)]
276#[fidl_decl(fidl_table = "finternal::Environment")]
277pub struct EnvironmentSource {
278    pub capability: ComponentCapability,
279    pub moniker: Moniker,
280}
281#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
282#[derive(FidlDecl, Debug, PartialEq, Clone)]
283#[fidl_decl(fidl_table = "finternal::Void")]
284pub struct VoidSource {
285    pub capability: InternalCapability,
286    pub moniker: Moniker,
287}
288
289impl CapabilitySource {
290    pub fn source_name(&self) -> Option<&Name> {
291        match self {
292            Self::Component(ComponentSource { capability, .. }) => capability.source_name(),
293            Self::Framework(FrameworkSource { capability, .. }) => Some(capability.source_name()),
294            Self::Builtin(BuiltinSource { capability }) => Some(capability.source_name()),
295            Self::Namespace(NamespaceSource { capability }) => capability.source_name(),
296            Self::Capability(CapabilityToCapabilitySource { .. }) => None,
297            Self::AnonymizedAggregate(AnonymizedAggregateSource { capability, .. }) => {
298                Some(capability.source_name())
299            }
300            Self::FilteredProvider(FilteredProviderSource { capability, .. })
301            | Self::FilteredAggregateProvider(FilteredAggregateProviderSource {
302                capability, ..
303            }) => Some(capability.source_name()),
304            Self::Environment(EnvironmentSource { capability, .. }) => capability.source_name(),
305            Self::Void(VoidSource { capability, .. }) => Some(capability.source_name()),
306            Self::RemotedAt(_) => None,
307        }
308    }
309
310    pub fn type_name(&self) -> CapabilityTypeName {
311        match self {
312            Self::Component(ComponentSource { capability, .. }) => capability.type_name(),
313            Self::Framework(FrameworkSource { capability, .. }) => capability.type_name(),
314            Self::Builtin(BuiltinSource { capability }) => capability.type_name(),
315            Self::Namespace(NamespaceSource { capability }) => capability.type_name(),
316            Self::Capability(CapabilityToCapabilitySource { source_capability, .. }) => {
317                source_capability.type_name()
318            }
319            Self::AnonymizedAggregate(AnonymizedAggregateSource { capability, .. }) => {
320                capability.type_name()
321            }
322            Self::FilteredProvider(FilteredProviderSource { capability, .. })
323            | Self::FilteredAggregateProvider(FilteredAggregateProviderSource {
324                capability, ..
325            }) => capability.type_name(),
326            Self::Environment(EnvironmentSource { capability, .. }) => capability.type_name(),
327            Self::Void(VoidSource { capability, .. }) => capability.type_name(),
328            Self::RemotedAt(_) => unimplemented!(),
329        }
330    }
331
332    pub fn source_moniker(&self) -> ExtendedMoniker {
333        match self {
334            Self::Component(ComponentSource { moniker, .. })
335            | Self::Framework(FrameworkSource { moniker, .. })
336            | Self::Capability(CapabilityToCapabilitySource { moniker, .. })
337            | Self::Environment(EnvironmentSource { moniker, .. })
338            | Self::Void(VoidSource { moniker, .. })
339            | Self::AnonymizedAggregate(AnonymizedAggregateSource { moniker, .. })
340            | Self::FilteredProvider(FilteredProviderSource { moniker, .. })
341            | Self::FilteredAggregateProvider(FilteredAggregateProviderSource {
342                moniker, ..
343            })
344            | Self::RemotedAt(moniker) => ExtendedMoniker::ComponentInstance(moniker.clone()),
345            Self::Builtin(_) | Self::Namespace(_) => ExtendedMoniker::ComponentManager,
346        }
347    }
348}
349
350impl fmt::Display for CapabilitySource {
351    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352        write!(
353            f,
354            "{}",
355            match self {
356                Self::Component(ComponentSource { capability, moniker }) => {
357                    format!("{} '{}'", capability, moniker)
358                }
359                Self::Framework(FrameworkSource { capability, .. }) => capability.to_string(),
360                Self::Builtin(BuiltinSource { capability }) => capability.to_string(),
361                Self::Namespace(NamespaceSource { capability }) => capability.to_string(),
362                Self::FilteredProvider(FilteredProviderSource { capability, .. })
363                | Self::FilteredAggregateProvider(FilteredAggregateProviderSource {
364                    capability,
365                    ..
366                }) => capability.to_string(),
367                Self::Capability(CapabilityToCapabilitySource { source_capability, .. }) =>
368                    format!("{}", source_capability),
369                Self::AnonymizedAggregate(AnonymizedAggregateSource {
370                    capability,
371                    members,
372                    moniker,
373                    ..
374                }) => {
375                    format!(
376                        "{} from component '{}' aggregated from {}",
377                        capability,
378                        moniker,
379                        members.iter().map(|s| format!("{s}")).collect::<Vec<_>>().join(","),
380                    )
381                }
382                Self::Environment(EnvironmentSource { capability, .. }) => capability.to_string(),
383                Self::Void(VoidSource { capability, .. }) => capability.to_string(),
384                Self::RemotedAt(moniker) => format!("route left component manager at {}", moniker),
385            }
386        )
387    }
388}
389
390impl TryFrom<CapabilitySource> for Capability {
391    type Error = fidl::Error;
392
393    fn try_from(capability_source: CapabilitySource) -> Result<Self, Self::Error> {
394        Ok(Data::try_from(capability_source)?.into())
395    }
396}
397
398impl TryFrom<CapabilitySource> for Data {
399    type Error = fidl::Error;
400
401    fn try_from(capability_source: CapabilitySource) -> Result<Self, Self::Error> {
402        Ok(Data::Bytes(persist(&capability_source.native_into_fidl())?.into()))
403    }
404}
405
406impl TryFrom<Capability> for CapabilitySource {
407    type Error = fidl::Error;
408
409    fn try_from(capability: Capability) -> Result<Self, Self::Error> {
410        let Capability::Data(data) = capability else {
411            return Err(fidl::Error::InvalidEnumValue);
412        };
413        Self::try_from(data)
414    }
415}
416
417impl TryFrom<Data> for CapabilitySource {
418    type Error = fidl::Error;
419
420    fn try_from(data: Data) -> Result<Self, Self::Error> {
421        let Data::Bytes(bytes) = data else {
422            return Err(fidl::Error::InvalidEnumValue);
423        };
424        Ok(unpersist::<finternal::CapabilitySource>(&bytes)?.fidl_into_native())
425    }
426}
427
428/// An individual instance in an aggregate.
429#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
430pub enum AggregateInstance {
431    Child(ChildName),
432    Parent,
433    Self_,
434}
435
436impl fmt::Display for AggregateInstance {
437    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
438        match self {
439            Self::Child(n) => {
440                write!(f, "child `{n}`")
441            }
442            Self::Parent => {
443                write!(f, "parent")
444            }
445            Self::Self_ => {
446                write!(f, "self")
447            }
448        }
449    }
450}
451
452/// The return value of the routing future returned by
453/// `FilteredAggregateCapabilityProvider::route_instances`, which contains information about the
454/// source of the route.
455#[derive(Debug)]
456pub struct FilteredAggregateCapabilityRouteData {
457    /// The source of the capability.
458    pub capability_source: CapabilitySource,
459    /// The filter to apply to service instances, as defined by
460    /// [`fuchsia.component.decl/OfferService.renamed_instances`](https://fuchsia.dev/reference/fidl/fuchsia.component.decl#OfferService).
461    pub instance_filter: Vec<NameMapping>,
462}
463
464/// A provider of a capability from an aggregation of zero or more offered instances of a
465/// capability, with filters.
466///
467/// This trait type-erases the capability type, so it can be handled and hosted generically.
468pub trait FilteredAggregateCapabilityProvider: Send + Sync {
469    /// Return a list of futures to route every instance in the aggregate to its source. Each
470    /// result is paired with the list of instances to include in the source.
471    fn route_instances(
472        &self,
473    ) -> Vec<BoxFuture<'_, Result<FilteredAggregateCapabilityRouteData, RoutingError>>>;
474
475    /// Trait-object compatible clone.
476    fn clone_boxed(&self) -> Box<dyn FilteredAggregateCapabilityProvider>;
477}
478
479impl Clone for Box<dyn FilteredAggregateCapabilityProvider> {
480    fn clone(&self) -> Self {
481        self.clone_boxed()
482    }
483}
484
485impl fmt::Debug for Box<dyn FilteredAggregateCapabilityProvider> {
486    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
487        f.debug_struct("Box<dyn FilteredAggregateCapabilityProvider>").finish()
488    }
489}
490
491/// Describes a capability provided by the component manager which could be a framework capability
492/// scoped to a realm, a built-in global capability, or a capability from component manager's own
493/// namespace.
494#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
495#[derive(FidlDecl, Clone, Debug, PartialEq, Eq)]
496#[fidl_decl(fidl_union = "finternal::InternalCapability")]
497pub enum InternalCapability {
498    Service(Name),
499    Protocol(Name),
500    Directory(Name),
501    Runner(Name),
502    Config(Name),
503    EventStream(Name),
504    Resolver(Name),
505    Storage(Name),
506    Dictionary(Name),
507}
508
509impl InternalCapability {
510    pub fn new(type_name: CapabilityTypeName, name: Name) -> Self {
511        match type_name {
512            CapabilityTypeName::Directory => InternalCapability::Directory(name),
513            CapabilityTypeName::EventStream => InternalCapability::Directory(name),
514            CapabilityTypeName::Protocol => InternalCapability::Protocol(name),
515            CapabilityTypeName::Resolver => InternalCapability::Resolver(name),
516            CapabilityTypeName::Runner => InternalCapability::Runner(name),
517            CapabilityTypeName::Service => InternalCapability::Service(name),
518            CapabilityTypeName::Storage => InternalCapability::Storage(name),
519            CapabilityTypeName::Dictionary => InternalCapability::Dictionary(name),
520            CapabilityTypeName::Config => InternalCapability::Config(name),
521        }
522    }
523
524    /// Returns a name for the capability type.
525    pub fn type_name(&self) -> CapabilityTypeName {
526        match self {
527            InternalCapability::Service(_) => CapabilityTypeName::Service,
528            InternalCapability::Protocol(_) => CapabilityTypeName::Protocol,
529            InternalCapability::Directory(_) => CapabilityTypeName::Directory,
530            InternalCapability::Runner(_) => CapabilityTypeName::Runner,
531            InternalCapability::Config(_) => CapabilityTypeName::Config,
532            InternalCapability::EventStream(_) => CapabilityTypeName::EventStream,
533            InternalCapability::Resolver(_) => CapabilityTypeName::Resolver,
534            InternalCapability::Storage(_) => CapabilityTypeName::Storage,
535            InternalCapability::Dictionary(_) => CapabilityTypeName::Dictionary,
536        }
537    }
538
539    pub fn source_name(&self) -> &Name {
540        match self {
541            InternalCapability::Service(name) => &name,
542            InternalCapability::Protocol(name) => &name,
543            InternalCapability::Directory(name) => &name,
544            InternalCapability::Runner(name) => &name,
545            InternalCapability::Config(name) => &name,
546            InternalCapability::EventStream(name) => &name,
547            InternalCapability::Resolver(name) => &name,
548            InternalCapability::Storage(name) => &name,
549            InternalCapability::Dictionary(name) => &name,
550        }
551    }
552
553    /// Returns true if this is a protocol with name that matches `name`.
554    pub fn matches_protocol(&self, name: &Name) -> bool {
555        match self {
556            Self::Protocol(source_name) => source_name == name,
557            _ => false,
558        }
559    }
560}
561
562impl fmt::Display for InternalCapability {
563    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
564        write!(f, "{} '{}' from component manager", self.type_name(), self.source_name())
565    }
566}
567
568impl From<CapabilityDecl> for InternalCapability {
569    fn from(capability: CapabilityDecl) -> Self {
570        match capability {
571            CapabilityDecl::Service(c) => InternalCapability::Service(c.name),
572            CapabilityDecl::Protocol(c) => InternalCapability::Protocol(c.name),
573            CapabilityDecl::Directory(c) => InternalCapability::Directory(c.name),
574            CapabilityDecl::Storage(c) => InternalCapability::Storage(c.name),
575            CapabilityDecl::Runner(c) => InternalCapability::Runner(c.name),
576            CapabilityDecl::Resolver(c) => InternalCapability::Resolver(c.name),
577            CapabilityDecl::EventStream(c) => InternalCapability::EventStream(c.name),
578            CapabilityDecl::Dictionary(c) => InternalCapability::Dictionary(c.name),
579            CapabilityDecl::Config(c) => InternalCapability::Config(c.name),
580        }
581    }
582}
583
584impl From<ServiceDecl> for InternalCapability {
585    fn from(service: ServiceDecl) -> Self {
586        Self::Service(service.name)
587    }
588}
589
590impl From<ProtocolDecl> for InternalCapability {
591    fn from(protocol: ProtocolDecl) -> Self {
592        Self::Protocol(protocol.name)
593    }
594}
595
596impl From<DirectoryDecl> for InternalCapability {
597    fn from(directory: DirectoryDecl) -> Self {
598        Self::Directory(directory.name)
599    }
600}
601
602impl From<RunnerDecl> for InternalCapability {
603    fn from(runner: RunnerDecl) -> Self {
604        Self::Runner(runner.name)
605    }
606}
607
608impl From<ResolverDecl> for InternalCapability {
609    fn from(resolver: ResolverDecl) -> Self {
610        Self::Resolver(resolver.name)
611    }
612}
613
614impl From<EventStreamDecl> for InternalCapability {
615    fn from(event: EventStreamDecl) -> Self {
616        Self::EventStream(event.name)
617    }
618}
619
620impl From<StorageDecl> for InternalCapability {
621    fn from(storage: StorageDecl) -> Self {
622        Self::Storage(storage.name)
623    }
624}
625
626impl From<cm_rust::ConfigurationDecl> for InternalCapability {
627    fn from(config: cm_rust::ConfigurationDecl) -> Self {
628        Self::Config(config.name)
629    }
630}
631
632/// A capability being routed from a component.
633#[cfg_attr(
634    feature = "serde",
635    derive(Deserialize, Serialize),
636    serde(tag = "type", rename_all = "snake_case")
637)]
638#[derive(FidlDecl, FromEnum, Clone, Debug, PartialEq, Eq)]
639#[fidl_decl(fidl_union = "finternal::ComponentCapability")]
640pub enum ComponentCapability {
641    Use_(UseDecl),
642    /// Models a capability used from the environment.
643    Environment(EnvironmentCapability),
644    Expose(ExposeDecl),
645    Offer(OfferDecl),
646    Protocol(ProtocolDecl),
647    Directory(DirectoryDecl),
648    Storage(StorageDecl),
649    Runner(RunnerDecl),
650    Resolver(ResolverDecl),
651    Service(ServiceDecl),
652    EventStream(EventStreamDecl),
653    Dictionary(DictionaryDecl),
654    Config(ConfigurationDecl),
655}
656
657impl ComponentCapability {
658    /// Returns a name for the capability type.
659    pub fn type_name(&self) -> CapabilityTypeName {
660        match self {
661            ComponentCapability::Use_(use_) => use_.into(),
662            ComponentCapability::Environment(env) => match env {
663                EnvironmentCapability::Runner(_) => CapabilityTypeName::Runner,
664                EnvironmentCapability::Resolver(_) => CapabilityTypeName::Resolver,
665                EnvironmentCapability::Debug(_) => CapabilityTypeName::Protocol,
666            },
667            ComponentCapability::Expose(expose) => expose.into(),
668            ComponentCapability::Offer(offer) => offer.into(),
669            ComponentCapability::Protocol(_) => CapabilityTypeName::Protocol,
670            ComponentCapability::Directory(_) => CapabilityTypeName::Directory,
671            ComponentCapability::Storage(_) => CapabilityTypeName::Storage,
672            ComponentCapability::Runner(_) => CapabilityTypeName::Runner,
673            ComponentCapability::Config(_) => CapabilityTypeName::Config,
674            ComponentCapability::Resolver(_) => CapabilityTypeName::Resolver,
675            ComponentCapability::Service(_) => CapabilityTypeName::Service,
676            ComponentCapability::EventStream(_) => CapabilityTypeName::EventStream,
677            ComponentCapability::Dictionary(_) => CapabilityTypeName::Dictionary,
678        }
679    }
680
681    /// Return the source path of the capability, if one exists.
682    pub fn source_path(&self) -> Option<&Path> {
683        match self {
684            ComponentCapability::Storage(_) => None,
685            ComponentCapability::Protocol(protocol) => protocol.source_path.as_ref(),
686            ComponentCapability::Directory(directory) => directory.source_path.as_ref(),
687            ComponentCapability::Runner(runner) => runner.source_path.as_ref(),
688            ComponentCapability::Resolver(resolver) => resolver.source_path.as_ref(),
689            ComponentCapability::Service(service) => service.source_path.as_ref(),
690            _ => None,
691        }
692    }
693
694    /// Return the name of the capability, if this is a capability declaration.
695    pub fn source_name(&self) -> Option<&Name> {
696        match self {
697            ComponentCapability::Storage(storage) => Some(&storage.name),
698            ComponentCapability::Protocol(protocol) => Some(&protocol.name),
699            ComponentCapability::Directory(directory) => Some(&directory.name),
700            ComponentCapability::Runner(runner) => Some(&runner.name),
701            ComponentCapability::Config(config) => Some(&config.name),
702            ComponentCapability::Resolver(resolver) => Some(&resolver.name),
703            ComponentCapability::Service(service) => Some(&service.name),
704            ComponentCapability::EventStream(event) => Some(&event.name),
705            ComponentCapability::Dictionary(dictionary) => Some(&dictionary.name),
706            ComponentCapability::Use_(use_) => match use_ {
707                UseDecl::Protocol(UseProtocolDecl { source_name, .. }) => Some(source_name),
708                UseDecl::Directory(UseDirectoryDecl { source_name, .. }) => Some(source_name),
709                UseDecl::Storage(UseStorageDecl { source_name, .. }) => Some(source_name),
710                UseDecl::Service(UseServiceDecl { source_name, .. }) => Some(source_name),
711                UseDecl::Config(cm_rust::UseConfigurationDecl { source_name, .. }) => {
712                    Some(source_name)
713                }
714                _ => None,
715            },
716            ComponentCapability::Environment(env_cap) => match env_cap {
717                EnvironmentCapability::Runner(EnvironmentCapabilityData {
718                    source_name, ..
719                }) => Some(source_name),
720                EnvironmentCapability::Resolver(EnvironmentCapabilityData {
721                    source_name, ..
722                }) => Some(source_name),
723                EnvironmentCapability::Debug(EnvironmentCapabilityData { source_name, .. }) => {
724                    Some(source_name)
725                }
726            },
727            ComponentCapability::Expose(expose) => match expose {
728                ExposeDecl::Protocol(ExposeProtocolDecl { source_name, .. }) => Some(source_name),
729                ExposeDecl::Directory(ExposeDirectoryDecl { source_name, .. }) => Some(source_name),
730                ExposeDecl::Runner(ExposeRunnerDecl { source_name, .. }) => Some(source_name),
731                ExposeDecl::Resolver(ExposeResolverDecl { source_name, .. }) => Some(source_name),
732                ExposeDecl::Service(ExposeServiceDecl { source_name, .. }) => Some(source_name),
733                ExposeDecl::Config(ExposeConfigurationDecl { source_name, .. }) => {
734                    Some(source_name)
735                }
736                ExposeDecl::Dictionary(ExposeDictionaryDecl { source_name, .. }) => {
737                    Some(source_name)
738                }
739            },
740            ComponentCapability::Offer(offer) => match offer {
741                OfferDecl::Protocol(OfferProtocolDecl { source_name, .. }) => Some(source_name),
742                OfferDecl::Directory(OfferDirectoryDecl { source_name, .. }) => Some(source_name),
743                OfferDecl::Runner(OfferRunnerDecl { source_name, .. }) => Some(source_name),
744                OfferDecl::Storage(OfferStorageDecl { source_name, .. }) => Some(source_name),
745                OfferDecl::Resolver(OfferResolverDecl { source_name, .. }) => Some(source_name),
746                OfferDecl::Service(OfferServiceDecl { source_name, .. }) => Some(source_name),
747                OfferDecl::Config(OfferConfigurationDecl { source_name, .. }) => Some(source_name),
748                OfferDecl::EventStream(OfferEventStreamDecl { source_name, .. }) => {
749                    Some(source_name)
750                }
751                OfferDecl::Dictionary(OfferDictionaryDecl { source_name, .. }) => Some(source_name),
752            },
753        }
754    }
755
756    pub fn source_capability_name(&self) -> Option<&Name> {
757        match self {
758            ComponentCapability::Offer(OfferDecl::Protocol(OfferProtocolDecl {
759                source: OfferSource::Capability(name),
760                ..
761            })) => Some(name),
762            ComponentCapability::Expose(ExposeDecl::Protocol(ExposeProtocolDecl {
763                source: ExposeSource::Capability(name),
764                ..
765            })) => Some(name),
766            ComponentCapability::Use_(UseDecl::Protocol(UseProtocolDecl {
767                source: UseSource::Capability(name),
768                ..
769            })) => Some(name),
770            _ => None,
771        }
772    }
773
774    /// Returns the path or name of the capability as a string, useful for debugging.
775    pub fn source_id(&self) -> String {
776        self.source_name()
777            .map(|p| format!("{}", p))
778            .or_else(|| self.source_path().map(|p| format!("{}", p)))
779            .unwrap_or_default()
780    }
781}
782
783impl From<CapabilityDecl> for ComponentCapability {
784    fn from(capability: CapabilityDecl) -> Self {
785        match capability {
786            CapabilityDecl::Service(c) => ComponentCapability::Service(c),
787            CapabilityDecl::Protocol(c) => ComponentCapability::Protocol(c),
788            CapabilityDecl::Directory(c) => ComponentCapability::Directory(c),
789            CapabilityDecl::Storage(c) => ComponentCapability::Storage(c),
790            CapabilityDecl::Runner(c) => ComponentCapability::Runner(c),
791            CapabilityDecl::Resolver(c) => ComponentCapability::Resolver(c),
792            CapabilityDecl::EventStream(c) => ComponentCapability::EventStream(c),
793            CapabilityDecl::Dictionary(c) => ComponentCapability::Dictionary(c),
794            CapabilityDecl::Config(c) => ComponentCapability::Config(c),
795        }
796    }
797}
798
799impl TryInto<CapabilityDecl> for ComponentCapability {
800    type Error = ();
801
802    fn try_into(self) -> Result<CapabilityDecl, Self::Error> {
803        match self {
804            Self::Service(c) => Ok(CapabilityDecl::Service(c)),
805            Self::Protocol(c) => Ok(CapabilityDecl::Protocol(c)),
806            Self::Directory(c) => Ok(CapabilityDecl::Directory(c)),
807            Self::Storage(c) => Ok(CapabilityDecl::Storage(c)),
808            Self::Runner(c) => Ok(CapabilityDecl::Runner(c)),
809            Self::Resolver(c) => Ok(CapabilityDecl::Resolver(c)),
810            Self::EventStream(c) => Ok(CapabilityDecl::EventStream(c)),
811            Self::Dictionary(c) => Ok(CapabilityDecl::Dictionary(c)),
812            Self::Config(c) => Ok(CapabilityDecl::Config(c)),
813            _ => Err(()),
814        }
815    }
816}
817
818impl fmt::Display for ComponentCapability {
819    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
820        write!(f, "{} '{}' from component", self.type_name(), self.source_id())
821    }
822}
823
824#[cfg_attr(
825    feature = "serde",
826    derive(Deserialize, Serialize),
827    serde(tag = "type", rename_all = "snake_case")
828)]
829#[derive(FidlDecl, Clone, Debug, PartialEq, Eq)]
830#[fidl_decl(fidl_union = "finternal::EnvironmentCapability")]
831pub enum EnvironmentCapability {
832    Runner(EnvironmentCapabilityData),
833    Resolver(EnvironmentCapabilityData),
834    Debug(EnvironmentCapabilityData),
835}
836
837impl EnvironmentCapability {
838    pub fn registration_source(&self) -> &RegistrationSource {
839        match self {
840            Self::Runner(EnvironmentCapabilityData { source, .. })
841            | Self::Resolver(EnvironmentCapabilityData { source, .. })
842            | Self::Debug(EnvironmentCapabilityData { source, .. }) => &source,
843        }
844    }
845}
846
847#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
848#[derive(FidlDecl, Clone, Debug, PartialEq, Eq)]
849#[fidl_decl(fidl_table = "finternal::EnvironmentSource")]
850pub struct EnvironmentCapabilityData {
851    source_name: Name,
852    source: RegistrationSource,
853}
854
855/// Describes a capability provided by component manager that is an aggregation
856/// of multiple instances of a capability.
857#[cfg_attr(
858    feature = "serde",
859    derive(Deserialize, Serialize),
860    serde(tag = "type", rename_all = "snake_case")
861)]
862#[derive(FidlDecl, Debug, Clone, PartialEq, Eq, Hash)]
863#[fidl_decl(fidl_union = "finternal::AggregateCapability")]
864pub enum AggregateCapability {
865    Service(Name),
866}
867
868impl AggregateCapability {
869    /// Returns a name for the capability type.
870    pub fn type_name(&self) -> CapabilityTypeName {
871        match self {
872            AggregateCapability::Service(_) => CapabilityTypeName::Service,
873        }
874    }
875
876    pub fn source_name(&self) -> &Name {
877        match self {
878            AggregateCapability::Service(name) => &name,
879        }
880    }
881}
882
883impl fmt::Display for AggregateCapability {
884    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
885        write!(f, "aggregate {} '{}'", self.type_name(), self.source_name())
886    }
887}
888
889impl From<ServiceDecl> for AggregateCapability {
890    fn from(service: ServiceDecl) -> Self {
891        Self::Service(service.name)
892    }
893}
894
895/// The list of declarations for capabilities from component manager's namespace.
896pub type NamespaceCapabilities = Vec<CapabilityDecl>;
897
898/// The list of declarations for capabilities offered by component manager as built-in capabilities.
899pub type BuiltinCapabilities = Vec<CapabilityDecl>;
900
901#[cfg(test)]
902mod tests {
903    use super::*;
904    use cm_rust::StorageDirectorySource;
905
906    #[test]
907    fn capability_type_name() {
908        let storage_capability = ComponentCapability::Storage(StorageDecl {
909            name: "foo".parse().unwrap(),
910            source: StorageDirectorySource::Parent,
911            backing_dir: "bar".parse().unwrap(),
912            subdir: Default::default(),
913            storage_id: fdecl::StorageId::StaticInstanceIdOrMoniker,
914        });
915        assert_eq!(storage_capability.type_name(), CapabilityTypeName::Storage);
916    }
917}