Skip to main content

capability_source/
lib.rs

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