blob: 7415594477131b005fa19a986bf2c5cc65b8e059 [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,
std::collections::HashMap,
std::convert::{From, TryFrom, TryInto},
std::fmt,
std::path::PathBuf,
std::str::FromStr,
thiserror::Error,
};
pub mod data;
/// 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.
/// - `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)]
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(), )+ }
}
}
}
}
/// 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_ident` must be identical to `from_type`.
/// - `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,
{ $( $variant:ident($type:ty), )+ } ) => {
#[derive(Debug, Clone, PartialEq)]
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_ident::__UnknownVariant {..} => { 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 children: Vec<ChildDecl>,
pub collections: Vec<CollectionDecl>,
pub storage: Vec<StorageDecl>,
pub facets: Option<fsys::Object>,
pub runners: Vec<RunnerDecl>,
pub environments: Vec<EnvironmentDecl>,
pub resolvers: Vec<ResolverDecl>,
}
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, CapabilityPath), Vec<_>> = HashMap::new();
for expose in e.into_iter() {
match expose {
fsys::ExposeDecl::Service(s) => services
.entry((s.target.fidl_into_native(), s.target_path.fidl_into_native()))
.or_default()
.push(ServiceSource::<ExposeServiceSource> {
source: s.source.fidl_into_native(),
source_path: s.source_path.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::ExposeDecl::__UnknownVariant { .. } => panic!("invalid variant"),
}
}
for ((target, target_path), sources) in services.into_iter() {
exposes.push(ExposeDecl::Service(ExposeServiceDecl {
sources,
target,
target_path,
}))
}
}
let mut offers = vec![];
if let Some(o) = self.offers {
let mut services: HashMap<(OfferTarget, CapabilityPath), Vec<_>> = HashMap::new();
for offer in o.into_iter() {
match offer {
fsys::OfferDecl::Service(s) => services
.entry((s.target.fidl_into_native(), s.target_path.fidl_into_native()))
.or_default()
.push(ServiceSource::<OfferServiceSource> {
source: s.source.fidl_into_native(),
source_path: s.source_path.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::__UnknownVariant { .. } => panic!("invalid variant"),
}
}
for ((target, target_path), sources) in services.into_iter() {
offers.push(OfferDecl::Service(OfferServiceDecl { sources, target, target_path }))
}
}
ComponentDecl {
program: self.program.fidl_into_native(),
uses: self.uses.fidl_into_native(),
exposes,
offers,
children: self.children.fidl_into_native(),
collections: self.collections.fidl_into_native(),
storage: self.storage.fidl_into_native(),
facets: self.facets.fidl_into_native(),
runners: self.runners.fidl_into_native(),
environments: self.environments.fidl_into_native(),
resolvers: self.resolvers.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_path: es.source_path.native_into_fidl(),
target: s.target.clone().native_into_fidl(),
target_path: s.target_path.clone().native_into_fidl(),
}))
}
}
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_path: os.source_path.native_into_fidl(),
target: s.target.clone().native_into_fidl(),
target_path: s.target_path.clone().native_into_fidl(),
}))
}
}
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()))
}
}
}
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) },
children: self.children.native_into_fidl(),
collections: self.collections.native_into_fidl(),
storage: self.storage.native_into_fidl(),
facets: self.facets.native_into_fidl(),
runners: self.runners.native_into_fidl(),
environments: self.environments.native_into_fidl(),
resolvers: self.resolvers.native_into_fidl(),
}
}
}
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(),
children: self.children.clone(),
collections: self.collections.clone(),
storage: self.storage.clone(),
facets: data::clone_option_object(&self.facets),
runners: self.runners.clone(),
environments: self.environments.clone(),
resolvers: self.resolvers.clone(),
}
}
}
impl ComponentDecl {
/// Returns the `StorageDecl` corresponding to `storage_name`.
pub fn find_storage_source<'a>(&'a self, storage_name: &str) -> Option<&'a StorageDecl> {
self.storage.iter().find(|s| &s.name == storage_name)
}
/// 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)
}
/// Returns the `RunnerDecl` corresponding to `runner_name`.
pub fn find_runner_source<'a>(&'a self, runner_name: &str) -> Option<&'a RunnerDecl> {
self.runners.iter().find(|s| &s.name == runner_name)
}
/// Indicates whether the capability specified by `target_path` is exposed to the framework.
pub fn is_protocol_exposed_to_framework(&self, target_path: &CapabilityPath) -> bool {
self.exposes.iter().any(|expose| match expose {
ExposeDecl::Protocol(ls) => {
ls.target == ExposeTarget::Framework && ls.target_path == *target_path
}
_ => false,
})
}
/// Indicates whether the capability specified by `target_path` is requested.
pub fn uses_protocol_from_framework(&self, target_path: &CapabilityPath) -> bool {
self.uses.iter().any(|use_decl| match use_decl {
UseDecl::Protocol(ls) => {
ls.source == UseSource::Framework && ls.target_path == *target_path
}
_ => false,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ExposeDecl {
Service(ExposeServiceDecl),
Protocol(ExposeProtocolDecl),
Directory(ExposeDirectoryDecl),
Runner(ExposeRunnerDecl),
Resolver(ExposeResolverDecl),
}
#[derive(Debug, Clone, PartialEq)]
pub struct ExposeServiceDecl {
pub sources: Vec<ServiceSource<ExposeServiceSource>>,
pub target: ExposeTarget,
pub target_path: CapabilityPath,
}
#[derive(Debug, Clone, PartialEq)]
pub enum OfferDecl {
Service(OfferServiceDecl),
Protocol(OfferProtocolDecl),
Directory(OfferDirectoryDecl),
Storage(OfferStorageDecl),
Runner(OfferRunnerDecl),
Resolver(OfferResolverDecl),
}
#[derive(Debug, Clone, PartialEq)]
pub struct OfferServiceDecl {
pub sources: Vec<ServiceSource<OfferServiceSource>>,
pub target: OfferTarget,
pub target_path: CapabilityPath,
}
fidl_into_enum!(UseDecl, UseDecl, fsys::UseDecl, fsys::UseDecl,
{
Service(UseServiceDecl),
Protocol(UseProtocolDecl),
Directory(UseDirectoryDecl),
Storage(UseStorageDecl),
Runner(UseRunnerDecl),
});
fidl_into_struct!(UseServiceDecl, UseServiceDecl, fsys::UseServiceDecl, fsys::UseServiceDecl,
{
source: UseSource,
source_path: CapabilityPath,
target_path: CapabilityPath,
});
fidl_into_struct!(UseProtocolDecl, UseProtocolDecl, fsys::UseProtocolDecl, fsys::UseProtocolDecl,
{
source: UseSource,
source_path: CapabilityPath,
target_path: CapabilityPath,
});
fidl_into_struct!(UseDirectoryDecl, UseDirectoryDecl, fsys::UseDirectoryDecl,
fsys::UseDirectoryDecl,
{
source: UseSource,
source_path: CapabilityPath,
target_path: CapabilityPath,
rights: fio2::Operations,
subdir: Option<PathBuf>,
});
fidl_into_struct!(UseRunnerDecl, UseRunnerDecl, fsys::UseRunnerDecl,
fsys::UseRunnerDecl,
{
source_name: CapabilityName,
});
fidl_into_struct!(ExposeProtocolDecl, ExposeProtocolDecl, fsys::ExposeProtocolDecl,
fsys::ExposeProtocolDecl,
{
source: ExposeSource,
source_path: CapabilityPath,
target: ExposeTarget,
target_path: CapabilityPath,
});
fidl_into_struct!(ExposeDirectoryDecl, ExposeDirectoryDecl, fsys::ExposeDirectoryDecl,
fsys::ExposeDirectoryDecl,
{
source: ExposeSource,
source_path: CapabilityPath,
target: ExposeTarget,
target_path: CapabilityPath,
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!(StorageDecl, StorageDecl, fsys::StorageDecl,
fsys::StorageDecl,
{
name: String,
source: StorageDirectorySource,
source_path: CapabilityPath,
});
fidl_into_struct!(OfferProtocolDecl, OfferProtocolDecl, fsys::OfferProtocolDecl,
fsys::OfferProtocolDecl,
{
source: OfferServiceSource,
source_path: CapabilityPath,
target: OfferTarget,
target_path: CapabilityPath,
dependency_type: DependencyType,
});
fidl_into_struct!(OfferDirectoryDecl, OfferDirectoryDecl, fsys::OfferDirectoryDecl,
fsys::OfferDirectoryDecl,
{
source: OfferDirectorySource,
source_path: CapabilityPath,
target: OfferTarget,
target_path: CapabilityPath,
rights: Option<fio2::Operations>,
subdir: Option<PathBuf>,
dependency_type: DependencyType,
});
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!(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,
});
fidl_into_struct!(ResolverDecl, ResolverDecl, fsys::ResolverDecl, fsys::ResolverDecl,
{
name: String,
source_path: CapabilityPath,
});
fidl_into_struct!(RunnerDecl, RunnerDecl, fsys::RunnerDecl, fsys::RunnerDecl,
{
name: String,
source: RunnerSource,
source_path: CapabilityPath,
});
fidl_into_struct!(EnvironmentDecl, EnvironmentDecl, fsys::EnvironmentDecl, fsys::EnvironmentDecl,
{
name: String,
extends: fsys::EnvironmentExtends,
});
fidl_into_vec!(UseDecl, fsys::UseDecl);
fidl_into_vec!(ChildDecl, fsys::ChildDecl);
fidl_into_vec!(CollectionDecl, fsys::CollectionDecl);
fidl_into_vec!(StorageDecl, fsys::StorageDecl);
fidl_into_vec!(ResolverDecl, fsys::ResolverDecl);
fidl_into_vec!(RunnerDecl, fsys::RunnerDecl);
fidl_into_vec!(EnvironmentDecl, fsys::EnvironmentDecl);
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> {
let path = match self {
UseDecl::Service(d) => &d.target_path,
UseDecl::Protocol(d) => &d.target_path,
UseDecl::Directory(d) => &d.target_path,
UseDecl::Storage(UseStorageDecl::Data(p)) => &p,
UseDecl::Storage(UseStorageDecl::Cache(p)) => &p,
UseDecl::Storage(UseStorageDecl::Meta) | UseDecl::Runner(_) => {
// Meta storage and runners don't show up in the namespace; no capability path.
return None;
}
};
Some(path)
}
}
/// 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 fmt::Display for CapabilityName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<String as fmt::Display>::fmt(&self.0, f)
}
}
// 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 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, PartialEq)]
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,
}
}
}
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(),
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum UseStorageDecl {
Data(CapabilityPath),
Cache(CapabilityPath),
Meta,
}
impl FidlIntoNative<UseStorageDecl> for fsys::UseStorageDecl {
fn fidl_into_native(self) -> UseStorageDecl {
match self.type_.unwrap() {
fsys::StorageType::Data => {
UseStorageDecl::Data(self.target_path.unwrap().as_str().try_into().unwrap())
}
fsys::StorageType::Cache => {
UseStorageDecl::Cache(self.target_path.unwrap().as_str().try_into().unwrap())
}
fsys::StorageType::Meta => UseStorageDecl::Meta,
}
}
}
impl NativeIntoFidl<fsys::UseStorageDecl> for UseStorageDecl {
fn native_into_fidl(self) -> fsys::UseStorageDecl {
match self {
UseStorageDecl::Data(p) => fsys::UseStorageDecl {
type_: Some(fsys::StorageType::Data),
target_path: p.native_into_fidl(),
},
UseStorageDecl::Cache(p) => fsys::UseStorageDecl {
type_: Some(fsys::StorageType::Cache),
target_path: p.native_into_fidl(),
},
UseStorageDecl::Meta => {
fsys::UseStorageDecl { type_: Some(fsys::StorageType::Meta), target_path: None }
}
}
}
}
impl UseStorageDecl {
pub fn type_(&self) -> fsys::StorageType {
match self {
UseStorageDecl::Data(_) => fsys::StorageType::Data,
UseStorageDecl::Cache(_) => fsys::StorageType::Cache,
UseStorageDecl::Meta => fsys::StorageType::Meta,
}
}
pub fn path<'a>(&'a self) -> Option<&'a CapabilityPath> {
match self {
UseStorageDecl::Data(p) => Some(p),
UseStorageDecl::Cache(p) => Some(p),
UseStorageDecl::Meta => None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum OfferStorageDecl {
Data(OfferStorage),
Cache(OfferStorage),
Meta(OfferStorage),
}
#[derive(Debug, Clone, PartialEq)]
pub struct OfferStorage {
pub source: OfferStorageSource,
pub target: OfferTarget,
}
impl FidlIntoNative<OfferStorageDecl> for fsys::OfferStorageDecl {
fn fidl_into_native(self) -> OfferStorageDecl {
match self.type_.unwrap() {
fsys::StorageType::Data => OfferStorageDecl::Data(OfferStorage {
source: self.source.fidl_into_native(),
target: self.target.fidl_into_native(),
}),
fsys::StorageType::Cache => OfferStorageDecl::Cache(OfferStorage {
source: self.source.fidl_into_native(),
target: self.target.fidl_into_native(),
}),
fsys::StorageType::Meta => OfferStorageDecl::Meta(OfferStorage {
source: self.source.fidl_into_native(),
target: self.target.fidl_into_native(),
}),
}
}
}
impl NativeIntoFidl<fsys::OfferStorageDecl> for OfferStorageDecl {
fn native_into_fidl(self) -> fsys::OfferStorageDecl {
let type_ = self.type_();
let (source, target) = match self {
OfferStorageDecl::Data(OfferStorage { source, target }) => (source, target),
OfferStorageDecl::Cache(OfferStorage { source, target }) => (source, target),
OfferStorageDecl::Meta(OfferStorage { source, target }) => (source, target),
};
fsys::OfferStorageDecl {
type_: Some(type_),
source: source.native_into_fidl(),
target: target.native_into_fidl(),
}
}
}
impl OfferStorageDecl {
pub fn type_(&self) -> fsys::StorageType {
match self {
OfferStorageDecl::Data(..) => fsys::StorageType::Data,
OfferStorageDecl::Cache(..) => fsys::StorageType::Cache,
OfferStorageDecl::Meta(..) => fsys::StorageType::Meta,
}
}
pub fn source(&self) -> &OfferStorageSource {
match self {
OfferStorageDecl::Data(OfferStorage { source, .. }) => source,
OfferStorageDecl::Cache(OfferStorage { source, .. }) => source,
OfferStorageDecl::Meta(OfferStorage { source, .. }) => source,
}
}
pub fn target(&self) -> &OfferTarget {
match self {
OfferStorageDecl::Data(OfferStorage { target, .. }) => target,
OfferStorageDecl::Cache(OfferStorage { target, .. }) => target,
OfferStorageDecl::Meta(OfferStorage { target, .. }) => target,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum UseSource {
Realm,
Framework,
}
impl FidlIntoNative<UseSource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> UseSource {
match self.unwrap() {
fsys::Ref::Realm(_) => UseSource::Realm,
fsys::Ref::Framework(_) => UseSource::Framework,
_ => panic!("invalid UseSource variant"),
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for UseSource {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
UseSource::Realm => fsys::Ref::Realm(fsys::RealmRef {}),
UseSource::Framework => fsys::Ref::Framework(fsys::FrameworkRef {}),
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ExposeSource {
Self_,
Child(String),
Framework,
}
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,
_ => 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 {}),
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ExposeTarget {
Realm,
Framework,
}
impl FidlIntoNative<ExposeTarget> for Option<fsys::Ref> {
fn fidl_into_native(self) -> ExposeTarget {
match self {
Some(dest) => match dest {
fsys::Ref::Realm(_) => ExposeTarget::Realm,
fsys::Ref::Framework(_) => ExposeTarget::Framework,
_ => panic!("invalid ExposeTarget variant"),
},
None => ExposeTarget::Realm,
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for ExposeTarget {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
ExposeTarget::Realm => fsys::Ref::Realm(fsys::RealmRef {}),
ExposeTarget::Framework => fsys::Ref::Framework(fsys::FrameworkRef {}),
})
}
}
/// A source for a service.
#[derive(Debug, Clone, PartialEq)]
pub struct ServiceSource<T> {
/// The provider of the service, relative to a component.
pub source: T,
/// The path at which the service is accessible.
pub source_path: CapabilityPath,
}
#[derive(Debug, Clone, PartialEq)]
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)]
pub enum OfferServiceSource {
Realm,
Self_,
Child(String),
}
impl FidlIntoNative<OfferServiceSource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> OfferServiceSource {
match self.unwrap() {
fsys::Ref::Realm(_) => OfferServiceSource::Realm,
fsys::Ref::Self_(_) => OfferServiceSource::Self_,
fsys::Ref::Child(c) => OfferServiceSource::Child(c.name),
_ => panic!("invalid OfferServiceSource variant"),
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for OfferServiceSource {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
OfferServiceSource::Realm => fsys::Ref::Realm(fsys::RealmRef {}),
OfferServiceSource::Self_ => fsys::Ref::Self_(fsys::SelfRef {}),
OfferServiceSource::Child(child_name) => {
fsys::Ref::Child(fsys::ChildRef { name: child_name, collection: None })
}
})
}
}
/// The valid sources of a service protocol's expose declaration.
#[derive(Debug, Clone, PartialEq)]
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)]
pub enum StorageDirectorySource {
Realm,
Self_,
Child(String),
}
impl FidlIntoNative<StorageDirectorySource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> StorageDirectorySource {
match self.unwrap() {
fsys::Ref::Realm(_) => StorageDirectorySource::Realm,
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::Realm => fsys::Ref::Realm(fsys::RealmRef {}),
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)]
pub enum RunnerSource {
Realm,
Self_,
Child(String),
}
impl FidlIntoNative<RunnerSource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> RunnerSource {
match self.unwrap() {
fsys::Ref::Realm(_) => RunnerSource::Realm,
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::Realm => fsys::Ref::Realm(fsys::RealmRef {}),
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)]
pub enum OfferDirectorySource {
Realm,
Self_,
Framework,
Child(String),
}
impl FidlIntoNative<OfferDirectorySource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> OfferDirectorySource {
match self.unwrap() {
fsys::Ref::Realm(_) => OfferDirectorySource::Realm,
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::Realm => fsys::Ref::Realm(fsys::RealmRef {}),
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)]
pub enum OfferStorageSource {
Realm,
Storage(String),
}
impl FidlIntoNative<OfferStorageSource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> OfferStorageSource {
match self.unwrap() {
fsys::Ref::Realm(_) => OfferStorageSource::Realm,
fsys::Ref::Storage(c) => OfferStorageSource::Storage(c.name),
_ => panic!("invalid OfferStorageSource variant"),
}
}
}
impl NativeIntoFidl<Option<fsys::Ref>> for OfferStorageSource {
fn native_into_fidl(self) -> Option<fsys::Ref> {
Some(match self {
OfferStorageSource::Realm => fsys::Ref::Realm(fsys::RealmRef {}),
OfferStorageSource::Storage(name) => fsys::Ref::Storage(fsys::StorageRef { name }),
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum OfferRunnerSource {
Realm,
Self_,
Child(String),
}
impl FidlIntoNative<OfferRunnerSource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> OfferRunnerSource {
match self.unwrap() {
fsys::Ref::Realm(_) => OfferRunnerSource::Realm,
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::Realm => fsys::Ref::Realm(fsys::RealmRef {}),
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)]
pub enum OfferResolverSource {
Realm,
Self_,
Child(String),
}
impl FidlIntoNative<OfferResolverSource> for Option<fsys::Ref> {
fn fidl_into_native(self) -> OfferResolverSource {
match self.unwrap() {
fsys::Ref::Realm(_) => OfferResolverSource::Realm,
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::Realm => fsys::Ref::Realm(fsys::RealmRef {}),
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, 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::*;
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,
children: None,
collections: None,
facets: None,
storage: None,
runners: None,
environments: None,
resolvers: None,
},
result = ComponentDecl {
program: None,
uses: vec![],
exposes: vec![],
offers: vec![],
children: vec![],
collections: vec![],
storage: vec![],
facets: None,
runners: vec![],
environments: vec![],
resolvers: 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()))),
},
])}),
uses: Some(vec![
fsys::UseDecl::Service(fsys::UseServiceDecl {
source: Some(fsys::Ref::Realm(fsys::RealmRef {})),
source_path: Some("/svc/netstack".to_string()),
target_path: Some("/svc/mynetstack".to_string()),
}),
fsys::UseDecl::Protocol(fsys::UseProtocolDecl {
source: Some(fsys::Ref::Realm(fsys::RealmRef {})),
source_path: Some("/svc/legacy_netstack".to_string()),
target_path: Some("/svc/legacy_mynetstack".to_string()),
}),
fsys::UseDecl::Directory(fsys::UseDirectoryDecl {
source: Some(fsys::Ref::Framework(fsys::FrameworkRef {})),
source_path: Some("/data/dir".to_string()),
target_path: Some("/data".to_string()),
rights: Some(fio2::Operations::Connect),
subdir: Some("foo/bar".to_string()),
}),
fsys::UseDecl::Storage(fsys::UseStorageDecl {
type_: Some(fsys::StorageType::Cache),
target_path: Some("/cache".to_string()),
}),
fsys::UseDecl::Storage(fsys::UseStorageDecl {
type_: Some(fsys::StorageType::Meta),
target_path: None,
}),
fsys::UseDecl::Runner(fsys::UseRunnerDecl {
source_name: Some("myrunner".to_string()),
}),
]),
exposes: Some(vec![
fsys::ExposeDecl::Protocol(fsys::ExposeProtocolDecl {
source: Some(fsys::Ref::Child(fsys::ChildRef {
name: "netstack".to_string(),
collection: None,
})),
source_path: Some("/svc/legacy_netstack".to_string()),
target_path: Some("/svc/legacy_mynetstack".to_string()),
target: Some(fsys::Ref::Realm(fsys::RealmRef {})),
}),
fsys::ExposeDecl::Directory(fsys::ExposeDirectoryDecl {
source: Some(fsys::Ref::Child(fsys::ChildRef {
name: "netstack".to_string(),
collection: None,
})),
source_path: Some("/data/dir".to_string()),
target_path: Some("/data".to_string()),
target: Some(fsys::Ref::Framework(fsys::FrameworkRef {})),
rights: Some(fio2::Operations::Connect),
subdir: Some("foo/bar".to_string()),
}),
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::Realm(fsys::RealmRef {})),
target_name: Some("elf".to_string()),
}),
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::Realm(fsys::RealmRef{})),
target_name: Some("pkg".to_string()),
}),
fsys::ExposeDecl::Service(fsys::ExposeServiceDecl {
source: Some(fsys::Ref::Child(fsys::ChildRef {
name: "netstack".to_string(),
collection: None,
})),
source_path: Some("/svc/netstack1".to_string()),
target_path: Some("/svc/mynetstack".to_string()),
target: Some(fsys::Ref::Realm(fsys::RealmRef {})),
}),
fsys::ExposeDecl::Service(fsys::ExposeServiceDecl {
source: Some(fsys::Ref::Child(fsys::ChildRef {
name: "netstack".to_string(),
collection: None,
})),
source_path: Some("/svc/netstack2".to_string()),
target_path: Some("/svc/mynetstack".to_string()),
target: Some(fsys::Ref::Realm(fsys::RealmRef {})),
}),
]),
offers: Some(vec![
fsys::OfferDecl::Protocol(fsys::OfferProtocolDecl {
source: Some(fsys::Ref::Realm(fsys::RealmRef {})),
source_path: Some("/svc/legacy_netstack".to_string()),
target: Some(fsys::Ref::Child(
fsys::ChildRef {
name: "echo".to_string(),
collection: None,
}
)),
target_path: Some("/svc/legacy_mynetstack".to_string()),
dependency_type: Some(fsys::DependencyType::WeakForMigration),
}),
fsys::OfferDecl::Directory(fsys::OfferDirectoryDecl {
source: Some(fsys::Ref::Realm(fsys::RealmRef {})),
source_path: Some("/data/dir".to_string()),
target: Some(fsys::Ref::Collection(
fsys::CollectionRef { name: "modular".to_string() }
)),
target_path: Some("/data".to_string()),
rights: Some(fio2::Operations::Connect),
subdir: None,
dependency_type: Some(fsys::DependencyType::Strong),
}),
fsys::OfferDecl::Storage(fsys::OfferStorageDecl {
type_: Some(fsys::StorageType::Cache),
source: Some(fsys::Ref::Storage(fsys::StorageRef {
name: "memfs".to_string(),
})),
target: Some(fsys::Ref::Collection(
fsys::CollectionRef { name: "modular".to_string() }
)),
}),
fsys::OfferDecl::Runner(fsys::OfferRunnerDecl {
source: Some(fsys::Ref::Realm(fsys::RealmRef {})),
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::OfferDecl::Resolver(fsys::OfferResolverDecl{
source: Some(fsys::Ref::Realm(fsys::RealmRef{})),
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::OfferDecl::Service(fsys::OfferServiceDecl {
source: Some(fsys::Ref::Realm(fsys::RealmRef {})),
source_path: Some("/svc/netstack1".to_string()),
target: Some(fsys::Ref::Child(
fsys::ChildRef {
name: "echo".to_string(),
collection: None,
}
)),
target_path: Some("/svc/mynetstack".to_string()),
}),
fsys::OfferDecl::Service(fsys::OfferServiceDecl {
source: Some(fsys::Ref::Realm(fsys::RealmRef {})),
source_path: Some("/svc/netstack2".to_string()),
target: Some(fsys::Ref::Child(
fsys::ChildRef {
name: "echo".to_string(),
collection: None,
}
)),
target_path: Some("/svc/mynetstack".to_string()),
}),
]),
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 {
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()),
},
]),
collections: Some(vec![
fsys::CollectionDecl {
name: Some("modular".to_string()),
durability: Some(fsys::Durability::Persistent),
},
fsys::CollectionDecl {
name: Some("tests".to_string()),
durability: Some(fsys::Durability::Transient),
},
]),
facets: Some(fsys::Object{entries: vec![
fsys::Entry{
key: "author".to_string(),
value: Some(Box::new(fsys::Value::Str("Fuchsia".to_string()))),
},
]}),
storage: Some(vec![
fsys::StorageDecl {
name: Some("memfs".to_string()),
source_path: Some("/memfs".to_string()),
source: Some(fsys::Ref::Realm(fsys::RealmRef {})),
}
]),
runners: Some(vec![
fsys::RunnerDecl {
name: Some("elf".to_string()),
source_path: Some("/elf".to_string()),
source: Some(fsys::Ref::Self_(fsys::SelfRef {})),
}
]),
resolvers: Some(vec![
fsys::ResolverDecl {
name: Some("pkg".to_string()),
source_path: Some("/pkg_resolver".to_string()),
}
]),
environments: Some(vec![
fsys::EnvironmentDecl {
name: Some("test_env".to_string()),
extends: Some(fsys::EnvironmentExtends::Realm),
}
]),
},
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()))),
},
])}),
uses: vec![
UseDecl::Service(UseServiceDecl {
source: UseSource::Realm,
source_path: "/svc/netstack".try_into().unwrap(),
target_path: "/svc/mynetstack".try_into().unwrap(),
}),
UseDecl::Protocol(UseProtocolDecl {
source: UseSource::Realm,
source_path: "/svc/legacy_netstack".try_into().unwrap(),
target_path: "/svc/legacy_mynetstack".try_into().unwrap(),
}),
UseDecl::Directory(UseDirectoryDecl {
source: UseSource::Framework,
source_path: "/data/dir".try_into().unwrap(),
target_path: "/data".try_into().unwrap(),
rights: fio2::Operations::Connect,
subdir: Some("foo/bar".into()),
}),
UseDecl::Storage(UseStorageDecl::Cache("/cache".try_into().unwrap())),
UseDecl::Storage(UseStorageDecl::Meta),
UseDecl::Runner(UseRunnerDecl {
source_name: "myrunner".into(),
}),
],
exposes: vec![
ExposeDecl::Protocol(ExposeProtocolDecl {
source: ExposeSource::Child("netstack".to_string()),
source_path: "/svc/legacy_netstack".try_into().unwrap(),
target_path: "/svc/legacy_mynetstack".try_into().unwrap(),
target: ExposeTarget::Realm,
}),
ExposeDecl::Directory(ExposeDirectoryDecl {
source: ExposeSource::Child("netstack".to_string()),
source_path: "/data/dir".try_into().unwrap(),
target_path: "/data".try_into().unwrap(),
target: ExposeTarget::Framework,
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::Realm,
target_name: "elf".try_into().unwrap(),
}),
ExposeDecl::Resolver(ExposeResolverDecl {
source: ExposeSource::Child("netstack".to_string()),
source_name: "pkg".try_into().unwrap(),
target: ExposeTarget::Realm,
target_name: "pkg".try_into().unwrap(),
}),
ExposeDecl::Service(ExposeServiceDecl {
sources: vec![
ServiceSource::<ExposeServiceSource> {
source: ExposeServiceSource::Child("netstack".to_string()),
source_path: "/svc/netstack1".try_into().unwrap(),
},
ServiceSource::<ExposeServiceSource> {
source: ExposeServiceSource::Child("netstack".to_string()),
source_path: "/svc/netstack2".try_into().unwrap(),
},
],
target_path: "/svc/mynetstack".try_into().unwrap(),
target: ExposeTarget::Realm,
}),
],
offers: vec![
OfferDecl::Protocol(OfferProtocolDecl {
source: OfferServiceSource::Realm,
source_path: "/svc/legacy_netstack".try_into().unwrap(),
target: OfferTarget::Child("echo".to_string()),
target_path: "/svc/legacy_mynetstack".try_into().unwrap(),
dependency_type: DependencyType::WeakForMigration,
}),
OfferDecl::Directory(OfferDirectoryDecl {
source: OfferDirectorySource::Realm,
source_path: "/data/dir".try_into().unwrap(),
target: OfferTarget::Collection("modular".to_string()),
target_path: "/data".try_into().unwrap(),
rights: Some(fio2::Operations::Connect),
subdir: None,
dependency_type: DependencyType::Strong,
}),
OfferDecl::Storage(OfferStorageDecl::Cache(
OfferStorage {
source: OfferStorageSource::Storage("memfs".to_string()),
target: OfferTarget::Collection("modular".to_string()),
}
)),
OfferDecl::Runner(OfferRunnerDecl {
source: OfferRunnerSource::Realm,
source_name: "elf".try_into().unwrap(),
target: OfferTarget::Child("echo".to_string()),
target_name: "elf2".try_into().unwrap(),
}),
OfferDecl::Resolver(OfferResolverDecl {
source: OfferResolverSource::Realm,
source_name: "pkg".try_into().unwrap(),
target: OfferTarget::Child("echo".to_string()),
target_name: "pkg".try_into().unwrap(),
}),
OfferDecl::Service(OfferServiceDecl {
sources: vec![
ServiceSource::<OfferServiceSource> {
source: OfferServiceSource::Realm,
source_path: "/svc/netstack1".try_into().unwrap(),
},
ServiceSource::<OfferServiceSource> {
source: OfferServiceSource::Realm,
source_path: "/svc/netstack2".try_into().unwrap(),
},
],
target: OfferTarget::Child("echo".to_string()),
target_path: "/svc/mynetstack".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: "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,
},
CollectionDecl {
name: "tests".to_string(),
durability: fsys::Durability::Transient,
},
],
facets: Some(fsys::Object{entries: vec![
fsys::Entry{
key: "author".to_string(),
value: Some(Box::new(fsys::Value::Str("Fuchsia".to_string()))),
},
]}),
storage: vec![
StorageDecl {
name: "memfs".to_string(),
source_path: "/memfs".try_into().unwrap(),
source: StorageDirectorySource::Realm,
},
],
runners: vec![
RunnerDecl {
name: "elf".to_string(),
source: RunnerSource::Self_,
source_path: "/elf".try_into().unwrap(),
}
],
resolvers: vec![
ResolverDecl {
name: "pkg".to_string(),
source_path: "/pkg_resolver".try_into().unwrap(),
}
],
environments: vec![
EnvironmentDecl {
name: "test_env".to_string(),
extends: fsys::EnvironmentExtends::Realm,
}
]
}
},
},
}
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::Realm(fsys::RealmRef {})),
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::Realm,
OfferServiceSource::Self_,
OfferServiceSource::Child("foo".to_string()),
],
result_type = OfferServiceSource,
},
fidl_into_and_from_offer_directory_source => {
input = vec![
Some(fsys::Ref::Realm(fsys::RealmRef {})),
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::Realm,
OfferDirectorySource::Self_,
OfferDirectorySource::Framework,
OfferDirectorySource::Child("foo".to_string()),
],
result_type = OfferDirectorySource,
},
fidl_into_and_from_offer_storage_source => {
input = vec![
Some(fsys::Ref::Realm(fsys::RealmRef {})),
Some(fsys::Ref::Storage(fsys::StorageRef {
name: "foo".to_string(),
})),
],
input_type = Option<fsys::Ref>,
result = vec![
OfferStorageSource::Realm,
OfferStorageSource::Storage("foo".to_string()),
],
result_type = OfferStorageSource,
},
fidl_into_and_from_storage_capability => {
input = vec![
fsys::StorageDecl {
name: Some("minfs".to_string()),
source_path: Some("/minfs".to_string()),
source: Some(fsys::Ref::Realm(fsys::RealmRef {})),
},
fsys::StorageDecl {
name: Some("minfs".to_string()),
source_path: Some("/minfs".to_string()),
source: Some(fsys::Ref::Child(fsys::ChildRef {
name: "foo".to_string(),
collection: None,
})),
},
],
input_type = fsys::StorageDecl,
result = vec![
StorageDecl {
name: "minfs".to_string(),
source_path: CapabilityPath::try_from("/minfs").unwrap(),
source: StorageDirectorySource::Realm,
},
StorageDecl {
name: "minfs".to_string(),
source_path: CapabilityPath::try_from("/minfs").unwrap(),
source: StorageDirectorySource::Child("foo".to_string()),
},
],
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)
},
},
}
}