blob: 616c87f027f6fd1b71890a096ed9fc0f84ae9d01 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
crate::{
component_instance::{
ComponentInstanceInterface, WeakComponentInstanceInterface,
WeakExtendedInstanceInterface,
},
error::RoutingError,
},
async_trait::async_trait,
cm_rust::{
CapabilityDecl, CapabilityTypeName, ConfigurationDecl, DictionaryDecl, DirectoryDecl,
EventStreamDecl, ExposeConfigurationDecl, ExposeDecl, ExposeDictionaryDecl,
ExposeDirectoryDecl, ExposeProtocolDecl, ExposeResolverDecl, ExposeRunnerDecl,
ExposeServiceDecl, ExposeSource, NameMapping, OfferConfigurationDecl, OfferDecl,
OfferDictionaryDecl, OfferDirectoryDecl, OfferEventStreamDecl, OfferProtocolDecl,
OfferResolverDecl, OfferRunnerDecl, OfferServiceDecl, OfferSource, OfferStorageDecl,
ProtocolDecl, RegistrationSource, ResolverDecl, RunnerDecl, ServiceDecl, StorageDecl,
UseDecl, UseDirectoryDecl, UseProtocolDecl, UseServiceDecl, UseSource, UseStorageDecl,
},
cm_types::{Name, Path},
derivative::Derivative,
from_enum::FromEnum,
futures::future::BoxFuture,
moniker::ChildName,
std::{fmt, sync::Weak},
thiserror::Error,
};
#[derive(Debug, Error)]
pub enum Error {
#[error("Invalid framework capability.")]
InvalidFrameworkCapability {},
#[error("Invalid builtin capability.")]
InvalidBuiltinCapability {},
}
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
pub enum AggregateMember {
Child(ChildName),
Collection(Name),
Parent,
Self_,
}
impl fmt::Display for AggregateMember {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Child(n) => {
write!(f, "child `{n}`")
}
Self::Collection(n) => {
write!(f, "collection `{n}`")
}
Self::Parent => {
write!(f, "parent")
}
Self::Self_ => {
write!(f, "self")
}
}
}
}
/// Describes the source of a capability, as determined by `find_capability_source`
#[derive(Debug, Derivative)]
#[derivative(Clone(bound = ""))]
pub enum CapabilitySource<C: ComponentInstanceInterface> {
/// This capability originates from the component instance for the given Realm.
/// point.
Component {
capability: ComponentCapability,
component: WeakComponentInstanceInterface<C>,
},
/// This capability originates from "framework". It's implemented by component manager and is
/// scoped to the realm of the source.
Framework {
capability: InternalCapability,
component: WeakComponentInstanceInterface<C>,
},
/// This capability originates from the parent of the root component, and is built in to
/// component manager. `top_instance` is the instance at the top of the tree, i.e. the
/// instance representing component manager.
Builtin {
capability: InternalCapability,
top_instance: Weak<C::TopInstance>,
},
/// This capability originates from the parent of the root component, and is offered from
/// component manager's namespace. `top_instance` is the instance at the top of the tree, i.e.
/// the instance representing component manager.
Namespace {
capability: ComponentCapability,
top_instance: Weak<C::TopInstance>,
},
/// This capability is provided by the framework based on some other capability.
Capability {
source_capability: ComponentCapability,
component: WeakComponentInstanceInterface<C>,
},
/// This capability is an aggregate of capabilities over a set of collections and static
/// children. The instance names in the aggregate service will be anonymized.
AnonymizedAggregate {
capability: AggregateCapability,
component: WeakComponentInstanceInterface<C>,
aggregate_capability_provider: Box<dyn AnonymizedAggregateCapabilityProvider<C>>,
members: Vec<AggregateMember>,
},
/// This capability is an aggregate of capabilities over a set of children with filters
/// The instances in the aggregate service are the union of these filters.
FilteredAggregate {
capability: AggregateCapability,
capability_provider: Box<dyn FilteredAggregateCapabilityProvider<C>>,
component: WeakComponentInstanceInterface<C>,
},
// This capability originates from "environment". It's implemented by a component instance.
Environment {
capability: ComponentCapability,
component: WeakComponentInstanceInterface<C>,
},
// This capability originates from "void". This is only a valid origination for optional capabilities.
Void {
capability: InternalCapability,
component: WeakComponentInstanceInterface<C>,
},
}
impl<C: ComponentInstanceInterface> CapabilitySource<C> {
/// Returns whether the given CapabilitySourceInterface can be available in a component's
/// namespace.
pub fn can_be_in_namespace(&self) -> bool {
match self {
Self::Component { capability, .. } => capability.can_be_in_namespace(),
Self::Framework { capability, .. } => capability.can_be_in_namespace(),
Self::Builtin { capability, .. } => capability.can_be_in_namespace(),
Self::Namespace { capability, .. } => capability.can_be_in_namespace(),
Self::Capability { .. } => true,
Self::AnonymizedAggregate { capability, .. } => capability.can_be_in_namespace(),
Self::FilteredAggregate { capability, .. } => capability.can_be_in_namespace(),
Self::Environment { capability, .. } => capability.can_be_in_namespace(),
Self::Void { capability, .. } => capability.can_be_in_namespace(),
}
}
pub fn source_name(&self) -> Option<&Name> {
match self {
Self::Component { capability, .. } => capability.source_name(),
Self::Framework { capability, .. } => Some(capability.source_name()),
Self::Builtin { capability, .. } => Some(capability.source_name()),
Self::Namespace { capability, .. } => capability.source_name(),
Self::Capability { .. } => None,
Self::AnonymizedAggregate { capability, .. } => Some(capability.source_name()),
Self::FilteredAggregate { capability, .. } => Some(capability.source_name()),
Self::Environment { capability, .. } => capability.source_name(),
Self::Void { capability, .. } => Some(capability.source_name()),
}
}
pub fn type_name(&self) -> CapabilityTypeName {
match self {
Self::Component { capability, .. } => capability.type_name(),
Self::Framework { capability, .. } => capability.type_name(),
Self::Builtin { capability, .. } => capability.type_name(),
Self::Namespace { capability, .. } => capability.type_name(),
Self::Capability { source_capability, .. } => source_capability.type_name(),
Self::AnonymizedAggregate { capability, .. } => capability.type_name(),
Self::FilteredAggregate { capability, .. } => capability.type_name(),
Self::Environment { capability, .. } => capability.type_name(),
Self::Void { capability, .. } => capability.type_name(),
}
}
pub fn source_instance(&self) -> WeakExtendedInstanceInterface<C> {
match self {
Self::Component { component, .. }
| Self::Framework { component, .. }
| Self::Capability { component, .. }
| Self::AnonymizedAggregate { component, .. }
| Self::FilteredAggregate { component, .. }
| Self::Void { component, .. }
| Self::Environment { component, .. } => {
WeakExtendedInstanceInterface::Component(component.clone())
}
Self::Builtin { top_instance, .. } | Self::Namespace { top_instance, .. } => {
WeakExtendedInstanceInterface::AboveRoot(top_instance.clone())
}
}
}
}
impl<C: ComponentInstanceInterface> fmt::Display for CapabilitySource<C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
Self::Component { capability, component } => {
format!("{} '{}'", capability, component.moniker)
}
Self::Framework { capability, .. } => capability.to_string(),
Self::Builtin { capability, .. } => capability.to_string(),
Self::Namespace { capability, .. } => capability.to_string(),
Self::FilteredAggregate { capability, .. } => capability.to_string(),
Self::Capability { source_capability, .. } => format!("{}", source_capability),
Self::AnonymizedAggregate { capability, members, component, .. } => {
format!(
"{} from component '{}' aggregated from {}",
capability,
&component.moniker,
members.iter().map(|s| format!("{s}")).collect::<Vec<_>>().join(","),
)
}
Self::Environment { capability, .. } => capability.to_string(),
Self::Void { capability, .. } => capability.to_string(),
}
)
}
}
/// An individual instance in an aggregate.
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum AggregateInstance {
Child(ChildName),
Parent,
Self_,
}
impl fmt::Display for AggregateInstance {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Child(n) => {
write!(f, "child `{n}`")
}
Self::Parent => {
write!(f, "parent")
}
Self::Self_ => {
write!(f, "self")
}
}
}
}
/// A provider of a capability from an aggregation of one or more collections and static children.
/// The instance names in the aggregate will be anonymized.
///
/// This trait type-erases the capability type, so it can be handled and hosted generically.
#[async_trait]
pub trait AnonymizedAggregateCapabilityProvider<C: ComponentInstanceInterface>:
Send + Sync
{
/// Lists the instances of the capability.
///
/// The instance is an opaque identifier that is only meaningful for a subsequent
/// call to `route_instance`.
async fn list_instances(&self) -> Result<Vec<AggregateInstance>, RoutingError>;
/// Route the given `instance` of the capability to its source.
async fn route_instance(
&self,
instance: &AggregateInstance,
) -> Result<CapabilitySource<C>, RoutingError>;
/// Trait-object compatible clone.
fn clone_boxed(&self) -> Box<dyn AnonymizedAggregateCapabilityProvider<C>>;
}
impl<C: ComponentInstanceInterface> Clone for Box<dyn AnonymizedAggregateCapabilityProvider<C>> {
fn clone(&self) -> Self {
self.clone_boxed()
}
}
impl<C> fmt::Debug for Box<dyn AnonymizedAggregateCapabilityProvider<C>> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Box<dyn AnonymizedAggregateCapabilityProvider>").finish()
}
}
/// The return value of the routing future returned by
/// `FilteredAggregateCapabilityProvider::route_instances`, which contains information about the
/// source of the route.
#[derive(Debug)]
pub struct FilteredAggregateCapabilityRouteData<C>
where
C: ComponentInstanceInterface,
{
/// The source of the capability.
pub capability_source: CapabilitySource<C>,
/// The filter to apply to service instances, as defined by
/// [`fuchsia.component.decl/OfferService.renamed_instances`](https://fuchsia.dev/reference/fidl/fuchsia.component.decl#OfferService).
pub instance_filter: Vec<NameMapping>,
}
/// A provider of a capability from an aggregation of zero or more offered instances of a
/// capability, with filters.
///
/// This trait type-erases the capability type, so it can be handled and hosted generically.
pub trait FilteredAggregateCapabilityProvider<C: ComponentInstanceInterface>: Send + Sync {
/// Return a list of futures to route every instance in the aggregate to its source. Each
/// result is paired with the list of instances to include in the source.
fn route_instances(
&self,
) -> Vec<BoxFuture<'_, Result<FilteredAggregateCapabilityRouteData<C>, RoutingError>>>;
/// Trait-object compatible clone.
fn clone_boxed(&self) -> Box<dyn FilteredAggregateCapabilityProvider<C>>;
}
impl<C: ComponentInstanceInterface> Clone for Box<dyn FilteredAggregateCapabilityProvider<C>> {
fn clone(&self) -> Self {
self.clone_boxed()
}
}
impl<C> fmt::Debug for Box<dyn FilteredAggregateCapabilityProvider<C>> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Box<dyn FilteredAggregateCapabilityProvider>").finish()
}
}
/// Describes a capability provided by the component manager which could be a framework capability
/// scoped to a realm, a built-in global capability, or a capability from component manager's own
/// namespace.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InternalCapability {
Service(Name),
Protocol(Name),
Directory(Name),
Runner(Name),
Config(Name),
EventStream(Name),
Resolver(Name),
Storage(Name),
Dictionary(Name),
}
impl InternalCapability {
pub fn new(type_name: CapabilityTypeName, name: Name) -> Self {
match type_name {
CapabilityTypeName::Directory => InternalCapability::Directory(name),
CapabilityTypeName::EventStream => InternalCapability::Directory(name),
CapabilityTypeName::Protocol => InternalCapability::Protocol(name),
CapabilityTypeName::Resolver => InternalCapability::Resolver(name),
CapabilityTypeName::Runner => InternalCapability::Runner(name),
CapabilityTypeName::Service => InternalCapability::Service(name),
CapabilityTypeName::Storage => InternalCapability::Storage(name),
CapabilityTypeName::Dictionary => InternalCapability::Dictionary(name),
CapabilityTypeName::Config => InternalCapability::Config(name),
}
}
/// Returns whether the given InternalCapability can be available in a component's namespace.
pub fn can_be_in_namespace(&self) -> bool {
matches!(
self,
InternalCapability::Service(_)
| InternalCapability::Protocol(_)
| InternalCapability::Directory(_)
)
}
/// Returns a name for the capability type.
pub fn type_name(&self) -> CapabilityTypeName {
match self {
InternalCapability::Service(_) => CapabilityTypeName::Service,
InternalCapability::Protocol(_) => CapabilityTypeName::Protocol,
InternalCapability::Directory(_) => CapabilityTypeName::Directory,
InternalCapability::Runner(_) => CapabilityTypeName::Runner,
InternalCapability::Config(_) => CapabilityTypeName::Config,
InternalCapability::EventStream(_) => CapabilityTypeName::EventStream,
InternalCapability::Resolver(_) => CapabilityTypeName::Resolver,
InternalCapability::Storage(_) => CapabilityTypeName::Storage,
InternalCapability::Dictionary(_) => CapabilityTypeName::Dictionary,
}
}
pub fn source_name(&self) -> &Name {
match self {
InternalCapability::Service(name) => &name,
InternalCapability::Protocol(name) => &name,
InternalCapability::Directory(name) => &name,
InternalCapability::Runner(name) => &name,
InternalCapability::Config(name) => &name,
InternalCapability::EventStream(name) => &name,
InternalCapability::Resolver(name) => &name,
InternalCapability::Storage(name) => &name,
InternalCapability::Dictionary(name) => &name,
}
}
/// Returns true if this is a protocol with name that matches `name`.
pub fn matches_protocol(&self, name: &Name) -> bool {
match self {
Self::Protocol(source_name) => source_name == name,
_ => false,
}
}
}
impl fmt::Display for InternalCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} '{}' from component manager", self.type_name(), self.source_name())
}
}
impl From<CapabilityDecl> for InternalCapability {
fn from(capability: CapabilityDecl) -> Self {
match capability {
CapabilityDecl::Service(c) => InternalCapability::Service(c.name),
CapabilityDecl::Protocol(c) => InternalCapability::Protocol(c.name),
CapabilityDecl::Directory(c) => InternalCapability::Directory(c.name),
CapabilityDecl::Storage(c) => InternalCapability::Storage(c.name),
CapabilityDecl::Runner(c) => InternalCapability::Runner(c.name),
CapabilityDecl::Resolver(c) => InternalCapability::Resolver(c.name),
CapabilityDecl::EventStream(c) => InternalCapability::EventStream(c.name),
CapabilityDecl::Dictionary(c) => InternalCapability::Dictionary(c.name),
CapabilityDecl::Config(c) => InternalCapability::Config(c.name),
}
}
}
impl From<ServiceDecl> for InternalCapability {
fn from(service: ServiceDecl) -> Self {
Self::Service(service.name)
}
}
impl From<ProtocolDecl> for InternalCapability {
fn from(protocol: ProtocolDecl) -> Self {
Self::Protocol(protocol.name)
}
}
impl From<DirectoryDecl> for InternalCapability {
fn from(directory: DirectoryDecl) -> Self {
Self::Directory(directory.name)
}
}
impl From<RunnerDecl> for InternalCapability {
fn from(runner: RunnerDecl) -> Self {
Self::Runner(runner.name)
}
}
impl From<ResolverDecl> for InternalCapability {
fn from(resolver: ResolverDecl) -> Self {
Self::Resolver(resolver.name)
}
}
impl From<EventStreamDecl> for InternalCapability {
fn from(event: EventStreamDecl) -> Self {
Self::EventStream(event.name)
}
}
impl From<StorageDecl> for InternalCapability {
fn from(storage: StorageDecl) -> Self {
Self::Storage(storage.name)
}
}
impl From<cm_rust::ConfigurationDecl> for InternalCapability {
fn from(config: cm_rust::ConfigurationDecl) -> Self {
Self::Config(config.name)
}
}
/// A capability being routed from a component.
#[derive(FromEnum, Clone, Debug, PartialEq, Eq)]
pub enum ComponentCapability {
Use(UseDecl),
/// Models a capability used from the environment.
Environment(EnvironmentCapability),
Expose(ExposeDecl),
Offer(OfferDecl),
Protocol(ProtocolDecl),
Directory(DirectoryDecl),
Storage(StorageDecl),
Runner(RunnerDecl),
Resolver(ResolverDecl),
Service(ServiceDecl),
EventStream(EventStreamDecl),
Dictionary(DictionaryDecl),
Config(ConfigurationDecl),
}
impl ComponentCapability {
/// Returns whether the given ComponentCapability can be available in a component's namespace.
pub fn can_be_in_namespace(&self) -> bool {
match self {
ComponentCapability::Use(use_) => {
matches!(use_, UseDecl::Protocol(_) | UseDecl::Directory(_) | UseDecl::Service(_))
}
ComponentCapability::Expose(expose) => matches!(
expose,
ExposeDecl::Protocol(_) | ExposeDecl::Directory(_) | ExposeDecl::Service(_)
),
ComponentCapability::Offer(offer) => matches!(
offer,
OfferDecl::Protocol(_) | OfferDecl::Directory(_) | OfferDecl::Service(_)
),
ComponentCapability::Protocol(_)
| ComponentCapability::Directory(_)
| ComponentCapability::Service(_) => true,
_ => false,
}
}
/// Returns a name for the capability type.
pub fn type_name(&self) -> CapabilityTypeName {
match self {
ComponentCapability::Use(use_) => use_.into(),
ComponentCapability::Environment(env) => match env {
EnvironmentCapability::Runner { .. } => CapabilityTypeName::Runner,
EnvironmentCapability::Resolver { .. } => CapabilityTypeName::Resolver,
EnvironmentCapability::Debug { .. } => CapabilityTypeName::Protocol,
},
ComponentCapability::Expose(expose) => expose.into(),
ComponentCapability::Offer(offer) => offer.into(),
ComponentCapability::Protocol(_) => CapabilityTypeName::Protocol,
ComponentCapability::Directory(_) => CapabilityTypeName::Directory,
ComponentCapability::Storage(_) => CapabilityTypeName::Storage,
ComponentCapability::Runner(_) => CapabilityTypeName::Runner,
ComponentCapability::Config(_) => CapabilityTypeName::Config,
ComponentCapability::Resolver(_) => CapabilityTypeName::Resolver,
ComponentCapability::Service(_) => CapabilityTypeName::Service,
ComponentCapability::EventStream(_) => CapabilityTypeName::EventStream,
ComponentCapability::Dictionary(_) => CapabilityTypeName::Dictionary,
}
}
/// Return the source path of the capability, if one exists.
pub fn source_path(&self) -> Option<&Path> {
match self {
ComponentCapability::Storage(_) => None,
ComponentCapability::Protocol(protocol) => protocol.source_path.as_ref(),
ComponentCapability::Directory(directory) => directory.source_path.as_ref(),
ComponentCapability::Runner(runner) => runner.source_path.as_ref(),
ComponentCapability::Resolver(resolver) => resolver.source_path.as_ref(),
ComponentCapability::Service(service) => service.source_path.as_ref(),
_ => None,
}
}
/// Return the name of the capability, if this is a capability declaration.
pub fn source_name(&self) -> Option<&Name> {
match self {
ComponentCapability::Storage(storage) => Some(&storage.name),
ComponentCapability::Protocol(protocol) => Some(&protocol.name),
ComponentCapability::Directory(directory) => Some(&directory.name),
ComponentCapability::Runner(runner) => Some(&runner.name),
ComponentCapability::Config(config) => Some(&config.name),
ComponentCapability::Resolver(resolver) => Some(&resolver.name),
ComponentCapability::Service(service) => Some(&service.name),
ComponentCapability::EventStream(event) => Some(&event.name),
ComponentCapability::Dictionary(dictionary) => Some(&dictionary.name),
ComponentCapability::Use(use_) => match use_ {
UseDecl::Protocol(UseProtocolDecl { source_name, .. }) => Some(source_name),
UseDecl::Directory(UseDirectoryDecl { source_name, .. }) => Some(source_name),
UseDecl::Storage(UseStorageDecl { source_name, .. }) => Some(source_name),
UseDecl::Service(UseServiceDecl { source_name, .. }) => Some(source_name),
UseDecl::Config(cm_rust::UseConfigurationDecl { source_name, .. }) => {
Some(source_name)
}
_ => None,
},
ComponentCapability::Environment(env_cap) => match env_cap {
EnvironmentCapability::Runner { source_name, .. } => Some(source_name),
EnvironmentCapability::Resolver { source_name, .. } => Some(source_name),
EnvironmentCapability::Debug { source_name, .. } => Some(source_name),
},
ComponentCapability::Expose(expose) => match expose {
ExposeDecl::Protocol(ExposeProtocolDecl { source_name, .. }) => Some(source_name),
ExposeDecl::Directory(ExposeDirectoryDecl { source_name, .. }) => Some(source_name),
ExposeDecl::Runner(ExposeRunnerDecl { source_name, .. }) => Some(source_name),
ExposeDecl::Resolver(ExposeResolverDecl { source_name, .. }) => Some(source_name),
ExposeDecl::Service(ExposeServiceDecl { source_name, .. }) => Some(source_name),
ExposeDecl::Config(ExposeConfigurationDecl { source_name, .. }) => {
Some(source_name)
}
ExposeDecl::Dictionary(ExposeDictionaryDecl { source_name, .. }) => {
Some(source_name)
}
},
ComponentCapability::Offer(offer) => match offer {
OfferDecl::Protocol(OfferProtocolDecl { source_name, .. }) => Some(source_name),
OfferDecl::Directory(OfferDirectoryDecl { source_name, .. }) => Some(source_name),
OfferDecl::Runner(OfferRunnerDecl { source_name, .. }) => Some(source_name),
OfferDecl::Storage(OfferStorageDecl { source_name, .. }) => Some(source_name),
OfferDecl::Resolver(OfferResolverDecl { source_name, .. }) => Some(source_name),
OfferDecl::Service(OfferServiceDecl { source_name, .. }) => Some(source_name),
OfferDecl::Config(OfferConfigurationDecl { source_name, .. }) => Some(source_name),
OfferDecl::EventStream(OfferEventStreamDecl { source_name, .. }) => {
Some(source_name)
}
OfferDecl::Dictionary(OfferDictionaryDecl { source_name, .. }) => Some(source_name),
},
}
}
pub fn source_capability_name(&self) -> Option<&Name> {
match self {
ComponentCapability::Offer(OfferDecl::Protocol(OfferProtocolDecl {
source: OfferSource::Capability(name),
..
})) => Some(name),
ComponentCapability::Expose(ExposeDecl::Protocol(ExposeProtocolDecl {
source: ExposeSource::Capability(name),
..
})) => Some(name),
ComponentCapability::Use(UseDecl::Protocol(UseProtocolDecl {
source: UseSource::Capability(name),
..
})) => Some(name),
_ => None,
}
}
/// Returns the path or name of the capability as a string, useful for debugging.
pub fn source_id(&self) -> String {
self.source_name()
.map(|p| format!("{}", p))
.or_else(|| self.source_path().map(|p| format!("{}", p)))
.unwrap_or_default()
}
}
impl From<CapabilityDecl> for ComponentCapability {
fn from(capability: CapabilityDecl) -> Self {
match capability {
CapabilityDecl::Service(c) => ComponentCapability::Service(c),
CapabilityDecl::Protocol(c) => ComponentCapability::Protocol(c),
CapabilityDecl::Directory(c) => ComponentCapability::Directory(c),
CapabilityDecl::Storage(c) => ComponentCapability::Storage(c),
CapabilityDecl::Runner(c) => ComponentCapability::Runner(c),
CapabilityDecl::Resolver(c) => ComponentCapability::Resolver(c),
CapabilityDecl::EventStream(c) => ComponentCapability::EventStream(c),
CapabilityDecl::Dictionary(c) => ComponentCapability::Dictionary(c),
CapabilityDecl::Config(c) => ComponentCapability::Config(c),
}
}
}
impl fmt::Display for ComponentCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} '{}' from component", self.type_name(), self.source_id())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum EnvironmentCapability {
Runner { source_name: Name, source: RegistrationSource },
Resolver { source_name: Name, source: RegistrationSource },
Debug { source_name: Name, source: RegistrationSource },
}
impl EnvironmentCapability {
pub fn registration_source(&self) -> &RegistrationSource {
match self {
Self::Runner { source, .. }
| Self::Resolver { source, .. }
| Self::Debug { source, .. } => &source,
}
}
}
/// Describes a capability provided by component manager that is an aggregation
/// of multiple instances of a capability.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum AggregateCapability {
Service(Name),
}
impl AggregateCapability {
/// Returns true if the AggregateCapability can be available in a component's namespace.
pub fn can_be_in_namespace(&self) -> bool {
matches!(self, AggregateCapability::Service(_))
}
/// Returns a name for the capability type.
pub fn type_name(&self) -> CapabilityTypeName {
match self {
AggregateCapability::Service(_) => CapabilityTypeName::Service,
}
}
pub fn source_name(&self) -> &Name {
match self {
AggregateCapability::Service(name) => &name,
}
}
}
impl fmt::Display for AggregateCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "aggregate {} '{}'", self.type_name(), self.source_name())
}
}
impl From<ServiceDecl> for AggregateCapability {
fn from(service: ServiceDecl) -> Self {
Self::Service(service.name)
}
}
/// The list of declarations for capabilities from component manager's namespace.
pub type NamespaceCapabilities = Vec<CapabilityDecl>;
/// The list of declarations for capabilities offered by component manager as built-in capabilities.
pub type BuiltinCapabilities = Vec<CapabilityDecl>;
#[cfg(test)]
mod tests {
use {super::*, cm_rust::StorageDirectorySource, fidl_fuchsia_component_decl as fdecl};
#[test]
fn capability_type_name() {
let storage_capability = ComponentCapability::Storage(StorageDecl {
name: "foo".parse().unwrap(),
source: StorageDirectorySource::Parent,
backing_dir: "bar".parse().unwrap(),
subdir: Default::default(),
storage_id: fdecl::StorageId::StaticInstanceIdOrMoniker,
});
assert_eq!(storage_capability.type_name(), CapabilityTypeName::Storage);
}
}