blob: 396826787cb9dfcd1ebaded5c12df3bad00caa03 [file] [log] [blame]
// Copyright 2019 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 {
cm_fidl_validator, cm_types, fidl_fuchsia_data as fdata, fidl_fuchsia_io2 as fio2,
fidl_fuchsia_sys2 as fsys,
lazy_static::lazy_static,
std::collections::HashMap,
std::convert::{From, TryFrom, TryInto},
std::fmt,
std::path::PathBuf,
std::str::FromStr,
thiserror::Error,
};
pub mod data;
lazy_static! {
static ref DATA_TYPENAME: CapabilityName = CapabilityName("Data".to_string());
static ref CACHE_TYPENAME: CapabilityName = CapabilityName("Cache".to_string());
static ref META_TYPENAME: CapabilityName = CapabilityName("Meta".to_string());
}
/// Converts a fidl object into its corresponding native representation.
pub trait FidlIntoNative<T> {
fn fidl_into_native(self) -> T;
}
pub trait NativeIntoFidl<T> {
fn native_into_fidl(self) -> T;
}
/// Generates `FidlIntoNative` and `NativeIntoFidl` implementations for a basic type from
/// `Option<type>` that respectively unwraps the Option and wraps the internal value in a `Some()`.
macro_rules! fidl_translations_opt_type {
($into_type:ty) => {
impl FidlIntoNative<$into_type> for Option<$into_type> {
fn fidl_into_native(self) -> $into_type {
self.unwrap()
}
}
impl NativeIntoFidl<Option<$into_type>> for $into_type {
fn native_into_fidl(self) -> Option<$into_type> {
Some(self)
}
}
};
}
/// Generates `FidlIntoNative` and `NativeIntoFidl` implementations that leaves the input unchanged.
macro_rules! fidl_translations_identical {
($into_type:ty) => {
impl FidlIntoNative<$into_type> for $into_type {
fn fidl_into_native(self) -> $into_type {
self
}
}
impl NativeIntoFidl<$into_type> for $into_type {
fn native_into_fidl(self) -> Self {
self
}
}
};
}
/// Generates a struct with a `FidlIntoNative` implementation that calls `fidl_into_native()` on
/// each field. The `from_type` must be a FIDL table, not a FIDL struct.
/// - `into_type` is the name of the struct and the into type for the conversion.
/// - `into_ident` must be identical to `into_type`.
/// - `from_type` is the from type for the conversion.
/// - `from_path` must be identical to `from_type`.
/// - `field: type` form a list of fields and their types for the generated struct.
macro_rules! fidl_into_struct {
($into_type:ty, $into_ident:ident, $from_type:ty, $from_path:path,
{ $( $field:ident: $type:ty, )+ } ) => {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct $into_ident {
$(
pub $field: $type,
)+
}
impl FidlIntoNative<$into_type> for $from_type {
fn fidl_into_native(self) -> $into_type {
$into_ident { $( $field: self.$field.fidl_into_native(), )+ }
}
}
impl NativeIntoFidl<$from_type> for $into_type {
fn native_into_fidl(self) -> $from_type {
use $from_path as from_ident;
from_ident {
$( $field: self.$field.native_into_fidl(), )+
..from_ident::EMPTY
}
}
}
}
}
/// Generates an enum with a `FidlIntoNative` implementation that calls `fidl_into_native()` on each
/// field.
/// - `into_type` is the name of the enum and the into type for the conversion.
/// - `into_ident` must be identical to `into_type`.
/// - `from_type` is the from type for the conversion.
/// - `from_path` must be identical to `from_type`.
/// - `from_unknown` is the from unknown macro, i.e. `from_path` with "Unknown" appended
/// - `variant(type)` form a list of variants and their types for the generated enum.
macro_rules! fidl_into_enum {
($into_type:ty, $into_ident:ident, $from_type:ty, $from_path:path, $from_unknown:path,
{ $( $variant:ident($type:ty), )+ } ) => {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum $into_ident {
$(
$variant($type),
)+
}
impl FidlIntoNative<$into_type> for $from_type {
fn fidl_into_native(self) -> $into_type {
use $from_path as from_ident;
match self {
$(
from_ident::$variant(e) => $into_ident::$variant(e.fidl_into_native()),
)+
$from_unknown!() => { panic!("invalid variant") }
}
}
}
impl NativeIntoFidl<$from_type> for $into_type {
fn native_into_fidl(self) -> $from_type {
use $from_path as from_ident;
match self {
$(
$into_ident::$variant(e) => from_ident::$variant(e.native_into_fidl()),
)+
}
}
}
}
}
/// Generates `FidlIntoNative` and `NativeIntoFidl` implementations between `Vec` and
/// `Option<Vec>`.
/// - `into_type` is the name of the struct and the into type for the conversion.
/// - `from_type` is the from type for the conversion.
macro_rules! fidl_into_vec {
($into_type:ty, $from_type:ty) => {
impl FidlIntoNative<Vec<$into_type>> for Option<Vec<$from_type>> {
fn fidl_into_native(self) -> Vec<$into_type> {
if let Some(from) = self {
from.into_iter().map(|e: $from_type| e.fidl_into_native()).collect()
} else {
vec![]
}
}
}
impl NativeIntoFidl<Option<Vec<$from_type>>> for Vec<$into_type> {
fn native_into_fidl(self) -> Option<Vec<$from_type>> {
if self.is_empty() {
None
} else {
Some(self.into_iter().map(|e: $into_type| e.native_into_fidl()).collect())
}
}
}
};
}
#[derive(Debug, PartialEq, Default)]
pub struct ComponentDecl {
pub program: Option<fdata::Dictionary>,
pub uses: Vec<UseDecl>,
pub exposes: Vec<ExposeDecl>,
pub offers: Vec<OfferDecl>,
pub capabilities: Vec<CapabilityDecl>,
pub children: Vec<ChildDecl>,
pub collections: Vec<CollectionDecl>,
pub facets: Option<fsys::Object>,
pub environments: Vec<EnvironmentDecl>,
}
impl FidlIntoNative<ComponentDecl> for fsys::ComponentDecl {
fn fidl_into_native(self) -> ComponentDecl {
// When transforming ExposeDecl::Service and OfferDecl::Service from
// FIDL to native, we aggregate the declarations by target.
let mut exposes = vec![];
if let Some(e) = self.exposes {
let mut services: HashMap<(ExposeTarget, CapabilityName), Vec<_>> = HashMap::new();
for expose in e.into_iter() {
match expose {
fsys::ExposeDecl::Service(s) => services
.entry((s.target.fidl_into_native(), s.target_name.fidl_into_native()))
.or_default()
.push(ServiceSource::<ExposeServiceSource> {
source: s.source.fidl_into_native(),
source_name: s.source_name.fidl_into_native(),
}),
fsys::ExposeDecl::Protocol(ls) => {
exposes.push(ExposeDecl::Protocol(ls.fidl_into_native()))
}
fsys::ExposeDecl::Directory(d) => {
exposes.push(ExposeDecl::Directory(d.fidl_into_native()))
}
fsys::ExposeDecl::Runner(r) => {
exposes.push(ExposeDecl::Runner(r.fidl_into_native()))
}
fsys::ExposeDecl::Resolver(r) => {
exposes.push(ExposeDecl::Resolver(r.fidl_into_native()))
}
fsys::ExposeDeclUnknown!() => panic!("invalid variant"),
}
}
for ((target, target_name), sources) in services.into_iter() {
exposes.push(ExposeDecl::Service(ExposeServiceDecl {
sources,
target,
target_name,
}))
}
}
let mut offers = vec![];
if let Some(o) = self.offers {
let mut services: HashMap<(OfferTarget, CapabilityName), Vec<_>> = HashMap::new();
for offer in o.into_iter() {
match offer {
fsys::OfferDecl::Service(s) => services
.entry((s.target.fidl_into_native(), s.target_name.fidl_into_native()))
.or_default()
.push(ServiceSource::<OfferServiceSource> {
source: s.source.fidl_into_native(),
source_name: s.source_name.fidl_into_native(),
}),
fsys::OfferDecl::Protocol(ls) => {
offers.push(OfferDecl::Protocol(ls.fidl_into_native()))
}
fsys::OfferDecl::Directory(d) => {
offers.push(OfferDecl::Directory(d.fidl_into_native()))
}
fsys::OfferDecl::Storage(s) => {
offers.push(OfferDecl::Storage(s.fidl_into_native()))
}
fsys::OfferDecl::Runner(s) => {
offers.push(OfferDecl::Runner(s.fidl_into_native()))
}
fsys::OfferDecl::Resolver(r) => {
offers.push(OfferDecl::Resolver(r.fidl_into_native()))
}
fsys::OfferDecl::Event(e) => {
offers.push(OfferDecl::Event(e.fidl_into_native()))
}
fsys::OfferDeclUnknown!() => panic!("invalid variant"),
}
}
for ((target, target_name), sources) in services.into_iter() {
offers.push(OfferDecl::Service(OfferServiceDecl { sources, target, target_name }))
}
}
ComponentDecl {
program: self.program.fidl_into_native(),
uses: self.uses.fidl_into_native(),
exposes,
offers,
capabilities: self.capabilities.fidl_into_native(),
children: self.children.fidl_into_native(),
collections: self.collections.fidl_into_native(),
facets: self.facets.fidl_into_native(),
environments: self.environments.fidl_into_native(),
}
}
}
impl NativeIntoFidl<fsys::ComponentDecl> for ComponentDecl {
fn native_into_fidl(self) -> fsys::ComponentDecl {
// When transforming ExposeDecl::Service and OfferDecl::Service from
// native to FIDL, we disaggregate the declarations.
let mut exposes = vec![];
for expose in self.exposes.into_iter() {
match expose {
ExposeDecl::Service(s) => {
for es in s.sources.into_iter() {
exposes.push(fsys::ExposeDecl::Service(fsys::ExposeServiceDecl {
source: es.source.native_into_fidl(),
source_name: es.source_name.native_into_fidl(),
target: s.target.clone().native_into_fidl(),
target_name: s.target_name.clone().native_into_fidl(),
..fsys::ExposeServiceDecl::EMPTY
}))
}
}
ExposeDecl::Protocol(ls) => {
exposes.push(fsys::ExposeDecl::Protocol(ls.native_into_fidl()))
}
ExposeDecl::Directory(d) => {
exposes.push(fsys::ExposeDecl::Directory(d.native_into_fidl()))
}
ExposeDecl::Runner(r) => {
exposes.push(fsys::ExposeDecl::Runner(r.native_into_fidl()))
}
ExposeDecl::Resolver(r) => {
exposes.push(fsys::ExposeDecl::Resolver(r.native_into_fidl()))
}
}
}
let mut offers = vec![];
for offer in self.offers.into_iter() {
match offer {
OfferDecl::Service(s) => {
for os in s.sources.into_iter() {
offers.push(fsys::OfferDecl::Service(fsys::OfferServiceDecl {
source: os.source.native_into_fidl(),
source_name: os.source_name.native_into_fidl(),
target: s.target.clone().native_into_fidl(),
target_name: s.target_name.clone().native_into_fidl(),
..fsys::OfferServiceDecl::EMPTY
}))
}
}
OfferDecl::Protocol(ls) => {
offers.push(fsys::OfferDecl::Protocol(ls.native_into_fidl()))
}
OfferDecl::Directory(d) => {
offers.push(fsys::OfferDecl::Directory(d.native_into_fidl()))
}
OfferDecl::Storage(s) => {
offers.push(fsys::OfferDecl::Storage(s.native_into_fidl()))
}
OfferDecl::Runner(s) => offers.push(fsys::OfferDecl::Runner(s.native_into_fidl())),
OfferDecl::Resolver(r) => {
offers.push(fsys::OfferDecl::Resolver(r.native_into_fidl()))
}
OfferDecl::Event(e) => offers.push(fsys::OfferDecl::Event(e.native_into_fidl())),
}
}
fsys::ComponentDecl {
program: self.program.native_into_fidl(),
uses: self.uses.native_into_fidl(),
exposes: if exposes.is_empty() { None } else { Some(exposes) },
offers: if offers.is_empty() { None } else { Some(offers) },
capabilities: self.capabilities.native_into_fidl(),
children: self.children.native_into_fidl(),
collections: self.collections.native_into_fidl(),
facets: self.facets.native_into_fidl(),
environments: self.environments.native_into_fidl(),
..fsys::ComponentDecl::EMPTY
}
}
}
impl Clone for ComponentDecl {
fn clone(&self) -> Self {
ComponentDecl {
program: data::clone_option_dictionary(&self.program),
uses: self.uses.clone(),
exposes: self.exposes.clone(),
offers: self.offers.clone(),
capabilities: self.capabilities.clone(),
children: self.children.clone(),
collections: self.collections.clone(),
facets: data::clone_option_object(&self.facets),
environments: self.environments.clone(),
}
}
}
impl ComponentDecl {
/// Returns the `UseRunnerDecl` for this component, or `None` if this is a non-executable
/// component.
pub fn get_used_runner(&self) -> Option<&UseRunnerDecl> {
self.uses.iter().find_map(|u| match u {
UseDecl::Runner(runner) => Some(runner),
_ => return None,
})
}
/// Returns the `StorageDecl` corresponding to `storage_name`.
pub fn find_storage_source<'a>(
&'a self,
storage_name: &CapabilityName,
) -> Option<&'a StorageDecl> {
self.capabilities.iter().find_map(|c| match c {
CapabilityDecl::Storage(s) if &s.name == storage_name => Some(s),
_ => None,
})
}
/// Returns the `ProtocolDecl` corresponding to `protocol_name`.
pub fn find_protocol_source<'a>(
&'a self,
protocol_name: &CapabilityName,
) -> Option<&'a ProtocolDecl> {
self.capabilities.iter().find_map(|c| match c {
CapabilityDecl::Protocol(r) if &r.name == protocol_name => Some(r),
_ => None,
})
}
/// Returns the `DirectoryDecl` corresponding to `directory_name`.
pub fn find_directory_source<'a>(
&'a self,
directory_name: &CapabilityName,
) -> Option<&'a DirectoryDecl> {
self.capabilities.iter().find_map(|c| match c {
CapabilityDecl::Directory(r) if &r.name == directory_name => Some(r),
_ => None,
})
}
/// Returns the `RunnerDecl` corresponding to `runner_name`.
pub fn find_runner_source<'a>(
&'a self,
runner_name: &CapabilityName,
) -> Option<&'a RunnerDecl> {
self.capabilities.iter().find_map(|c| match c {
CapabilityDecl::Runner(r) if &r.name == runner_name => Some(r),
_ => None,
})
}
/// Returns the `ResolverDecl` corresponding to `resolver_name`.
pub fn find_resolver_source<'a>(
&'a self,
resolver_name: &CapabilityName,
) -> Option<&'a ResolverDecl> {
self.capabilities.iter().find_map(|c| match c {
CapabilityDecl::Resolver(r) if &r.name == resolver_name => Some(r),
_ => None,
})
}
/// Returns the `CollectionDecl` corresponding to `collection_name`.
pub fn find_collection<'a>(&'a self, collection_name: &str) -> Option<&'a CollectionDecl> {
self.collections.iter().find(|c| c.name == collection_name)
}
/// Indicates whether the capability specified by `target_name` is exposed to the framework.
pub fn is_protocol_exposed_to_framework(&self, in_target_name: &CapabilityName) -> bool {
self.exposes.iter().any(|expose| match expose {
ExposeDecl::Protocol(ExposeProtocolDecl { target, target_name, .. })
if target == &ExposeTarget::Framework =>
{
target_name == in_target_name
}
_ => false,
})
}
/// Indicates whether the capability specified by `source_name` is requested.
pub fn uses_protocol(&self, source_name: &CapabilityName) -> bool {
self.uses.iter().any(|use_decl| match use_decl {
UseDecl::Protocol(ls) => &ls.source_name == source_name,
_ => false,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExposeDecl {
Service(ExposeServiceDecl),
Protocol(ExposeProtocolDecl),
Directory(ExposeDirectoryDecl),
Runner(ExposeRunnerDecl),
Resolver(ExposeResolverDecl),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExposeServiceDecl {
pub sources: Vec<ServiceSource<ExposeServiceSource>>,
pub target: ExposeTarget,
pub target_name: CapabilityName,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OfferDecl {
Service(OfferServiceDecl),
Protocol(OfferProtocolDecl),
Directory(OfferDirectoryDecl),
Storage(OfferStorageDecl),
Runner(OfferRunnerDecl),
Resolver(OfferResolverDecl),
Event(OfferEventDecl),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OfferServiceDecl {
pub sources: Vec<ServiceSource<OfferServiceSource>>,
pub target: OfferTarget,
pub target_name: CapabilityName,
}
fidl_into_enum!(UseDecl, UseDecl, fsys::UseDecl, fsys::UseDecl, fsys::UseDeclUnknown,
{
Service(UseServiceDecl),
Protocol(UseProtocolDecl),
Directory(UseDirectoryDecl),
Storage(UseStorageDecl),
Runner(UseRunnerDecl),
Event(UseEventDecl),
EventStream(UseEventStreamDecl),
});
fidl_into_struct!(UseServiceDecl, UseServiceDecl, fsys::UseServiceDecl, fsys::UseServiceDecl,
{
source: UseSource,
source_name: CapabilityName,
target_path: CapabilityPath,
});
fidl_into_struct!(UseProtocolDecl, UseProtocolDecl, fsys::UseProtocolDecl, fsys::UseProtocolDecl,
{
source: UseSource,
source_name: CapabilityName,
target_path: CapabilityPath,
});
fidl_into_struct!(UseDirectoryDecl, UseDirectoryDecl, fsys::UseDirectoryDecl,
fsys::UseDirectoryDecl,
{
source: UseSource,
source_name: CapabilityName,
target_path: CapabilityPath,
rights: fio2::Operations,
subdir: Option<PathBuf>,
});
fidl_into_struct!(UseStorageDecl, UseStorageDecl, fsys::UseStorageDecl, fsys::UseStorageDecl,
{
source_name: CapabilityName,
target_path: CapabilityPath,
});
fidl_into_struct!(UseRunnerDecl, UseRunnerDecl, fsys::UseRunnerDecl,
fsys::UseRunnerDecl,
{
source_name: CapabilityName,
});
fidl_into_struct!(EventSubscription, EventSubscription, fsys::EventSubscription,
fsys::EventSubscription, {
event_name: String,
mode: EventMode,
});
fidl_into_struct!(UseEventDecl, UseEventDecl, fsys::UseEventDecl,
fsys::UseEventDecl,
{
source: UseSource,
source_name: CapabilityName,
target_name: CapabilityName,
filter: Option<HashMap<String, DictionaryValue>>,
mode: EventMode,
});
fidl_into_struct!(UseEventStreamDecl, UseEventStreamDecl, fsys::UseEventStreamDecl,
fsys::UseEventStreamDecl,
{
target_path: CapabilityPath,
events: Vec<EventSubscription>,
});
fidl_into_struct!(ExposeProtocolDecl, ExposeProtocolDecl, fsys::ExposeProtocolDecl,
fsys::ExposeProtocolDecl,
{
source: ExposeSource,
source_name: CapabilityName,
target: ExposeTarget,
target_name: CapabilityName,
});
fidl_into_struct!(ExposeDirectoryDecl, ExposeDirectoryDecl, fsys::ExposeDirectoryDecl,
fsys::ExposeDirectoryDecl,
{
source: ExposeSource,
source_name: CapabilityName,
target: ExposeTarget,
target_name: CapabilityName,
rights: Option<fio2::Operations>,
subdir: Option<PathBuf>,
});
fidl_into_struct!(ExposeResolverDecl, ExposeResolverDecl, fsys::ExposeResolverDecl,
fsys::ExposeResolverDecl,
{
source: ExposeSource,
source_name: CapabilityName,
target: ExposeTarget,
target_name: CapabilityName,
});
fidl_into_struct!(ExposeRunnerDecl, ExposeRunnerDecl, fsys::ExposeRunnerDecl,
fsys::ExposeRunnerDecl,
{
source: ExposeSource,
source_name: CapabilityName,
target: ExposeTarget,
target_name: CapabilityName,
});
fidl_into_struct!(OfferProtocolDecl, OfferProtocolDecl, fsys::OfferProtocolDecl,
fsys::OfferProtocolDecl,
{
source: OfferServiceSource,
source_name: CapabilityName,
target: OfferTarget,
target_name: CapabilityName,
dependency_type: DependencyType,
});
fidl_into_struct!(OfferDirectoryDecl, OfferDirectoryDecl, fsys::OfferDirectoryDecl,
fsys::OfferDirectoryDecl,
{
source: OfferDirectorySource,
source_name: CapabilityName,
target: OfferTarget,
target_name: CapabilityName,
rights: Option<fio2::Operations>,
subdir: Option<PathBuf>,
dependency_type: DependencyType,
});
fidl_into_struct!(OfferStorageDecl, OfferStorageDecl, fsys::OfferStorageDecl,
fsys::OfferStorageDecl,
{
source_name: CapabilityName,
source: OfferStorageSource,
target: OfferTarget,
target_name: CapabilityName,
});
fidl_into_struct!(OfferResolverDecl, OfferResolverDecl, fsys::OfferResolverDecl,
fsys::OfferResolverDecl,
{
source: OfferResolverSource,
source_name: CapabilityName,
target: OfferTarget,
target_name: CapabilityName,
});
fidl_into_struct!(OfferRunnerDecl, OfferRunnerDecl, fsys::OfferRunnerDecl,
fsys::OfferRunnerDecl,
{
source: OfferRunnerSource,
source_name: CapabilityName,
target: OfferTarget,
target_name: CapabilityName,
});
fidl_into_struct!(OfferEventDecl, OfferEventDecl, fsys::OfferEventDecl,
fsys::OfferEventDecl,
{
source: OfferEventSource,
source_name: CapabilityName,
target: OfferTarget,
target_name: CapabilityName,
filter: Option<HashMap<String, DictionaryValue>>,
mode: EventMode,
});
fidl_into_enum!(CapabilityDecl, CapabilityDecl, fsys::CapabilityDecl, fsys::CapabilityDecl, fsys::CapabilityDeclUnknown,
{
Service(ServiceDecl),
Protocol(ProtocolDecl),
Directory(DirectoryDecl),
Storage(StorageDecl),
Runner(RunnerDecl), Resolver(ResolverDecl),
});
fidl_into_struct!(ServiceDecl, ServiceDecl, fsys::ServiceDecl, fsys::ServiceDecl,
{
name: CapabilityName,
source_path: CapabilityPath,
});
fidl_into_struct!(ProtocolDecl, ProtocolDecl, fsys::ProtocolDecl, fsys::ProtocolDecl,
{
name: CapabilityName,
source_path: CapabilityPath,
});
fidl_into_struct!(DirectoryDecl, DirectoryDecl, fsys::DirectoryDecl, fsys::DirectoryDecl,
{
name: CapabilityName,
source_path: CapabilityPath,
rights: fio2::Operations,
});
fidl_into_struct!(StorageDecl, StorageDecl, fsys::StorageDecl,
fsys::StorageDecl,
{
name: CapabilityName,
source: StorageDirectorySource,
backing_dir: CapabilityName,
subdir: Option<PathBuf>,
});
fidl_into_struct!(RunnerDecl, RunnerDecl, fsys::RunnerDecl, fsys::RunnerDecl,
{
name: CapabilityName,
source: RunnerSource,
source_path: CapabilityPath,
});
fidl_into_struct!(ResolverDecl, ResolverDecl, fsys::ResolverDecl, fsys::ResolverDecl,
{
name: CapabilityName,
source_path: CapabilityPath,
});
fidl_into_struct!(ChildDecl, ChildDecl, fsys::ChildDecl, fsys::ChildDecl,
{
name: String,
url: String,
startup: fsys::StartupMode,
environment: Option<String>,
});
fidl_into_struct!(CollectionDecl, CollectionDecl, fsys::CollectionDecl, fsys::CollectionDecl,
{
name: String,
durability: fsys::Durability,
environment: Option<String>,
});
fidl_into_struct!(EnvironmentDecl, EnvironmentDecl, fsys::EnvironmentDecl, fsys::EnvironmentDecl,
{
name: String,
extends: fsys::EnvironmentExtends,
runners: Vec<RunnerRegistration>,
resolvers: Vec<ResolverRegistration>,
stop_timeout_ms: Option<u32>,
});
fidl_into_struct!(RunnerRegistration, RunnerRegistration, fsys::RunnerRegistration,
fsys::RunnerRegistration,
{
source_name: CapabilityName,
source: RegistrationSource,
target_name: CapabilityName,
});
fidl_into_struct!(ResolverRegistration, ResolverRegistration, fsys::ResolverRegistration,
fsys::ResolverRegistration,
{
resolver: CapabilityName,
source: RegistrationSource,
scheme: String,
});
fidl_into_vec!(UseDecl, fsys::UseDecl);
fidl_into_vec!(ChildDecl, fsys::ChildDecl);
fidl_into_vec!(CollectionDecl, fsys::CollectionDecl);
fidl_into_vec!(CapabilityDecl, fsys::CapabilityDecl);
fidl_into_vec!(EnvironmentDecl, fsys::EnvironmentDecl);
fidl_into_vec!(RunnerRegistration, fsys::RunnerRegistration);
fidl_into_vec!(ResolverRegistration, fsys::ResolverRegistration);
fidl_into_vec!(EventSubscription, fsys::EventSubscription);
fidl_translations_opt_type!(Vec<String>);
fidl_translations_opt_type!(String);
fidl_translations_opt_type!(fsys::StartupMode);
fidl_translations_opt_type!(fsys::Durability);
fidl_translations_opt_type!(fsys::Object);
fidl_translations_opt_type!(fdata::Dictionary);
fidl_translations_opt_type!(fio2::Operations);
fidl_translations_opt_type!(fsys::EnvironmentExtends);
fidl_translations_identical!(Option<fio2::Operations>);
fidl_translations_identical!(Option<fsys::Object>);
fidl_translations_identical!(Option<fdata::Dictionary>);
fidl_translations_identical!(Option<String>);
/// A path to a capability.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CapabilityPath {
/// The directory containing the last path element, e.g. `/svc/foo` in `/svc/foo/bar`.
pub dirname: String,
/// The last path element: e.g. `bar` in `/svc/foo/bar`.
pub basename: String,
}
impl CapabilityPath {
pub fn to_path_buf(&self) -> PathBuf {
PathBuf::from(self.to_string())
}
/// Splits the path according to "/", ignoring empty path components
pub fn split(&self) -> Vec<String> {
self.to_string().split("/").map(|s| s.to_string()).filter(|s| !s.is_empty()).collect()
}
}
impl FromStr for CapabilityPath {
type Err = Error;
fn from_str(path: &str) -> Result<CapabilityPath, Error> {
cm_types::Path::validate(path)
.map_err(|_| Error::InvalidCapabilityPath { raw: path.to_string() })?;
let idx = path.rfind('/').expect("path validation is wrong");
Ok(CapabilityPath {
dirname: if idx == 0 { "/".to_string() } else { path[0..idx].to_string() },
basename: path[idx + 1..].to_string(),
})
}
}
impl TryFrom<&str> for CapabilityPath {
type Error = Error;
fn try_from(path: &str) -> Result<CapabilityPath, Error> {
Self::from_str(path)
}
}
impl fmt::Display for CapabilityPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if &self.dirname == "/" {
write!(f, "/{}", self.basename)
} else {
write!(f, "{}/{}", self.dirname, self.basename)
}
}
}
impl UseDecl {
pub fn path(&self) -> Option<&CapabilityPath> {
match self {
UseDecl::Service(d) => Some(&d.target_path),
UseDecl::Protocol(d) => Some(&d.target_path),
UseDecl::Directory(d) => Some(&d.target_path),
UseDecl::Storage(d) => Some(&d.target_path),
UseDecl::EventStream(e) => Some(&e.target_path),
UseDecl::Runner(_) | UseDecl::Event(_) => None,
}
}
pub fn name(&self) -> Option<&CapabilityName> {
match self {
UseDecl::Event(event_decl) => Some(&event_decl.source_name),
UseDecl::Runner(runner_decl) => Some(&runner_decl.source_name),
UseDecl::Storage(storage_decl) => Some(&storage_decl.source_name),
UseDecl::Service(_)
| UseDecl::Protocol(_)
| UseDecl::Directory(_)
| UseDecl::EventStream(_) => None,
}
}
}
/// A named capability.
///
/// Unlike a `CapabilityPath`, a `CapabilityName` doesn't encode any form
/// of hierarchy.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CapabilityName(pub String);
impl CapabilityName {
pub fn str(&self) -> &str {
&self.0
}
}
impl From<&str> for CapabilityName {
fn from(name: &str) -> CapabilityName {
CapabilityName(name.to_string())
}
}
impl From<String> for CapabilityName {
fn from(name: String) -> CapabilityName {
CapabilityName(name)
}
}
impl fmt::Display for CapabilityName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
/// A named capability type.
///
/// `CapabilityTypeName` provides a user friendly type encoding for a capability.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum CapabilityTypeName {
Directory,
Event,
EventStream,
Protocol,
Resolver,
Runner,
Service,
Storage,
}
impl fmt::Display for CapabilityTypeName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let display_name = match &self {
CapabilityTypeName::Directory => "directory",
CapabilityTypeName::Event => "event",
CapabilityTypeName::EventStream => "event_stream",
CapabilityTypeName::Protocol => "protocol",
CapabilityTypeName::Resolver => "resolver",
CapabilityTypeName::Runner => "runner",
CapabilityTypeName::Service => "service",
CapabilityTypeName::Storage => "storage",
};
write!(f, "{}", display_name)
}
}
// TODO: Runners and third parties can use this to parse `facets`.
impl FidlIntoNative<Option<HashMap<String, Value>>> for Option<fsys::Object> {
fn fidl_into_native(self) -> Option<HashMap<String, Value>> {
self.map(|o| from_fidl_obj(o))
}
}
impl FidlIntoNative<Option<HashMap<String, DictionaryValue>>> for Option<fdata::Dictionary> {
fn fidl_into_native(self) -> Option<HashMap<String, DictionaryValue>> {
self.map(|d| from_fidl_dict(d))
}
}
impl NativeIntoFidl<Option<fdata::Dictionary>> for Option<HashMap<String, DictionaryValue>> {
fn native_into_fidl(self) -> Option<fdata::Dictionary> {
self.map(|d| to_fidl_dict(d))
}
}
fidl_translations_identical!(Option<u32>);
impl FidlIntoNative<CapabilityPath> for Option<String> {
fn fidl_into_native(self) -> CapabilityPath {
let s: &str = &self.unwrap();
s.try_into().expect("invalid capability path")
}
}
impl NativeIntoFidl<Option<String>> for CapabilityPath {
fn native_into_fidl(self) -> Option<String> {
Some(self.to_string())
}
}
impl FidlIntoNative<Option<PathBuf>> for Option<String> {
fn fidl_into_native(self) -> Option<PathBuf> {
self.map(|p| PathBuf::from(p))
}
}
impl NativeIntoFidl<Option<String>> for Option<PathBuf> {
fn native_into_fidl(self) -> Option<String> {
self.map(|p| p.to_str().expect("invalid utf8").to_string())
}
}
impl FidlIntoNative<CapabilityName> for Option<String> {
fn fidl_into_native(self) -> CapabilityName {
let s: &str = &self.unwrap();
s.into()
}
}
impl NativeIntoFidl<Option<String>> for CapabilityName {
fn native_into_fidl(self) -> Option<String> {
Some(self.to_string())
}
}
impl FidlIntoNative<bool> for Option<bool> {
fn fidl_into_native(self) -> bool {
self.unwrap()
}
}
impl NativeIntoFidl<Option<bool>> for bool {
fn native_into_fidl(self) -> Option<bool> {
Some(self)
}
}
#[derive(Debug, PartialEq)]
pub enum Value {
Bit(bool),
Inum(i64),
Fnum(f64),
Str(String),
Vec(Vec<Value>),
Obj(HashMap<String, Value>),
Null,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DictionaryValue {
Str(String),
StrVec(Vec<String>),
Null,
}
impl FidlIntoNative<Value> for Option<Box<fsys::Value>> {
fn fidl_into_native(self) -> Value {
match self {
Some(v) => match *v {
fsys::Value::Bit(b) => Value::Bit(b),
fsys::Value::Inum(i) => Value::Inum(i),
fsys::Value::Fnum(f) => Value::Fnum(f),
fsys::Value::Str(s) => Value::Str(s),
fsys::Value::Vec(v) => Value::Vec(from_fidl_vec(v)),
fsys::Value::Obj(d) => Value::Obj(from_fidl_obj(d)),
},
None => Value::Null,
}
}
}
impl FidlIntoNative<DictionaryValue> for Option<Box<fdata::DictionaryValue>> {
fn fidl_into_native(self) -> DictionaryValue {
match self {
Some(v) => match *v {
fdata::DictionaryValue::Str(s) => DictionaryValue::Str(s),
fdata::DictionaryValue::StrVec(ss) => DictionaryValue::StrVec(ss),
},
None => DictionaryValue::Null,
}
}
}
impl NativeIntoFidl<Option<Box<fdata::DictionaryValue>>> for DictionaryValue {
fn native_into_fidl(self) -> Option<Box<fdata::DictionaryValue>> {
match self {
DictionaryValue::Str(s) => Some(Box::new(fdata::DictionaryValue::Str(s))),
DictionaryValue::StrVec(ss) => Some(Box::new(fdata::DictionaryValue::StrVec(ss))),
DictionaryValue::Null => None,
}
}
}
fn from_fidl_vec(vec: fsys::Vector) -> Vec<Value> {
vec.values.into_iter().map(|v| v.fidl_into_native()).collect()
}
fn from_fidl_obj(obj: fsys::Object) -> HashMap<String, Value> {
obj.entries.into_iter().map(|e| (e.key, e.value.fidl_into_native())).collect()
}
fn from_fidl_dict(dict: fdata::Dictionary) -> HashMap<String, DictionaryValue> {
match dict.entries {
Some(entries) => entries.into_iter().map(|e| (e.key, e.value.fidl_into_native())).collect(),
_ => HashMap::new(),
}
}
fn to_fidl_dict(dict: HashMap<String, DictionaryValue>) -> fdata::Dictionary {
fdata::Dictionary {
entries: Some(
dict.into_iter()
.map(|(key, value)| fdata::DictionaryEntry { key, value: value.native_into_fidl() })
.collect(),
),
..fdata::Dictionary::EMPTY
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UseSource {
Parent,
Framework,
Capability(CapabilityName),
}
impl FidlIntoNative<UseSource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> UseSource {
match self.unwrap() {
fsys::Ref::Parent(_) => UseSource::Parent,
fsys::Ref::Framework(_) => UseSource::Framework,
fsys::Ref::Capability(c) => UseSource::Capability(c.name.into()),
_ => panic!("invalid UseSource variant"),
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for UseSource {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
UseSource::Parent => fsys::Ref::Parent(fsys::ParentRef {}),
UseSource::Framework => fsys::Ref::Framework(fsys::FrameworkRef {}),
UseSource::Capability(name) => {
fsys::Ref::Capability(fsys::CapabilityRef { name: name.to_string() })
}
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExposeSource {
Self_,
Child(String),
Framework,
Capability(CapabilityName),
}
impl FidlIntoNative<ExposeSource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> ExposeSource {
match self.unwrap() {
fsys::Ref::Self_(_) => ExposeSource::Self_,
fsys::Ref::Child(c) => ExposeSource::Child(c.name),
fsys::Ref::Framework(_) => ExposeSource::Framework,
fsys::Ref::Capability(c) => ExposeSource::Capability(c.name.into()),
_ => panic!("invalid ExposeSource variant"),
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for ExposeSource {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
ExposeSource::Self_ => fsys::Ref::Self_(fsys::SelfRef {}),
ExposeSource::Child(child_name) => {
fsys::Ref::Child(fsys::ChildRef { name: child_name, collection: None })
}
ExposeSource::Framework => fsys::Ref::Framework(fsys::FrameworkRef {}),
ExposeSource::Capability(name) => {
fsys::Ref::Capability(fsys::CapabilityRef { name: name.to_string() })
}
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ExposeTarget {
Parent,
Framework,
}
impl FidlIntoNative<ExposeTarget> for Option<fsys::Ref> {
fn fidl_into_native(self) -> ExposeTarget {
match self {
Some(dest) => match dest {
fsys::Ref::Parent(_) => ExposeTarget::Parent,
fsys::Ref::Framework(_) => ExposeTarget::Framework,
_ => panic!("invalid ExposeTarget variant"),
},
None => ExposeTarget::Parent,
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for ExposeTarget {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
ExposeTarget::Parent => fsys::Ref::Parent(fsys::ParentRef {}),
ExposeTarget::Framework => fsys::Ref::Framework(fsys::FrameworkRef {}),
})
}
}
/// A source for a service.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ServiceSource<T> {
/// The provider of the service, relative to a component.
pub source: T,
/// The name of the service.
pub source_name: CapabilityName,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DependencyType {
Strong,
WeakForMigration,
}
impl FidlIntoNative<DependencyType> for Option<fsys::DependencyType> {
fn fidl_into_native(self) -> DependencyType {
match self.unwrap() {
fsys::DependencyType::Strong => DependencyType::Strong,
fsys::DependencyType::WeakForMigration => DependencyType::WeakForMigration,
}
}
}
impl NativeIntoFidl<Option<fsys::DependencyType>> for DependencyType {
fn native_into_fidl(self) -> Option<fsys::DependencyType> {
Some(match self {
DependencyType::Strong => fsys::DependencyType::Strong,
DependencyType::WeakForMigration => fsys::DependencyType::WeakForMigration,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OfferServiceSource {
Parent,
Self_,
Child(String),
Capability(CapabilityName),
}
impl FidlIntoNative<OfferServiceSource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> OfferServiceSource {
match self.unwrap() {
fsys::Ref::Parent(_) => OfferServiceSource::Parent,
fsys::Ref::Self_(_) => OfferServiceSource::Self_,
fsys::Ref::Child(c) => OfferServiceSource::Child(c.name),
fsys::Ref::Capability(c) => OfferServiceSource::Capability(c.name.into()),
_ => panic!("invalid OfferServiceSource variant"),
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for OfferServiceSource {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
OfferServiceSource::Parent => fsys::Ref::Parent(fsys::ParentRef {}),
OfferServiceSource::Self_ => fsys::Ref::Self_(fsys::SelfRef {}),
OfferServiceSource::Child(child_name) => {
fsys::Ref::Child(fsys::ChildRef { name: child_name, collection: None })
}
OfferServiceSource::Capability(name) => {
fsys::Ref::Capability(fsys::CapabilityRef { name: name.to_string() })
}
})
}
}
/// The valid sources of a service protocol's expose declaration.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExposeServiceSource {
/// The service is exposed from the component manager itself.
Framework,
/// The service is exposed by the component itself.
Self_,
/// The service is exposed by a named child component.
Child(String),
}
impl FidlIntoNative<ExposeServiceSource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> ExposeServiceSource {
match self.unwrap() {
fsys::Ref::Framework(_) => ExposeServiceSource::Framework,
fsys::Ref::Self_(_) => ExposeServiceSource::Self_,
fsys::Ref::Child(c) => ExposeServiceSource::Child(c.name),
_ => panic!("invalid ExposeServiceSource variant"),
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for ExposeServiceSource {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
ExposeServiceSource::Framework => fsys::Ref::Framework(fsys::FrameworkRef {}),
ExposeServiceSource::Self_ => fsys::Ref::Self_(fsys::SelfRef {}),
ExposeServiceSource::Child(child_name) => {
fsys::Ref::Child(fsys::ChildRef { name: child_name, collection: None })
}
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StorageDirectorySource {
Parent,
Self_,
Child(String),
}
impl FidlIntoNative<StorageDirectorySource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> StorageDirectorySource {
match self.unwrap() {
fsys::Ref::Parent(_) => StorageDirectorySource::Parent,
fsys::Ref::Self_(_) => StorageDirectorySource::Self_,
fsys::Ref::Child(c) => StorageDirectorySource::Child(c.name),
_ => panic!("invalid OfferDirectorySource variant"),
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for StorageDirectorySource {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
StorageDirectorySource::Parent => fsys::Ref::Parent(fsys::ParentRef {}),
StorageDirectorySource::Self_ => fsys::Ref::Self_(fsys::SelfRef {}),
StorageDirectorySource::Child(child_name) => {
fsys::Ref::Child(fsys::ChildRef { name: child_name, collection: None })
}
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RunnerSource {
Parent,
Self_,
Child(String),
}
impl FidlIntoNative<RunnerSource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> RunnerSource {
match self.unwrap() {
fsys::Ref::Parent(_) => RunnerSource::Parent,
fsys::Ref::Self_(_) => RunnerSource::Self_,
fsys::Ref::Child(c) => RunnerSource::Child(c.name),
_ => panic!("invalid RunnerSource variant"),
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for RunnerSource {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
RunnerSource::Parent => fsys::Ref::Parent(fsys::ParentRef {}),
RunnerSource::Self_ => fsys::Ref::Self_(fsys::SelfRef {}),
RunnerSource::Child(child_name) => {
fsys::Ref::Child(fsys::ChildRef { name: child_name, collection: None })
}
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RegistrationSource {
Parent,
Self_,
Child(String),
}
impl FidlIntoNative<RegistrationSource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> RegistrationSource {
match self.unwrap() {
fsys::Ref::Parent(_) => RegistrationSource::Parent,
fsys::Ref::Self_(_) => RegistrationSource::Self_,
fsys::Ref::Child(c) => RegistrationSource::Child(c.name),
_ => panic!("invalid RegistrationSource variant"),
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for RegistrationSource {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
RegistrationSource::Parent => fsys::Ref::Parent(fsys::ParentRef {}),
RegistrationSource::Self_ => fsys::Ref::Self_(fsys::SelfRef {}),
RegistrationSource::Child(child_name) => {
fsys::Ref::Child(fsys::ChildRef { name: child_name, collection: None })
}
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OfferDirectorySource {
Parent,
Self_,
Framework,
Child(String),
}
impl FidlIntoNative<OfferDirectorySource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> OfferDirectorySource {
match self.unwrap() {
fsys::Ref::Parent(_) => OfferDirectorySource::Parent,
fsys::Ref::Self_(_) => OfferDirectorySource::Self_,
fsys::Ref::Framework(_) => OfferDirectorySource::Framework,
fsys::Ref::Child(c) => OfferDirectorySource::Child(c.name),
_ => panic!("invalid OfferDirectorySource variant"),
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for OfferDirectorySource {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
OfferDirectorySource::Parent => fsys::Ref::Parent(fsys::ParentRef {}),
OfferDirectorySource::Self_ => fsys::Ref::Self_(fsys::SelfRef {}),
OfferDirectorySource::Framework => fsys::Ref::Framework(fsys::FrameworkRef {}),
OfferDirectorySource::Child(child_name) => {
fsys::Ref::Child(fsys::ChildRef { name: child_name, collection: None })
}
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OfferStorageSource {
Parent,
Self_,
}
impl FidlIntoNative<OfferStorageSource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> OfferStorageSource {
match self.unwrap() {
fsys::Ref::Parent(_) => OfferStorageSource::Parent,
fsys::Ref::Self_(_) => OfferStorageSource::Self_,
_ => panic!("invalid OfferStorageSource variant"),
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for OfferStorageSource {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
OfferStorageSource::Parent => fsys::Ref::Parent(fsys::ParentRef {}),
OfferStorageSource::Self_ => fsys::Ref::Self_(fsys::SelfRef {}),
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OfferRunnerSource {
Parent,
Self_,
Child(String),
}
impl FidlIntoNative<OfferRunnerSource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> OfferRunnerSource {
match self.unwrap() {
fsys::Ref::Parent(_) => OfferRunnerSource::Parent,
fsys::Ref::Self_(_) => OfferRunnerSource::Self_,
fsys::Ref::Child(c) => OfferRunnerSource::Child(c.name),
_ => panic!("invalid OfferRunnerSource variant"),
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for OfferRunnerSource {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
OfferRunnerSource::Parent => fsys::Ref::Parent(fsys::ParentRef {}),
OfferRunnerSource::Self_ => fsys::Ref::Self_(fsys::SelfRef {}),
OfferRunnerSource::Child(child_name) => {
fsys::Ref::Child(fsys::ChildRef { name: child_name, collection: None })
}
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OfferResolverSource {
Parent,
Self_,
Child(String),
}
impl FidlIntoNative<OfferResolverSource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> OfferResolverSource {
match self.unwrap() {
fsys::Ref::Parent(_) => OfferResolverSource::Parent,
fsys::Ref::Self_(_) => OfferResolverSource::Self_,
fsys::Ref::Child(c) => OfferResolverSource::Child(c.name),
_ => panic!("invalid OfferResolverSource variant"),
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for OfferResolverSource {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
OfferResolverSource::Parent => fsys::Ref::Parent(fsys::ParentRef {}),
OfferResolverSource::Self_ => fsys::Ref::Self_(fsys::SelfRef {}),
OfferResolverSource::Child(child_name) => {
fsys::Ref::Child(fsys::ChildRef { name: child_name, collection: None })
}
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OfferEventSource {
Framework,
Parent,
}
impl FidlIntoNative<OfferEventSource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> OfferEventSource {
match self.unwrap() {
fsys::Ref::Framework(_) => OfferEventSource::Framework,
fsys::Ref::Parent(_) => OfferEventSource::Parent,
_ => panic!("invalid OfferEventSource variant"),
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for OfferEventSource {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
OfferEventSource::Framework => fsys::Ref::Framework(fsys::FrameworkRef {}),
OfferEventSource::Parent => fsys::Ref::Parent(fsys::ParentRef {}),
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EventMode {
Sync,
Async,
}
impl NativeIntoFidl<Option<fsys::EventMode>> for EventMode {
fn native_into_fidl(self) -> Option<fsys::EventMode> {
match self {
EventMode::Sync => Some(fsys::EventMode::Sync),
EventMode::Async => Some(fsys::EventMode::Async),
}
}
}
impl FidlIntoNative<EventMode> for Option<fsys::EventMode> {
fn fidl_into_native(self) -> EventMode {
match self {
Some(fsys::EventMode::Sync) => EventMode::Sync,
Some(fsys::EventMode::Async) => EventMode::Async,
None => panic!("invalid EventMode variant"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum OfferTarget {
Child(String),
Collection(String),
}
impl FidlIntoNative<OfferTarget> for fsys::Ref {
fn fidl_into_native(self) -> OfferTarget {
match self {
fsys::Ref::Child(c) => OfferTarget::Child(c.name),
fsys::Ref::Collection(c) => OfferTarget::Collection(c.name),
_ => panic!("invalid OfferTarget variant"),
}
}
}
impl NativeIntoFidl<fsys::Ref> for OfferTarget {
fn native_into_fidl(self) -> fsys::Ref {
match self {
OfferTarget::Child(child_name) => {
fsys::Ref::Child(fsys::ChildRef { name: child_name, collection: None })
}
OfferTarget::Collection(collection_name) => {
fsys::Ref::Collection(fsys::CollectionRef { name: collection_name })
}
}
}
}
impl FidlIntoNative<OfferTarget> for Option<fsys::Ref> {
fn fidl_into_native(self) -> OfferTarget {
self.unwrap().fidl_into_native()
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for OfferTarget {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(self.native_into_fidl())
}
}
/// Converts the contents of a CM-FIDL declaration and produces the equivalent CM-Rust
/// struct.
/// This function applies cm_fidl_validator to check correctness.
impl TryFrom<fsys::ComponentDecl> for ComponentDecl {
type Error = Error;
fn try_from(decl: fsys::ComponentDecl) -> Result<Self, Self::Error> {
cm_fidl_validator::validate(&decl).map_err(|err| Error::Validate { err })?;
Ok(decl.fidl_into_native())
}
}
// Converts the contents of a CM-Rust declaration into a CM_FIDL declaration
impl TryFrom<ComponentDecl> for fsys::ComponentDecl {
type Error = Error;
fn try_from(decl: ComponentDecl) -> Result<Self, Self::Error> {
Ok(decl.native_into_fidl())
}
}
/// Errors produced by cm_rust.
#[derive(Debug, Error)]
pub enum Error {
#[error("Fidl validation failed: {}", err)]
Validate {
#[source]
err: cm_fidl_validator::ErrorList,
},
#[error("Invalid capability path: {}", raw)]
InvalidCapabilityPath { raw: String },
}
#[cfg(test)]
mod tests {
use {super::*, maplit::hashmap};
macro_rules! test_try_from_decl {
(
$(
$test_name:ident => {
input = $input:expr,
result = $result:expr,
},
)+
) => {
$(
#[test]
fn $test_name() {
{
let res = ComponentDecl::try_from($input).expect("try_from failed");
assert_eq!(res, $result);
}
{
let res = fsys::ComponentDecl::try_from($result).expect("try_from failed");
assert_eq!(res, $input);
}
}
)+
}
}
macro_rules! test_fidl_into_and_from {
(
$(
$test_name:ident => {
input = $input:expr,
input_type = $input_type:ty,
result = $result:expr,
result_type = $result_type:ty,
},
)+
) => {
$(
#[test]
fn $test_name() {
{
let res: Vec<$result_type> =
$input.into_iter().map(|e| e.fidl_into_native()).collect();
assert_eq!(res, $result);
}
{
let res: Vec<$input_type> =
$result.into_iter().map(|e| e.native_into_fidl()).collect();
assert_eq!(res, $input);
}
}
)+
}
}
macro_rules! test_fidl_into {
(
$(
$test_name:ident => {
input = $input:expr,
result = $result:expr,
},
)+
) => {
$(
#[test]
fn $test_name() {
test_fidl_into_helper($input, $result);
}
)+
}
}
fn test_fidl_into_helper<T, U>(input: T, expected_res: U)
where
T: FidlIntoNative<U>,
U: std::cmp::PartialEq + std::fmt::Debug,
{
let res: U = input.fidl_into_native();
assert_eq!(res, expected_res);
}
macro_rules! test_capability_path {
(
$(
$test_name:ident => {
input = $input:expr,
result = $result:expr,
},
)+
) => {
$(
#[test]
fn $test_name() {
test_capability_path_helper($input, $result);
}
)+
}
}
fn test_capability_path_helper(input: &str, result: Result<CapabilityPath, Error>) {
let res = CapabilityPath::try_from(input);
assert_eq!(format!("{:?}", res), format!("{:?}", result));
if let Ok(p) = res {
assert_eq!(&p.to_string(), input);
}
}
test_try_from_decl! {
try_from_empty => {
input = fsys::ComponentDecl {
program: None,
uses: None,
exposes: None,
offers: None,
capabilities: None,
children: None,
collections: None,
facets: None,
environments: None,
..fsys::ComponentDecl::EMPTY
},
result = ComponentDecl {
program: None,
uses: vec![],
exposes: vec![],
offers: vec![],
capabilities: vec![],
children: vec![],
collections: vec![],
facets: None,
environments: vec![],
},
},
try_from_all => {
input = fsys::ComponentDecl {
program: Some(fdata::Dictionary{entries: Some(vec![
fdata::DictionaryEntry {
key: "args".to_string(),
value: Some(Box::new(fdata::DictionaryValue::StrVec(vec!["foo".to_string(), "bar".to_string()]))),
},
fdata::DictionaryEntry {
key: "binary".to_string(),
value: Some(Box::new(fdata::DictionaryValue::Str("bin/app".to_string()))),
},
]), ..fdata::Dictionary::EMPTY}),
uses: Some(vec![
fsys::UseDecl::Service(fsys::UseServiceDecl {
source: Some(fsys::Ref::Parent(fsys::ParentRef {})),
source_name: Some("netstack".to_string()),
target_path: Some("/svc/mynetstack".to_string()),
..fsys::UseServiceDecl::EMPTY
}),
fsys::UseDecl::Protocol(fsys::UseProtocolDecl {
source: Some(fsys::Ref::Parent(fsys::ParentRef {})),
source_name: Some("legacy_netstack".to_string()),
target_path: Some("/svc/legacy_mynetstack".to_string()),
..fsys::UseProtocolDecl::EMPTY
}),
fsys::UseDecl::Directory(fsys::UseDirectoryDecl {
source: Some(fsys::Ref::Framework(fsys::FrameworkRef {})),
source_name: Some("dir".to_string()),
target_path: Some("/data".to_string()),
rights: Some(fio2::Operations::Connect),
subdir: Some("foo/bar".to_string()),
..fsys::UseDirectoryDecl::EMPTY
}),
fsys::UseDecl::Storage(fsys::UseStorageDecl {
source_name: Some("cache".to_string()),
target_path: Some("/cache".to_string()),
..fsys::UseStorageDecl::EMPTY
}),
fsys::UseDecl::Storage(fsys::UseStorageDecl {
source_name: Some("temp".to_string()),
target_path: Some("/temp".to_string()),
..fsys::UseStorageDecl::EMPTY
}),
fsys::UseDecl::Runner(fsys::UseRunnerDecl {
source_name: Some("myrunner".to_string()),
..fsys::UseRunnerDecl::EMPTY
}),
fsys::UseDecl::Event(fsys::UseEventDecl {
source: Some(fsys::Ref::Parent(fsys::ParentRef {})),
source_name: Some("capability_ready".to_string()),
target_name: Some("diagnostics_ready".to_string()),
filter: Some(fdata::Dictionary{
entries: Some(vec![
fdata::DictionaryEntry {
key: "path".to_string(),
value: Some(Box::new(fdata::DictionaryValue::Str("/diagnostics".to_string()))),
},
]),
..fdata::Dictionary::EMPTY
}),
mode: Some(fsys::EventMode::Sync),
..fsys::UseEventDecl::EMPTY
}),
]),
exposes: Some(vec![
fsys::ExposeDecl::Protocol(fsys::ExposeProtocolDecl {
source: Some(fsys::Ref::Child(fsys::ChildRef {
name: "netstack".to_string(),
collection: None,
})),
source_name: Some("legacy_netstack".to_string()),
target_name: Some("legacy_mynetstack".to_string()),
target: Some(fsys::Ref::Parent(fsys::ParentRef {})),
..fsys::ExposeProtocolDecl::EMPTY
}),
fsys::ExposeDecl::Directory(fsys::ExposeDirectoryDecl {
source: Some(fsys::Ref::Child(fsys::ChildRef {
name: "netstack".to_string(),
collection: None,
})),
source_name: Some("dir".to_string()),
target_name: Some("data".to_string()),
target: Some(fsys::Ref::Parent(fsys::ParentRef {})),
rights: Some(fio2::Operations::Connect),
subdir: Some("foo/bar".to_string()),
..fsys::ExposeDirectoryDecl::EMPTY
}),
fsys::ExposeDecl::Runner(fsys::ExposeRunnerDecl {
source: Some(fsys::Ref::Child(fsys::ChildRef {
name: "netstack".to_string(),
collection: None,
})),
source_name: Some("elf".to_string()),
target: Some(fsys::Ref::Parent(fsys::ParentRef {})),
target_name: Some("elf".to_string()),
..fsys::ExposeRunnerDecl::EMPTY
}),
fsys::ExposeDecl::Resolver(fsys::ExposeResolverDecl{
source: Some(fsys::Ref::Child(fsys::ChildRef {
name: "netstack".to_string(),
collection: None,
})),
source_name: Some("pkg".to_string()),
target: Some(fsys::Ref::Parent(fsys::ParentRef{})),
target_name: Some("pkg".to_string()),
..fsys::ExposeResolverDecl::EMPTY
}),
fsys::ExposeDecl::Service(fsys::ExposeServiceDecl {
source: Some(fsys::Ref::Child(fsys::ChildRef {
name: "netstack".to_string(),
collection: None,
})),
source_name: Some("netstack1".to_string()),
target_name: Some("mynetstack".to_string()),
target: Some(fsys::Ref::Parent(fsys::ParentRef {})),
..fsys::ExposeServiceDecl::EMPTY
}),
fsys::ExposeDecl::Service(fsys::ExposeServiceDecl {
source: Some(fsys::Ref::Child(fsys::ChildRef {
name: "netstack".to_string(),
collection: None,
})),
source_name: Some("netstack2".to_string()),
target_name: Some("mynetstack".to_string()),
target: Some(fsys::Ref::Parent(fsys::ParentRef {})),
..fsys::ExposeServiceDecl::EMPTY
}),
]),
offers: Some(vec![
fsys::OfferDecl::Protocol(fsys::OfferProtocolDecl {
source: Some(fsys::Ref::Parent(fsys::ParentRef {})),
source_name: Some("legacy_netstack".to_string()),
target: Some(fsys::Ref::Child(
fsys::ChildRef {
name: "echo".to_string(),
collection: None,
}
)),
target_name: Some("legacy_mynetstack".to_string()),
dependency_type: Some(fsys::DependencyType::WeakForMigration),
..fsys::OfferProtocolDecl::EMPTY
}),
fsys::OfferDecl::Directory(fsys::OfferDirectoryDecl {
source: Some(fsys::Ref::Parent(fsys::ParentRef {})),
source_name: Some("dir".to_string()),
target: Some(fsys::Ref::Collection(
fsys::CollectionRef { name: "modular".to_string() }
)),
target_name: Some("data".to_string()),
rights: Some(fio2::Operations::Connect),
subdir: None,
dependency_type: Some(fsys::DependencyType::Strong),
..fsys::OfferDirectoryDecl::EMPTY
}),
fsys::OfferDecl::Storage(fsys::OfferStorageDecl {
source_name: Some("cache".to_string()),
source: Some(fsys::Ref::Self_(fsys::SelfRef {})),
target: Some(fsys::Ref::Collection(
fsys::CollectionRef { name: "modular".to_string() }
)),
target_name: Some("cache".to_string()),
..fsys::OfferStorageDecl::EMPTY
}),
fsys::OfferDecl::Runner(fsys::OfferRunnerDecl {
source: Some(fsys::Ref::Parent(fsys::ParentRef {})),
source_name: Some("elf".to_string()),
target: Some(fsys::Ref::Child(
fsys::ChildRef {
name: "echo".to_string(),
collection: None,
}
)),
target_name: Some("elf2".to_string()),
..fsys::OfferRunnerDecl::EMPTY
}),
fsys::OfferDecl::Resolver(fsys::OfferResolverDecl{
source: Some(fsys::Ref::Parent(fsys::ParentRef{})),
source_name: Some("pkg".to_string()),
target: Some(fsys::Ref::Child(
fsys::ChildRef {
name: "echo".to_string(),
collection: None,
}
)),
target_name: Some("pkg".to_string()),
..fsys::OfferResolverDecl::EMPTY
}),
fsys::OfferDecl::Event(fsys::OfferEventDecl {
source: Some(fsys::Ref::Parent(fsys::ParentRef {})),
source_name: Some("started".to_string()),
target: Some(fsys::Ref::Child(
fsys::ChildRef {
name: "echo".to_string(),
collection: None,
}
)),
target_name: Some("mystarted".to_string()),
filter: Some(fdata::Dictionary {
entries: Some(vec![
fdata::DictionaryEntry {
key: "path".to_string(),
value: Some(Box::new(fdata::DictionaryValue::Str("/a".to_string()))),
},
]),
..fdata::Dictionary::EMPTY
}),
mode: Some(fsys::EventMode::Sync),
..fsys::OfferEventDecl::EMPTY
}),
fsys::OfferDecl::Service(fsys::OfferServiceDecl {
source: Some(fsys::Ref::Parent(fsys::ParentRef {})),
source_name: Some("netstack1".to_string()),
target: Some(fsys::Ref::Child(
fsys::ChildRef {
name: "echo".to_string(),
collection: None,
}
)),
target_name: Some("mynetstack".to_string()),
..fsys::OfferServiceDecl::EMPTY
}),
fsys::OfferDecl::Service(fsys::OfferServiceDecl {
source: Some(fsys::Ref::Parent(fsys::ParentRef {})),
source_name: Some("netstack2".to_string()),
target: Some(fsys::Ref::Child(
fsys::ChildRef {
name: "echo".to_string(),
collection: None,
}
)),
target_name: Some("mynetstack".to_string()),
..fsys::OfferServiceDecl::EMPTY
}),
]),
capabilities: Some(vec![
fsys::CapabilityDecl::Service(fsys::ServiceDecl {
name: Some("netstack".to_string()),
source_path: Some("/netstack".to_string()),
..fsys::ServiceDecl::EMPTY
}),
fsys::CapabilityDecl::Protocol(fsys::ProtocolDecl {
name: Some("netstack2".to_string()),
source_path: Some("/netstack2".to_string()),
..fsys::ProtocolDecl::EMPTY
}),
fsys::CapabilityDecl::Directory(fsys::DirectoryDecl {
name: Some("data".to_string()),
source_path: Some("/data".to_string()),
rights: Some(fio2::Operations::Connect),
..fsys::DirectoryDecl::EMPTY
}),
fsys::CapabilityDecl::Storage(fsys::StorageDecl {
name: Some("cache".to_string()),
backing_dir: Some("data".to_string()),
source: Some(fsys::Ref::Parent(fsys::ParentRef {})),
subdir: Some("cache".to_string()),
..fsys::StorageDecl::EMPTY
}),
fsys::CapabilityDecl::Runner(fsys::RunnerDecl {
name: Some("elf".to_string()),
source_path: Some("/elf".to_string()),
source: Some(fsys::Ref::Self_(fsys::SelfRef {})),
..fsys::RunnerDecl::EMPTY
}),
fsys::CapabilityDecl::Resolver(fsys::ResolverDecl {
name: Some("pkg".to_string()),
source_path: Some("/pkg_resolver".to_string()),
..fsys::ResolverDecl::EMPTY
}),
]),
children: Some(vec![
fsys::ChildDecl {
name: Some("netstack".to_string()),
url: Some("fuchsia-pkg://fuchsia.com/netstack#meta/netstack.cm"
.to_string()),
startup: Some(fsys::StartupMode::Lazy),
environment: None,
..fsys::ChildDecl::EMPTY
},
fsys::ChildDecl {
name: Some("gtest".to_string()),
url: Some("fuchsia-pkg://fuchsia.com/gtest#meta/gtest.cm".to_string()),
startup: Some(fsys::StartupMode::Lazy),
environment: None,
..fsys::ChildDecl::EMPTY
},
fsys::ChildDecl {
name: Some("echo".to_string()),
url: Some("fuchsia-pkg://fuchsia.com/echo#meta/echo.cm"
.to_string()),
startup: Some(fsys::StartupMode::Eager),
environment: Some("test_env".to_string()),
..fsys::ChildDecl::EMPTY
},
]),
collections: Some(vec![
fsys::CollectionDecl {
name: Some("modular".to_string()),
durability: Some(fsys::Durability::Persistent),
environment: None,
..fsys::CollectionDecl::EMPTY
},
fsys::CollectionDecl {
name: Some("tests".to_string()),
durability: Some(fsys::Durability::Transient),
environment: Some("test_env".to_string()),
..fsys::CollectionDecl::EMPTY
},
]),
facets: Some(fsys::Object{entries: vec![
fsys::Entry{
key: "author".to_string(),
value: Some(Box::new(fsys::Value::Str("Fuchsia".to_string()))),
},
]}),
environments: Some(vec![
fsys::EnvironmentDecl {
name: Some("test_env".to_string()),
extends: Some(fsys::EnvironmentExtends::Realm),
runners: Some(vec![
fsys::RunnerRegistration {
source_name: Some("runner".to_string()),
source: Some(fsys::Ref::Child(fsys::ChildRef {
name: "gtest".to_string(),
collection: None,
})),
target_name: Some("gtest-runner".to_string()),
..fsys::RunnerRegistration::EMPTY
}
]),
resolvers: Some(vec![
fsys::ResolverRegistration {
resolver: Some("pkg_resolver".to_string()),
source: Some(fsys::Ref::Parent(fsys::ParentRef{})),
scheme: Some("fuchsia-pkg".to_string()),
..fsys::ResolverRegistration::EMPTY
}
]),
stop_timeout_ms: Some(4567),
..fsys::EnvironmentDecl::EMPTY
}
]),
..fsys::ComponentDecl::EMPTY
},
result = {
ComponentDecl {
program: Some(fdata::Dictionary{entries: Some(vec![
fdata::DictionaryEntry {
key: "args".to_string(),
value: Some(Box::new(fdata::DictionaryValue::StrVec(vec!["foo".to_string(), "bar".to_string()]))),
},
fdata::DictionaryEntry{
key: "binary".to_string(),
value: Some(Box::new(fdata::DictionaryValue::Str("bin/app".to_string()))),
},
]), ..fdata::Dictionary::EMPTY}),
uses: vec![
UseDecl::Service(UseServiceDecl {
source: UseSource::Parent,
source_name: "netstack".try_into().unwrap(),
target_path: "/svc/mynetstack".try_into().unwrap(),
}),
UseDecl::Protocol(UseProtocolDecl {
source: UseSource::Parent,
source_name: "legacy_netstack".try_into().unwrap(),
target_path: "/svc/legacy_mynetstack".try_into().unwrap(),
}),
UseDecl::Directory(UseDirectoryDecl {
source: UseSource::Framework,
source_name: "dir".try_into().unwrap(),
target_path: "/data".try_into().unwrap(),
rights: fio2::Operations::Connect,
subdir: Some("foo/bar".into()),
}),
UseDecl::Storage(UseStorageDecl {
source_name: "cache".into(),
target_path: "/cache".try_into().unwrap(),
}),
UseDecl::Storage(UseStorageDecl {
source_name: "temp".into(),
target_path: "/temp".try_into().unwrap(),
}),
UseDecl::Runner(UseRunnerDecl {
source_name: "myrunner".into(),
}),
UseDecl::Event(UseEventDecl {
source: UseSource::Parent,
source_name: "capability_ready".into(),
target_name: "diagnostics_ready".into(),
filter: Some(hashmap!{"path".to_string() => DictionaryValue::Str("/diagnostics".to_string())}),
mode: EventMode::Sync,
})
],
exposes: vec![
ExposeDecl::Protocol(ExposeProtocolDecl {
source: ExposeSource::Child("netstack".to_string()),
source_name: "legacy_netstack".try_into().unwrap(),
target_name: "legacy_mynetstack".try_into().unwrap(),
target: ExposeTarget::Parent,
}),
ExposeDecl::Directory(ExposeDirectoryDecl {
source: ExposeSource::Child("netstack".to_string()),
source_name: "dir".try_into().unwrap(),
target_name: "data".try_into().unwrap(),
target: ExposeTarget::Parent,
rights: Some(fio2::Operations::Connect),
subdir: Some("foo/bar".into()),
}),
ExposeDecl::Runner(ExposeRunnerDecl {
source: ExposeSource::Child("netstack".to_string()),
source_name: "elf".try_into().unwrap(),
target: ExposeTarget::Parent,
target_name: "elf".try_into().unwrap(),
}),
ExposeDecl::Resolver(ExposeResolverDecl {
source: ExposeSource::Child("netstack".to_string()),
source_name: "pkg".try_into().unwrap(),
target: ExposeTarget::Parent,
target_name: "pkg".try_into().unwrap(),
}),
ExposeDecl::Service(ExposeServiceDecl {
sources: vec![
ServiceSource::<ExposeServiceSource> {
source: ExposeServiceSource::Child("netstack".to_string()),
source_name: "netstack1".try_into().unwrap(),
},
ServiceSource::<ExposeServiceSource> {
source: ExposeServiceSource::Child("netstack".to_string()),
source_name: "netstack2".try_into().unwrap(),
},
],
target_name: "mynetstack".try_into().unwrap(),
target: ExposeTarget::Parent,
}),
],
offers: vec![
OfferDecl::Protocol(OfferProtocolDecl {
source: OfferServiceSource::Parent,
source_name: "legacy_netstack".try_into().unwrap(),
target: OfferTarget::Child("echo".to_string()),
target_name: "legacy_mynetstack".try_into().unwrap(),
dependency_type: DependencyType::WeakForMigration,
}),
OfferDecl::Directory(OfferDirectoryDecl {
source: OfferDirectorySource::Parent,
source_name: "dir".try_into().unwrap(),
target: OfferTarget::Collection("modular".to_string()),
target_name: "data".try_into().unwrap(),
rights: Some(fio2::Operations::Connect),
subdir: None,
dependency_type: DependencyType::Strong,
}),
OfferDecl::Storage(OfferStorageDecl {
source_name: "cache".try_into().unwrap(),
source: OfferStorageSource::Self_,
target: OfferTarget::Collection("modular".to_string()),
target_name: "cache".try_into().unwrap(),
}),
OfferDecl::Runner(OfferRunnerDecl {
source: OfferRunnerSource::Parent,
source_name: "elf".try_into().unwrap(),
target: OfferTarget::Child("echo".to_string()),
target_name: "elf2".try_into().unwrap(),
}),
OfferDecl::Resolver(OfferResolverDecl {
source: OfferResolverSource::Parent,
source_name: "pkg".try_into().unwrap(),
target: OfferTarget::Child("echo".to_string()),
target_name: "pkg".try_into().unwrap(),
}),
OfferDecl::Event(OfferEventDecl {
source: OfferEventSource::Parent,
source_name: "started".into(),
target: OfferTarget::Child("echo".to_string()),
target_name: "mystarted".into(),
filter: Some(hashmap!{"path".to_string() => DictionaryValue::Str("/a".to_string())}),
mode: EventMode::Sync,
}),
OfferDecl::Service(OfferServiceDecl {
sources: vec![
ServiceSource::<OfferServiceSource> {
source: OfferServiceSource::Parent,
source_name: "netstack1".try_into().unwrap(),
},
ServiceSource::<OfferServiceSource> {
source: OfferServiceSource::Parent,
source_name: "netstack2".try_into().unwrap(),
},
],
target: OfferTarget::Child("echo".to_string()),
target_name: "mynetstack".try_into().unwrap(),
}),
],
capabilities: vec![
CapabilityDecl::Service(ServiceDecl {
name: "netstack".into(),
source_path: "/netstack".try_into().unwrap(),
}),
CapabilityDecl::Protocol(ProtocolDecl {
name: "netstack2".into(),
source_path: "/netstack2".try_into().unwrap(),
}),
CapabilityDecl::Directory(DirectoryDecl {
name: "data".into(),
source_path: "/data".try_into().unwrap(),
rights: fio2::Operations::Connect,
}),
CapabilityDecl::Storage(StorageDecl {
name: "cache".into(),
backing_dir: "data".try_into().unwrap(),
source: StorageDirectorySource::Parent,
subdir: Some("cache".try_into().unwrap()),
}),
CapabilityDecl::Runner(RunnerDecl {
name: "elf".into(),
source: RunnerSource::Self_,
source_path: "/elf".try_into().unwrap(),
}),
CapabilityDecl::Resolver(ResolverDecl {
name: "pkg".into(),
source_path: "/pkg_resolver".try_into().unwrap(),
}),
],
children: vec![
ChildDecl {
name: "netstack".to_string(),
url: "fuchsia-pkg://fuchsia.com/netstack#meta/netstack.cm".to_string(),
startup: fsys::StartupMode::Lazy,
environment: None,
},
ChildDecl {
name: "gtest".to_string(),
url: "fuchsia-pkg://fuchsia.com/gtest#meta/gtest.cm".to_string(),
startup: fsys::StartupMode::Lazy,
environment: None,
},
ChildDecl {
name: "echo".to_string(),
url: "fuchsia-pkg://fuchsia.com/echo#meta/echo.cm".to_string(),
startup: fsys::StartupMode::Eager,
environment: Some("test_env".to_string()),
},
],
collections: vec![
CollectionDecl {
name: "modular".to_string(),
durability: fsys::Durability::Persistent,
environment: None,
},
CollectionDecl {
name: "tests".to_string(),
durability: fsys::Durability::Transient,
environment: Some("test_env".to_string()),
},
],
facets: Some(fsys::Object{entries: vec![
fsys::Entry{
key: "author".to_string(),
value: Some(Box::new(fsys::Value::Str("Fuchsia".to_string()))),
},
]}),
environments: vec![
EnvironmentDecl {
name: "test_env".into(),
extends: fsys::EnvironmentExtends::Realm,
runners: vec![
RunnerRegistration {
source_name: "runner".into(),
source: RegistrationSource::Child("gtest".to_string()),
target_name: "gtest-runner".into(),
}
],
resolvers: vec![
ResolverRegistration {
resolver: "pkg_resolver".into(),
source: RegistrationSource::Parent,
scheme: "fuchsia-pkg".to_string(),
}
],
stop_timeout_ms: Some(4567),
}
]
}
},
},
}
test_capability_path! {
capability_path_one_part => {
input = "/foo",
result = Ok(CapabilityPath{dirname: "/".to_string(), basename: "foo".to_string()}),
},
capability_path_two_parts => {
input = "/foo/bar",
result = Ok(CapabilityPath{dirname: "/foo".to_string(), basename: "bar".to_string()}),
},
capability_path_many_parts => {
input = "/foo/bar/long/path",
result = Ok(CapabilityPath{
dirname: "/foo/bar/long".to_string(),
basename: "path".to_string()
}),
},
capability_path_invalid_empty_part => {
input = "/foo/bar//long/path",
result = Err(Error::InvalidCapabilityPath{raw: "/foo/bar//long/path".to_string()}),
},
capability_path_invalid_empty => {
input = "",
result = Err(Error::InvalidCapabilityPath{raw: "".to_string()}),
},
capability_path_invalid_root => {
input = "/",
result = Err(Error::InvalidCapabilityPath{raw: "/".to_string()}),
},
capability_path_invalid_relative => {
input = "foo/bar",
result = Err(Error::InvalidCapabilityPath{raw: "foo/bar".to_string()}),
},
capability_path_invalid_trailing => {
input = "/foo/bar/",
result = Err(Error::InvalidCapabilityPath{raw: "/foo/bar/".to_string()}),
},
}
test_fidl_into_and_from! {
fidl_into_and_from_expose_source => {
input = vec![
Some(fsys::Ref::Self_(fsys::SelfRef {})),
Some(fsys::Ref::Child(fsys::ChildRef {
name: "foo".to_string(),
collection: None,
})),
Some(fsys::Ref::Framework(fsys::FrameworkRef {})),
],
input_type = Option<fsys::Ref>,
result = vec![
ExposeSource::Self_,
ExposeSource::Child("foo".to_string()),
ExposeSource::Framework,
],
result_type = ExposeSource,
},
fidl_into_and_from_offer_service_source => {
input = vec![
Some(fsys::Ref::Parent(fsys::ParentRef {})),
Some(fsys::Ref::Self_(fsys::SelfRef {})),
Some(fsys::Ref::Child(fsys::ChildRef {
name: "foo".to_string(),
collection: None,
})),
],
input_type = Option<fsys::Ref>,
result = vec![
OfferServiceSource::Parent,
OfferServiceSource::Self_,
OfferServiceSource::Child("foo".to_string()),
],
result_type = OfferServiceSource,
},
fidl_into_and_from_offer_event_source => {
input = vec![Some(fsys::Ref::Parent(fsys::ParentRef {}))],
input_type = Option<fsys::Ref>,
result = vec![OfferEventSource::Parent],
result_type = OfferEventSource,
},
fidl_into_and_from_offer_directory_source => {
input = vec![
Some(fsys::Ref::Parent(fsys::ParentRef {})),
Some(fsys::Ref::Self_(fsys::SelfRef {})),
Some(fsys::Ref::Framework(fsys::FrameworkRef {})),
Some(fsys::Ref::Child(fsys::ChildRef {
name: "foo".to_string(),
collection: None,
})),
],
input_type = Option<fsys::Ref>,
result = vec![
OfferDirectorySource::Parent,
OfferDirectorySource::Self_,
OfferDirectorySource::Framework,
OfferDirectorySource::Child("foo".to_string()),
],
result_type = OfferDirectorySource,
},
fidl_into_and_from_offer_storage_source => {
input = vec![
Some(fsys::Ref::Parent(fsys::ParentRef {})),
Some(fsys::Ref::Self_(fsys::SelfRef {})),
],
input_type = Option<fsys::Ref>,
result = vec![
OfferStorageSource::Parent,
OfferStorageSource::Self_,
],
result_type = OfferStorageSource,
},
fidl_into_and_from_storage_capability => {
input = vec![
fsys::StorageDecl {
name: Some("minfs".to_string()),
backing_dir: Some("minfs".into()),
source: Some(fsys::Ref::Child(fsys::ChildRef {
name: "foo".to_string(),
collection: None,
})),
subdir: None,
..fsys::StorageDecl::EMPTY
},
],
input_type = fsys::StorageDecl,
result = vec![
StorageDecl {
name: "minfs".into(),
backing_dir: "minfs".into(),
source: StorageDirectorySource::Child("foo".to_string()),
subdir: None,
},
],
result_type = StorageDecl,
},
}
test_fidl_into! {
fidl_into_object => {
input = {
let obj_inner = fsys::Object{entries: vec![
fsys::Entry{
key: "string".to_string(),
value: Some(Box::new(fsys::Value::Str("bar".to_string()))),
},
]};
let vector = fsys::Vector{values: vec![
Some(Box::new(fsys::Value::Obj(obj_inner))),
Some(Box::new(fsys::Value::Inum(-42)))
]};
let obj_outer = fsys::Object{entries: vec![
fsys::Entry{
key: "array".to_string(),
value: Some(Box::new(fsys::Value::Vec(vector))),
},
]};
let obj = fsys::Object {entries: vec![
fsys::Entry {
key: "bool".to_string(),
value: Some(Box::new(fsys::Value::Bit(true))),
},
fsys::Entry {
key: "obj".to_string(),
value: Some(Box::new(fsys::Value::Obj(obj_outer))),
},
fsys::Entry {
key: "float".to_string(),
value: Some(Box::new(fsys::Value::Fnum(3.14))),
},
fsys::Entry {
key: "int".to_string(),
value: Some(Box::new(fsys::Value::Inum(-42))),
},
fsys::Entry {
key: "null".to_string(),
value: None,
},
fsys::Entry {
key: "string".to_string(),
value: Some(Box::new(fsys::Value::Str("bar".to_string()))),
},
]};
Some(obj)
},
result = {
let mut obj_inner = HashMap::new();
obj_inner.insert("string".to_string(), Value::Str("bar".to_string()));
let mut obj_outer = HashMap::new();
let vector = vec![Value::Obj(obj_inner), Value::Inum(-42)];
obj_outer.insert("array".to_string(), Value::Vec(vector));
let mut obj: HashMap<String, Value> = HashMap::new();
obj.insert("bool".to_string(), Value::Bit(true));
obj.insert("float".to_string(), Value::Fnum(3.14));
obj.insert("int".to_string(), Value::Inum(-42));
obj.insert("string".to_string(), Value::Str("bar".to_string()));
obj.insert("obj".to_string(), Value::Obj(obj_outer));
obj.insert("null".to_string(), Value::Null);
Some(obj)
},
},
}
}