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    #[cfg_attr(feature = "serde", serde(with = "serde_config_name"))]
590    Config(Name),
591}
592
593#[cfg(feature = "serde")]
594mod serde_config_name {
595    use cm_types::Name;
596    use serde::{Deserialize, Deserializer, Serialize, Serializer};
597
598    #[derive(Serialize)]
599    struct ConfigNameRef<'a> {
600        name: &'a Name,
601    }
602
603    #[derive(Deserialize)]
604    struct ConfigNameOwned {
605        name: Name,
606    }
607
608    pub fn serialize<S: Serializer>(name: &Name, serializer: S) -> Result<S::Ok, S::Error> {
609        ConfigNameRef { name }.serialize(serializer)
610    }
611
612    pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Name, D::Error> {
613        Ok(ConfigNameOwned::deserialize(deserializer)?.name)
614    }
615}
616
617impl ComponentCapability {
618    /// Returns a name for the capability type.
619    pub fn type_name(&self) -> CapabilityTypeName {
620        match self {
621            ComponentCapability::Use_(use_) => use_.into(),
622            ComponentCapability::Environment(env) => match env {
623                EnvironmentCapability::Runner(_) => CapabilityTypeName::Runner,
624                EnvironmentCapability::Resolver(_) => CapabilityTypeName::Resolver,
625                EnvironmentCapability::Debug(_) => CapabilityTypeName::Protocol,
626            },
627            ComponentCapability::Expose(expose) => expose.into(),
628            ComponentCapability::Offer(offer) => offer.into(),
629            ComponentCapability::Protocol(_) => CapabilityTypeName::Protocol,
630            ComponentCapability::Directory(_) => CapabilityTypeName::Directory,
631            ComponentCapability::Storage(_) => CapabilityTypeName::Storage,
632            ComponentCapability::Runner(_) => CapabilityTypeName::Runner,
633            ComponentCapability::Config(_) => CapabilityTypeName::Config,
634            ComponentCapability::Resolver(_) => CapabilityTypeName::Resolver,
635            ComponentCapability::Service(_) => CapabilityTypeName::Service,
636            ComponentCapability::EventStream(_) => CapabilityTypeName::EventStream,
637            ComponentCapability::Dictionary(_) => CapabilityTypeName::Dictionary,
638        }
639    }
640
641    /// Return the source path of the capability, if one exists.
642    pub fn source_path(&self) -> Option<&Path> {
643        match self {
644            ComponentCapability::Storage(_) => None,
645            ComponentCapability::Protocol(protocol) => protocol.source_path.as_ref(),
646            ComponentCapability::Directory(directory) => directory.source_path.as_ref(),
647            ComponentCapability::Runner(runner) => runner.source_path.as_ref(),
648            ComponentCapability::Resolver(resolver) => resolver.source_path.as_ref(),
649            ComponentCapability::Service(service) => service.source_path.as_ref(),
650            _ => None,
651        }
652    }
653
654    /// Return the name of the capability, if this is a capability declaration.
655    pub fn source_name(&self) -> Option<&Name> {
656        match self {
657            ComponentCapability::Storage(storage) => Some(&storage.name),
658            ComponentCapability::Protocol(protocol) => Some(&protocol.name),
659            ComponentCapability::Directory(directory) => Some(&directory.name),
660            ComponentCapability::Runner(runner) => Some(&runner.name),
661            ComponentCapability::Config(name) => Some(name),
662            ComponentCapability::Resolver(resolver) => Some(&resolver.name),
663            ComponentCapability::Service(service) => Some(&service.name),
664            ComponentCapability::EventStream(event) => Some(&event.name),
665            ComponentCapability::Dictionary(dictionary) => Some(&dictionary.name),
666            ComponentCapability::Use_(use_) => match use_ {
667                UseDecl::Protocol(UseProtocolDecl { source_name, .. }) => Some(source_name),
668                UseDecl::Directory(UseDirectoryDecl { source_name, .. }) => Some(source_name),
669                UseDecl::Storage(UseStorageDecl { source_name, .. }) => Some(source_name),
670                UseDecl::Service(UseServiceDecl { source_name, .. }) => Some(source_name),
671                UseDecl::Config(config) => Some(&config.source_name),
672                _ => None,
673            },
674            ComponentCapability::Environment(env_cap) => match env_cap {
675                EnvironmentCapability::Runner(EnvironmentCapabilityData {
676                    source_name, ..
677                }) => Some(source_name),
678                EnvironmentCapability::Resolver(EnvironmentCapabilityData {
679                    source_name, ..
680                }) => Some(source_name),
681                EnvironmentCapability::Debug(EnvironmentCapabilityData { source_name, .. }) => {
682                    Some(source_name)
683                }
684            },
685            ComponentCapability::Expose(expose) => match expose {
686                ExposeDecl::Protocol(ExposeProtocolDecl { source_name, .. }) => Some(source_name),
687                ExposeDecl::Directory(ExposeDirectoryDecl { source_name, .. }) => Some(source_name),
688                ExposeDecl::Runner(ExposeRunnerDecl { source_name, .. }) => Some(source_name),
689                ExposeDecl::Resolver(ExposeResolverDecl { source_name, .. }) => Some(source_name),
690                ExposeDecl::Service(ExposeServiceDecl { source_name, .. }) => Some(source_name),
691                ExposeDecl::Config(ExposeConfigurationDecl { source_name, .. }) => {
692                    Some(source_name)
693                }
694                ExposeDecl::Dictionary(ExposeDictionaryDecl { source_name, .. }) => {
695                    Some(source_name)
696                }
697            },
698            ComponentCapability::Offer(offer) => match offer {
699                OfferDecl::Protocol(OfferProtocolDecl { source_name, .. }) => Some(source_name),
700                OfferDecl::Directory(directory) => Some(&directory.source_name),
701                OfferDecl::Runner(OfferRunnerDecl { source_name, .. }) => Some(source_name),
702                OfferDecl::Storage(OfferStorageDecl { source_name, .. }) => Some(source_name),
703                OfferDecl::Resolver(OfferResolverDecl { source_name, .. }) => Some(source_name),
704                OfferDecl::Service(service) => Some(&service.source_name),
705                OfferDecl::Config(OfferConfigurationDecl { source_name, .. }) => Some(source_name),
706                OfferDecl::EventStream(event_stream) => Some(&event_stream.source_name),
707                OfferDecl::Dictionary(OfferDictionaryDecl { source_name, .. }) => Some(source_name),
708            },
709        }
710    }
711
712    pub fn source_capability_name(&self) -> Option<&Name> {
713        match self {
714            ComponentCapability::Offer(OfferDecl::Protocol(OfferProtocolDecl {
715                source: OfferSource::Capability(name),
716                ..
717            })) => Some(name),
718            ComponentCapability::Expose(ExposeDecl::Protocol(ExposeProtocolDecl {
719                source: ExposeSource::Capability(name),
720                ..
721            })) => Some(name),
722            ComponentCapability::Use_(UseDecl::Protocol(UseProtocolDecl {
723                source: UseSource::Capability(name),
724                ..
725            })) => Some(name),
726            _ => None,
727        }
728    }
729
730    /// Returns the path or name of the capability as a string, useful for debugging.
731    pub fn source_id(&self) -> String {
732        self.source_name()
733            .map(|p| format!("{}", p))
734            .or_else(|| self.source_path().map(|p| format!("{}", p)))
735            .unwrap_or_default()
736    }
737}
738
739impl From<CapabilityDecl> for ComponentCapability {
740    fn from(capability: CapabilityDecl) -> Self {
741        match capability {
742            CapabilityDecl::Service(c) => ComponentCapability::Service(c),
743            CapabilityDecl::Protocol(c) => ComponentCapability::Protocol(c),
744            CapabilityDecl::Directory(c) => ComponentCapability::Directory(c),
745            CapabilityDecl::Storage(c) => ComponentCapability::Storage(c),
746            CapabilityDecl::Runner(c) => ComponentCapability::Runner(c),
747            CapabilityDecl::Resolver(c) => ComponentCapability::Resolver(c),
748            CapabilityDecl::EventStream(c) => ComponentCapability::EventStream(c),
749            CapabilityDecl::Dictionary(c) => ComponentCapability::Dictionary(c),
750            CapabilityDecl::Config(c) => ComponentCapability::Config(c.name),
751        }
752    }
753}
754
755impl From<ConfigurationDecl> for ComponentCapability {
756    fn from(config: ConfigurationDecl) -> Self {
757        Self::Config(config.name)
758    }
759}
760
761impl TryInto<CapabilityDecl> for ComponentCapability {
762    type Error = ();
763
764    fn try_into(self) -> Result<CapabilityDecl, Self::Error> {
765        match self {
766            Self::Service(c) => Ok(CapabilityDecl::Service(c)),
767            Self::Protocol(c) => Ok(CapabilityDecl::Protocol(c)),
768            Self::Directory(c) => Ok(CapabilityDecl::Directory(c)),
769            Self::Storage(c) => Ok(CapabilityDecl::Storage(c)),
770            Self::Runner(c) => Ok(CapabilityDecl::Runner(c)),
771            Self::Resolver(c) => Ok(CapabilityDecl::Resolver(c)),
772            Self::EventStream(c) => Ok(CapabilityDecl::EventStream(c)),
773            Self::Dictionary(c) => Ok(CapabilityDecl::Dictionary(c)),
774            _ => Err(()),
775        }
776    }
777}
778
779impl fmt::Display for ComponentCapability {
780    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
781        write!(f, "{} '{}' from component", self.type_name(), self.source_id())
782    }
783}
784
785#[cfg_attr(
786    feature = "serde",
787    derive(Deserialize, Serialize),
788    serde(tag = "type", rename_all = "snake_case")
789)]
790#[derive(Clone, Debug, PartialEq, Eq)]
791pub enum EnvironmentCapability {
792    Runner(EnvironmentCapabilityData),
793    Resolver(EnvironmentCapabilityData),
794    Debug(EnvironmentCapabilityData),
795}
796
797impl EnvironmentCapability {
798    pub fn registration_source(&self) -> &RegistrationSource {
799        match self {
800            Self::Runner(EnvironmentCapabilityData { source, .. })
801            | Self::Resolver(EnvironmentCapabilityData { source, .. })
802            | Self::Debug(EnvironmentCapabilityData { source, .. }) => &source,
803        }
804    }
805}
806
807#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
808#[derive(Clone, Debug, PartialEq, Eq)]
809pub struct EnvironmentCapabilityData {
810    source_name: Name,
811    source: RegistrationSource,
812}
813
814/// Describes a capability provided by component manager that is an aggregation
815/// of multiple instances of a capability.
816#[cfg_attr(
817    feature = "serde",
818    derive(Deserialize, Serialize),
819    serde(tag = "type", rename_all = "snake_case")
820)]
821#[derive(Debug, Clone, PartialEq, Eq, Hash)]
822pub enum AggregateCapability {
823    Service(Name),
824}
825
826impl AggregateCapability {
827    /// Returns a name for the capability type.
828    pub fn type_name(&self) -> CapabilityTypeName {
829        match self {
830            AggregateCapability::Service(_) => CapabilityTypeName::Service,
831        }
832    }
833
834    pub fn source_name(&self) -> &Name {
835        match self {
836            AggregateCapability::Service(name) => &name,
837        }
838    }
839}
840
841impl fmt::Display for AggregateCapability {
842    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
843        write!(f, "aggregate {} '{}'", self.type_name(), self.source_name())
844    }
845}
846
847impl From<ServiceDecl> for AggregateCapability {
848    fn from(service: ServiceDecl) -> Self {
849        Self::Service(service.name)
850    }
851}
852
853/// The list of declarations for capabilities from component manager's namespace.
854pub type NamespaceCapabilities = Vec<CapabilityDecl>;
855
856/// The list of declarations for capabilities offered by component manager as built-in capabilities.
857pub type BuiltinCapabilities = Vec<CapabilityDecl>;
858
859#[cfg(test)]
860mod tests {
861    use super::*;
862    use cm_rust::StorageDirectorySource;
863    use fidl_fuchsia_component_decl as fdecl;
864
865    #[test]
866    fn capability_type_name() {
867        let storage_capability = ComponentCapability::Storage(StorageDecl {
868            name: "foo".parse().unwrap(),
869            source: StorageDirectorySource::Parent,
870            backing_dir: "bar".parse().unwrap(),
871            subdir: Default::default(),
872            storage_id: fdecl::StorageId::StaticInstanceIdOrMoniker,
873        });
874        assert_eq!(storage_capability.type_name(), CapabilityTypeName::Storage);
875    }
876}