1use cm_rust_derive::{ExposeDeclCommon, ExposeDeclCommonAlwaysRequired, FidlDecl, ToGenericRef};
6use cm_types::{AllowedOffers, BorrowedSeparatedPath, LongName, Name, Path, RelativePath, Url};
7use directed_graph::DirectedGraph;
8use fidl_fuchsia_component_decl as fdecl;
9use fidl_fuchsia_data as fdata;
10use fidl_fuchsia_io as fio;
11use fidl_fuchsia_process as fprocess;
12use fidl_fuchsia_sys2 as fsys;
13use from_enum::FromEnum;
14use std::collections::{BTreeMap, HashMap};
15use std::hash::Hash;
16use std::sync::LazyLock;
17use std::{fmt, mem};
18use strum_macros::EnumIter;
19use thiserror::Error;
20
21#[cfg(feature = "serde")]
22use serde::{Deserialize, Serialize};
23
24#[cfg(feature = "serde")]
25mod serde_ext;
26
27pub mod capability;
28pub mod config;
29pub mod offer;
30pub mod r#use;
31
32pub use crate::capability::*;
33pub use crate::config::*;
34#[allow(unused_imports)]
35pub use crate::offer::*; pub use crate::r#use::*;
37
38pub trait FidlIntoNative<T> {
40 fn fidl_into_native(self) -> T;
41}
42
43impl<Native, Fidl> FidlIntoNative<Box<[Native]>> for Vec<Fidl>
44where
45 Fidl: FidlIntoNative<Native>,
46{
47 fn fidl_into_native(self) -> Box<[Native]> {
48 IntoIterator::into_iter(self).map(|s| s.fidl_into_native()).collect()
49 }
50}
51
52pub trait NativeIntoFidl<T> {
53 fn native_into_fidl(self) -> T;
54}
55
56impl<Native, Fidl> NativeIntoFidl<Vec<Fidl>> for Box<[Native]>
57where
58 Native: NativeIntoFidl<Fidl>,
59{
60 fn native_into_fidl(self) -> Vec<Fidl> {
61 IntoIterator::into_iter(self).map(|s| s.native_into_fidl()).collect()
62 }
63}
64
65impl FidlIntoNative<Name> for String {
66 fn fidl_into_native(self) -> Name {
67 self.parse().unwrap()
69 }
70}
71
72impl NativeIntoFidl<String> for Name {
73 fn native_into_fidl(self) -> String {
74 self.to_string()
75 }
76}
77
78impl FidlIntoNative<LongName> for String {
79 fn fidl_into_native(self) -> LongName {
80 self.parse().unwrap()
82 }
83}
84
85impl NativeIntoFidl<String> for LongName {
86 fn native_into_fidl(self) -> String {
87 self.to_string()
88 }
89}
90
91impl FidlIntoNative<Path> for String {
92 fn fidl_into_native(self) -> Path {
93 self.parse().unwrap()
95 }
96}
97
98impl NativeIntoFidl<String> for Path {
99 fn native_into_fidl(self) -> String {
100 self.to_string()
101 }
102}
103
104impl FidlIntoNative<RelativePath> for String {
105 fn fidl_into_native(self) -> RelativePath {
106 self.parse().unwrap()
108 }
109}
110
111impl NativeIntoFidl<String> for RelativePath {
112 fn native_into_fidl(self) -> String {
113 self.to_string()
114 }
115}
116
117impl NativeIntoFidl<Option<String>> for RelativePath {
118 fn native_into_fidl(self) -> Option<String> {
119 if self.is_dot() { None } else { Some(self.to_string()) }
120 }
121}
122
123impl FidlIntoNative<Url> for String {
124 fn fidl_into_native(self) -> Url {
125 self.parse().unwrap()
127 }
128}
129
130impl NativeIntoFidl<String> for Url {
131 fn native_into_fidl(self) -> String {
132 self.to_string()
133 }
134}
135
136impl<F, N> FidlIntoNative<Box<N>> for F
137where
138 F: FidlIntoNative<N>,
139{
140 fn fidl_into_native(self) -> Box<N> {
141 Box::new(self.fidl_into_native())
142 }
143}
144
145impl<N, F> NativeIntoFidl<F> for Box<N>
146where
147 N: NativeIntoFidl<F>,
148{
149 fn native_into_fidl(self) -> F {
150 (*self).native_into_fidl()
151 }
152}
153
154macro_rules! fidl_translations_identical {
156 ($into_type:ty) => {
157 impl FidlIntoNative<$into_type> for $into_type {
158 fn fidl_into_native(self) -> $into_type {
159 self
160 }
161 }
162 impl NativeIntoFidl<$into_type> for $into_type {
163 fn native_into_fidl(self) -> Self {
164 self
165 }
166 }
167 };
168}
169
170macro_rules! fidl_translations_from_into {
173 ($native_type:ty, $fidl_type:ty) => {
174 impl FidlIntoNative<$native_type> for $fidl_type {
175 fn fidl_into_native(self) -> $native_type {
176 self.into()
177 }
178 }
179 impl NativeIntoFidl<$fidl_type> for $native_type {
180 fn native_into_fidl(self) -> $fidl_type {
181 self.into()
182 }
183 }
184 };
185}
186
187macro_rules! fidl_translations_symmetrical_enums {
193($fidl_type:ty , $native_type:ty, $($variant: ident),*) => {
194 impl FidlIntoNative<$native_type> for $fidl_type {
195 fn fidl_into_native(self) -> $native_type {
196 match self {
197 $( <$fidl_type>::$variant => <$native_type>::$variant, )*
198 }
199 }
200 }
201 impl NativeIntoFidl<$fidl_type> for $native_type {
202 fn native_into_fidl(self) -> $fidl_type {
203 match self {
204 $( <$native_type>::$variant => <$fidl_type>::$variant, )*
205 }
206 }
207 }
208 };
209}
210
211#[derive(FidlDecl, Debug, Clone, PartialEq, Default)]
212#[fidl_decl(fidl_table = "fdecl::Component")]
213pub struct ComponentDecl {
214 pub program: Option<ProgramDecl>,
215 pub uses: Box<[UseDecl]>,
216 pub exposes: Box<[ExposeDecl]>,
217 pub offers: Box<[OfferDecl]>,
218 pub capabilities: Box<[CapabilityDecl]>,
219 pub children: Box<[ChildDecl]>,
220 pub collections: Box<[CollectionDecl]>,
221 pub facets: Option<fdata::Dictionary>,
222 pub environments: Box<[EnvironmentDecl]>,
223 pub config: Option<ConfigDecl>,
224 #[cfg(fuchsia_api_level_at_least = "31")]
225 pub debug_info: Option<DebugInfo>,
226}
227
228impl ComponentDecl {
229 #[cfg(fuchsia_api_level_at_least = "HEAD")]
231 pub fn get_runner(&self) -> Option<UseRunnerDecl> {
232 self.program
233 .as_ref()
234 .and_then(|p| p.runner.as_ref())
235 .map(|r| UseRunnerDecl {
236 source: UseSource::Environment,
237 source_name: r.clone(),
238 source_dictionary: Default::default(),
239 })
240 .or_else(|| {
241 self.uses.iter().find_map(|u| match u {
242 UseDecl::Runner(r) => Some(r.clone()),
243 _ => None,
244 })
245 })
246 }
247
248 pub fn find_storage_source<'a>(&'a self, storage_name: &Name) -> Option<&'a StorageDecl> {
250 self.capabilities.iter().find_map(|c| match c {
251 CapabilityDecl::Storage(s) if &s.name == storage_name => Some(s),
252 _ => None,
253 })
254 }
255
256 pub fn find_protocol_source<'a>(&'a self, protocol_name: &Name) -> Option<&'a ProtocolDecl> {
258 self.capabilities.iter().find_map(|c| match c {
259 CapabilityDecl::Protocol(r) if &r.name == protocol_name => Some(r),
260 _ => None,
261 })
262 }
263
264 pub fn find_directory_source<'a>(&'a self, directory_name: &Name) -> Option<&'a DirectoryDecl> {
266 self.capabilities.iter().find_map(|c| match c {
267 CapabilityDecl::Directory(r) if &r.name == directory_name => Some(r),
268 _ => None,
269 })
270 }
271
272 pub fn find_runner_source<'a>(&'a self, runner_name: &Name) -> Option<&'a RunnerDecl> {
274 self.capabilities.iter().find_map(|c| match c {
275 CapabilityDecl::Runner(r) if &r.name == runner_name => Some(r),
276 _ => None,
277 })
278 }
279
280 pub fn find_resolver_source<'a>(&'a self, resolver_name: &Name) -> Option<&'a ResolverDecl> {
282 self.capabilities.iter().find_map(|c| match c {
283 CapabilityDecl::Resolver(r) if &r.name == resolver_name => Some(r),
284 _ => None,
285 })
286 }
287
288 pub fn find_collection<'a>(&'a self, collection_name: &str) -> Option<&'a CollectionDecl> {
290 self.collections.iter().find(|c| c.name == collection_name)
291 }
292
293 pub fn is_protocol_exposed_to_framework(&self, in_target_name: &Name) -> bool {
295 self.exposes.iter().any(|expose| match expose {
296 ExposeDecl::Protocol(ExposeProtocolDecl { target, target_name, .. })
297 if target == &ExposeTarget::Framework =>
298 {
299 target_name == in_target_name
300 }
301 _ => false,
302 })
303 }
304
305 pub fn uses_protocol(&self, source_name: &Name) -> bool {
307 self.uses.iter().any(|use_decl| match use_decl {
308 UseDecl::Protocol(ls) => &ls.source_name == source_name,
309 _ => false,
310 })
311 }
312}
313
314pub use cm_types::Availability;
315
316fidl_translations_symmetrical_enums!(
317 fdecl::Availability,
318 Availability,
319 Required,
320 Optional,
321 SameAsTarget,
322 Transitional
323);
324
325pub use cm_types::DeliveryType;
326
327#[cfg(fuchsia_api_level_at_least = "HEAD")]
328impl FidlIntoNative<DeliveryType> for fdecl::DeliveryType {
329 fn fidl_into_native(self) -> DeliveryType {
330 self.try_into().unwrap()
331 }
332}
333
334#[cfg(fuchsia_api_level_at_least = "HEAD")]
335impl NativeIntoFidl<fdecl::DeliveryType> for DeliveryType {
336 fn native_into_fidl(self) -> fdecl::DeliveryType {
337 self.into()
338 }
339}
340
341pub trait SourcePath {
342 fn source_path(&self) -> BorrowedSeparatedPath<'_>;
343 fn is_from_dictionary(&self) -> bool {
344 !self.source_path().dirname.is_dot()
345 }
346}
347
348#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
349#[derive(Debug, Clone, PartialEq, Eq)]
350pub struct NameMapping {
351 pub source_name: Name,
352 pub target_name: Name,
353}
354
355impl NativeIntoFidl<fdecl::NameMapping> for NameMapping {
356 fn native_into_fidl(self) -> fdecl::NameMapping {
357 fdecl::NameMapping {
358 source_name: self.source_name.native_into_fidl(),
359 target_name: self.target_name.native_into_fidl(),
360 }
361 }
362}
363
364impl FidlIntoNative<NameMapping> for fdecl::NameMapping {
365 fn fidl_into_native(self) -> NameMapping {
366 NameMapping {
367 source_name: self.source_name.fidl_into_native(),
368 target_name: self.target_name.fidl_into_native(),
369 }
370 }
371}
372
373#[cfg_attr(
374 feature = "serde",
375 derive(Deserialize, Serialize),
376 serde(tag = "type", rename_all = "snake_case")
377)]
378#[derive(FidlDecl, FromEnum, Debug, Clone, PartialEq, Eq)]
379#[fidl_decl(fidl_union = "fdecl::Expose")]
380pub enum ExposeDecl {
381 Service(ExposeServiceDecl),
382 Protocol(ExposeProtocolDecl),
383 Directory(ExposeDirectoryDecl),
384 Runner(ExposeRunnerDecl),
385 Resolver(ExposeResolverDecl),
386 Dictionary(ExposeDictionaryDecl),
387 Config(ExposeConfigurationDecl),
388}
389
390impl SourceName for ExposeDecl {
391 fn source_name(&self) -> &Name {
392 match self {
393 Self::Service(e) => e.source_name(),
394 Self::Protocol(e) => e.source_name(),
395 Self::Directory(e) => e.source_name(),
396 Self::Runner(e) => e.source_name(),
397 Self::Resolver(e) => e.source_name(),
398 Self::Dictionary(e) => e.source_name(),
399 Self::Config(e) => e.source_name(),
400 }
401 }
402}
403
404impl SourcePath for ExposeDecl {
405 fn source_path(&self) -> BorrowedSeparatedPath<'_> {
406 match self {
407 Self::Service(e) => e.source_path(),
408 Self::Protocol(e) => e.source_path(),
409 Self::Directory(e) => e.source_path(),
410 Self::Runner(e) => e.source_path(),
411 Self::Resolver(e) => e.source_path(),
412 Self::Dictionary(e) => e.source_path(),
413 Self::Config(e) => e.source_path(),
414 }
415 }
416}
417
418impl ExposeDeclCommon for ExposeDecl {
419 fn source(&self) -> &ExposeSource {
420 match self {
421 Self::Service(e) => e.source(),
422 Self::Protocol(e) => e.source(),
423 Self::Directory(e) => e.source(),
424 Self::Runner(e) => e.source(),
425 Self::Resolver(e) => e.source(),
426 Self::Dictionary(e) => e.source(),
427 Self::Config(e) => e.source(),
428 }
429 }
430
431 fn target(&self) -> &ExposeTarget {
432 match self {
433 Self::Service(e) => e.target(),
434 Self::Protocol(e) => e.target(),
435 Self::Directory(e) => e.target(),
436 Self::Runner(e) => e.target(),
437 Self::Resolver(e) => e.target(),
438 Self::Dictionary(e) => e.target(),
439 Self::Config(e) => e.target(),
440 }
441 }
442
443 fn target_name(&self) -> &Name {
444 match self {
445 Self::Service(e) => e.target_name(),
446 Self::Protocol(e) => e.target_name(),
447 Self::Directory(e) => e.target_name(),
448 Self::Runner(e) => e.target_name(),
449 Self::Resolver(e) => e.target_name(),
450 Self::Dictionary(e) => e.target_name(),
451 Self::Config(e) => e.target_name(),
452 }
453 }
454
455 fn availability(&self) -> &Availability {
456 match self {
457 Self::Service(e) => e.availability(),
458 Self::Protocol(e) => e.availability(),
459 Self::Directory(e) => e.availability(),
460 Self::Runner(e) => e.availability(),
461 Self::Resolver(e) => e.availability(),
462 Self::Dictionary(e) => e.availability(),
463 Self::Config(e) => e.availability(),
464 }
465 }
466}
467
468#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
469#[derive(FidlDecl, ExposeDeclCommon, Debug, Clone, PartialEq, Eq)]
470#[fidl_decl(fidl_table = "fdecl::ExposeService", source_path = "dictionary")]
471pub struct ExposeServiceDecl {
472 pub source: ExposeSource,
473 pub source_name: Name,
474 #[fidl_decl(default_preserve_none)]
475 pub source_dictionary: RelativePath,
476 pub target: ExposeTarget,
477 pub target_name: Name,
478 #[fidl_decl(default)]
479 pub availability: Availability,
480}
481
482#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
483#[derive(FidlDecl, ExposeDeclCommon, Debug, Clone, PartialEq, Eq)]
484#[fidl_decl(fidl_table = "fdecl::ExposeProtocol", source_path = "dictionary")]
485pub struct ExposeProtocolDecl {
486 pub source: ExposeSource,
487 pub source_name: Name,
488 #[fidl_decl(default_preserve_none)]
489 pub source_dictionary: RelativePath,
490 pub target: ExposeTarget,
491 pub target_name: Name,
492 #[fidl_decl(default)]
493 pub availability: Availability,
494}
495
496#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
497#[derive(FidlDecl, ExposeDeclCommon, Debug, Clone, PartialEq, Eq)]
498#[fidl_decl(fidl_table = "fdecl::ExposeDirectory", source_path = "dictionary")]
499pub struct ExposeDirectoryDecl {
500 pub source: ExposeSource,
501 pub source_name: Name,
502 #[fidl_decl(default_preserve_none)]
503 pub source_dictionary: RelativePath,
504 pub target: ExposeTarget,
505 pub target_name: Name,
506
507 #[cfg_attr(
508 feature = "serde",
509 serde(
510 deserialize_with = "serde_ext::deserialize_opt_fio_operations",
511 serialize_with = "serde_ext::serialize_opt_fio_operations"
512 )
513 )]
514 pub rights: Option<fio::Operations>,
515
516 #[fidl_decl(default_preserve_none)]
517 pub subdir: RelativePath,
518
519 #[fidl_decl(default)]
520 pub availability: Availability,
521}
522
523#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
524#[derive(FidlDecl, ExposeDeclCommonAlwaysRequired, Debug, Clone, PartialEq, Eq)]
525#[fidl_decl(fidl_table = "fdecl::ExposeRunner", source_path = "dictionary")]
526pub struct ExposeRunnerDecl {
527 pub source: ExposeSource,
528 pub source_name: Name,
529 #[fidl_decl(default_preserve_none)]
530 pub source_dictionary: RelativePath,
531 pub target: ExposeTarget,
532 pub target_name: Name,
533}
534
535#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
536#[derive(FidlDecl, ExposeDeclCommonAlwaysRequired, Debug, Clone, PartialEq, Eq)]
537#[fidl_decl(fidl_table = "fdecl::ExposeResolver", source_path = "dictionary")]
538pub struct ExposeResolverDecl {
539 pub source: ExposeSource,
540 pub source_name: Name,
541 #[fidl_decl(default_preserve_none)]
542 pub source_dictionary: RelativePath,
543 pub target: ExposeTarget,
544 pub target_name: Name,
545}
546
547#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
548#[derive(FidlDecl, ExposeDeclCommon, Debug, Clone, PartialEq, Eq)]
549#[fidl_decl(fidl_table = "fdecl::ExposeDictionary", source_path = "dictionary")]
550pub struct ExposeDictionaryDecl {
551 pub source: ExposeSource,
552 pub source_name: Name,
553 #[fidl_decl(default_preserve_none)]
554 pub source_dictionary: RelativePath,
555 pub target: ExposeTarget,
556 pub target_name: Name,
557 #[fidl_decl(default)]
558 pub availability: Availability,
559}
560
561#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
562#[derive(FidlDecl, ExposeDeclCommon, Debug, Clone, PartialEq, Eq)]
563#[fidl_decl(fidl_table = "fdecl::ExposeConfiguration", source_path = "name_only")]
564pub struct ExposeConfigurationDecl {
565 pub source: ExposeSource,
566 pub source_name: Name,
567 pub target: ExposeTarget,
568 pub target_name: Name,
569 #[fidl_decl(default_preserve_none)]
570 pub source_dictionary: RelativePath,
571 #[fidl_decl(default)]
572 pub availability: Availability,
573}
574
575#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
576#[fidl_decl(fidl_table = "fdecl::Child")]
577pub struct ChildDecl {
578 pub name: LongName,
579 pub url: Url,
580 pub startup: fdecl::StartupMode,
581 pub on_terminate: Option<fdecl::OnTerminate>,
582 pub environment: Option<Name>,
583 pub config_overrides: Option<Box<[ConfigOverride]>>,
584}
585
586#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
587#[derive(Debug, Clone, PartialEq, Eq, Hash)]
588pub struct ChildRef {
589 pub name: LongName,
590 pub collection: Option<Name>,
591}
592
593impl std::fmt::Display for ChildRef {
594 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
595 if let Some(collection) = &self.collection {
596 write!(f, "{}:{}", collection, self.name)
597 } else {
598 write!(f, "{}", self.name)
599 }
600 }
601}
602
603impl FidlIntoNative<ChildRef> for fdecl::ChildRef {
604 fn fidl_into_native(self) -> ChildRef {
605 ChildRef {
607 name: self.name.parse().unwrap(),
608 collection: self.collection.map(|c| c.parse().unwrap()),
609 }
610 }
611}
612
613impl NativeIntoFidl<fdecl::ChildRef> for ChildRef {
614 fn native_into_fidl(self) -> fdecl::ChildRef {
615 fdecl::ChildRef {
616 name: self.name.to_string(),
617 collection: self.collection.map(|c| c.to_string()),
618 }
619 }
620}
621
622#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
623#[fidl_decl(fidl_table = "fdecl::Collection")]
624pub struct CollectionDecl {
625 pub name: Name,
626 pub durability: fdecl::Durability,
627 pub environment: Option<Name>,
628
629 #[fidl_decl(default)]
630 pub allowed_offers: AllowedOffers,
631 #[fidl_decl(default)]
632 pub allow_long_names: bool,
633
634 pub persistent_storage: Option<bool>,
635}
636
637#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
638#[fidl_decl(fidl_table = "fdecl::Environment")]
639pub struct EnvironmentDecl {
640 pub name: Name,
641 pub extends: fdecl::EnvironmentExtends,
642 pub runners: Box<[RunnerRegistration]>,
643 pub resolvers: Box<[ResolverRegistration]>,
644 pub debug_capabilities: Box<[DebugRegistration]>,
645 pub stop_timeout_ms: Option<u32>,
646}
647
648#[cfg(fuchsia_api_level_at_least = "31")]
649#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
650#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
651#[fidl_decl(fidl_table = "fdecl::DebugInfo")]
652pub struct DebugInfo {
653 pub manifest_sources: Option<Box<[String]>>,
654}
655
656#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
657#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
658#[fidl_decl(fidl_table = "fdecl::RunnerRegistration")]
659pub struct RunnerRegistration {
660 pub source_name: Name,
661 pub target_name: Name,
662 pub source: RegistrationSource,
663}
664
665impl SourceName for RunnerRegistration {
666 fn source_name(&self) -> &Name {
667 &self.source_name
668 }
669}
670
671impl RegistrationDeclCommon for RunnerRegistration {
672 const TYPE: &'static str = "runner";
673
674 fn source(&self) -> &RegistrationSource {
675 &self.source
676 }
677}
678
679#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
680#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
681#[fidl_decl(fidl_table = "fdecl::ResolverRegistration")]
682pub struct ResolverRegistration {
683 pub resolver: Name,
684 pub source: RegistrationSource,
685 pub scheme: String,
686}
687
688impl SourceName for ResolverRegistration {
689 fn source_name(&self) -> &Name {
690 &self.resolver
691 }
692}
693
694impl RegistrationDeclCommon for ResolverRegistration {
695 const TYPE: &'static str = "resolver";
696
697 fn source(&self) -> &RegistrationSource {
698 &self.source
699 }
700}
701
702#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
703#[fidl_decl(fidl_union = "fdecl::DebugRegistration")]
704pub enum DebugRegistration {
705 Protocol(DebugProtocolRegistration),
706}
707
708impl RegistrationDeclCommon for DebugRegistration {
709 const TYPE: &'static str = "debug_protocol";
710
711 fn source(&self) -> &RegistrationSource {
712 match self {
713 DebugRegistration::Protocol(protocol_reg) => &protocol_reg.source,
714 }
715 }
716}
717
718impl SourceName for DebugRegistration {
719 fn source_name(&self) -> &Name {
720 match self {
721 DebugRegistration::Protocol(protocol_reg) => &protocol_reg.source_name,
722 }
723 }
724}
725
726#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
727#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
728#[fidl_decl(fidl_table = "fdecl::DebugProtocolRegistration")]
729pub struct DebugProtocolRegistration {
730 pub source_name: Name,
731 pub source: RegistrationSource,
732 pub target_name: Name,
733}
734
735#[derive(FidlDecl, Debug, Clone, PartialEq)]
736#[fidl_decl(fidl_table = "fdecl::Program")]
737pub struct ProgramDecl {
738 pub runner: Option<Name>,
739 pub info: fdata::Dictionary,
740}
741
742impl Default for ProgramDecl {
743 fn default() -> Self {
744 Self { runner: None, info: fdata::Dictionary::default() }
745 }
746}
747
748fidl_translations_identical!([u8; 32]);
749fidl_translations_identical!(u8);
750fidl_translations_identical!(u16);
751fidl_translations_identical!(u32);
752fidl_translations_identical!(u64);
753fidl_translations_identical!(i8);
754fidl_translations_identical!(i16);
755fidl_translations_identical!(i32);
756fidl_translations_identical!(i64);
757fidl_translations_identical!(bool);
758fidl_translations_identical!(String);
759fidl_translations_identical!(Vec<Name>);
760fidl_translations_identical!(fdecl::StartupMode);
761fidl_translations_identical!(fdecl::OnTerminate);
762fidl_translations_identical!(fdecl::Durability);
763fidl_translations_identical!(fdata::Dictionary);
764fidl_translations_identical!(fio::Operations);
765fidl_translations_identical!(fio::Flags);
766fidl_translations_identical!(fdecl::EnvironmentExtends);
767fidl_translations_identical!(fdecl::StorageId);
768fidl_translations_identical!(Vec<fprocess::HandleInfo>);
769fidl_translations_identical!(fsys::ServiceInstance);
770fidl_translations_from_into!(cm_types::AllowedOffers, fdecl::AllowedOffers);
771
772#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
773#[derive(Debug, Clone, PartialEq, Eq)]
774pub enum DependencyType {
775 Strong,
776 Weak,
777}
778
779impl Default for DependencyType {
780 fn default() -> Self {
781 Self::Strong
782 }
783}
784
785fidl_translations_symmetrical_enums!(fdecl::DependencyType, DependencyType, Strong, Weak);
786
787impl UseDecl {
788 pub fn path(&self) -> Option<&Path> {
789 match self {
790 UseDecl::Service(d) => Some(&d.target_path),
791 UseDecl::Protocol(d) => d.target_path.as_ref(),
792 UseDecl::Directory(d) => Some(&d.target_path),
793 UseDecl::Storage(d) => Some(&d.target_path),
794 UseDecl::EventStream(d) => Some(&d.target_path),
795 #[cfg(fuchsia_api_level_at_least = "HEAD")]
796 UseDecl::Runner(_) => None,
797 UseDecl::Config(_) => None,
798 #[cfg(fuchsia_api_level_at_least = "29")]
799 UseDecl::Dictionary(d) => Some(&d.target_path),
800 }
801 }
802
803 pub fn name(&self) -> Option<&Name> {
804 match self {
805 UseDecl::Storage(storage_decl) => Some(&storage_decl.source_name),
806 UseDecl::EventStream(_) => None,
807 UseDecl::Service(_) | UseDecl::Protocol(_) | UseDecl::Directory(_) => None,
808 #[cfg(fuchsia_api_level_at_least = "HEAD")]
809 UseDecl::Runner(_) => None,
810 UseDecl::Config(_) => None,
811 #[cfg(fuchsia_api_level_at_least = "29")]
812 UseDecl::Dictionary(_) => None,
813 }
814 }
815}
816
817impl SourceName for UseDecl {
818 fn source_name(&self) -> &Name {
819 match self {
820 UseDecl::Storage(storage_decl) => &storage_decl.source_name,
821 UseDecl::Service(service_decl) => &service_decl.source_name,
822 UseDecl::Protocol(protocol_decl) => &protocol_decl.source_name,
823 UseDecl::Directory(directory_decl) => &directory_decl.source_name,
824 UseDecl::EventStream(event_stream_decl) => &event_stream_decl.source_name,
825 #[cfg(fuchsia_api_level_at_least = "HEAD")]
826 UseDecl::Runner(runner_decl) => &runner_decl.source_name,
827 UseDecl::Config(u) => &u.source_name,
828 #[cfg(fuchsia_api_level_at_least = "29")]
829 UseDecl::Dictionary(dictionary_decl) => &dictionary_decl.source_name,
830 }
831 }
832}
833
834impl SourcePath for UseDecl {
835 fn source_path(&self) -> BorrowedSeparatedPath<'_> {
836 match self {
837 UseDecl::Service(u) => u.source_path(),
838 UseDecl::Protocol(u) => u.source_path(),
839 UseDecl::Directory(u) => u.source_path(),
840 UseDecl::Storage(u) => u.source_path(),
841 UseDecl::EventStream(u) => u.source_path(),
842 #[cfg(fuchsia_api_level_at_least = "HEAD")]
843 UseDecl::Runner(u) => u.source_path(),
844 UseDecl::Config(u) => u.source_path(),
845 #[cfg(fuchsia_api_level_at_least = "29")]
846 UseDecl::Dictionary(u) => u.source_path(),
847 }
848 }
849}
850
851pub trait SourceName {
853 fn source_name(&self) -> &Name;
854}
855
856pub trait RegistrationDeclCommon: SourceName + Send + Sync {
858 const TYPE: &'static str;
860 fn source(&self) -> &RegistrationSource;
861}
862
863pub trait ExposeDeclCommon: SourceName + SourcePath + fmt::Debug + Send + Sync {
865 fn target_name(&self) -> &Name;
866 fn target(&self) -> &ExposeTarget;
867 fn source(&self) -> &ExposeSource;
868 fn availability(&self) -> &Availability;
869}
870
871#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
875#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)]
876pub enum CapabilityTypeName {
877 Directory,
878 EventStream,
879 Protocol,
880 Resolver,
881 Runner,
882 Service,
883 Storage,
884 Dictionary,
885 Config,
886}
887
888impl std::str::FromStr for CapabilityTypeName {
889 type Err = Error;
890
891 fn from_str(s: &str) -> Result<Self, Self::Err> {
892 match s {
893 "directory" => Ok(CapabilityTypeName::Directory),
894 "event_stream" => Ok(CapabilityTypeName::EventStream),
895 "protocol" => Ok(CapabilityTypeName::Protocol),
896 "resolver" => Ok(CapabilityTypeName::Resolver),
897 "runner" => Ok(CapabilityTypeName::Runner),
898 "service" => Ok(CapabilityTypeName::Service),
899 "storage" => Ok(CapabilityTypeName::Storage),
900 "dictionary" => Ok(CapabilityTypeName::Dictionary),
901 "configuration" => Ok(CapabilityTypeName::Config),
902 _ => Err(Error::ParseCapabilityTypeName { raw: s.to_string() }),
903 }
904 }
905}
906
907impl FidlIntoNative<CapabilityTypeName> for String {
908 fn fidl_into_native(self) -> CapabilityTypeName {
909 self.parse().unwrap()
910 }
911}
912
913impl NativeIntoFidl<String> for CapabilityTypeName {
914 fn native_into_fidl(self) -> String {
915 self.to_string()
916 }
917}
918
919impl AsRef<str> for CapabilityTypeName {
920 fn as_ref(&self) -> &str {
921 match self {
922 CapabilityTypeName::Directory => "directory",
923 CapabilityTypeName::EventStream => "event_stream",
924 CapabilityTypeName::Protocol => "protocol",
925 CapabilityTypeName::Resolver => "resolver",
926 CapabilityTypeName::Runner => "runner",
927 CapabilityTypeName::Service => "service",
928 CapabilityTypeName::Storage => "storage",
929 CapabilityTypeName::Dictionary => "dictionary",
930 CapabilityTypeName::Config => "configuration",
931 }
932 }
933}
934
935impl fmt::Display for CapabilityTypeName {
936 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
937 write!(f, "{}", self.as_ref())
938 }
939}
940
941impl From<&UseDecl> for CapabilityTypeName {
942 fn from(use_decl: &UseDecl) -> Self {
943 match use_decl {
944 UseDecl::Service(_) => Self::Service,
945 UseDecl::Protocol(_) => Self::Protocol,
946 UseDecl::Directory(_) => Self::Directory,
947 UseDecl::Storage(_) => Self::Storage,
948 UseDecl::EventStream(_) => Self::EventStream,
949 #[cfg(fuchsia_api_level_at_least = "HEAD")]
950 UseDecl::Runner(_) => Self::Runner,
951 UseDecl::Config(_) => Self::Config,
952 #[cfg(fuchsia_api_level_at_least = "29")]
953 UseDecl::Dictionary(_) => Self::Dictionary,
954 }
955 }
956}
957
958impl From<&ExposeDecl> for CapabilityTypeName {
959 fn from(expose_decl: &ExposeDecl) -> Self {
960 match expose_decl {
961 ExposeDecl::Service(_) => Self::Service,
962 ExposeDecl::Protocol(_) => Self::Protocol,
963 ExposeDecl::Directory(_) => Self::Directory,
964 ExposeDecl::Runner(_) => Self::Runner,
965 ExposeDecl::Resolver(_) => Self::Resolver,
966 ExposeDecl::Dictionary(_) => Self::Dictionary,
967 ExposeDecl::Config(_) => Self::Config,
968 }
969 }
970}
971
972impl From<&DebugRegistration> for CapabilityTypeName {
973 fn from(debug: &DebugRegistration) -> Self {
974 match debug {
975 DebugRegistration::Protocol(_) => Self::Protocol,
976 }
977 }
978}
979
980impl From<&RunnerRegistration> for CapabilityTypeName {
981 fn from(_: &RunnerRegistration) -> Self {
982 Self::Runner
983 }
984}
985
986impl From<&ResolverRegistration> for CapabilityTypeName {
987 fn from(_: &ResolverRegistration) -> Self {
988 Self::Resolver
989 }
990}
991
992impl From<CapabilityTypeName> for fio::DirentType {
993 fn from(value: CapabilityTypeName) -> Self {
994 match value {
995 CapabilityTypeName::Directory => fio::DirentType::Directory,
996 CapabilityTypeName::EventStream => fio::DirentType::Service,
997 CapabilityTypeName::Protocol => fio::DirentType::Service,
998 CapabilityTypeName::Service => fio::DirentType::Directory,
999 CapabilityTypeName::Storage => fio::DirentType::Directory,
1000 CapabilityTypeName::Dictionary => fio::DirentType::Directory,
1001 CapabilityTypeName::Resolver => fio::DirentType::Service,
1002 CapabilityTypeName::Runner => fio::DirentType::Service,
1003 CapabilityTypeName::Config => fio::DirentType::Unknown,
1005 }
1006 }
1007}
1008
1009impl FidlIntoNative<HashMap<String, DictionaryValue>> for fdata::Dictionary {
1011 fn fidl_into_native(self) -> HashMap<String, DictionaryValue> {
1012 from_fidl_dict(self)
1013 }
1014}
1015
1016impl NativeIntoFidl<fdata::Dictionary> for HashMap<String, DictionaryValue> {
1017 fn native_into_fidl(self) -> fdata::Dictionary {
1018 to_fidl_dict(self)
1019 }
1020}
1021
1022impl FidlIntoNative<BTreeMap<String, DictionaryValue>> for fdata::Dictionary {
1023 fn fidl_into_native(self) -> BTreeMap<String, DictionaryValue> {
1024 from_fidl_dict_btree(self)
1025 }
1026}
1027
1028impl NativeIntoFidl<fdata::Dictionary> for BTreeMap<String, DictionaryValue> {
1029 fn native_into_fidl(self) -> fdata::Dictionary {
1030 to_fidl_dict_btree(self)
1031 }
1032}
1033
1034#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1035pub enum DictionaryValue {
1036 Str(String),
1037 StrVec(Vec<String>),
1038 Null,
1039}
1040
1041impl FidlIntoNative<DictionaryValue> for Option<Box<fdata::DictionaryValue>> {
1042 fn fidl_into_native(self) -> DictionaryValue {
1043 match self {
1044 Some(v) => match *v {
1045 fdata::DictionaryValue::Str(s) => DictionaryValue::Str(s),
1046 fdata::DictionaryValue::StrVec(ss) => DictionaryValue::StrVec(ss),
1047 _ => DictionaryValue::Null,
1048 },
1049 None => DictionaryValue::Null,
1050 }
1051 }
1052}
1053
1054impl NativeIntoFidl<Option<Box<fdata::DictionaryValue>>> for DictionaryValue {
1055 fn native_into_fidl(self) -> Option<Box<fdata::DictionaryValue>> {
1056 match self {
1057 DictionaryValue::Str(s) => Some(Box::new(fdata::DictionaryValue::Str(s))),
1058 DictionaryValue::StrVec(ss) => Some(Box::new(fdata::DictionaryValue::StrVec(ss))),
1059 DictionaryValue::Null => None,
1060 }
1061 }
1062}
1063
1064fn from_fidl_dict(dict: fdata::Dictionary) -> HashMap<String, DictionaryValue> {
1065 match dict.entries {
1066 Some(entries) => entries.into_iter().map(|e| (e.key, e.value.fidl_into_native())).collect(),
1067 _ => HashMap::new(),
1068 }
1069}
1070
1071fn to_fidl_dict(dict: HashMap<String, DictionaryValue>) -> fdata::Dictionary {
1072 fdata::Dictionary {
1073 entries: Some(
1074 dict.into_iter()
1075 .map(|(key, value)| fdata::DictionaryEntry { key, value: value.native_into_fidl() })
1076 .collect(),
1077 ),
1078 ..Default::default()
1079 }
1080}
1081
1082fn from_fidl_dict_btree(dict: fdata::Dictionary) -> BTreeMap<String, DictionaryValue> {
1083 match dict.entries {
1084 Some(entries) => entries.into_iter().map(|e| (e.key, e.value.fidl_into_native())).collect(),
1085 _ => BTreeMap::new(),
1086 }
1087}
1088
1089fn to_fidl_dict_btree(dict: BTreeMap<String, DictionaryValue>) -> fdata::Dictionary {
1090 fdata::Dictionary {
1091 entries: Some(
1092 dict.into_iter()
1093 .map(|(key, value)| fdata::DictionaryEntry { key, value: value.native_into_fidl() })
1094 .collect(),
1095 ),
1096 ..Default::default()
1097 }
1098}
1099
1100#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
1101#[derive(Debug, Clone, PartialEq, Eq, Hash, Error)]
1102pub enum GenericRef {
1103 Parent,
1104 Self_,
1105 Child(Name),
1106 ChildInCollection(LongName, Name),
1107 Collection(Name),
1108 Framework,
1109 Capability(Name),
1110 Debug,
1111 Void,
1112 #[cfg(fuchsia_api_level_at_least = "HEAD")]
1113 Environment,
1114}
1115
1116impl std::fmt::Display for GenericRef {
1117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1118 match self {
1119 Self::Parent => write!(f, "parent"),
1120 Self::Self_ => write!(f, "self"),
1121 Self::Child(name) => write!(f, "child {name}"),
1122 Self::ChildInCollection(name, collection) => {
1123 write!(f, "child {name} in collection {collection}")
1124 }
1125 Self::Collection(name) => write!(f, "collection {name}"),
1126 Self::Framework => write!(f, "framework"),
1127 Self::Capability(name) => write!(f, "capability {name}"),
1128 Self::Debug => write!(f, "debug"),
1129 Self::Void => write!(f, "void"),
1130 #[cfg(fuchsia_api_level_at_least = "HEAD")]
1131 Self::Environment => write!(f, "environment"),
1132 }
1133 }
1134}
1135
1136pub trait ToGenericRef {
1137 fn to_generic(self) -> GenericRef;
1138}
1139
1140impl ToGenericRef for ChildRef {
1141 fn to_generic(self) -> GenericRef {
1142 if let Some(collection) = self.collection {
1143 GenericRef::ChildInCollection(self.name, collection)
1144 } else {
1145 GenericRef::Child(self.name.to_short_infallible())
1146 }
1147 }
1148}
1149
1150impl FidlIntoNative<GenericRef> for fdecl::Ref {
1151 fn fidl_into_native(self) -> GenericRef {
1152 match self {
1153 fdecl::Ref::Parent(_) => GenericRef::Parent,
1154 fdecl::Ref::Self_(_) => GenericRef::Self_,
1155 fdecl::Ref::Child(child_ref) => {
1156 let child_ref: ChildRef = child_ref.fidl_into_native();
1157 child_ref.to_generic()
1158 }
1159 fdecl::Ref::Collection(collection) => {
1160 GenericRef::Collection(collection.name.fidl_into_native())
1161 }
1162 fdecl::Ref::Framework(_) => GenericRef::Framework,
1163 fdecl::Ref::Capability(capability) => {
1164 GenericRef::Capability(capability.name.fidl_into_native())
1165 }
1166 fdecl::Ref::Debug(_) => GenericRef::Debug,
1167 fdecl::Ref::VoidType(_) => GenericRef::Void,
1168 #[cfg(fuchsia_api_level_at_least = "HEAD")]
1169 fdecl::Ref::Environment(_) => GenericRef::Environment,
1170 _ => panic!("unexpected fdecl::Ref variant found"),
1171 }
1172 }
1173}
1174
1175impl NativeIntoFidl<fdecl::Ref> for GenericRef {
1176 fn native_into_fidl(self) -> fdecl::Ref {
1177 match self {
1178 GenericRef::Parent => fdecl::Ref::Parent(fdecl::ParentRef {}),
1179 GenericRef::Self_ => fdecl::Ref::Self_(fdecl::SelfRef {}),
1180 GenericRef::Child(name) => fdecl::Ref::Child(fdecl::ChildRef {
1181 name: name.native_into_fidl(),
1182 collection: None,
1183 }),
1184 GenericRef::ChildInCollection(name, collection) => fdecl::Ref::Child(fdecl::ChildRef {
1185 name: name.native_into_fidl(),
1186 collection: Some(collection.native_into_fidl()),
1187 }),
1188 GenericRef::Collection(name) => {
1189 fdecl::Ref::Collection(fdecl::CollectionRef { name: name.native_into_fidl() })
1190 }
1191 GenericRef::Framework => fdecl::Ref::Framework(fdecl::FrameworkRef {}),
1192 GenericRef::Capability(name) => {
1193 fdecl::Ref::Capability(fdecl::CapabilityRef { name: name.native_into_fidl() })
1194 }
1195 GenericRef::Debug => fdecl::Ref::Debug(fdecl::DebugRef {}),
1196 GenericRef::Void => fdecl::Ref::VoidType(fdecl::VoidRef {}),
1197 #[cfg(fuchsia_api_level_at_least = "HEAD")]
1198 GenericRef::Environment => fdecl::Ref::Environment(fdecl::EnvironmentRef {}),
1199 }
1200 }
1201}
1202
1203#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
1204#[derive(Debug, Clone, PartialEq, Eq, Hash, ToGenericRef)]
1205pub enum EventScope {
1206 Child(ChildRef),
1207 Collection(Name),
1208}
1209
1210impl FidlIntoNative<EventScope> for fdecl::Ref {
1211 fn fidl_into_native(self) -> EventScope {
1212 match self {
1213 fdecl::Ref::Child(c) => {
1214 if let Some(_) = c.collection {
1215 panic!("Dynamic children scopes are not supported for EventStreams");
1216 } else {
1217 EventScope::Child(ChildRef { name: c.name.parse().unwrap(), collection: None })
1218 }
1219 }
1220 fdecl::Ref::Collection(collection) => {
1221 EventScope::Collection(collection.name.parse().unwrap())
1223 }
1224 _ => panic!("invalid EventScope variant"),
1225 }
1226 }
1227}
1228
1229#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
1230#[derive(Debug, Clone, PartialEq, Eq, ToGenericRef)]
1231pub enum ExposeSource {
1232 Self_,
1233 Child(Name),
1234 Collection(Name),
1235 Framework,
1236 Capability(Name),
1237 Void,
1238}
1239
1240impl std::fmt::Display for ExposeSource {
1241 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1242 match self {
1243 Self::Framework => write!(f, "framework"),
1244 Self::Child(c) => write!(f, "child `#{}`", c),
1245 Self::Collection(c) => write!(f, "collection `#{}`", c),
1246 Self::Self_ => write!(f, "self"),
1247 Self::Capability(c) => write!(f, "capability `{}`", c),
1248 Self::Void => write!(f, "void"),
1249 }
1250 }
1251}
1252
1253impl FidlIntoNative<ExposeSource> for fdecl::Ref {
1254 fn fidl_into_native(self) -> ExposeSource {
1255 match self {
1256 fdecl::Ref::Self_(_) => ExposeSource::Self_,
1257 fdecl::Ref::Child(c) => ExposeSource::Child(c.name.parse().unwrap()),
1259 fdecl::Ref::Collection(c) => ExposeSource::Collection(c.name.parse().unwrap()),
1261 fdecl::Ref::Framework(_) => ExposeSource::Framework,
1262 fdecl::Ref::Capability(c) => ExposeSource::Capability(c.name.parse().unwrap()),
1264 fdecl::Ref::VoidType(_) => ExposeSource::Void,
1265 _ => panic!("invalid ExposeSource variant"),
1266 }
1267 }
1268}
1269
1270#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
1271#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, ToGenericRef)]
1272pub enum ExposeTarget {
1273 Parent,
1274 Framework,
1275}
1276
1277impl std::fmt::Display for ExposeTarget {
1278 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1279 match self {
1280 Self::Framework => write!(f, "framework"),
1281 Self::Parent => write!(f, "parent"),
1282 }
1283 }
1284}
1285
1286impl FidlIntoNative<ExposeTarget> for fdecl::Ref {
1287 fn fidl_into_native(self) -> ExposeTarget {
1288 match self {
1289 fdecl::Ref::Parent(_) => ExposeTarget::Parent,
1290 fdecl::Ref::Framework(_) => ExposeTarget::Framework,
1291 _ => panic!("invalid ExposeTarget variant"),
1292 }
1293 }
1294}
1295
1296#[derive(Debug, Clone, PartialEq, Eq)]
1298pub struct ServiceSource<T> {
1299 pub source: T,
1301 pub source_name: Name,
1303}
1304
1305#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
1306#[derive(Debug, Clone, PartialEq, Eq, ToGenericRef)]
1307pub enum StorageDirectorySource {
1308 Parent,
1309 Self_,
1310 Child(String),
1311}
1312
1313impl FidlIntoNative<StorageDirectorySource> for fdecl::Ref {
1314 fn fidl_into_native(self) -> StorageDirectorySource {
1315 match self {
1316 fdecl::Ref::Parent(_) => StorageDirectorySource::Parent,
1317 fdecl::Ref::Self_(_) => StorageDirectorySource::Self_,
1318 fdecl::Ref::Child(c) => StorageDirectorySource::Child(c.name),
1319 _ => panic!("invalid StorageDirectorySource variant"),
1320 }
1321 }
1322}
1323
1324#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
1325#[derive(Debug, Clone, PartialEq, Eq, ToGenericRef)]
1326pub enum DictionarySource {
1327 Parent,
1328 Self_,
1329 Child(ChildRef),
1330}
1331
1332impl FidlIntoNative<DictionarySource> for fdecl::Ref {
1333 fn fidl_into_native(self) -> DictionarySource {
1334 match self {
1335 Self::Parent(_) => DictionarySource::Parent,
1336 Self::Self_(_) => DictionarySource::Self_,
1337 Self::Child(c) => DictionarySource::Child(c.fidl_into_native()),
1338 _ => panic!("invalid DictionarySource variant"),
1339 }
1340 }
1341}
1342
1343#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
1344#[derive(Debug, Clone, PartialEq, Eq, ToGenericRef)]
1345pub enum RegistrationSource {
1346 Parent,
1347 Self_,
1348 Child(String),
1349}
1350
1351impl FidlIntoNative<RegistrationSource> for fdecl::Ref {
1352 fn fidl_into_native(self) -> RegistrationSource {
1353 match self {
1354 fdecl::Ref::Parent(_) => RegistrationSource::Parent,
1355 fdecl::Ref::Self_(_) => RegistrationSource::Self_,
1356 fdecl::Ref::Child(c) => RegistrationSource::Child(c.name),
1357 _ => panic!("invalid RegistrationSource variant"),
1358 }
1359 }
1360}
1361
1362impl TryFrom<fdecl::Component> for ComponentDecl {
1366 type Error = Error;
1367
1368 fn try_from(decl: fdecl::Component) -> Result<Self, Self::Error> {
1369 cm_fidl_validator::validate(&decl, &mut DirectedGraph::new())
1370 .map_err(|err| Error::Validate { err })?;
1371 Ok(decl.fidl_into_native())
1372 }
1373}
1374
1375impl From<ComponentDecl> for fdecl::Component {
1377 fn from(decl: ComponentDecl) -> Self {
1378 decl.native_into_fidl()
1379 }
1380}
1381
1382#[derive(Debug, Error, Clone)]
1384pub enum Error {
1385 #[error("Fidl validation failed: {}", err)]
1386 Validate {
1387 #[source]
1388 err: cm_fidl_validator::error::ErrorList,
1389 },
1390 #[error("Invalid capability path: {}", raw)]
1391 InvalidCapabilityPath { raw: String },
1392 #[error("Invalid capability type name: {}", raw)]
1393 ParseCapabilityTypeName { raw: String },
1394}
1395
1396pub fn push_box<T>(container: &mut Box<[T]>, value: T) {
1399 let boxed = mem::replace(container, Box::from([]));
1400 let mut new_container: Vec<_> = boxed.into();
1401 new_container.push(value);
1402 *container = new_container.into();
1403}
1404
1405pub fn append_box<T>(container: &mut Box<[T]>, other: &mut Vec<T>) {
1408 let boxed = mem::replace(container, Box::from([]));
1409 let mut new_container: Vec<_> = boxed.into();
1410 new_container.append(other);
1411 *container = new_container.into();
1412}
1413
1414#[cfg(test)]
1415mod tests {
1416 use super::*;
1417 use difference::Changeset;
1418 use fidl_fuchsia_component_decl as fdecl;
1419
1420 fn offer_source_static_child(name: &str) -> OfferSource {
1421 OfferSource::Child(ChildRef { name: name.parse().unwrap(), collection: None })
1422 }
1423
1424 fn offer_target_static_child(name: &str) -> OfferTarget {
1425 OfferTarget::Child(ChildRef { name: name.parse().unwrap(), collection: None })
1426 }
1427
1428 macro_rules! test_try_from_decl {
1429 (
1430 $(
1431 $test_name:ident => {
1432 input = $input:expr,
1433 result = $result:expr,
1434 },
1435 )+
1436 ) => {
1437 $(
1438 #[test]
1439 fn $test_name() {
1440 {
1441 let res = ComponentDecl::try_from($input).expect("try_from failed");
1442 if res != $result {
1443 let a = format!("{:#?}", res);
1444 let e = format!("{:#?}", $result);
1445 panic!("Conversion from fidl to cm_rust did not yield expected result:\n{}", Changeset::new(&a, &e, "\n"));
1446 }
1447 }
1448 {
1449 let res = fdecl::Component::try_from($result).expect("try_from failed");
1450 if res != $input {
1451 let a = format!("{:#?}", res);
1452 let e = format!("{:#?}", $input);
1453 panic!("Conversion from cm_rust to fidl did not yield expected result:\n{}", Changeset::new(&a, &e, "\n"));
1454 }
1455 }
1456 }
1457 )+
1458 }
1459 }
1460
1461 macro_rules! test_fidl_into_and_from {
1462 (
1463 $(
1464 $test_name:ident => {
1465 input = $input:expr,
1466 input_type = $input_type:ty,
1467 result = $result:expr,
1468 result_type = $result_type:ty,
1469 },
1470 )+
1471 ) => {
1472 $(
1473 #[test]
1474 fn $test_name() {
1475 {
1476 let res: Vec<$result_type> =
1477 $input.into_iter().map(|e| e.fidl_into_native()).collect();
1478 assert_eq!(res, $result);
1479 }
1480 {
1481 let res: Vec<$input_type> =
1482 $result.into_iter().map(|e| e.native_into_fidl()).collect();
1483 assert_eq!(res, $input);
1484 }
1485 }
1486 )+
1487 }
1488 }
1489
1490 macro_rules! test_fidl_into {
1491 (
1492 $(
1493 $test_name:ident => {
1494 input = $input:expr,
1495 result = $result:expr,
1496 },
1497 )+
1498 ) => {
1499 $(
1500 #[test]
1501 fn $test_name() {
1502 test_fidl_into_helper($input, $result);
1503 }
1504 )+
1505 }
1506 }
1507
1508 fn test_fidl_into_helper<T, U>(input: T, expected_res: U)
1509 where
1510 T: FidlIntoNative<U>,
1511 U: std::cmp::PartialEq + std::fmt::Debug,
1512 {
1513 let res: U = input.fidl_into_native();
1514 assert_eq!(res, expected_res);
1515 }
1516
1517 test_try_from_decl! {
1518 try_from_empty => {
1519 input = fdecl::Component {
1520 program: None,
1521 uses: None,
1522 exposes: None,
1523 offers: None,
1524 capabilities: None,
1525 children: None,
1526 collections: None,
1527 facets: None,
1528 environments: None,
1529 ..Default::default()
1530 },
1531 result = ComponentDecl {
1532 program: None,
1533 uses: Box::from([]),
1534 exposes: Box::from([]),
1535 offers: Box::from([]),
1536 capabilities: Box::from([]),
1537 children: Box::from([]),
1538 collections: Box::from([]),
1539 facets: None,
1540 environments: Box::from([]),
1541 config: None,
1542 debug_info: None,
1543 },
1544 },
1545 try_from_all => {
1546 input = fdecl::Component {
1547 program: Some(fdecl::Program {
1548 runner: Some("elf".to_string()),
1549 info: Some(fdata::Dictionary {
1550 entries: Some(vec![
1551 fdata::DictionaryEntry {
1552 key: "args".to_string(),
1553 value: Some(Box::new(fdata::DictionaryValue::StrVec(vec!["foo".to_string(), "bar".to_string()]))),
1554 },
1555 fdata::DictionaryEntry {
1556 key: "binary".to_string(),
1557 value: Some(Box::new(fdata::DictionaryValue::Str("bin/app".to_string()))),
1558 },
1559 ]),
1560 ..Default::default()
1561 }),
1562 ..Default::default()
1563 }),
1564 uses: Some(vec![
1565 fdecl::Use::Service(fdecl::UseService {
1566 dependency_type: Some(fdecl::DependencyType::Strong),
1567 source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1568 source_name: Some("netstack".to_string()),
1569 source_dictionary: Some("in/dict".to_string()),
1570 target_path: Some("/svc/mynetstack".to_string()),
1571 availability: Some(fdecl::Availability::Required),
1572 ..Default::default()
1573 }),
1574 fdecl::Use::Protocol(fdecl::UseProtocol {
1575 dependency_type: Some(fdecl::DependencyType::Strong),
1576 source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1577 source_name: Some("legacy_netstack".to_string()),
1578 source_dictionary: Some("in/dict".to_string()),
1579 target_path: None,
1580 numbered_handle: Some(0xab),
1581 availability: Some(fdecl::Availability::Optional),
1582 ..Default::default()
1583 }),
1584 fdecl::Use::Protocol(fdecl::UseProtocol {
1585 dependency_type: Some(fdecl::DependencyType::Strong),
1586 source: Some(fdecl::Ref::Child(fdecl::ChildRef { name: "echo".to_string(), collection: None})),
1587 source_name: Some("echo_service".to_string()),
1588 source_dictionary: Some("in/dict".to_string()),
1589 target_path: Some("/svc/echo_service".to_string()),
1590 availability: Some(fdecl::Availability::Required),
1591 ..Default::default()
1592 }),
1593 fdecl::Use::Directory(fdecl::UseDirectory {
1594 dependency_type: Some(fdecl::DependencyType::Strong),
1595 source: Some(fdecl::Ref::Self_(fdecl::SelfRef {})),
1596 source_name: Some("dir".to_string()),
1597 source_dictionary: Some("dict1/me".to_string()),
1598 target_path: Some("/data".to_string()),
1599 rights: Some(fio::Operations::CONNECT),
1600 subdir: Some("foo/bar".to_string()),
1601 availability: Some(fdecl::Availability::Required),
1602 ..Default::default()
1603 }),
1604 fdecl::Use::Storage(fdecl::UseStorage {
1605 source_name: Some("cache".to_string()),
1606 target_path: Some("/cache".to_string()),
1607 availability: Some(fdecl::Availability::Required),
1608 ..Default::default()
1609 }),
1610 fdecl::Use::Storage(fdecl::UseStorage {
1611 source_name: Some("temp".to_string()),
1612 target_path: Some("/temp".to_string()),
1613 availability: Some(fdecl::Availability::Optional),
1614 ..Default::default()
1615 }),
1616 fdecl::Use::EventStream(fdecl::UseEventStream {
1617 source: Some(fdecl::Ref::Child(fdecl::ChildRef {
1618 collection: None,
1619 name: "netstack".to_string(),
1620 })),
1621 source_name: Some("stopped".to_string()),
1622 scope: Some(vec![
1623 fdecl::Ref::Child(fdecl::ChildRef {
1624 collection: None,
1625 name:"a".to_string(),
1626 }), fdecl::Ref::Collection(fdecl::CollectionRef {
1627 name:"b".to_string(),
1628 })]),
1629 target_path: Some("/svc/test".to_string()),
1630 availability: Some(fdecl::Availability::Optional),
1631 ..Default::default()
1632 }),
1633 fdecl::Use::Runner(fdecl::UseRunner {
1634 source: Some(fdecl::Ref::Environment(fdecl::EnvironmentRef {})),
1635 source_name: Some("elf".to_string()),
1636 source_dictionary: None,
1637 ..Default::default()
1638 }),
1639 fdecl::Use::Config(fdecl::UseConfiguration {
1640 source: Some(fdecl::Ref::Parent(fdecl::ParentRef)),
1641 source_name: Some("fuchsia.config.MyConfig".to_string()),
1642 target_name: Some("my_config".to_string()),
1643 availability: Some(fdecl::Availability::Required),
1644 type_: Some(fdecl::ConfigType{
1645 layout: fdecl::ConfigTypeLayout::Bool,
1646 parameters: Some(Vec::new()),
1647 constraints: Vec::new(),
1648 }),
1649 ..Default::default()
1650 }),
1651 #[cfg(fuchsia_api_level_at_least = "29")]
1652 fdecl::Use::Dictionary(fdecl::UseDictionary {
1653 dependency_type: Some(fdecl::DependencyType::Strong),
1654 source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1655 source_name: Some("dictionary".to_string()),
1656 source_dictionary: Some("other_dictionary".to_string()),
1657 target_path: Some("/svc".to_string()),
1658 availability: Some(fdecl::Availability::Optional),
1659 ..Default::default()
1660 }),
1661 ]),
1662 exposes: Some(vec![
1663 fdecl::Expose::Protocol(fdecl::ExposeProtocol {
1664 source: Some(fdecl::Ref::Child(fdecl::ChildRef {
1665 name: "netstack".to_string(),
1666 collection: None,
1667 })),
1668 source_name: Some("legacy_netstack".to_string()),
1669 source_dictionary: Some("in/dict".to_string()),
1670 target_name: Some("legacy_mynetstack".to_string()),
1671 target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1672 availability: Some(fdecl::Availability::Required),
1673 ..Default::default()
1674 }),
1675 fdecl::Expose::Directory(fdecl::ExposeDirectory {
1676 source: Some(fdecl::Ref::Child(fdecl::ChildRef {
1677 name: "netstack".to_string(),
1678 collection: None,
1679 })),
1680 source_name: Some("dir".to_string()),
1681 source_dictionary: Some("in/dict".to_string()),
1682 target_name: Some("data".to_string()),
1683 target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1684 rights: Some(fio::Operations::CONNECT),
1685 subdir: Some("foo/bar".to_string()),
1686 availability: Some(fdecl::Availability::Optional),
1687 ..Default::default()
1688 }),
1689 fdecl::Expose::Runner(fdecl::ExposeRunner {
1690 source: Some(fdecl::Ref::Child(fdecl::ChildRef {
1691 name: "netstack".to_string(),
1692 collection: None,
1693 })),
1694 source_name: Some("elf".to_string()),
1695 source_dictionary: Some("in/dict".to_string()),
1696 target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1697 target_name: Some("elf".to_string()),
1698 ..Default::default()
1699 }),
1700 fdecl::Expose::Resolver(fdecl::ExposeResolver{
1701 source: Some(fdecl::Ref::Child(fdecl::ChildRef {
1702 name: "netstack".to_string(),
1703 collection: None,
1704 })),
1705 source_name: Some("pkg".to_string()),
1706 source_dictionary: Some("in/dict".to_string()),
1707 target: Some(fdecl::Ref::Parent(fdecl::ParentRef{})),
1708 target_name: Some("pkg".to_string()),
1709 ..Default::default()
1710 }),
1711 fdecl::Expose::Service(fdecl::ExposeService {
1712 source: Some(fdecl::Ref::Child(fdecl::ChildRef {
1713 name: "netstack".to_string(),
1714 collection: None,
1715 })),
1716 source_name: Some("netstack1".to_string()),
1717 source_dictionary: Some("in/dict".to_string()),
1718 target_name: Some("mynetstack".to_string()),
1719 target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1720 availability: Some(fdecl::Availability::Required),
1721 ..Default::default()
1722 }),
1723 fdecl::Expose::Service(fdecl::ExposeService {
1724 source: Some(fdecl::Ref::Collection(fdecl::CollectionRef {
1725 name: "modular".to_string(),
1726 })),
1727 source_name: Some("netstack2".to_string()),
1728 source_dictionary: None,
1729 target_name: Some("mynetstack".to_string()),
1730 target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1731 availability: Some(fdecl::Availability::Required),
1732 ..Default::default()
1733 }),
1734 fdecl::Expose::Dictionary(fdecl::ExposeDictionary {
1735 source: Some(fdecl::Ref::Child(fdecl::ChildRef {
1736 name: "netstack".to_string(),
1737 collection: None,
1738 })),
1739 source_name: Some("bundle".to_string()),
1740 source_dictionary: Some("in/dict".to_string()),
1741 target_name: Some("mybundle".to_string()),
1742 target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1743 availability: Some(fdecl::Availability::Required),
1744 ..Default::default()
1745 }),
1746 ]),
1747 offers: Some(vec![
1748 fdecl::Offer::Protocol(fdecl::OfferProtocol {
1749 source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1750 source_name: Some("legacy_netstack".to_string()),
1751 source_dictionary: Some("in/dict".to_string()),
1752 target: Some(fdecl::Ref::Child(
1753 fdecl::ChildRef {
1754 name: "echo".to_string(),
1755 collection: None,
1756 }
1757 )),
1758 target_name: Some("legacy_mynetstack".to_string()),
1759 dependency_type: Some(fdecl::DependencyType::Weak),
1760 availability: Some(fdecl::Availability::Required),
1761 ..Default::default()
1762 }),
1763 fdecl::Offer::Directory(fdecl::OfferDirectory {
1764 source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1765 source_name: Some("dir".to_string()),
1766 source_dictionary: Some("in/dict".to_string()),
1767 target: Some(fdecl::Ref::Collection(
1768 fdecl::CollectionRef { name: "modular".to_string() }
1769 )),
1770 target_name: Some("data".to_string()),
1771 rights: Some(fio::Operations::CONNECT),
1772 subdir: None,
1773 dependency_type: Some(fdecl::DependencyType::Strong),
1774 availability: Some(fdecl::Availability::Optional),
1775 ..Default::default()
1776 }),
1777 fdecl::Offer::Storage(fdecl::OfferStorage {
1778 source_name: Some("cache".to_string()),
1779 source: Some(fdecl::Ref::Self_(fdecl::SelfRef {})),
1780 target: Some(fdecl::Ref::Collection(
1781 fdecl::CollectionRef { name: "modular".to_string() }
1782 )),
1783 target_name: Some("cache".to_string()),
1784 availability: Some(fdecl::Availability::Required),
1785 ..Default::default()
1786 }),
1787 fdecl::Offer::Runner(fdecl::OfferRunner {
1788 source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1789 source_name: Some("elf".to_string()),
1790 source_dictionary: Some("in/dict".to_string()),
1791 target: Some(fdecl::Ref::Child(
1792 fdecl::ChildRef {
1793 name: "echo".to_string(),
1794 collection: None,
1795 }
1796 )),
1797 target_name: Some("elf2".to_string()),
1798 ..Default::default()
1799 }),
1800 fdecl::Offer::Resolver(fdecl::OfferResolver{
1801 source: Some(fdecl::Ref::Parent(fdecl::ParentRef{})),
1802 source_name: Some("pkg".to_string()),
1803 source_dictionary: Some("in/dict".to_string()),
1804 target: Some(fdecl::Ref::Child(
1805 fdecl::ChildRef {
1806 name: "echo".to_string(),
1807 collection: None,
1808 }
1809 )),
1810 target_name: Some("pkg".to_string()),
1811 ..Default::default()
1812 }),
1813 fdecl::Offer::Service(fdecl::OfferService {
1814 source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1815 source_name: Some("netstack1".to_string()),
1816 source_dictionary: Some("in/dict".to_string()),
1817 target: Some(fdecl::Ref::Child(
1818 fdecl::ChildRef {
1819 name: "echo".to_string(),
1820 collection: None,
1821 }
1822 )),
1823 target_name: Some("mynetstack1".to_string()),
1824 availability: Some(fdecl::Availability::Required),
1825 dependency_type: Some(fdecl::DependencyType::Strong),
1826 ..Default::default()
1827 }),
1828 fdecl::Offer::Service(fdecl::OfferService {
1829 source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1830 source_name: Some("netstack2".to_string()),
1831 source_dictionary: None,
1832 target: Some(fdecl::Ref::Child(
1833 fdecl::ChildRef {
1834 name: "echo".to_string(),
1835 collection: None,
1836 }
1837 )),
1838 target_name: Some("mynetstack2".to_string()),
1839 availability: Some(fdecl::Availability::Optional),
1840 dependency_type: Some(fdecl::DependencyType::Strong),
1841 ..Default::default()
1842 }),
1843 fdecl::Offer::Service(fdecl::OfferService {
1844 source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1845 source_name: Some("netstack3".to_string()),
1846 source_dictionary: None,
1847 target: Some(fdecl::Ref::Child(
1848 fdecl::ChildRef {
1849 name: "echo".to_string(),
1850 collection: None,
1851 }
1852 )),
1853 target_name: Some("mynetstack3".to_string()),
1854 source_instance_filter: Some(vec!["allowedinstance".to_string()]),
1855 renamed_instances: Some(vec![fdecl::NameMapping{source_name: "default".to_string(), target_name: "allowedinstance".to_string()}]),
1856 availability: Some(fdecl::Availability::Required),
1857 dependency_type: Some(fdecl::DependencyType::Strong),
1858 ..Default::default()
1859 }),
1860 fdecl::Offer::Dictionary(fdecl::OfferDictionary {
1861 source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1862 source_name: Some("bundle".to_string()),
1863 source_dictionary: Some("in/dict".to_string()),
1864 target: Some(fdecl::Ref::Child(
1865 fdecl::ChildRef {
1866 name: "echo".to_string(),
1867 collection: None,
1868 }
1869 )),
1870 target_name: Some("mybundle".to_string()),
1871 dependency_type: Some(fdecl::DependencyType::Weak),
1872 availability: Some(fdecl::Availability::Required),
1873 ..Default::default()
1874 }),
1875 ]),
1876 capabilities: Some(vec![
1877 fdecl::Capability::Service(fdecl::Service {
1878 name: Some("netstack".to_string()),
1879 source_path: Some("/netstack".to_string()),
1880 ..Default::default()
1881 }),
1882 fdecl::Capability::Protocol(fdecl::Protocol {
1883 name: Some("netstack2".to_string()),
1884 source_path: Some("/netstack2".to_string()),
1885 delivery: Some(fdecl::DeliveryType::Immediate),
1886 ..Default::default()
1887 }),
1888 fdecl::Capability::Directory(fdecl::Directory {
1889 name: Some("data".to_string()),
1890 source_path: Some("/data".to_string()),
1891 rights: Some(fio::Operations::CONNECT),
1892 ..Default::default()
1893 }),
1894 fdecl::Capability::Storage(fdecl::Storage {
1895 name: Some("cache".to_string()),
1896 backing_dir: Some("data".to_string()),
1897 source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
1898 subdir: Some("cache".to_string()),
1899 storage_id: Some(fdecl::StorageId::StaticInstanceId),
1900 ..Default::default()
1901 }),
1902 fdecl::Capability::Runner(fdecl::Runner {
1903 name: Some("elf".to_string()),
1904 source_path: Some("/elf".to_string()),
1905 ..Default::default()
1906 }),
1907 fdecl::Capability::Resolver(fdecl::Resolver {
1908 name: Some("pkg".to_string()),
1909 source_path: Some("/pkg_resolver".to_string()),
1910 ..Default::default()
1911 }),
1912 fdecl::Capability::Dictionary(fdecl::Dictionary {
1913 name: Some("dict1".to_string()),
1914 ..Default::default()
1915 }),
1916 fdecl::Capability::Dictionary(fdecl::Dictionary {
1917 name: Some("dict2".to_string()),
1918 source_path: Some("/in/other".to_string()),
1919 ..Default::default()
1920 }),
1921 ]),
1922 children: Some(vec![
1923 fdecl::Child {
1924 name: Some("netstack".to_string()),
1925 url: Some("fuchsia-pkg://fuchsia.com/netstack#meta/netstack.cm"
1926 .to_string()),
1927 startup: Some(fdecl::StartupMode::Lazy),
1928 on_terminate: None,
1929 environment: None,
1930 ..Default::default()
1931 },
1932 fdecl::Child {
1933 name: Some("gtest".to_string()),
1934 url: Some("fuchsia-pkg://fuchsia.com/gtest#meta/gtest.cm".to_string()),
1935 startup: Some(fdecl::StartupMode::Lazy),
1936 on_terminate: Some(fdecl::OnTerminate::None),
1937 environment: None,
1938 ..Default::default()
1939 },
1940 fdecl::Child {
1941 name: Some("echo".to_string()),
1942 url: Some("fuchsia-pkg://fuchsia.com/echo#meta/echo.cm"
1943 .to_string()),
1944 startup: Some(fdecl::StartupMode::Eager),
1945 on_terminate: Some(fdecl::OnTerminate::Reboot),
1946 environment: Some("test_env".to_string()),
1947 ..Default::default()
1948 },
1949 ]),
1950 collections: Some(vec![
1951 fdecl::Collection {
1952 name: Some("modular".to_string()),
1953 durability: Some(fdecl::Durability::Transient),
1954 environment: None,
1955 allowed_offers: Some(fdecl::AllowedOffers::StaticOnly),
1956 allow_long_names: Some(true),
1957 persistent_storage: None,
1958 ..Default::default()
1959 },
1960 fdecl::Collection {
1961 name: Some("tests".to_string()),
1962 durability: Some(fdecl::Durability::Transient),
1963 environment: Some("test_env".to_string()),
1964 allowed_offers: Some(fdecl::AllowedOffers::StaticAndDynamic),
1965 allow_long_names: Some(true),
1966 persistent_storage: Some(true),
1967 ..Default::default()
1968 },
1969 ]),
1970 facets: Some(fdata::Dictionary {
1971 entries: Some(vec![
1972 fdata::DictionaryEntry {
1973 key: "author".to_string(),
1974 value: Some(Box::new(fdata::DictionaryValue::Str("Fuchsia".to_string()))),
1975 },
1976 ]),
1977 ..Default::default()
1978 }),
1979 environments: Some(vec![
1980 fdecl::Environment {
1981 name: Some("test_env".to_string()),
1982 extends: Some(fdecl::EnvironmentExtends::Realm),
1983 runners: Some(vec![
1984 fdecl::RunnerRegistration {
1985 source_name: Some("runner".to_string()),
1986 source: Some(fdecl::Ref::Child(fdecl::ChildRef {
1987 name: "gtest".to_string(),
1988 collection: None,
1989 })),
1990 target_name: Some("gtest-runner".to_string()),
1991 ..Default::default()
1992 }
1993 ]),
1994 resolvers: Some(vec![
1995 fdecl::ResolverRegistration {
1996 resolver: Some("pkg_resolver".to_string()),
1997 source: Some(fdecl::Ref::Parent(fdecl::ParentRef{})),
1998 scheme: Some("fuchsia-pkg".to_string()),
1999 ..Default::default()
2000 }
2001 ]),
2002 debug_capabilities: Some(vec![
2003 fdecl::DebugRegistration::Protocol(fdecl::DebugProtocolRegistration {
2004 source_name: Some("some_protocol".to_string()),
2005 source: Some(fdecl::Ref::Child(fdecl::ChildRef {
2006 name: "gtest".to_string(),
2007 collection: None,
2008 })),
2009 target_name: Some("some_protocol".to_string()),
2010 ..Default::default()
2011 })
2012 ]),
2013 stop_timeout_ms: Some(4567),
2014 ..Default::default()
2015 }
2016 ]),
2017 config: Some(fdecl::ConfigSchema{
2018 fields: Some(vec![
2019 fdecl::ConfigField {
2020 key: Some("enable_logging".to_string()),
2021 type_: Some(fdecl::ConfigType {
2022 layout: fdecl::ConfigTypeLayout::Bool,
2023 parameters: Some(vec![]),
2024 constraints: vec![],
2025 }),
2026 mutability: Some(Default::default()),
2027 ..Default::default()
2028 }
2029 ]),
2030 checksum: Some(fdecl::ConfigChecksum::Sha256([
2031 0x64, 0x49, 0x9E, 0x75, 0xF3, 0x37, 0x69, 0x88, 0x74, 0x3B, 0x38, 0x16,
2032 0xCD, 0x14, 0x70, 0x9F, 0x3D, 0x4A, 0xD3, 0xE2, 0x24, 0x9A, 0x1A, 0x34,
2033 0x80, 0xB4, 0x9E, 0xB9, 0x63, 0x57, 0xD6, 0xED,
2034 ])),
2035 value_source: Some(
2036 fdecl::ConfigValueSource::PackagePath("fake.cvf".to_string())
2037 ),
2038 ..Default::default()
2039 }),
2040 ..Default::default()
2041 },
2042 result = {
2043 ComponentDecl {
2044 program: Some(ProgramDecl {
2045 runner: Some("elf".parse().unwrap()),
2046 info: fdata::Dictionary {
2047 entries: Some(vec![
2048 fdata::DictionaryEntry {
2049 key: "args".to_string(),
2050 value: Some(Box::new(fdata::DictionaryValue::StrVec(vec!["foo".to_string(), "bar".to_string()]))),
2051 },
2052 fdata::DictionaryEntry{
2053 key: "binary".to_string(),
2054 value: Some(Box::new(fdata::DictionaryValue::Str("bin/app".to_string()))),
2055 },
2056 ]),
2057 ..Default::default()
2058 },
2059 }),
2060 uses: Box::from([
2061 UseDecl::Service(UseServiceDecl {
2062 dependency_type: DependencyType::Strong,
2063 source: UseSource::Parent,
2064 source_name: "netstack".parse().unwrap(),
2065 source_dictionary: "in/dict".parse().unwrap(),
2066 target_path: "/svc/mynetstack".parse().unwrap(),
2067 availability: Availability::Required,
2068 }),
2069 UseDecl::Protocol(UseProtocolDecl {
2070 dependency_type: DependencyType::Strong,
2071 source: UseSource::Parent,
2072 source_name: "legacy_netstack".parse().unwrap(),
2073 source_dictionary: "in/dict".parse().unwrap(),
2074 target_path: None,
2075 numbered_handle: Some(HandleType::from(0xab)),
2076 availability: Availability::Optional,
2077 }),
2078 UseDecl::Protocol(UseProtocolDecl {
2079 dependency_type: DependencyType::Strong,
2080 source: UseSource::Child("echo".parse().unwrap()),
2081 source_name: "echo_service".parse().unwrap(),
2082 source_dictionary: "in/dict".parse().unwrap(),
2083 target_path: Some("/svc/echo_service".parse().unwrap()),
2084 numbered_handle: None,
2085 availability: Availability::Required,
2086 }),
2087 UseDecl::Directory(UseDirectoryDecl {
2088 dependency_type: DependencyType::Strong,
2089 source: UseSource::Self_,
2090 source_name: "dir".parse().unwrap(),
2091 source_dictionary: "dict1/me".parse().unwrap(),
2092 target_path: "/data".parse().unwrap(),
2093 rights: fio::Operations::CONNECT,
2094 subdir: "foo/bar".parse().unwrap(),
2095 availability: Availability::Required,
2096 }),
2097 UseDecl::Storage(UseStorageDecl {
2098 source_name: "cache".parse().unwrap(),
2099 target_path: "/cache".parse().unwrap(),
2100 availability: Availability::Required,
2101 }),
2102 UseDecl::Storage(UseStorageDecl {
2103 source_name: "temp".parse().unwrap(),
2104 target_path: "/temp".parse().unwrap(),
2105 availability: Availability::Optional,
2106 }),
2107 UseDecl::EventStream(Box::new(UseEventStreamDecl {
2108 source: UseSource::Child("netstack".parse().unwrap()),
2109 scope: Some(Box::from([EventScope::Child(ChildRef{ name: "a".parse().unwrap(), collection: None}), EventScope::Collection("b".parse().unwrap())])),
2110 source_name: "stopped".parse().unwrap(),
2111 target_path: "/svc/test".parse().unwrap(),
2112 filter: None,
2113 availability: Availability::Optional,
2114 })),
2115 UseDecl::Runner(UseRunnerDecl {
2116 source: UseSource::Environment,
2117 source_name: "elf".parse().unwrap(),
2118 source_dictionary: ".".parse().unwrap(),
2119 }),
2120 UseDecl::Config(Box::new(UseConfigurationDecl {
2121 source: UseSource::Parent,
2122 source_name: "fuchsia.config.MyConfig".parse().unwrap(),
2123 target_name: "my_config".parse().unwrap(),
2124 availability: Availability::Required,
2125 type_: ConfigValueType::Bool,
2126 default: None,
2127 source_dictionary: ".".parse().unwrap(),
2128 })),
2129 #[cfg(fuchsia_api_level_at_least = "29")]
2130 UseDecl::Dictionary(UseDictionaryDecl {
2131 dependency_type: DependencyType::Strong,
2132 source: UseSource::Parent,
2133 source_name: "dictionary".parse().unwrap(),
2134 source_dictionary: "other_dictionary".parse().unwrap(),
2135 target_path: "/svc".parse().unwrap(),
2136 availability: Availability::Optional,
2137 }),
2138 ]),
2139 exposes: Box::from([
2140 ExposeDecl::Protocol(ExposeProtocolDecl {
2141 source: ExposeSource::Child("netstack".parse().unwrap()),
2142 source_name: "legacy_netstack".parse().unwrap(),
2143 source_dictionary: "in/dict".parse().unwrap(),
2144 target_name: "legacy_mynetstack".parse().unwrap(),
2145 target: ExposeTarget::Parent,
2146 availability: Availability::Required,
2147 }),
2148 ExposeDecl::Directory(ExposeDirectoryDecl {
2149 source: ExposeSource::Child("netstack".parse().unwrap()),
2150 source_name: "dir".parse().unwrap(),
2151 source_dictionary: "in/dict".parse().unwrap(),
2152 target_name: "data".parse().unwrap(),
2153 target: ExposeTarget::Parent,
2154 rights: Some(fio::Operations::CONNECT),
2155 subdir: "foo/bar".parse().unwrap(),
2156 availability: Availability::Optional,
2157 }),
2158 ExposeDecl::Runner(ExposeRunnerDecl {
2159 source: ExposeSource::Child("netstack".parse().unwrap()),
2160 source_name: "elf".parse().unwrap(),
2161 source_dictionary: "in/dict".parse().unwrap(),
2162 target: ExposeTarget::Parent,
2163 target_name: "elf".parse().unwrap(),
2164 }),
2165 ExposeDecl::Resolver(ExposeResolverDecl {
2166 source: ExposeSource::Child("netstack".parse().unwrap()),
2167 source_name: "pkg".parse().unwrap(),
2168 source_dictionary: "in/dict".parse().unwrap(),
2169 target: ExposeTarget::Parent,
2170 target_name: "pkg".parse().unwrap(),
2171 }),
2172 ExposeDecl::Service(ExposeServiceDecl {
2173 source: ExposeSource::Child("netstack".parse().unwrap()),
2174 source_name: "netstack1".parse().unwrap(),
2175 source_dictionary: "in/dict".parse().unwrap(),
2176 target_name: "mynetstack".parse().unwrap(),
2177 target: ExposeTarget::Parent,
2178 availability: Availability::Required,
2179 }),
2180 ExposeDecl::Service(ExposeServiceDecl {
2181 source: ExposeSource::Collection("modular".parse().unwrap()),
2182 source_name: "netstack2".parse().unwrap(),
2183 source_dictionary: ".".parse().unwrap(),
2184 target_name: "mynetstack".parse().unwrap(),
2185 target: ExposeTarget::Parent,
2186 availability: Availability::Required,
2187 }),
2188 ExposeDecl::Dictionary(ExposeDictionaryDecl {
2189 source: ExposeSource::Child("netstack".parse().unwrap()),
2190 source_name: "bundle".parse().unwrap(),
2191 source_dictionary: "in/dict".parse().unwrap(),
2192 target_name: "mybundle".parse().unwrap(),
2193 target: ExposeTarget::Parent,
2194 availability: Availability::Required,
2195 }),
2196 ]),
2197 offers: Box::from([
2198 OfferDecl::Protocol(OfferProtocolDecl {
2199 source: OfferSource::Parent,
2200 source_name: "legacy_netstack".parse().unwrap(),
2201 source_dictionary: "in/dict".parse().unwrap(),
2202 target: offer_target_static_child("echo"),
2203 target_name: "legacy_mynetstack".parse().unwrap(),
2204 dependency_type: DependencyType::Weak,
2205 availability: Availability::Required,
2206 }),
2207 OfferDecl::Directory(Box::new(OfferDirectoryDecl {
2208 source: OfferSource::Parent,
2209 source_name: "dir".parse().unwrap(),
2210 source_dictionary: "in/dict".parse().unwrap(),
2211 target: OfferTarget::Collection("modular".parse().unwrap()),
2212 target_name: "data".parse().unwrap(),
2213 rights: Some(fio::Operations::CONNECT),
2214 subdir: ".".parse().unwrap(),
2215 dependency_type: DependencyType::Strong,
2216 availability: Availability::Optional,
2217 })),
2218 OfferDecl::Storage(OfferStorageDecl {
2219 source_name: "cache".parse().unwrap(),
2220 source: OfferSource::Self_,
2221 target: OfferTarget::Collection("modular".parse().unwrap()),
2222 target_name: "cache".parse().unwrap(),
2223 availability: Availability::Required,
2224 }),
2225 OfferDecl::Runner(OfferRunnerDecl {
2226 source: OfferSource::Parent,
2227 source_name: "elf".parse().unwrap(),
2228 source_dictionary: "in/dict".parse().unwrap(),
2229 target: offer_target_static_child("echo"),
2230 target_name: "elf2".parse().unwrap(),
2231 }),
2232 OfferDecl::Resolver(OfferResolverDecl {
2233 source: OfferSource::Parent,
2234 source_name: "pkg".parse().unwrap(),
2235 source_dictionary: "in/dict".parse().unwrap(),
2236 target: offer_target_static_child("echo"),
2237 target_name: "pkg".parse().unwrap(),
2238 }),
2239 OfferDecl::Service(Box::new(OfferServiceDecl {
2240 source: OfferSource::Parent,
2241 source_name: "netstack1".parse().unwrap(),
2242 source_dictionary: "in/dict".parse().unwrap(),
2243 source_instance_filter: None,
2244 renamed_instances: None,
2245 target: offer_target_static_child("echo"),
2246 target_name: "mynetstack1".parse().unwrap(),
2247 availability: Availability::Required,
2248 dependency_type: Default::default(),
2249 })),
2250 OfferDecl::Service(Box::new(OfferServiceDecl {
2251 source: OfferSource::Parent,
2252 source_name: "netstack2".parse().unwrap(),
2253 source_dictionary: ".".parse().unwrap(),
2254 source_instance_filter: None,
2255 renamed_instances: None,
2256 target: offer_target_static_child("echo"),
2257 target_name: "mynetstack2".parse().unwrap(),
2258 availability: Availability::Optional,
2259 dependency_type: Default::default(),
2260 })),
2261 OfferDecl::Service(Box::new(OfferServiceDecl {
2262 source: OfferSource::Parent,
2263 source_name: "netstack3".parse().unwrap(),
2264 source_dictionary: ".".parse().unwrap(),
2265 source_instance_filter: Some(Box::from(["allowedinstance".parse().unwrap()])),
2266 renamed_instances: Some(Box::from([NameMapping{source_name: "default".parse().unwrap(), target_name: "allowedinstance".parse().unwrap()}])),
2267 target: offer_target_static_child("echo"),
2268 target_name: "mynetstack3".parse().unwrap(),
2269 availability: Availability::Required,
2270 dependency_type: Default::default(),
2271 })),
2272 OfferDecl::Dictionary(OfferDictionaryDecl {
2273 source: OfferSource::Parent,
2274 source_name: "bundle".parse().unwrap(),
2275 source_dictionary: "in/dict".parse().unwrap(),
2276 target: offer_target_static_child("echo"),
2277 target_name: "mybundle".parse().unwrap(),
2278 dependency_type: DependencyType::Weak,
2279 availability: Availability::Required,
2280 }),
2281 ]),
2282 capabilities: Box::from([
2283 CapabilityDecl::Service(ServiceDecl {
2284 name: "netstack".parse().unwrap(),
2285 source_path: Some("/netstack".parse().unwrap()),
2286 }),
2287 CapabilityDecl::Protocol(ProtocolDecl {
2288 name: "netstack2".parse().unwrap(),
2289 source_path: Some("/netstack2".parse().unwrap()),
2290 delivery: DeliveryType::Immediate,
2291 }),
2292 CapabilityDecl::Directory(DirectoryDecl {
2293 name: "data".parse().unwrap(),
2294 source_path: Some("/data".parse().unwrap()),
2295 rights: fio::Operations::CONNECT,
2296 }),
2297 CapabilityDecl::Storage(StorageDecl {
2298 name: "cache".parse().unwrap(),
2299 backing_dir: "data".parse().unwrap(),
2300 source: StorageDirectorySource::Parent,
2301 subdir: "cache".parse().unwrap(),
2302 storage_id: fdecl::StorageId::StaticInstanceId,
2303 }),
2304 CapabilityDecl::Runner(RunnerDecl {
2305 name: "elf".parse().unwrap(),
2306 source_path: Some("/elf".parse().unwrap()),
2307 }),
2308 CapabilityDecl::Resolver(ResolverDecl {
2309 name: "pkg".parse().unwrap(),
2310 source_path: Some("/pkg_resolver".parse().unwrap()),
2311 }),
2312 CapabilityDecl::Dictionary(DictionaryDecl {
2313 name: "dict1".parse().unwrap(),
2314 source_path: None,
2315 }),
2316 CapabilityDecl::Dictionary(DictionaryDecl {
2317 name: "dict2".parse().unwrap(),
2318 source_path: Some("/in/other".parse().unwrap()),
2319 }),
2320 ]),
2321 children: Box::from([
2322 ChildDecl {
2323 name: "netstack".parse().unwrap(),
2324 url: "fuchsia-pkg://fuchsia.com/netstack#meta/netstack.cm".parse().unwrap(),
2325 startup: fdecl::StartupMode::Lazy,
2326 on_terminate: None,
2327 environment: None,
2328 config_overrides: None,
2329 },
2330 ChildDecl {
2331 name: "gtest".parse().unwrap(),
2332 url: "fuchsia-pkg://fuchsia.com/gtest#meta/gtest.cm".parse().unwrap(),
2333 startup: fdecl::StartupMode::Lazy,
2334 on_terminate: Some(fdecl::OnTerminate::None),
2335 environment: None,
2336 config_overrides: None,
2337 },
2338 ChildDecl {
2339 name: "echo".parse().unwrap(),
2340 url: "fuchsia-pkg://fuchsia.com/echo#meta/echo.cm".parse().unwrap(),
2341 startup: fdecl::StartupMode::Eager,
2342 on_terminate: Some(fdecl::OnTerminate::Reboot),
2343 environment: Some("test_env".parse().unwrap()),
2344 config_overrides: None,
2345 },
2346 ]),
2347 collections: Box::from([
2348 CollectionDecl {
2349 name: "modular".parse().unwrap(),
2350 durability: fdecl::Durability::Transient,
2351 environment: None,
2352 allowed_offers: cm_types::AllowedOffers::StaticOnly,
2353 allow_long_names: true,
2354 persistent_storage: None,
2355 },
2356 CollectionDecl {
2357 name: "tests".parse().unwrap(),
2358 durability: fdecl::Durability::Transient,
2359 environment: Some("test_env".parse().unwrap()),
2360 allowed_offers: cm_types::AllowedOffers::StaticAndDynamic,
2361 allow_long_names: true,
2362 persistent_storage: Some(true),
2363 },
2364 ]),
2365 facets: Some(fdata::Dictionary {
2366 entries: Some(vec![
2367 fdata::DictionaryEntry {
2368 key: "author".to_string(),
2369 value: Some(Box::new(fdata::DictionaryValue::Str("Fuchsia".to_string()))),
2370 },
2371 ]),
2372 ..Default::default()
2373 }),
2374 environments: Box::from([
2375 EnvironmentDecl {
2376 name: "test_env".parse().unwrap(),
2377 extends: fdecl::EnvironmentExtends::Realm,
2378 runners: Box::from([
2379 RunnerRegistration {
2380 source_name: "runner".parse().unwrap(),
2381 source: RegistrationSource::Child("gtest".to_string()),
2382 target_name: "gtest-runner".parse().unwrap(),
2383 }
2384 ]),
2385 resolvers: Box::from([
2386 ResolverRegistration {
2387 resolver: "pkg_resolver".parse().unwrap(),
2388 source: RegistrationSource::Parent,
2389 scheme: "fuchsia-pkg".to_string(),
2390 }
2391 ]),
2392 debug_capabilities: Box::from([
2393 DebugRegistration::Protocol(DebugProtocolRegistration {
2394 source_name: "some_protocol".parse().unwrap(),
2395 source: RegistrationSource::Child("gtest".to_string()),
2396 target_name: "some_protocol".parse().unwrap(),
2397 })
2398 ]),
2399 stop_timeout_ms: Some(4567),
2400 }
2401 ]),
2402 config: Some(ConfigDecl {
2403 fields: Box::from([
2404 ConfigField {
2405 key: "enable_logging".into(),
2406 type_: ConfigValueType::Bool,
2407 mutability: ConfigMutability::default(),
2408 }
2409 ]),
2410 checksum: ConfigChecksum::Sha256([
2411 0x64, 0x49, 0x9E, 0x75, 0xF3, 0x37, 0x69, 0x88, 0x74, 0x3B, 0x38, 0x16,
2412 0xCD, 0x14, 0x70, 0x9F, 0x3D, 0x4A, 0xD3, 0xE2, 0x24, 0x9A, 0x1A, 0x34,
2413 0x80, 0xB4, 0x9E, 0xB9, 0x63, 0x57, 0xD6, 0xED,
2414 ]),
2415 value_source: ConfigValueSource::PackagePath("fake.cvf".into())
2416 }),
2417 debug_info: None,
2418 }
2419 },
2420 },
2421 }
2422
2423 test_fidl_into_and_from! {
2424 fidl_into_and_from_use_source => {
2425 input = vec![
2426 fdecl::Ref::Parent(fdecl::ParentRef{}),
2427 fdecl::Ref::Framework(fdecl::FrameworkRef{}),
2428 fdecl::Ref::Debug(fdecl::DebugRef{}),
2429 fdecl::Ref::Capability(fdecl::CapabilityRef {name: "capability".to_string()}),
2430 fdecl::Ref::Child(fdecl::ChildRef {
2431 name: "foo".into(),
2432 collection: None,
2433 }),
2434 fdecl::Ref::Environment(fdecl::EnvironmentRef{}),
2435 ],
2436 input_type = fdecl::Ref,
2437 result = vec![
2438 UseSource::Parent,
2439 UseSource::Framework,
2440 UseSource::Debug,
2441 UseSource::Capability("capability".parse().unwrap()),
2442 UseSource::Child("foo".parse().unwrap()),
2443 UseSource::Environment,
2444 ],
2445 result_type = UseSource,
2446 },
2447 fidl_into_and_from_expose_source => {
2448 input = vec![
2449 fdecl::Ref::Self_(fdecl::SelfRef {}),
2450 fdecl::Ref::Child(fdecl::ChildRef {
2451 name: "foo".into(),
2452 collection: None,
2453 }),
2454 fdecl::Ref::Framework(fdecl::FrameworkRef {}),
2455 fdecl::Ref::Collection(fdecl::CollectionRef { name: "foo".to_string() }),
2456 ],
2457 input_type = fdecl::Ref,
2458 result = vec![
2459 ExposeSource::Self_,
2460 ExposeSource::Child("foo".parse().unwrap()),
2461 ExposeSource::Framework,
2462 ExposeSource::Collection("foo".parse().unwrap()),
2463 ],
2464 result_type = ExposeSource,
2465 },
2466 fidl_into_and_from_offer_source => {
2467 input = vec![
2468 fdecl::Ref::Self_(fdecl::SelfRef {}),
2469 fdecl::Ref::Child(fdecl::ChildRef {
2470 name: "foo".into(),
2471 collection: None,
2472 }),
2473 fdecl::Ref::Framework(fdecl::FrameworkRef {}),
2474 fdecl::Ref::Capability(fdecl::CapabilityRef { name: "foo".to_string() }),
2475 fdecl::Ref::Parent(fdecl::ParentRef {}),
2476 fdecl::Ref::Collection(fdecl::CollectionRef { name: "foo".to_string() }),
2477 fdecl::Ref::VoidType(fdecl::VoidRef {}),
2478 ],
2479 input_type = fdecl::Ref,
2480 result = vec![
2481 OfferSource::Self_,
2482 offer_source_static_child("foo"),
2483 OfferSource::Framework,
2484 OfferSource::Capability("foo".parse().unwrap()),
2485 OfferSource::Parent,
2486 OfferSource::Collection("foo".parse().unwrap()),
2487 OfferSource::Void,
2488 ],
2489 result_type = OfferSource,
2490 },
2491 fidl_into_and_from_dictionary_source => {
2492 input = vec![
2493 fdecl::Ref::Self_(fdecl::SelfRef {}),
2494 fdecl::Ref::Child(fdecl::ChildRef {
2495 name: "foo".into(),
2496 collection: None,
2497 }),
2498 fdecl::Ref::Parent(fdecl::ParentRef {}),
2499 ],
2500 input_type = fdecl::Ref,
2501 result = vec![
2502 DictionarySource::Self_,
2503 DictionarySource::Child(ChildRef {
2504 name: "foo".parse().unwrap(),
2505 collection: None,
2506 }),
2507 DictionarySource::Parent,
2508 ],
2509 result_type = DictionarySource,
2510 },
2511
2512 fidl_into_and_from_capability_without_path => {
2513 input = vec![
2514 fdecl::Protocol {
2515 name: Some("foo_protocol".to_string()),
2516 source_path: None,
2517 delivery: Some(fdecl::DeliveryType::Immediate),
2518 ..Default::default()
2519 },
2520 ],
2521 input_type = fdecl::Protocol,
2522 result = vec![
2523 ProtocolDecl {
2524 name: "foo_protocol".parse().unwrap(),
2525 source_path: None,
2526 delivery: DeliveryType::Immediate,
2527 }
2528 ],
2529 result_type = ProtocolDecl,
2530 },
2531 fidl_into_and_from_storage_capability => {
2532 input = vec![
2533 fdecl::Storage {
2534 name: Some("minfs".to_string()),
2535 backing_dir: Some("minfs".into()),
2536 source: Some(fdecl::Ref::Child(fdecl::ChildRef {
2537 name: "foo".into(),
2538 collection: None,
2539 })),
2540 subdir: None,
2541 storage_id: Some(fdecl::StorageId::StaticInstanceIdOrMoniker),
2542 ..Default::default()
2543 },
2544 ],
2545 input_type = fdecl::Storage,
2546 result = vec![
2547 StorageDecl {
2548 name: "minfs".parse().unwrap(),
2549 backing_dir: "minfs".parse().unwrap(),
2550 source: StorageDirectorySource::Child("foo".to_string()),
2551 subdir: ".".parse().unwrap(),
2552 storage_id: fdecl::StorageId::StaticInstanceIdOrMoniker,
2553 },
2554 ],
2555 result_type = StorageDecl,
2556 },
2557 fidl_into_and_from_storage_capability_restricted => {
2558 input = vec![
2559 fdecl::Storage {
2560 name: Some("minfs".to_string()),
2561 backing_dir: Some("minfs".into()),
2562 source: Some(fdecl::Ref::Child(fdecl::ChildRef {
2563 name: "foo".into(),
2564 collection: None,
2565 })),
2566 subdir: None,
2567 storage_id: Some(fdecl::StorageId::StaticInstanceId),
2568 ..Default::default()
2569 },
2570 ],
2571 input_type = fdecl::Storage,
2572 result = vec![
2573 StorageDecl {
2574 name: "minfs".parse().unwrap(),
2575 backing_dir: "minfs".parse().unwrap(),
2576 source: StorageDirectorySource::Child("foo".to_string()),
2577 subdir: ".".parse().unwrap(),
2578 storage_id: fdecl::StorageId::StaticInstanceId,
2579 },
2580 ],
2581 result_type = StorageDecl,
2582 },
2583 }
2584
2585 test_fidl_into! {
2586 all_with_omitted_defaults => {
2587 input = fdecl::Component {
2588 program: Some(fdecl::Program {
2589 runner: Some("elf".to_string()),
2590 info: Some(fdata::Dictionary {
2591 entries: Some(vec![]),
2592 ..Default::default()
2593 }),
2594 ..Default::default()
2595 }),
2596 uses: Some(vec![]),
2597 exposes: Some(vec![]),
2598 offers: Some(vec![]),
2599 capabilities: Some(vec![]),
2600 children: Some(vec![]),
2601 collections: Some(vec![
2602 fdecl::Collection {
2603 name: Some("modular".to_string()),
2604 durability: Some(fdecl::Durability::Transient),
2605 environment: None,
2606 allowed_offers: None,
2607 allow_long_names: None,
2608 persistent_storage: None,
2609 ..Default::default()
2610 },
2611 fdecl::Collection {
2612 name: Some("tests".to_string()),
2613 durability: Some(fdecl::Durability::Transient),
2614 environment: Some("test_env".to_string()),
2615 allowed_offers: Some(fdecl::AllowedOffers::StaticOnly),
2616 allow_long_names: None,
2617 persistent_storage: Some(false),
2618 ..Default::default()
2619 },
2620 fdecl::Collection {
2621 name: Some("dyn_offers".to_string()),
2622 durability: Some(fdecl::Durability::Transient),
2623 allowed_offers: Some(fdecl::AllowedOffers::StaticAndDynamic),
2624 allow_long_names: None,
2625 persistent_storage: Some(true),
2626 ..Default::default()
2627 },
2628 fdecl::Collection {
2629 name: Some("long_child_names".to_string()),
2630 durability: Some(fdecl::Durability::Transient),
2631 allowed_offers: None,
2632 allow_long_names: Some(true),
2633 persistent_storage: None,
2634 ..Default::default()
2635 },
2636 ]),
2637 facets: Some(fdata::Dictionary{
2638 entries: Some(vec![]),
2639 ..Default::default()
2640 }),
2641 environments: Some(vec![]),
2642 ..Default::default()
2643 },
2644 result = {
2645 ComponentDecl {
2646 program: Some(ProgramDecl {
2647 runner: Some("elf".parse().unwrap()),
2648 info: fdata::Dictionary {
2649 entries: Some(vec![]),
2650 ..Default::default()
2651 },
2652 }),
2653 uses: Box::from([]),
2654 exposes: Box::from([]),
2655 offers: Box::from([]),
2656 capabilities: Box::from([]),
2657 children: Box::from([]),
2658 collections: Box::from([
2659 CollectionDecl {
2660 name: "modular".parse().unwrap(),
2661 durability: fdecl::Durability::Transient,
2662 environment: None,
2663 allowed_offers: cm_types::AllowedOffers::StaticOnly,
2664 allow_long_names: false,
2665 persistent_storage: None,
2666 },
2667 CollectionDecl {
2668 name: "tests".parse().unwrap(),
2669 durability: fdecl::Durability::Transient,
2670 environment: Some("test_env".parse().unwrap()),
2671 allowed_offers: cm_types::AllowedOffers::StaticOnly,
2672 allow_long_names: false,
2673 persistent_storage: Some(false),
2674 },
2675 CollectionDecl {
2676 name: "dyn_offers".parse().unwrap(),
2677 durability: fdecl::Durability::Transient,
2678 environment: None,
2679 allowed_offers: cm_types::AllowedOffers::StaticAndDynamic,
2680 allow_long_names: false,
2681 persistent_storage: Some(true),
2682 },
2683 CollectionDecl {
2684 name: "long_child_names".parse().unwrap(),
2685 durability: fdecl::Durability::Transient,
2686 environment: None,
2687 allowed_offers: cm_types::AllowedOffers::StaticOnly,
2688 allow_long_names: true,
2689 persistent_storage: None,
2690 },
2691 ]),
2692 facets: Some(fdata::Dictionary{
2693 entries: Some(vec![]),
2694 ..Default::default()
2695 }),
2696 environments: Box::from([]),
2697 config: None,
2698 debug_info: None,
2699 }
2700 },
2701 },
2702 }
2703
2704 #[test]
2705 fn default_expose_availability() {
2706 let source = fdecl::Ref::Self_(fdecl::SelfRef {});
2707 let source_name = "source";
2708 let target = fdecl::Ref::Parent(fdecl::ParentRef {});
2709 let target_name = "target";
2710 let expose_service: ExposeServiceDecl = fdecl::ExposeService {
2711 source: Some(source.clone()),
2712 source_name: Some(source_name.into()),
2713 target: Some(target.clone()),
2714 target_name: Some(target_name.into()),
2715 availability: None,
2716 ..Default::default()
2717 }
2718 .fidl_into_native();
2719 assert_eq!(*expose_service.availability(), Availability::Required);
2720
2721 let expose_protocol: ExposeProtocolDecl = fdecl::ExposeProtocol {
2722 source: Some(source.clone()),
2723 source_name: Some(source_name.into()),
2724 target: Some(target.clone()),
2725 target_name: Some(target_name.into()),
2726 ..Default::default()
2727 }
2728 .fidl_into_native();
2729 assert_eq!(*expose_protocol.availability(), Availability::Required);
2730
2731 let expose_directory: ExposeDirectoryDecl = fdecl::ExposeDirectory {
2732 source: Some(source.clone()),
2733 source_name: Some(source_name.into()),
2734 target: Some(target.clone()),
2735 target_name: Some(target_name.into()),
2736 ..Default::default()
2737 }
2738 .fidl_into_native();
2739 assert_eq!(*expose_directory.availability(), Availability::Required);
2740
2741 let expose_runner: ExposeRunnerDecl = fdecl::ExposeRunner {
2742 source: Some(source.clone()),
2743 source_name: Some(source_name.into()),
2744 target: Some(target.clone()),
2745 target_name: Some(target_name.into()),
2746 ..Default::default()
2747 }
2748 .fidl_into_native();
2749 assert_eq!(*expose_runner.availability(), Availability::Required);
2750
2751 let expose_resolver: ExposeResolverDecl = fdecl::ExposeResolver {
2752 source: Some(source.clone()),
2753 source_name: Some(source_name.into()),
2754 target: Some(target.clone()),
2755 target_name: Some(target_name.into()),
2756 ..Default::default()
2757 }
2758 .fidl_into_native();
2759 assert_eq!(*expose_resolver.availability(), Availability::Required);
2760
2761 let expose_dictionary: ExposeDictionaryDecl = fdecl::ExposeDictionary {
2762 source: Some(source.clone()),
2763 source_name: Some(source_name.into()),
2764 target: Some(target.clone()),
2765 target_name: Some(target_name.into()),
2766 ..Default::default()
2767 }
2768 .fidl_into_native();
2769 assert_eq!(*expose_dictionary.availability(), Availability::Required);
2770 }
2771
2772 #[test]
2773 fn default_delivery_type() {
2774 let protocol: ProtocolDecl = fdecl::Protocol {
2775 name: Some("foo".to_string()),
2776 source_path: Some("/foo".to_string()),
2777 delivery: None,
2778 ..Default::default()
2779 }
2780 .fidl_into_native();
2781 assert_eq!(protocol.delivery, DeliveryType::Immediate)
2782 }
2783
2784 #[test]
2785 fn on_readable_delivery_type() {
2786 let protocol: ProtocolDecl = fdecl::Protocol {
2787 name: Some("foo".to_string()),
2788 source_path: Some("/foo".to_string()),
2789 delivery: Some(fdecl::DeliveryType::OnReadable),
2790 ..Default::default()
2791 }
2792 .fidl_into_native();
2793 assert_eq!(protocol.delivery, DeliveryType::OnReadable)
2794 }
2795
2796 #[test]
2797 fn config_value_matches_type() {
2798 let bool_true = ConfigValue::Single(ConfigSingleValue::Bool(true));
2799 let bool_false = ConfigValue::Single(ConfigSingleValue::Bool(false));
2800 let uint8_zero = ConfigValue::Single(ConfigSingleValue::Uint8(0));
2801 let vec_bool_true = ConfigValue::Vector(ConfigVectorValue::BoolVector(Box::from([true])));
2802 let vec_bool_false = ConfigValue::Vector(ConfigVectorValue::BoolVector(Box::from([false])));
2803
2804 assert!(bool_true.matches_type(&bool_false));
2805 assert!(vec_bool_true.matches_type(&vec_bool_false));
2806
2807 assert!(!bool_true.matches_type(&uint8_zero));
2808 assert!(!bool_true.matches_type(&vec_bool_true));
2809 }
2810}