Skip to main content

cm_rust/
lib.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use cm_rust_derive::{ExposeDeclCommon, ExposeDeclCommonAlwaysRequired, FidlDecl, UseDeclCommon};
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 offer;
28
29#[allow(unused_imports)]
30pub use crate::offer::*; // TODO: remove glob after refactor lands
31
32/// Converts a fidl object into its corresponding native representation.
33pub trait FidlIntoNative<T> {
34    fn fidl_into_native(self) -> T;
35}
36
37impl<Native, Fidl> FidlIntoNative<Box<[Native]>> for Vec<Fidl>
38where
39    Fidl: FidlIntoNative<Native>,
40{
41    fn fidl_into_native(self) -> Box<[Native]> {
42        IntoIterator::into_iter(self).map(|s| s.fidl_into_native()).collect()
43    }
44}
45
46pub trait NativeIntoFidl<T> {
47    fn native_into_fidl(self) -> T;
48}
49
50impl<Native, Fidl> NativeIntoFidl<Vec<Fidl>> for Box<[Native]>
51where
52    Native: NativeIntoFidl<Fidl>,
53{
54    fn native_into_fidl(self) -> Vec<Fidl> {
55        IntoIterator::into_iter(self).map(|s| s.native_into_fidl()).collect()
56    }
57}
58
59impl FidlIntoNative<Name> for String {
60    fn fidl_into_native(self) -> Name {
61        // cm_fidl_validator should have already validated this
62        self.parse().unwrap()
63    }
64}
65
66impl NativeIntoFidl<String> for Name {
67    fn native_into_fidl(self) -> String {
68        self.to_string()
69    }
70}
71
72impl FidlIntoNative<LongName> for String {
73    fn fidl_into_native(self) -> LongName {
74        // cm_fidl_validator should have already validated this
75        self.parse().unwrap()
76    }
77}
78
79impl NativeIntoFidl<String> for LongName {
80    fn native_into_fidl(self) -> String {
81        self.to_string()
82    }
83}
84
85impl FidlIntoNative<Path> for String {
86    fn fidl_into_native(self) -> Path {
87        // cm_fidl_validator should have already validated this
88        self.parse().unwrap()
89    }
90}
91
92impl NativeIntoFidl<String> for Path {
93    fn native_into_fidl(self) -> String {
94        self.to_string()
95    }
96}
97
98impl FidlIntoNative<RelativePath> for String {
99    fn fidl_into_native(self) -> RelativePath {
100        // cm_fidl_validator should have already validated this
101        self.parse().unwrap()
102    }
103}
104
105impl NativeIntoFidl<String> for RelativePath {
106    fn native_into_fidl(self) -> String {
107        self.to_string()
108    }
109}
110
111impl NativeIntoFidl<Option<String>> for RelativePath {
112    fn native_into_fidl(self) -> Option<String> {
113        if self.is_dot() { None } else { Some(self.to_string()) }
114    }
115}
116
117impl FidlIntoNative<Url> for String {
118    fn fidl_into_native(self) -> Url {
119        // cm_fidl_validator should have already validated this
120        self.parse().unwrap()
121    }
122}
123
124impl NativeIntoFidl<String> for Url {
125    fn native_into_fidl(self) -> String {
126        self.to_string()
127    }
128}
129
130/// Generates `FidlIntoNative` and `NativeIntoFidl` implementations that leaves the input unchanged.
131macro_rules! fidl_translations_identical {
132    ($into_type:ty) => {
133        impl FidlIntoNative<$into_type> for $into_type {
134            fn fidl_into_native(self) -> $into_type {
135                self
136            }
137        }
138        impl NativeIntoFidl<$into_type> for $into_type {
139            fn native_into_fidl(self) -> Self {
140                self
141            }
142        }
143    };
144}
145
146/// Generates `FidlIntoNative` and `NativeIntoFidl` implementations that
147/// delegate to existing `Into` implementations.
148macro_rules! fidl_translations_from_into {
149    ($native_type:ty, $fidl_type:ty) => {
150        impl FidlIntoNative<$native_type> for $fidl_type {
151            fn fidl_into_native(self) -> $native_type {
152                self.into()
153            }
154        }
155        impl NativeIntoFidl<$fidl_type> for $native_type {
156            fn native_into_fidl(self) -> $fidl_type {
157                self.into()
158            }
159        }
160    };
161}
162
163/// Generates `FidlIntoNative` and `NativeIntoFidl` implementations for
164/// an symmetrical enum types.
165/// `fidl_type` should be the FIDL type while `native_type` should be
166/// the Rust native type defined elsewhere in this file.
167/// Each field of the enums must be provided in the `variant` fieldset.
168macro_rules! fidl_translations_symmetrical_enums {
169($fidl_type:ty , $native_type:ty, $($variant: ident),*) => {
170        impl FidlIntoNative<$native_type> for $fidl_type {
171            fn fidl_into_native(self) -> $native_type {
172                match self {
173                    $( <$fidl_type>::$variant => <$native_type>::$variant,  )*
174                }
175            }
176        }
177        impl NativeIntoFidl<$fidl_type> for $native_type {
178            fn native_into_fidl(self) -> $fidl_type {
179                match self {
180                    $( <$native_type>::$variant => <$fidl_type>::$variant,  )*
181                }
182            }
183        }
184    };
185}
186
187#[derive(FidlDecl, Debug, Clone, PartialEq, Default)]
188#[fidl_decl(fidl_table = "fdecl::Component")]
189pub struct ComponentDecl {
190    pub program: Option<ProgramDecl>,
191    pub uses: Box<[UseDecl]>,
192    pub exposes: Box<[ExposeDecl]>,
193    pub offers: Box<[OfferDecl]>,
194    pub capabilities: Box<[CapabilityDecl]>,
195    pub children: Box<[ChildDecl]>,
196    pub collections: Box<[CollectionDecl]>,
197    pub facets: Option<fdata::Dictionary>,
198    pub environments: Box<[EnvironmentDecl]>,
199    pub config: Option<ConfigDecl>,
200    #[cfg(fuchsia_api_level_at_least = "NEXT")]
201    pub debug_info: Option<DebugInfo>,
202}
203
204impl ComponentDecl {
205    /// Returns the runner used by this component, or `None` if this is a non-executable component.
206    #[cfg(fuchsia_api_level_at_least = "HEAD")]
207    pub fn get_runner(&self) -> Option<UseRunnerDecl> {
208        self.program
209            .as_ref()
210            .and_then(|p| p.runner.as_ref())
211            .map(|r| UseRunnerDecl {
212                source: UseSource::Environment,
213                source_name: r.clone(),
214                source_dictionary: Default::default(),
215            })
216            .or_else(|| {
217                self.uses.iter().find_map(|u| match u {
218                    UseDecl::Runner(r) => Some(r.clone()),
219                    _ => None,
220                })
221            })
222    }
223
224    /// Returns the `StorageDecl` corresponding to `storage_name`.
225    pub fn find_storage_source<'a>(&'a self, storage_name: &Name) -> Option<&'a StorageDecl> {
226        self.capabilities.iter().find_map(|c| match c {
227            CapabilityDecl::Storage(s) if &s.name == storage_name => Some(s),
228            _ => None,
229        })
230    }
231
232    /// Returns the `ProtocolDecl` corresponding to `protocol_name`.
233    pub fn find_protocol_source<'a>(&'a self, protocol_name: &Name) -> Option<&'a ProtocolDecl> {
234        self.capabilities.iter().find_map(|c| match c {
235            CapabilityDecl::Protocol(r) if &r.name == protocol_name => Some(r),
236            _ => None,
237        })
238    }
239
240    /// Returns the `DirectoryDecl` corresponding to `directory_name`.
241    pub fn find_directory_source<'a>(&'a self, directory_name: &Name) -> Option<&'a DirectoryDecl> {
242        self.capabilities.iter().find_map(|c| match c {
243            CapabilityDecl::Directory(r) if &r.name == directory_name => Some(r),
244            _ => None,
245        })
246    }
247
248    /// Returns the `RunnerDecl` corresponding to `runner_name`.
249    pub fn find_runner_source<'a>(&'a self, runner_name: &Name) -> Option<&'a RunnerDecl> {
250        self.capabilities.iter().find_map(|c| match c {
251            CapabilityDecl::Runner(r) if &r.name == runner_name => Some(r),
252            _ => None,
253        })
254    }
255
256    /// Returns the `ResolverDecl` corresponding to `resolver_name`.
257    pub fn find_resolver_source<'a>(&'a self, resolver_name: &Name) -> Option<&'a ResolverDecl> {
258        self.capabilities.iter().find_map(|c| match c {
259            CapabilityDecl::Resolver(r) if &r.name == resolver_name => Some(r),
260            _ => None,
261        })
262    }
263
264    /// Returns the `CollectionDecl` corresponding to `collection_name`.
265    pub fn find_collection<'a>(&'a self, collection_name: &str) -> Option<&'a CollectionDecl> {
266        self.collections.iter().find(|c| c.name == collection_name)
267    }
268
269    /// Indicates whether the capability specified by `target_name` is exposed to the framework.
270    pub fn is_protocol_exposed_to_framework(&self, in_target_name: &Name) -> bool {
271        self.exposes.iter().any(|expose| match expose {
272            ExposeDecl::Protocol(ExposeProtocolDecl { target, target_name, .. })
273                if target == &ExposeTarget::Framework =>
274            {
275                target_name == in_target_name
276            }
277            _ => false,
278        })
279    }
280
281    /// Indicates whether the capability specified by `source_name` is requested.
282    pub fn uses_protocol(&self, source_name: &Name) -> bool {
283        self.uses.iter().any(|use_decl| match use_decl {
284            UseDecl::Protocol(ls) => &ls.source_name == source_name,
285            _ => false,
286        })
287    }
288}
289
290pub use cm_types::Availability;
291
292fidl_translations_symmetrical_enums!(
293    fdecl::Availability,
294    Availability,
295    Required,
296    Optional,
297    SameAsTarget,
298    Transitional
299);
300
301pub use cm_types::DeliveryType;
302
303#[cfg(fuchsia_api_level_at_least = "HEAD")]
304impl FidlIntoNative<DeliveryType> for fdecl::DeliveryType {
305    fn fidl_into_native(self) -> DeliveryType {
306        self.try_into().unwrap()
307    }
308}
309
310#[cfg(fuchsia_api_level_at_least = "HEAD")]
311impl NativeIntoFidl<fdecl::DeliveryType> for DeliveryType {
312    fn native_into_fidl(self) -> fdecl::DeliveryType {
313        self.into()
314    }
315}
316
317#[cfg(fuchsia_api_level_at_least = "29")]
318pub use cm_types::HandleType;
319
320#[cfg(fuchsia_api_level_at_least = "29")]
321impl FidlIntoNative<HandleType> for u8 {
322    fn fidl_into_native(self) -> HandleType {
323        self.into()
324    }
325}
326
327#[cfg(fuchsia_api_level_at_least = "29")]
328impl NativeIntoFidl<u8> for HandleType {
329    fn native_into_fidl(self) -> u8 {
330        self.into()
331    }
332}
333
334pub trait SourcePath {
335    fn source_path(&self) -> BorrowedSeparatedPath<'_>;
336    fn is_from_dictionary(&self) -> bool {
337        !self.source_path().dirname.is_dot()
338    }
339}
340
341#[cfg_attr(
342    feature = "serde",
343    derive(Deserialize, Serialize),
344    serde(tag = "type", rename_all = "snake_case")
345)]
346#[derive(FidlDecl, FromEnum, Debug, Clone, PartialEq, Eq)]
347#[fidl_decl(fidl_union = "fdecl::Use")]
348pub enum UseDecl {
349    Service(UseServiceDecl),
350    Protocol(UseProtocolDecl),
351    Directory(UseDirectoryDecl),
352    Storage(UseStorageDecl),
353    EventStream(UseEventStreamDecl),
354    #[cfg(fuchsia_api_level_at_least = "HEAD")]
355    Runner(UseRunnerDecl),
356    Config(UseConfigurationDecl),
357    #[cfg(fuchsia_api_level_at_least = "29")]
358    Dictionary(UseDictionaryDecl),
359}
360
361#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
362#[derive(FidlDecl, UseDeclCommon, Debug, Clone, PartialEq, Eq)]
363#[fidl_decl(fidl_table = "fdecl::UseService", source_path = "dictionary")]
364pub struct UseServiceDecl {
365    pub source: UseSource,
366    pub source_name: Name,
367    #[fidl_decl(default_preserve_none)]
368    pub source_dictionary: RelativePath,
369    pub target_path: Path,
370    pub dependency_type: DependencyType,
371    #[fidl_decl(default)]
372    pub availability: Availability,
373}
374
375#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
376#[derive(FidlDecl, UseDeclCommon, Debug, Clone, PartialEq, Eq)]
377#[fidl_decl(fidl_table = "fdecl::UseProtocol", source_path = "dictionary")]
378pub struct UseProtocolDecl {
379    pub source: UseSource,
380    pub source_name: Name,
381    #[fidl_decl(default_preserve_none)]
382    pub source_dictionary: RelativePath,
383    pub target_path: Option<Path>,
384    #[cfg(fuchsia_api_level_at_least = "29")]
385    pub numbered_handle: Option<HandleType>,
386    pub dependency_type: DependencyType,
387    #[fidl_decl(default)]
388    pub availability: Availability,
389}
390
391#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
392#[derive(FidlDecl, UseDeclCommon, Debug, Clone, PartialEq, Eq)]
393#[fidl_decl(fidl_table = "fdecl::UseDirectory", source_path = "dictionary")]
394pub struct UseDirectoryDecl {
395    pub source: UseSource,
396    pub source_name: Name,
397    #[fidl_decl(default_preserve_none)]
398    pub source_dictionary: RelativePath,
399    pub target_path: Path,
400
401    #[cfg_attr(
402        feature = "serde",
403        serde(
404            deserialize_with = "serde_ext::deserialize_fio_operations",
405            serialize_with = "serde_ext::serialize_fio_operations"
406        )
407    )]
408    pub rights: fio::Operations,
409
410    #[fidl_decl(default_preserve_none)]
411    pub subdir: RelativePath,
412    pub dependency_type: DependencyType,
413    #[fidl_decl(default)]
414    pub availability: Availability,
415}
416
417#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
418#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
419#[fidl_decl(fidl_table = "fdecl::UseStorage", source_path = "name_only")]
420pub struct UseStorageDecl {
421    pub source_name: Name,
422    pub target_path: Path,
423    #[fidl_decl(default)]
424    pub availability: Availability,
425}
426
427impl SourceName for UseStorageDecl {
428    fn source_name(&self) -> &Name {
429        &self.source_name
430    }
431}
432
433impl UseDeclCommon for UseStorageDecl {
434    fn source(&self) -> &UseSource {
435        &UseSource::Parent
436    }
437
438    fn availability(&self) -> &Availability {
439        &self.availability
440    }
441}
442
443#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
444#[derive(FidlDecl, UseDeclCommon, Debug, Clone, PartialEq, Eq, Hash)]
445#[fidl_decl(fidl_table = "fdecl::UseEventStream", source_path = "name_only")]
446pub struct UseEventStreamDecl {
447    pub source_name: Name,
448    pub source: UseSource,
449    pub scope: Option<Box<[EventScope]>>,
450    pub target_path: Path,
451    pub filter: Option<BTreeMap<String, DictionaryValue>>,
452    #[fidl_decl(default)]
453    pub availability: Availability,
454}
455
456#[cfg(fuchsia_api_level_at_least = "HEAD")]
457#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
458#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
459#[fidl_decl(fidl_table = "fdecl::UseRunner", source_path = "dictionary")]
460pub struct UseRunnerDecl {
461    pub source: UseSource,
462    pub source_name: Name,
463    #[fidl_decl(default_preserve_none)]
464    pub source_dictionary: RelativePath,
465}
466
467#[cfg(fuchsia_api_level_at_least = "29")]
468#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
469#[derive(FidlDecl, UseDeclCommon, Debug, Clone, PartialEq, Eq)]
470#[fidl_decl(fidl_table = "fdecl::UseDictionary", source_path = "dictionary")]
471pub struct UseDictionaryDecl {
472    pub source: UseSource,
473    pub source_name: Name,
474    #[fidl_decl(default_preserve_none)]
475    pub source_dictionary: RelativePath,
476    pub target_path: Path,
477    pub dependency_type: DependencyType,
478    #[fidl_decl(default)]
479    pub availability: Availability,
480}
481
482#[cfg(fuchsia_api_level_at_least = "HEAD")]
483impl SourceName for UseRunnerDecl {
484    fn source_name(&self) -> &Name {
485        &self.source_name
486    }
487}
488
489#[cfg(fuchsia_api_level_at_least = "HEAD")]
490impl UseDeclCommon for UseRunnerDecl {
491    fn source(&self) -> &UseSource {
492        &self.source
493    }
494
495    fn availability(&self) -> &Availability {
496        &Availability::Required
497    }
498}
499
500#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
501#[derive(FidlDecl, UseDeclCommon, Debug, Clone, PartialEq, Eq)]
502#[fidl_decl(fidl_table = "fdecl::UseConfiguration", source_path = "dictionary")]
503pub struct UseConfigurationDecl {
504    pub source: UseSource,
505    pub source_name: Name,
506    #[fidl_decl(default_preserve_none)]
507    pub source_dictionary: RelativePath,
508    pub target_name: Name,
509    #[fidl_decl(default)]
510    pub availability: Availability,
511    pub type_: ConfigValueType,
512    pub default: Option<ConfigValue>,
513}
514
515#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
516#[derive(Debug, Clone, PartialEq, Eq)]
517pub struct NameMapping {
518    pub source_name: Name,
519    pub target_name: Name,
520}
521
522impl NativeIntoFidl<fdecl::NameMapping> for NameMapping {
523    fn native_into_fidl(self) -> fdecl::NameMapping {
524        fdecl::NameMapping {
525            source_name: self.source_name.native_into_fidl(),
526            target_name: self.target_name.native_into_fidl(),
527        }
528    }
529}
530
531impl FidlIntoNative<NameMapping> for fdecl::NameMapping {
532    fn fidl_into_native(self) -> NameMapping {
533        NameMapping {
534            source_name: self.source_name.fidl_into_native(),
535            target_name: self.target_name.fidl_into_native(),
536        }
537    }
538}
539
540impl UseDeclCommon for UseDecl {
541    fn source(&self) -> &UseSource {
542        match &self {
543            UseDecl::Service(u) => u.source(),
544            UseDecl::Protocol(u) => u.source(),
545            UseDecl::Directory(u) => u.source(),
546            UseDecl::Storage(u) => u.source(),
547            UseDecl::EventStream(u) => u.source(),
548            #[cfg(fuchsia_api_level_at_least = "HEAD")]
549            UseDecl::Runner(u) => u.source(),
550            UseDecl::Config(u) => u.source(),
551            #[cfg(fuchsia_api_level_at_least = "29")]
552            UseDecl::Dictionary(u) => u.source(),
553        }
554    }
555
556    fn availability(&self) -> &Availability {
557        match &self {
558            UseDecl::Service(u) => u.availability(),
559            UseDecl::Protocol(u) => u.availability(),
560            UseDecl::Directory(u) => u.availability(),
561            UseDecl::Storage(u) => u.availability(),
562            UseDecl::EventStream(u) => u.availability(),
563            #[cfg(fuchsia_api_level_at_least = "HEAD")]
564            UseDecl::Runner(u) => u.availability(),
565            UseDecl::Config(u) => u.availability(),
566            #[cfg(fuchsia_api_level_at_least = "29")]
567            UseDecl::Dictionary(u) => u.availability(),
568        }
569    }
570}
571
572#[cfg_attr(
573    feature = "serde",
574    derive(Deserialize, Serialize),
575    serde(tag = "type", rename_all = "snake_case")
576)]
577#[derive(FidlDecl, FromEnum, Debug, Clone, PartialEq, Eq)]
578#[fidl_decl(fidl_union = "fdecl::Expose")]
579pub enum ExposeDecl {
580    Service(ExposeServiceDecl),
581    Protocol(ExposeProtocolDecl),
582    Directory(ExposeDirectoryDecl),
583    Runner(ExposeRunnerDecl),
584    Resolver(ExposeResolverDecl),
585    Dictionary(ExposeDictionaryDecl),
586    Config(ExposeConfigurationDecl),
587}
588
589impl SourceName for ExposeDecl {
590    fn source_name(&self) -> &Name {
591        match self {
592            Self::Service(e) => e.source_name(),
593            Self::Protocol(e) => e.source_name(),
594            Self::Directory(e) => e.source_name(),
595            Self::Runner(e) => e.source_name(),
596            Self::Resolver(e) => e.source_name(),
597            Self::Dictionary(e) => e.source_name(),
598            Self::Config(e) => e.source_name(),
599        }
600    }
601}
602
603impl SourcePath for ExposeDecl {
604    fn source_path(&self) -> BorrowedSeparatedPath<'_> {
605        match self {
606            Self::Service(e) => e.source_path(),
607            Self::Protocol(e) => e.source_path(),
608            Self::Directory(e) => e.source_path(),
609            Self::Runner(e) => e.source_path(),
610            Self::Resolver(e) => e.source_path(),
611            Self::Dictionary(e) => e.source_path(),
612            Self::Config(e) => e.source_path(),
613        }
614    }
615}
616
617impl ExposeDeclCommon for ExposeDecl {
618    fn source(&self) -> &ExposeSource {
619        match self {
620            Self::Service(e) => e.source(),
621            Self::Protocol(e) => e.source(),
622            Self::Directory(e) => e.source(),
623            Self::Runner(e) => e.source(),
624            Self::Resolver(e) => e.source(),
625            Self::Dictionary(e) => e.source(),
626            Self::Config(e) => e.source(),
627        }
628    }
629
630    fn target(&self) -> &ExposeTarget {
631        match self {
632            Self::Service(e) => e.target(),
633            Self::Protocol(e) => e.target(),
634            Self::Directory(e) => e.target(),
635            Self::Runner(e) => e.target(),
636            Self::Resolver(e) => e.target(),
637            Self::Dictionary(e) => e.target(),
638            Self::Config(e) => e.target(),
639        }
640    }
641
642    fn target_name(&self) -> &Name {
643        match self {
644            Self::Service(e) => e.target_name(),
645            Self::Protocol(e) => e.target_name(),
646            Self::Directory(e) => e.target_name(),
647            Self::Runner(e) => e.target_name(),
648            Self::Resolver(e) => e.target_name(),
649            Self::Dictionary(e) => e.target_name(),
650            Self::Config(e) => e.target_name(),
651        }
652    }
653
654    fn availability(&self) -> &Availability {
655        match self {
656            Self::Service(e) => e.availability(),
657            Self::Protocol(e) => e.availability(),
658            Self::Directory(e) => e.availability(),
659            Self::Runner(e) => e.availability(),
660            Self::Resolver(e) => e.availability(),
661            Self::Dictionary(e) => e.availability(),
662            Self::Config(e) => e.availability(),
663        }
664    }
665}
666
667#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
668#[derive(FidlDecl, ExposeDeclCommon, Debug, Clone, PartialEq, Eq)]
669#[fidl_decl(fidl_table = "fdecl::ExposeService", source_path = "dictionary")]
670pub struct ExposeServiceDecl {
671    pub source: ExposeSource,
672    pub source_name: Name,
673    #[fidl_decl(default_preserve_none)]
674    pub source_dictionary: RelativePath,
675    pub target: ExposeTarget,
676    pub target_name: Name,
677    #[fidl_decl(default)]
678    pub availability: Availability,
679}
680
681#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
682#[derive(FidlDecl, ExposeDeclCommon, Debug, Clone, PartialEq, Eq)]
683#[fidl_decl(fidl_table = "fdecl::ExposeProtocol", source_path = "dictionary")]
684pub struct ExposeProtocolDecl {
685    pub source: ExposeSource,
686    pub source_name: Name,
687    #[fidl_decl(default_preserve_none)]
688    pub source_dictionary: RelativePath,
689    pub target: ExposeTarget,
690    pub target_name: Name,
691    #[fidl_decl(default)]
692    pub availability: Availability,
693}
694
695#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
696#[derive(FidlDecl, ExposeDeclCommon, Debug, Clone, PartialEq, Eq)]
697#[fidl_decl(fidl_table = "fdecl::ExposeDirectory", source_path = "dictionary")]
698pub struct ExposeDirectoryDecl {
699    pub source: ExposeSource,
700    pub source_name: Name,
701    #[fidl_decl(default_preserve_none)]
702    pub source_dictionary: RelativePath,
703    pub target: ExposeTarget,
704    pub target_name: Name,
705
706    #[cfg_attr(
707        feature = "serde",
708        serde(
709            deserialize_with = "serde_ext::deserialize_opt_fio_operations",
710            serialize_with = "serde_ext::serialize_opt_fio_operations"
711        )
712    )]
713    pub rights: Option<fio::Operations>,
714
715    #[fidl_decl(default_preserve_none)]
716    pub subdir: RelativePath,
717
718    #[fidl_decl(default)]
719    pub availability: Availability,
720}
721
722#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
723#[derive(FidlDecl, ExposeDeclCommonAlwaysRequired, Debug, Clone, PartialEq, Eq)]
724#[fidl_decl(fidl_table = "fdecl::ExposeRunner", source_path = "dictionary")]
725pub struct ExposeRunnerDecl {
726    pub source: ExposeSource,
727    pub source_name: Name,
728    #[fidl_decl(default_preserve_none)]
729    pub source_dictionary: RelativePath,
730    pub target: ExposeTarget,
731    pub target_name: Name,
732}
733
734#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
735#[derive(FidlDecl, ExposeDeclCommonAlwaysRequired, Debug, Clone, PartialEq, Eq)]
736#[fidl_decl(fidl_table = "fdecl::ExposeResolver", source_path = "dictionary")]
737pub struct ExposeResolverDecl {
738    pub source: ExposeSource,
739    pub source_name: Name,
740    #[fidl_decl(default_preserve_none)]
741    pub source_dictionary: RelativePath,
742    pub target: ExposeTarget,
743    pub target_name: Name,
744}
745
746#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
747#[derive(FidlDecl, ExposeDeclCommon, Debug, Clone, PartialEq, Eq)]
748#[fidl_decl(fidl_table = "fdecl::ExposeDictionary", source_path = "dictionary")]
749pub struct ExposeDictionaryDecl {
750    pub source: ExposeSource,
751    pub source_name: Name,
752    #[fidl_decl(default_preserve_none)]
753    pub source_dictionary: RelativePath,
754    pub target: ExposeTarget,
755    pub target_name: Name,
756    #[fidl_decl(default)]
757    pub availability: Availability,
758}
759
760#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
761#[derive(FidlDecl, ExposeDeclCommon, Debug, Clone, PartialEq, Eq)]
762#[fidl_decl(fidl_table = "fdecl::ExposeConfiguration", source_path = "name_only")]
763pub struct ExposeConfigurationDecl {
764    pub source: ExposeSource,
765    pub source_name: Name,
766    pub target: ExposeTarget,
767    pub target_name: Name,
768    #[fidl_decl(default_preserve_none)]
769    pub source_dictionary: RelativePath,
770    #[fidl_decl(default)]
771    pub availability: Availability,
772}
773
774#[cfg_attr(
775    feature = "serde",
776    derive(Deserialize, Serialize),
777    serde(tag = "type", rename_all = "snake_case")
778)]
779#[derive(FidlDecl, FromEnum, Debug, Clone, PartialEq, Eq)]
780#[fidl_decl(fidl_union = "fdecl::Capability")]
781pub enum CapabilityDecl {
782    Service(ServiceDecl),
783    Protocol(ProtocolDecl),
784    Directory(DirectoryDecl),
785    Storage(StorageDecl),
786    Runner(RunnerDecl),
787    Resolver(ResolverDecl),
788    EventStream(EventStreamDecl),
789    Dictionary(DictionaryDecl),
790    Config(ConfigurationDecl),
791}
792
793#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
794#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
795#[fidl_decl(fidl_table = "fdecl::Service")]
796pub struct ServiceDecl {
797    pub name: Name,
798    pub source_path: Option<Path>,
799}
800
801#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
802#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
803#[fidl_decl(fidl_table = "fdecl::Protocol")]
804pub struct ProtocolDecl {
805    pub name: Name,
806    pub source_path: Option<Path>,
807    #[fidl_decl(default)]
808    #[cfg(fuchsia_api_level_at_least = "HEAD")]
809    pub delivery: DeliveryType,
810}
811
812#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
813#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
814#[fidl_decl(fidl_table = "fdecl::Directory")]
815pub struct DirectoryDecl {
816    pub name: Name,
817    pub source_path: Option<Path>,
818
819    #[cfg_attr(
820        feature = "serde",
821        serde(
822            deserialize_with = "serde_ext::deserialize_fio_operations",
823            serialize_with = "serde_ext::serialize_fio_operations"
824        )
825    )]
826    pub rights: fio::Operations,
827}
828
829#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
830#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
831#[fidl_decl(fidl_table = "fdecl::Storage")]
832pub struct StorageDecl {
833    pub name: Name,
834    pub source: StorageDirectorySource,
835    pub backing_dir: Name,
836    #[fidl_decl(default_preserve_none)]
837    pub subdir: RelativePath,
838    #[cfg_attr(feature = "serde", serde(with = "serde_ext::StorageId"))]
839    pub storage_id: fdecl::StorageId,
840}
841
842#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
843#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
844#[fidl_decl(fidl_table = "fdecl::Runner")]
845pub struct RunnerDecl {
846    pub name: Name,
847    pub source_path: Option<Path>,
848}
849
850#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
851#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
852#[fidl_decl(fidl_table = "fdecl::Resolver")]
853pub struct ResolverDecl {
854    pub name: Name,
855    pub source_path: Option<Path>,
856}
857
858#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
859#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
860#[fidl_decl(fidl_table = "fdecl::EventStream")]
861pub struct EventStreamDecl {
862    pub name: Name,
863}
864
865#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
866#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
867#[fidl_decl(fidl_table = "fdecl::Dictionary")]
868pub struct DictionaryDecl {
869    pub name: Name,
870    pub source_path: Option<Path>,
871}
872
873#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
874#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
875#[fidl_decl(fidl_table = "fdecl::Configuration")]
876pub struct ConfigurationDecl {
877    pub name: Name,
878    pub value: ConfigValue,
879}
880
881impl CapabilityDecl {
882    pub fn name(&self) -> &Name {
883        match self {
884            CapabilityDecl::Directory(decl) => &decl.name,
885            CapabilityDecl::Protocol(decl) => &decl.name,
886            CapabilityDecl::Resolver(decl) => &decl.name,
887            CapabilityDecl::Runner(decl) => &decl.name,
888            CapabilityDecl::Service(decl) => &decl.name,
889            CapabilityDecl::Storage(decl) => &decl.name,
890            CapabilityDecl::EventStream(decl) => &decl.name,
891            CapabilityDecl::Dictionary(decl) => &decl.name,
892            CapabilityDecl::Config(decl) => &decl.name,
893        }
894    }
895
896    pub fn path(&self) -> Option<&Path> {
897        match self {
898            CapabilityDecl::Directory(decl) => decl.source_path.as_ref(),
899            CapabilityDecl::Protocol(decl) => decl.source_path.as_ref(),
900            CapabilityDecl::Resolver(decl) => decl.source_path.as_ref(),
901            CapabilityDecl::Runner(decl) => decl.source_path.as_ref(),
902            CapabilityDecl::Service(decl) => decl.source_path.as_ref(),
903            CapabilityDecl::Storage(_) => None,
904            CapabilityDecl::EventStream(_) => None,
905            CapabilityDecl::Dictionary(_) => None,
906            CapabilityDecl::Config(_) => None,
907        }
908    }
909}
910
911#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
912#[fidl_decl(fidl_table = "fdecl::Child")]
913pub struct ChildDecl {
914    pub name: LongName,
915    pub url: Url,
916    pub startup: fdecl::StartupMode,
917    pub on_terminate: Option<fdecl::OnTerminate>,
918    pub environment: Option<Name>,
919    pub config_overrides: Option<Box<[ConfigOverride]>>,
920}
921
922#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
923#[derive(Debug, Clone, PartialEq, Eq, Hash)]
924pub struct ChildRef {
925    pub name: LongName,
926    pub collection: Option<Name>,
927}
928
929impl std::fmt::Display for ChildRef {
930    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
931        if let Some(collection) = &self.collection {
932            write!(f, "{}:{}", collection, self.name)
933        } else {
934            write!(f, "{}", self.name)
935        }
936    }
937}
938
939impl FidlIntoNative<ChildRef> for fdecl::ChildRef {
940    fn fidl_into_native(self) -> ChildRef {
941        // cm_fidl_validator should have already validated this
942        ChildRef {
943            name: self.name.parse().unwrap(),
944            collection: self.collection.map(|c| c.parse().unwrap()),
945        }
946    }
947}
948
949impl NativeIntoFidl<fdecl::ChildRef> for ChildRef {
950    fn native_into_fidl(self) -> fdecl::ChildRef {
951        fdecl::ChildRef {
952            name: self.name.to_string(),
953            collection: self.collection.map(|c| c.to_string()),
954        }
955    }
956}
957
958#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
959#[fidl_decl(fidl_table = "fdecl::Collection")]
960pub struct CollectionDecl {
961    pub name: Name,
962    pub durability: fdecl::Durability,
963    pub environment: Option<Name>,
964
965    #[fidl_decl(default)]
966    pub allowed_offers: AllowedOffers,
967    #[fidl_decl(default)]
968    pub allow_long_names: bool,
969
970    pub persistent_storage: Option<bool>,
971}
972
973#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
974#[fidl_decl(fidl_table = "fdecl::Environment")]
975pub struct EnvironmentDecl {
976    pub name: Name,
977    pub extends: fdecl::EnvironmentExtends,
978    pub runners: Box<[RunnerRegistration]>,
979    pub resolvers: Box<[ResolverRegistration]>,
980    pub debug_capabilities: Box<[DebugRegistration]>,
981    pub stop_timeout_ms: Option<u32>,
982}
983
984#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
985#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
986#[fidl_decl(fidl_table = "fdecl::ConfigOverride")]
987pub struct ConfigOverride {
988    pub key: String,
989    pub value: ConfigValue,
990}
991
992#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
993#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
994#[fidl_decl(fidl_table = "fdecl::ConfigSchema")]
995pub struct ConfigDecl {
996    pub fields: Box<[ConfigField]>,
997    pub checksum: ConfigChecksum,
998    pub value_source: ConfigValueSource,
999}
1000
1001#[cfg(fuchsia_api_level_at_least = "NEXT")]
1002#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
1003#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1004#[fidl_decl(fidl_table = "fdecl::DebugInfo")]
1005pub struct DebugInfo {
1006    pub manifest_sources: Option<Box<[String]>>,
1007}
1008
1009#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
1010#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1011#[fidl_decl(fidl_union = "fdecl::ConfigChecksum")]
1012pub enum ConfigChecksum {
1013    Sha256([u8; 32]),
1014}
1015
1016#[cfg(fuchsia_api_level_at_least = "HEAD")]
1017#[derive(FidlDecl, Debug, Default, Clone, PartialEq, Eq)]
1018#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1019#[fidl_decl(fidl_table = "fdecl::ConfigSourceCapabilities")]
1020pub struct ConfigSourceCapabilities {}
1021
1022#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
1023#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1024#[fidl_decl(fidl_union = "fdecl::ConfigValueSource")]
1025pub enum ConfigValueSource {
1026    PackagePath(String),
1027    #[cfg(fuchsia_api_level_at_least = "HEAD")]
1028    Capabilities(ConfigSourceCapabilities),
1029}
1030
1031#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
1032#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1033#[fidl_decl(fidl_table = "fdecl::ConfigField")]
1034pub struct ConfigField {
1035    pub key: String,
1036    pub type_: ConfigValueType,
1037
1038    // This field will not be present in compiled manifests which predate F12.
1039    #[fidl_decl(default)]
1040    pub mutability: ConfigMutability,
1041}
1042
1043#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1044#[derive(Debug, Clone, PartialEq, Eq)]
1045pub enum ConfigNestedValueType {
1046    Bool,
1047    Uint8,
1048    Int8,
1049    Uint16,
1050    Int16,
1051    Uint32,
1052    Int32,
1053    Uint64,
1054    Int64,
1055    String { max_size: u32 },
1056}
1057
1058#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1059#[derive(Debug, Clone, PartialEq, Eq)]
1060pub enum ConfigValueType {
1061    Bool,
1062    Uint8,
1063    Int8,
1064    Uint16,
1065    Int16,
1066    Uint32,
1067    Int32,
1068    Uint64,
1069    Int64,
1070    String { max_size: u32 },
1071    Vector { nested_type: ConfigNestedValueType, max_count: u32 },
1072}
1073
1074impl ConfigValueType {
1075    pub fn get_max_size(&self) -> Option<u32> {
1076        match self {
1077            ConfigValueType::String { max_size } => Some(*max_size),
1078            ConfigValueType::Bool
1079            | ConfigValueType::Uint8
1080            | ConfigValueType::Int8
1081            | ConfigValueType::Uint16
1082            | ConfigValueType::Int16
1083            | ConfigValueType::Uint32
1084            | ConfigValueType::Int32
1085            | ConfigValueType::Uint64
1086            | ConfigValueType::Int64
1087            | ConfigValueType::Vector { .. } => None,
1088        }
1089    }
1090
1091    pub fn get_nested_type(&self) -> Option<ConfigNestedValueType> {
1092        match self {
1093            ConfigValueType::Vector { nested_type, .. } => Some(nested_type.clone()),
1094            ConfigValueType::Bool
1095            | ConfigValueType::Uint8
1096            | ConfigValueType::Int8
1097            | ConfigValueType::Uint16
1098            | ConfigValueType::Int16
1099            | ConfigValueType::Uint32
1100            | ConfigValueType::Int32
1101            | ConfigValueType::Uint64
1102            | ConfigValueType::Int64
1103            | ConfigValueType::String { .. } => None,
1104        }
1105    }
1106
1107    pub fn get_max_count(&self) -> Option<u32> {
1108        match self {
1109            ConfigValueType::Vector { max_count, .. } => Some(*max_count),
1110            ConfigValueType::Bool
1111            | ConfigValueType::Uint8
1112            | ConfigValueType::Int8
1113            | ConfigValueType::Uint16
1114            | ConfigValueType::Int16
1115            | ConfigValueType::Uint32
1116            | ConfigValueType::Int32
1117            | ConfigValueType::Uint64
1118            | ConfigValueType::Int64
1119            | ConfigValueType::String { .. } => None,
1120        }
1121    }
1122}
1123
1124impl FidlIntoNative<ConfigNestedValueType> for fdecl::ConfigType {
1125    fn fidl_into_native(mut self) -> ConfigNestedValueType {
1126        match self.layout {
1127            fdecl::ConfigTypeLayout::Bool => ConfigNestedValueType::Bool,
1128            fdecl::ConfigTypeLayout::Uint8 => ConfigNestedValueType::Uint8,
1129            fdecl::ConfigTypeLayout::Uint16 => ConfigNestedValueType::Uint16,
1130            fdecl::ConfigTypeLayout::Uint32 => ConfigNestedValueType::Uint32,
1131            fdecl::ConfigTypeLayout::Uint64 => ConfigNestedValueType::Uint64,
1132            fdecl::ConfigTypeLayout::Int8 => ConfigNestedValueType::Int8,
1133            fdecl::ConfigTypeLayout::Int16 => ConfigNestedValueType::Int16,
1134            fdecl::ConfigTypeLayout::Int32 => ConfigNestedValueType::Int32,
1135            fdecl::ConfigTypeLayout::Int64 => ConfigNestedValueType::Int64,
1136            fdecl::ConfigTypeLayout::String => {
1137                let max_size =
1138                    if let fdecl::LayoutConstraint::MaxSize(s) = self.constraints.remove(0) {
1139                        s
1140                    } else {
1141                        panic!("Unexpected constraint on String layout type for config field");
1142                    };
1143                ConfigNestedValueType::String { max_size }
1144            }
1145            fdecl::ConfigTypeLayout::Vector => {
1146                panic!("Nested vectors are not supported in structured config")
1147            }
1148            fdecl::ConfigTypeLayoutUnknown!() => panic!("Unknown layout type for config field"),
1149        }
1150    }
1151}
1152
1153impl NativeIntoFidl<fdecl::ConfigType> for ConfigNestedValueType {
1154    fn native_into_fidl(self) -> fdecl::ConfigType {
1155        let layout = match self {
1156            ConfigNestedValueType::Bool => fdecl::ConfigTypeLayout::Bool,
1157            ConfigNestedValueType::Uint8 => fdecl::ConfigTypeLayout::Uint8,
1158            ConfigNestedValueType::Uint16 => fdecl::ConfigTypeLayout::Uint16,
1159            ConfigNestedValueType::Uint32 => fdecl::ConfigTypeLayout::Uint32,
1160            ConfigNestedValueType::Uint64 => fdecl::ConfigTypeLayout::Uint64,
1161            ConfigNestedValueType::Int8 => fdecl::ConfigTypeLayout::Int8,
1162            ConfigNestedValueType::Int16 => fdecl::ConfigTypeLayout::Int16,
1163            ConfigNestedValueType::Int32 => fdecl::ConfigTypeLayout::Int32,
1164            ConfigNestedValueType::Int64 => fdecl::ConfigTypeLayout::Int64,
1165            ConfigNestedValueType::String { .. } => fdecl::ConfigTypeLayout::String,
1166        };
1167        let constraints = match self {
1168            ConfigNestedValueType::String { max_size } => {
1169                vec![fdecl::LayoutConstraint::MaxSize(max_size)]
1170            }
1171            _ => vec![],
1172        };
1173        fdecl::ConfigType { layout, constraints, parameters: Some(vec![]) }
1174    }
1175}
1176
1177impl FidlIntoNative<ConfigValueType> for fdecl::ConfigType {
1178    fn fidl_into_native(mut self) -> ConfigValueType {
1179        match self.layout {
1180            fdecl::ConfigTypeLayout::Bool => ConfigValueType::Bool,
1181            fdecl::ConfigTypeLayout::Uint8 => ConfigValueType::Uint8,
1182            fdecl::ConfigTypeLayout::Uint16 => ConfigValueType::Uint16,
1183            fdecl::ConfigTypeLayout::Uint32 => ConfigValueType::Uint32,
1184            fdecl::ConfigTypeLayout::Uint64 => ConfigValueType::Uint64,
1185            fdecl::ConfigTypeLayout::Int8 => ConfigValueType::Int8,
1186            fdecl::ConfigTypeLayout::Int16 => ConfigValueType::Int16,
1187            fdecl::ConfigTypeLayout::Int32 => ConfigValueType::Int32,
1188            fdecl::ConfigTypeLayout::Int64 => ConfigValueType::Int64,
1189            fdecl::ConfigTypeLayout::String => {
1190                let max_size = if let fdecl::LayoutConstraint::MaxSize(s) =
1191                    self.constraints.remove(0)
1192                {
1193                    s
1194                } else {
1195                    panic!(
1196                        "Unexpected constraint on String layout type for config field. Expected MaxSize."
1197                    );
1198                };
1199                ConfigValueType::String { max_size }
1200            }
1201            fdecl::ConfigTypeLayout::Vector => {
1202                let max_count = if let fdecl::LayoutConstraint::MaxSize(c) =
1203                    self.constraints.remove(0)
1204                {
1205                    c
1206                } else {
1207                    panic!(
1208                        "Unexpected constraint on Vector layout type for config field. Expected MaxSize."
1209                    );
1210                };
1211                let mut parameters =
1212                    self.parameters.expect("Config field must have parameters set");
1213                let nested_type = if let fdecl::LayoutParameter::NestedType(nested_type) =
1214                    parameters.remove(0)
1215                {
1216                    nested_type.fidl_into_native()
1217                } else {
1218                    panic!(
1219                        "Unexpected parameter on Vector layout type for config field. Expected NestedType."
1220                    );
1221                };
1222                ConfigValueType::Vector { max_count, nested_type }
1223            }
1224            fdecl::ConfigTypeLayoutUnknown!() => panic!("Unknown layout type for config field"),
1225        }
1226    }
1227}
1228
1229impl NativeIntoFidl<fdecl::ConfigType> for ConfigValueType {
1230    fn native_into_fidl(self) -> fdecl::ConfigType {
1231        let layout = match self {
1232            ConfigValueType::Bool => fdecl::ConfigTypeLayout::Bool,
1233            ConfigValueType::Uint8 => fdecl::ConfigTypeLayout::Uint8,
1234            ConfigValueType::Uint16 => fdecl::ConfigTypeLayout::Uint16,
1235            ConfigValueType::Uint32 => fdecl::ConfigTypeLayout::Uint32,
1236            ConfigValueType::Uint64 => fdecl::ConfigTypeLayout::Uint64,
1237            ConfigValueType::Int8 => fdecl::ConfigTypeLayout::Int8,
1238            ConfigValueType::Int16 => fdecl::ConfigTypeLayout::Int16,
1239            ConfigValueType::Int32 => fdecl::ConfigTypeLayout::Int32,
1240            ConfigValueType::Int64 => fdecl::ConfigTypeLayout::Int64,
1241            ConfigValueType::String { .. } => fdecl::ConfigTypeLayout::String,
1242            ConfigValueType::Vector { .. } => fdecl::ConfigTypeLayout::Vector,
1243        };
1244        let (constraints, parameters) = match self {
1245            ConfigValueType::String { max_size } => {
1246                (vec![fdecl::LayoutConstraint::MaxSize(max_size)], vec![])
1247            }
1248            ConfigValueType::Vector { max_count, nested_type } => {
1249                let nested_type = nested_type.native_into_fidl();
1250                (
1251                    vec![fdecl::LayoutConstraint::MaxSize(max_count)],
1252                    vec![fdecl::LayoutParameter::NestedType(nested_type)],
1253                )
1254            }
1255            _ => (vec![], vec![]),
1256        };
1257        fdecl::ConfigType { layout, constraints, parameters: Some(parameters) }
1258    }
1259}
1260
1261bitflags::bitflags! {
1262    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1263    // TODO(https://fxbug.dev/42075220) uncomment once bitflags is updated
1264    // pub struct ConfigMutability: <fdecl::ConfigMutability as bitflags::BitFlags>::Bits {
1265    pub struct ConfigMutability: u32 {
1266        const PARENT = fdecl::ConfigMutability::PARENT.bits();
1267    }
1268}
1269
1270#[cfg(feature = "serde")]
1271bitflags_serde_legacy::impl_traits!(ConfigMutability);
1272
1273impl NativeIntoFidl<fdecl::ConfigMutability> for ConfigMutability {
1274    fn native_into_fidl(self) -> fdecl::ConfigMutability {
1275        fdecl::ConfigMutability::from_bits_allow_unknown(self.bits())
1276    }
1277}
1278
1279impl FidlIntoNative<ConfigMutability> for fdecl::ConfigMutability {
1280    fn fidl_into_native(self) -> ConfigMutability {
1281        ConfigMutability::from_bits_retain(self.bits())
1282    }
1283}
1284
1285#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
1286#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1287#[fidl_decl(fidl_table = "fdecl::ConfigValuesData")]
1288pub struct ConfigValuesData {
1289    pub values: Box<[ConfigValueSpec]>,
1290    pub checksum: ConfigChecksum,
1291}
1292
1293#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
1294#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1295#[fidl_decl(fidl_table = "fdecl::ConfigValueSpec")]
1296pub struct ConfigValueSpec {
1297    pub value: ConfigValue,
1298}
1299
1300#[derive(FromEnum, FidlDecl, Debug, Clone, PartialEq, Eq)]
1301#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1302#[fidl_decl(fidl_union = "fdecl::ConfigValue")]
1303pub enum ConfigValue {
1304    Single(ConfigSingleValue),
1305    Vector(ConfigVectorValue),
1306}
1307
1308impl ConfigValue {
1309    /// Return the type of this value.
1310    pub fn ty(&self) -> ConfigValueType {
1311        match self {
1312            Self::Single(sv) => sv.ty(),
1313            Self::Vector(vv) => vv.ty(),
1314        }
1315    }
1316
1317    /// Check if this value matches the type of another value.
1318    pub fn matches_type(&self, other: &ConfigValue) -> bool {
1319        match (self, other) {
1320            (ConfigValue::Single(a), ConfigValue::Single(b)) => {
1321                std::mem::discriminant(a) == std::mem::discriminant(b)
1322            }
1323            (ConfigValue::Vector(a), ConfigValue::Vector(b)) => {
1324                std::mem::discriminant(a) == std::mem::discriminant(b)
1325            }
1326            _ => false,
1327        }
1328    }
1329}
1330
1331impl From<&str> for ConfigValue {
1332    fn from(value: &str) -> Self {
1333        ConfigValue::Single(value.to_string().into())
1334    }
1335}
1336
1337impl From<Vec<&str>> for ConfigValue {
1338    fn from(value: Vec<&str>) -> Self {
1339        let value: Box<[_]> = value.into_iter().map(|s| s.to_string()).collect();
1340        ConfigValue::Vector(value.into())
1341    }
1342}
1343
1344macro_rules! generate_configvalue_from {
1345    ($name:expr, $type:ty) => {
1346        impl From<$type> for ConfigValue {
1347            fn from(value: $type) -> Self {
1348                $name(value.into())
1349            }
1350        }
1351    };
1352}
1353
1354generate_configvalue_from!(ConfigValue::Single, bool);
1355generate_configvalue_from!(ConfigValue::Single, u8);
1356generate_configvalue_from!(ConfigValue::Single, u16);
1357generate_configvalue_from!(ConfigValue::Single, u32);
1358generate_configvalue_from!(ConfigValue::Single, u64);
1359generate_configvalue_from!(ConfigValue::Single, i8);
1360generate_configvalue_from!(ConfigValue::Single, i16);
1361generate_configvalue_from!(ConfigValue::Single, i32);
1362generate_configvalue_from!(ConfigValue::Single, i64);
1363generate_configvalue_from!(ConfigValue::Single, String);
1364generate_configvalue_from!(ConfigValue::Vector, Box<[bool]>);
1365generate_configvalue_from!(ConfigValue::Vector, Box<[u8]>);
1366generate_configvalue_from!(ConfigValue::Vector, Box<[u16]>);
1367generate_configvalue_from!(ConfigValue::Vector, Box<[u32]>);
1368generate_configvalue_from!(ConfigValue::Vector, Box<[u64]>);
1369generate_configvalue_from!(ConfigValue::Vector, Box<[i8]>);
1370generate_configvalue_from!(ConfigValue::Vector, Box<[i16]>);
1371generate_configvalue_from!(ConfigValue::Vector, Box<[i32]>);
1372generate_configvalue_from!(ConfigValue::Vector, Box<[i64]>);
1373generate_configvalue_from!(ConfigValue::Vector, Box<[String]>);
1374generate_configvalue_from!(ConfigValue::Vector, Vec<bool>);
1375generate_configvalue_from!(ConfigValue::Vector, Vec<u8>);
1376generate_configvalue_from!(ConfigValue::Vector, Vec<u16>);
1377generate_configvalue_from!(ConfigValue::Vector, Vec<u32>);
1378generate_configvalue_from!(ConfigValue::Vector, Vec<u64>);
1379generate_configvalue_from!(ConfigValue::Vector, Vec<i8>);
1380generate_configvalue_from!(ConfigValue::Vector, Vec<i16>);
1381generate_configvalue_from!(ConfigValue::Vector, Vec<i32>);
1382generate_configvalue_from!(ConfigValue::Vector, Vec<i64>);
1383generate_configvalue_from!(ConfigValue::Vector, Vec<String>);
1384
1385impl fmt::Display for ConfigValue {
1386    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1387        match self {
1388            ConfigValue::Single(sv) => sv.fmt(f),
1389            ConfigValue::Vector(lv) => lv.fmt(f),
1390        }
1391    }
1392}
1393
1394#[derive(FromEnum, FidlDecl, Debug, Clone, PartialEq, Eq)]
1395#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1396#[fidl_decl(fidl_union = "fdecl::ConfigSingleValue")]
1397pub enum ConfigSingleValue {
1398    Bool(bool),
1399    Uint8(u8),
1400    Uint16(u16),
1401    Uint32(u32),
1402    Uint64(u64),
1403    Int8(i8),
1404    Int16(i16),
1405    Int32(i32),
1406    Int64(i64),
1407    String(String),
1408}
1409
1410impl ConfigSingleValue {
1411    fn ty(&self) -> ConfigValueType {
1412        match self {
1413            ConfigSingleValue::Bool(_) => ConfigValueType::Bool,
1414            ConfigSingleValue::Uint8(_) => ConfigValueType::Uint8,
1415            ConfigSingleValue::Uint16(_) => ConfigValueType::Uint16,
1416            ConfigSingleValue::Uint32(_) => ConfigValueType::Uint32,
1417            ConfigSingleValue::Uint64(_) => ConfigValueType::Uint64,
1418            ConfigSingleValue::Int8(_) => ConfigValueType::Int8,
1419            ConfigSingleValue::Int16(_) => ConfigValueType::Int16,
1420            ConfigSingleValue::Int32(_) => ConfigValueType::Int32,
1421            ConfigSingleValue::Int64(_) => ConfigValueType::Int64,
1422            // We substitute the max size limit because the value itself doesn't carry the info.
1423            ConfigSingleValue::String(_) => ConfigValueType::String { max_size: std::u32::MAX },
1424        }
1425    }
1426}
1427
1428impl fmt::Display for ConfigSingleValue {
1429    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1430        use ConfigSingleValue::*;
1431        match self {
1432            Bool(v) => write!(f, "{}", v),
1433            Uint8(v) => write!(f, "{}", v),
1434            Uint16(v) => write!(f, "{}", v),
1435            Uint32(v) => write!(f, "{}", v),
1436            Uint64(v) => write!(f, "{}", v),
1437            Int8(v) => write!(f, "{}", v),
1438            Int16(v) => write!(f, "{}", v),
1439            Int32(v) => write!(f, "{}", v),
1440            Int64(v) => write!(f, "{}", v),
1441            String(v) => write!(f, "\"{}\"", v),
1442        }
1443    }
1444}
1445
1446#[derive(FromEnum, FidlDecl, Debug, Clone, PartialEq, Eq)]
1447#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1448#[fidl_decl(fidl_union = "fdecl::ConfigVectorValue")]
1449pub enum ConfigVectorValue {
1450    BoolVector(Box<[bool]>),
1451    Uint8Vector(Box<[u8]>),
1452    Uint16Vector(Box<[u16]>),
1453    Uint32Vector(Box<[u32]>),
1454    Uint64Vector(Box<[u64]>),
1455    Int8Vector(Box<[i8]>),
1456    Int16Vector(Box<[i16]>),
1457    Int32Vector(Box<[i32]>),
1458    Int64Vector(Box<[i64]>),
1459    StringVector(Box<[String]>),
1460}
1461
1462impl From<Vec<bool>> for ConfigVectorValue {
1463    fn from(v: Vec<bool>) -> Self {
1464        Self::BoolVector(v.into())
1465    }
1466}
1467
1468impl From<Vec<u8>> for ConfigVectorValue {
1469    fn from(v: Vec<u8>) -> Self {
1470        Self::Uint8Vector(v.into())
1471    }
1472}
1473
1474impl From<Vec<u16>> for ConfigVectorValue {
1475    fn from(v: Vec<u16>) -> Self {
1476        Self::Uint16Vector(v.into())
1477    }
1478}
1479
1480impl From<Vec<u32>> for ConfigVectorValue {
1481    fn from(v: Vec<u32>) -> Self {
1482        Self::Uint32Vector(v.into())
1483    }
1484}
1485
1486impl From<Vec<u64>> for ConfigVectorValue {
1487    fn from(v: Vec<u64>) -> Self {
1488        Self::Uint64Vector(v.into())
1489    }
1490}
1491
1492impl From<Vec<i8>> for ConfigVectorValue {
1493    fn from(v: Vec<i8>) -> Self {
1494        Self::Int8Vector(v.into())
1495    }
1496}
1497
1498impl From<Vec<i16>> for ConfigVectorValue {
1499    fn from(v: Vec<i16>) -> Self {
1500        Self::Int16Vector(v.into())
1501    }
1502}
1503
1504impl From<Vec<i32>> for ConfigVectorValue {
1505    fn from(v: Vec<i32>) -> Self {
1506        Self::Int32Vector(v.into())
1507    }
1508}
1509
1510impl From<Vec<i64>> for ConfigVectorValue {
1511    fn from(v: Vec<i64>) -> Self {
1512        Self::Int64Vector(v.into())
1513    }
1514}
1515
1516impl From<Vec<String>> for ConfigVectorValue {
1517    fn from(v: Vec<String>) -> Self {
1518        Self::StringVector(v.into())
1519    }
1520}
1521
1522impl ConfigVectorValue {
1523    fn ty(&self) -> ConfigValueType {
1524        // We substitute the max size limit because the value itself doesn't carry the info.
1525        match self {
1526            ConfigVectorValue::BoolVector(_) => ConfigValueType::Vector {
1527                nested_type: ConfigNestedValueType::Bool,
1528                max_count: std::u32::MAX,
1529            },
1530            ConfigVectorValue::Uint8Vector(_) => ConfigValueType::Vector {
1531                nested_type: ConfigNestedValueType::Uint8,
1532                max_count: std::u32::MAX,
1533            },
1534            ConfigVectorValue::Uint16Vector(_) => ConfigValueType::Vector {
1535                nested_type: ConfigNestedValueType::Uint16,
1536                max_count: std::u32::MAX,
1537            },
1538            ConfigVectorValue::Uint32Vector(_) => ConfigValueType::Vector {
1539                nested_type: ConfigNestedValueType::Uint32,
1540                max_count: std::u32::MAX,
1541            },
1542            ConfigVectorValue::Uint64Vector(_) => ConfigValueType::Vector {
1543                nested_type: ConfigNestedValueType::Uint64,
1544                max_count: std::u32::MAX,
1545            },
1546            ConfigVectorValue::Int8Vector(_) => ConfigValueType::Vector {
1547                nested_type: ConfigNestedValueType::Int8,
1548                max_count: std::u32::MAX,
1549            },
1550            ConfigVectorValue::Int16Vector(_) => ConfigValueType::Vector {
1551                nested_type: ConfigNestedValueType::Int16,
1552                max_count: std::u32::MAX,
1553            },
1554            ConfigVectorValue::Int32Vector(_) => ConfigValueType::Vector {
1555                nested_type: ConfigNestedValueType::Int32,
1556                max_count: std::u32::MAX,
1557            },
1558            ConfigVectorValue::Int64Vector(_) => ConfigValueType::Vector {
1559                nested_type: ConfigNestedValueType::Int64,
1560                max_count: std::u32::MAX,
1561            },
1562            ConfigVectorValue::StringVector(_) => ConfigValueType::Vector {
1563                nested_type: ConfigNestedValueType::String { max_size: std::u32::MAX },
1564                max_count: std::u32::MAX,
1565            },
1566        }
1567    }
1568}
1569
1570impl fmt::Display for ConfigVectorValue {
1571    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1572        use ConfigVectorValue::*;
1573        macro_rules! print_list {
1574            ($f:ident, $list:ident) => {{
1575                $f.write_str("[")?;
1576
1577                for (i, item) in $list.iter().enumerate() {
1578                    if i > 0 {
1579                        $f.write_str(", ")?;
1580                    }
1581                    write!($f, "{}", item)?;
1582                }
1583
1584                $f.write_str("]")
1585            }};
1586        }
1587        match self {
1588            BoolVector(l) => print_list!(f, l),
1589            Uint8Vector(l) => print_list!(f, l),
1590            Uint16Vector(l) => print_list!(f, l),
1591            Uint32Vector(l) => print_list!(f, l),
1592            Uint64Vector(l) => print_list!(f, l),
1593            Int8Vector(l) => print_list!(f, l),
1594            Int16Vector(l) => print_list!(f, l),
1595            Int32Vector(l) => print_list!(f, l),
1596            Int64Vector(l) => print_list!(f, l),
1597            StringVector(l) => {
1598                f.write_str("[")?;
1599                for (i, item) in l.iter().enumerate() {
1600                    if i > 0 {
1601                        f.write_str(", ")?;
1602                    }
1603                    write!(f, "\"{}\"", item)?;
1604                }
1605                f.write_str("]")
1606            }
1607        }
1608    }
1609}
1610
1611#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1612#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
1613#[fidl_decl(fidl_table = "fdecl::RunnerRegistration")]
1614pub struct RunnerRegistration {
1615    pub source_name: Name,
1616    pub target_name: Name,
1617    pub source: RegistrationSource,
1618}
1619
1620impl SourceName for RunnerRegistration {
1621    fn source_name(&self) -> &Name {
1622        &self.source_name
1623    }
1624}
1625
1626impl RegistrationDeclCommon for RunnerRegistration {
1627    const TYPE: &'static str = "runner";
1628
1629    fn source(&self) -> &RegistrationSource {
1630        &self.source
1631    }
1632}
1633
1634#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1635#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
1636#[fidl_decl(fidl_table = "fdecl::ResolverRegistration")]
1637pub struct ResolverRegistration {
1638    pub resolver: Name,
1639    pub source: RegistrationSource,
1640    pub scheme: String,
1641}
1642
1643impl SourceName for ResolverRegistration {
1644    fn source_name(&self) -> &Name {
1645        &self.resolver
1646    }
1647}
1648
1649impl RegistrationDeclCommon for ResolverRegistration {
1650    const TYPE: &'static str = "resolver";
1651
1652    fn source(&self) -> &RegistrationSource {
1653        &self.source
1654    }
1655}
1656
1657#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
1658#[fidl_decl(fidl_union = "fdecl::DebugRegistration")]
1659pub enum DebugRegistration {
1660    Protocol(DebugProtocolRegistration),
1661}
1662
1663impl RegistrationDeclCommon for DebugRegistration {
1664    const TYPE: &'static str = "debug_protocol";
1665
1666    fn source(&self) -> &RegistrationSource {
1667        match self {
1668            DebugRegistration::Protocol(protocol_reg) => &protocol_reg.source,
1669        }
1670    }
1671}
1672
1673impl SourceName for DebugRegistration {
1674    fn source_name(&self) -> &Name {
1675        match self {
1676            DebugRegistration::Protocol(protocol_reg) => &protocol_reg.source_name,
1677        }
1678    }
1679}
1680
1681#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1682#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
1683#[fidl_decl(fidl_table = "fdecl::DebugProtocolRegistration")]
1684pub struct DebugProtocolRegistration {
1685    pub source_name: Name,
1686    pub source: RegistrationSource,
1687    pub target_name: Name,
1688}
1689
1690#[derive(FidlDecl, Debug, Clone, PartialEq)]
1691#[fidl_decl(fidl_table = "fdecl::Program")]
1692pub struct ProgramDecl {
1693    pub runner: Option<Name>,
1694    pub info: fdata::Dictionary,
1695}
1696
1697impl Default for ProgramDecl {
1698    fn default() -> Self {
1699        Self { runner: None, info: fdata::Dictionary::default() }
1700    }
1701}
1702
1703fidl_translations_identical!([u8; 32]);
1704fidl_translations_identical!(u8);
1705fidl_translations_identical!(u16);
1706fidl_translations_identical!(u32);
1707fidl_translations_identical!(u64);
1708fidl_translations_identical!(i8);
1709fidl_translations_identical!(i16);
1710fidl_translations_identical!(i32);
1711fidl_translations_identical!(i64);
1712fidl_translations_identical!(bool);
1713fidl_translations_identical!(String);
1714fidl_translations_identical!(Vec<Name>);
1715fidl_translations_identical!(fdecl::StartupMode);
1716fidl_translations_identical!(fdecl::OnTerminate);
1717fidl_translations_identical!(fdecl::Durability);
1718fidl_translations_identical!(fdata::Dictionary);
1719fidl_translations_identical!(fio::Operations);
1720fidl_translations_identical!(fdecl::EnvironmentExtends);
1721fidl_translations_identical!(fdecl::StorageId);
1722fidl_translations_identical!(Vec<fprocess::HandleInfo>);
1723fidl_translations_identical!(fsys::ServiceInstance);
1724fidl_translations_from_into!(cm_types::AllowedOffers, fdecl::AllowedOffers);
1725
1726#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
1727#[derive(Debug, Clone, PartialEq, Eq)]
1728pub enum DependencyType {
1729    Strong,
1730    Weak,
1731}
1732
1733impl Default for DependencyType {
1734    fn default() -> Self {
1735        Self::Strong
1736    }
1737}
1738
1739fidl_translations_symmetrical_enums!(fdecl::DependencyType, DependencyType, Strong, Weak);
1740
1741impl UseDecl {
1742    pub fn path(&self) -> Option<&Path> {
1743        match self {
1744            UseDecl::Service(d) => Some(&d.target_path),
1745            UseDecl::Protocol(d) => d.target_path.as_ref(),
1746            UseDecl::Directory(d) => Some(&d.target_path),
1747            UseDecl::Storage(d) => Some(&d.target_path),
1748            UseDecl::EventStream(d) => Some(&d.target_path),
1749            #[cfg(fuchsia_api_level_at_least = "HEAD")]
1750            UseDecl::Runner(_) => None,
1751            UseDecl::Config(_) => None,
1752            #[cfg(fuchsia_api_level_at_least = "29")]
1753            UseDecl::Dictionary(d) => Some(&d.target_path),
1754        }
1755    }
1756
1757    pub fn name(&self) -> Option<&Name> {
1758        match self {
1759            UseDecl::Storage(storage_decl) => Some(&storage_decl.source_name),
1760            UseDecl::EventStream(_) => None,
1761            UseDecl::Service(_) | UseDecl::Protocol(_) | UseDecl::Directory(_) => None,
1762            #[cfg(fuchsia_api_level_at_least = "HEAD")]
1763            UseDecl::Runner(_) => None,
1764            UseDecl::Config(_) => None,
1765            #[cfg(fuchsia_api_level_at_least = "29")]
1766            UseDecl::Dictionary(_) => None,
1767        }
1768    }
1769}
1770
1771impl SourceName for UseDecl {
1772    fn source_name(&self) -> &Name {
1773        match self {
1774            UseDecl::Storage(storage_decl) => &storage_decl.source_name,
1775            UseDecl::Service(service_decl) => &service_decl.source_name,
1776            UseDecl::Protocol(protocol_decl) => &protocol_decl.source_name,
1777            UseDecl::Directory(directory_decl) => &directory_decl.source_name,
1778            UseDecl::EventStream(event_stream_decl) => &event_stream_decl.source_name,
1779            #[cfg(fuchsia_api_level_at_least = "HEAD")]
1780            UseDecl::Runner(runner_decl) => &runner_decl.source_name,
1781            UseDecl::Config(u) => &u.source_name,
1782            #[cfg(fuchsia_api_level_at_least = "29")]
1783            UseDecl::Dictionary(dictionary_decl) => &dictionary_decl.source_name,
1784        }
1785    }
1786}
1787
1788impl SourcePath for UseDecl {
1789    fn source_path(&self) -> BorrowedSeparatedPath<'_> {
1790        match self {
1791            UseDecl::Service(u) => u.source_path(),
1792            UseDecl::Protocol(u) => u.source_path(),
1793            UseDecl::Directory(u) => u.source_path(),
1794            UseDecl::Storage(u) => u.source_path(),
1795            UseDecl::EventStream(u) => u.source_path(),
1796            #[cfg(fuchsia_api_level_at_least = "HEAD")]
1797            UseDecl::Runner(u) => u.source_path(),
1798            UseDecl::Config(u) => u.source_path(),
1799            #[cfg(fuchsia_api_level_at_least = "29")]
1800            UseDecl::Dictionary(u) => u.source_path(),
1801        }
1802    }
1803}
1804
1805/// The trait for all declarations that have a source name.
1806pub trait SourceName {
1807    fn source_name(&self) -> &Name;
1808}
1809
1810/// The common properties of a [Use](fdecl::Use) declaration.
1811pub trait UseDeclCommon: SourceName + SourcePath + Send + Sync {
1812    fn source(&self) -> &UseSource;
1813    fn availability(&self) -> &Availability;
1814}
1815
1816/// The common properties of a Registration-with-environment declaration.
1817pub trait RegistrationDeclCommon: SourceName + Send + Sync {
1818    /// The name of the registration type, for error messages.
1819    const TYPE: &'static str;
1820    fn source(&self) -> &RegistrationSource;
1821}
1822
1823/// The common properties of an [Expose](fdecl::Expose) declaration.
1824pub trait ExposeDeclCommon: SourceName + SourcePath + fmt::Debug + Send + Sync {
1825    fn target_name(&self) -> &Name;
1826    fn target(&self) -> &ExposeTarget;
1827    fn source(&self) -> &ExposeSource;
1828    fn availability(&self) -> &Availability;
1829}
1830
1831/// A named capability type.
1832///
1833/// `CapabilityTypeName` provides a user friendly type encoding for a capability.
1834#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
1835#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)]
1836pub enum CapabilityTypeName {
1837    Directory,
1838    EventStream,
1839    Protocol,
1840    Resolver,
1841    Runner,
1842    Service,
1843    Storage,
1844    Dictionary,
1845    Config,
1846}
1847
1848impl std::str::FromStr for CapabilityTypeName {
1849    type Err = Error;
1850
1851    fn from_str(s: &str) -> Result<Self, Self::Err> {
1852        match s {
1853            "directory" => Ok(CapabilityTypeName::Directory),
1854            "event_stream" => Ok(CapabilityTypeName::EventStream),
1855            "protocol" => Ok(CapabilityTypeName::Protocol),
1856            "resolver" => Ok(CapabilityTypeName::Resolver),
1857            "runner" => Ok(CapabilityTypeName::Runner),
1858            "service" => Ok(CapabilityTypeName::Service),
1859            "storage" => Ok(CapabilityTypeName::Storage),
1860            "dictionary" => Ok(CapabilityTypeName::Dictionary),
1861            "configuration" => Ok(CapabilityTypeName::Config),
1862            _ => Err(Error::ParseCapabilityTypeName { raw: s.to_string() }),
1863        }
1864    }
1865}
1866
1867impl FidlIntoNative<CapabilityTypeName> for String {
1868    fn fidl_into_native(self) -> CapabilityTypeName {
1869        self.parse().unwrap()
1870    }
1871}
1872
1873impl NativeIntoFidl<String> for CapabilityTypeName {
1874    fn native_into_fidl(self) -> String {
1875        self.to_string()
1876    }
1877}
1878
1879impl fmt::Display for CapabilityTypeName {
1880    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1881        let display_name = match &self {
1882            CapabilityTypeName::Directory => "directory",
1883            CapabilityTypeName::EventStream => "event_stream",
1884            CapabilityTypeName::Protocol => "protocol",
1885            CapabilityTypeName::Resolver => "resolver",
1886            CapabilityTypeName::Runner => "runner",
1887            CapabilityTypeName::Service => "service",
1888            CapabilityTypeName::Storage => "storage",
1889            CapabilityTypeName::Dictionary => "dictionary",
1890            CapabilityTypeName::Config => "configuration",
1891        };
1892        write!(f, "{}", display_name)
1893    }
1894}
1895
1896impl From<&UseDecl> for CapabilityTypeName {
1897    fn from(use_decl: &UseDecl) -> Self {
1898        match use_decl {
1899            UseDecl::Service(_) => Self::Service,
1900            UseDecl::Protocol(_) => Self::Protocol,
1901            UseDecl::Directory(_) => Self::Directory,
1902            UseDecl::Storage(_) => Self::Storage,
1903            UseDecl::EventStream(_) => Self::EventStream,
1904            #[cfg(fuchsia_api_level_at_least = "HEAD")]
1905            UseDecl::Runner(_) => Self::Runner,
1906            UseDecl::Config(_) => Self::Config,
1907            #[cfg(fuchsia_api_level_at_least = "29")]
1908            UseDecl::Dictionary(_) => Self::Dictionary,
1909        }
1910    }
1911}
1912
1913impl From<&ExposeDecl> for CapabilityTypeName {
1914    fn from(expose_decl: &ExposeDecl) -> Self {
1915        match expose_decl {
1916            ExposeDecl::Service(_) => Self::Service,
1917            ExposeDecl::Protocol(_) => Self::Protocol,
1918            ExposeDecl::Directory(_) => Self::Directory,
1919            ExposeDecl::Runner(_) => Self::Runner,
1920            ExposeDecl::Resolver(_) => Self::Resolver,
1921            ExposeDecl::Dictionary(_) => Self::Dictionary,
1922            ExposeDecl::Config(_) => Self::Config,
1923        }
1924    }
1925}
1926
1927impl From<&CapabilityDecl> for CapabilityTypeName {
1928    fn from(capability: &CapabilityDecl) -> Self {
1929        match capability {
1930            CapabilityDecl::Service(_) => Self::Service,
1931            CapabilityDecl::Protocol(_) => Self::Protocol,
1932            CapabilityDecl::Directory(_) => Self::Directory,
1933            CapabilityDecl::Storage(_) => Self::Storage,
1934            CapabilityDecl::Runner(_) => Self::Runner,
1935            CapabilityDecl::Resolver(_) => Self::Resolver,
1936            CapabilityDecl::EventStream(_) => Self::EventStream,
1937            CapabilityDecl::Dictionary(_) => Self::Dictionary,
1938            CapabilityDecl::Config(_) => Self::Config,
1939        }
1940    }
1941}
1942
1943impl From<CapabilityTypeName> for fio::DirentType {
1944    fn from(value: CapabilityTypeName) -> Self {
1945        match value {
1946            CapabilityTypeName::Directory => fio::DirentType::Directory,
1947            CapabilityTypeName::EventStream => fio::DirentType::Service,
1948            CapabilityTypeName::Protocol => fio::DirentType::Service,
1949            CapabilityTypeName::Service => fio::DirentType::Directory,
1950            CapabilityTypeName::Storage => fio::DirentType::Directory,
1951            CapabilityTypeName::Dictionary => fio::DirentType::Directory,
1952            CapabilityTypeName::Resolver => fio::DirentType::Service,
1953            CapabilityTypeName::Runner => fio::DirentType::Service,
1954            // Config capabilities don't appear in exposed or used dir
1955            CapabilityTypeName::Config => fio::DirentType::Unknown,
1956        }
1957    }
1958}
1959
1960// TODO: Runners and third parties can use this to parse `facets`.
1961impl FidlIntoNative<HashMap<String, DictionaryValue>> for fdata::Dictionary {
1962    fn fidl_into_native(self) -> HashMap<String, DictionaryValue> {
1963        from_fidl_dict(self)
1964    }
1965}
1966
1967impl NativeIntoFidl<fdata::Dictionary> for HashMap<String, DictionaryValue> {
1968    fn native_into_fidl(self) -> fdata::Dictionary {
1969        to_fidl_dict(self)
1970    }
1971}
1972
1973impl FidlIntoNative<BTreeMap<String, DictionaryValue>> for fdata::Dictionary {
1974    fn fidl_into_native(self) -> BTreeMap<String, DictionaryValue> {
1975        from_fidl_dict_btree(self)
1976    }
1977}
1978
1979impl NativeIntoFidl<fdata::Dictionary> for BTreeMap<String, DictionaryValue> {
1980    fn native_into_fidl(self) -> fdata::Dictionary {
1981        to_fidl_dict_btree(self)
1982    }
1983}
1984
1985#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1986pub enum DictionaryValue {
1987    Str(String),
1988    StrVec(Vec<String>),
1989    Null,
1990}
1991
1992impl FidlIntoNative<DictionaryValue> for Option<Box<fdata::DictionaryValue>> {
1993    fn fidl_into_native(self) -> DictionaryValue {
1994        match self {
1995            Some(v) => match *v {
1996                fdata::DictionaryValue::Str(s) => DictionaryValue::Str(s),
1997                fdata::DictionaryValue::StrVec(ss) => DictionaryValue::StrVec(ss),
1998                _ => DictionaryValue::Null,
1999            },
2000            None => DictionaryValue::Null,
2001        }
2002    }
2003}
2004
2005impl NativeIntoFidl<Option<Box<fdata::DictionaryValue>>> for DictionaryValue {
2006    fn native_into_fidl(self) -> Option<Box<fdata::DictionaryValue>> {
2007        match self {
2008            DictionaryValue::Str(s) => Some(Box::new(fdata::DictionaryValue::Str(s))),
2009            DictionaryValue::StrVec(ss) => Some(Box::new(fdata::DictionaryValue::StrVec(ss))),
2010            DictionaryValue::Null => None,
2011        }
2012    }
2013}
2014
2015fn from_fidl_dict(dict: fdata::Dictionary) -> HashMap<String, DictionaryValue> {
2016    match dict.entries {
2017        Some(entries) => entries.into_iter().map(|e| (e.key, e.value.fidl_into_native())).collect(),
2018        _ => HashMap::new(),
2019    }
2020}
2021
2022fn to_fidl_dict(dict: HashMap<String, DictionaryValue>) -> fdata::Dictionary {
2023    fdata::Dictionary {
2024        entries: Some(
2025            dict.into_iter()
2026                .map(|(key, value)| fdata::DictionaryEntry { key, value: value.native_into_fidl() })
2027                .collect(),
2028        ),
2029        ..Default::default()
2030    }
2031}
2032
2033fn from_fidl_dict_btree(dict: fdata::Dictionary) -> BTreeMap<String, DictionaryValue> {
2034    match dict.entries {
2035        Some(entries) => entries.into_iter().map(|e| (e.key, e.value.fidl_into_native())).collect(),
2036        _ => BTreeMap::new(),
2037    }
2038}
2039
2040fn to_fidl_dict_btree(dict: BTreeMap<String, DictionaryValue>) -> fdata::Dictionary {
2041    fdata::Dictionary {
2042        entries: Some(
2043            dict.into_iter()
2044                .map(|(key, value)| fdata::DictionaryEntry { key, value: value.native_into_fidl() })
2045                .collect(),
2046        ),
2047        ..Default::default()
2048    }
2049}
2050
2051#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2052#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2053pub enum UseSource {
2054    Parent,
2055    Framework,
2056    Debug,
2057    Self_,
2058    Capability(Name),
2059    Child(Name),
2060    Collection(Name),
2061    #[cfg(fuchsia_api_level_at_least = "HEAD")]
2062    Environment,
2063}
2064
2065impl std::fmt::Display for UseSource {
2066    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2067        match self {
2068            Self::Framework => write!(f, "framework"),
2069            Self::Parent => write!(f, "parent"),
2070            Self::Debug => write!(f, "debug environment"),
2071            Self::Self_ => write!(f, "self"),
2072            Self::Capability(c) => write!(f, "capability `{}`", c),
2073            Self::Child(c) => write!(f, "child `#{}`", c),
2074            Self::Collection(c) => write!(f, "collection `#{}`", c),
2075            #[cfg(fuchsia_api_level_at_least = "HEAD")]
2076            Self::Environment => write!(f, "environment"),
2077        }
2078    }
2079}
2080
2081impl FidlIntoNative<UseSource> for fdecl::Ref {
2082    fn fidl_into_native(self) -> UseSource {
2083        match self {
2084            fdecl::Ref::Parent(_) => UseSource::Parent,
2085            fdecl::Ref::Framework(_) => UseSource::Framework,
2086            fdecl::Ref::Debug(_) => UseSource::Debug,
2087            fdecl::Ref::Self_(_) => UseSource::Self_,
2088            // cm_fidl_validator should have already validated this
2089            fdecl::Ref::Capability(c) => UseSource::Capability(c.name.parse().unwrap()),
2090            fdecl::Ref::Child(c) => UseSource::Child(c.name.parse().unwrap()),
2091            fdecl::Ref::Collection(c) => UseSource::Collection(c.name.parse().unwrap()),
2092            #[cfg(fuchsia_api_level_at_least = "HEAD")]
2093            fdecl::Ref::Environment(_) => UseSource::Environment,
2094            _ => panic!("invalid UseSource variant"),
2095        }
2096    }
2097}
2098
2099impl NativeIntoFidl<fdecl::Ref> for UseSource {
2100    fn native_into_fidl(self) -> fdecl::Ref {
2101        match self {
2102            UseSource::Parent => fdecl::Ref::Parent(fdecl::ParentRef {}),
2103            UseSource::Framework => fdecl::Ref::Framework(fdecl::FrameworkRef {}),
2104            UseSource::Debug => fdecl::Ref::Debug(fdecl::DebugRef {}),
2105            UseSource::Self_ => fdecl::Ref::Self_(fdecl::SelfRef {}),
2106            UseSource::Capability(name) => {
2107                fdecl::Ref::Capability(fdecl::CapabilityRef { name: name.to_string() })
2108            }
2109            UseSource::Child(name) => {
2110                fdecl::Ref::Child(fdecl::ChildRef { name: name.to_string(), collection: None })
2111            }
2112            UseSource::Collection(name) => {
2113                fdecl::Ref::Collection(fdecl::CollectionRef { name: name.to_string() })
2114            }
2115            #[cfg(fuchsia_api_level_at_least = "HEAD")]
2116            UseSource::Environment => fdecl::Ref::Environment(fdecl::EnvironmentRef {}),
2117        }
2118    }
2119}
2120
2121#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2122#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2123pub enum EventScope {
2124    Child(ChildRef),
2125    Collection(Name),
2126}
2127
2128impl FidlIntoNative<EventScope> for fdecl::Ref {
2129    fn fidl_into_native(self) -> EventScope {
2130        match self {
2131            fdecl::Ref::Child(c) => {
2132                if let Some(_) = c.collection {
2133                    panic!("Dynamic children scopes are not supported for EventStreams");
2134                } else {
2135                    EventScope::Child(ChildRef { name: c.name.parse().unwrap(), collection: None })
2136                }
2137            }
2138            fdecl::Ref::Collection(collection) => {
2139                // cm_fidl_validator should have already validated this
2140                EventScope::Collection(collection.name.parse().unwrap())
2141            }
2142            _ => panic!("invalid EventScope variant"),
2143        }
2144    }
2145}
2146
2147impl NativeIntoFidl<fdecl::Ref> for EventScope {
2148    fn native_into_fidl(self) -> fdecl::Ref {
2149        match self {
2150            EventScope::Child(child) => fdecl::Ref::Child(child.native_into_fidl()),
2151            EventScope::Collection(name) => {
2152                fdecl::Ref::Collection(fdecl::CollectionRef { name: name.native_into_fidl() })
2153            }
2154        }
2155    }
2156}
2157
2158#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2159#[derive(Debug, Clone, PartialEq, Eq)]
2160pub enum ExposeSource {
2161    Self_,
2162    Child(Name),
2163    Collection(Name),
2164    Framework,
2165    Capability(Name),
2166    Void,
2167}
2168
2169impl std::fmt::Display for ExposeSource {
2170    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2171        match self {
2172            Self::Framework => write!(f, "framework"),
2173            Self::Child(c) => write!(f, "child `#{}`", c),
2174            Self::Collection(c) => write!(f, "collection `#{}`", c),
2175            Self::Self_ => write!(f, "self"),
2176            Self::Capability(c) => write!(f, "capability `{}`", c),
2177            Self::Void => write!(f, "void"),
2178        }
2179    }
2180}
2181
2182impl FidlIntoNative<ExposeSource> for fdecl::Ref {
2183    fn fidl_into_native(self) -> ExposeSource {
2184        match self {
2185            fdecl::Ref::Self_(_) => ExposeSource::Self_,
2186            // cm_fidl_validator should have already validated this
2187            fdecl::Ref::Child(c) => ExposeSource::Child(c.name.parse().unwrap()),
2188            // cm_fidl_validator should have already validated this
2189            fdecl::Ref::Collection(c) => ExposeSource::Collection(c.name.parse().unwrap()),
2190            fdecl::Ref::Framework(_) => ExposeSource::Framework,
2191            // cm_fidl_validator should have already validated this
2192            fdecl::Ref::Capability(c) => ExposeSource::Capability(c.name.parse().unwrap()),
2193            fdecl::Ref::VoidType(_) => ExposeSource::Void,
2194            _ => panic!("invalid ExposeSource variant"),
2195        }
2196    }
2197}
2198
2199impl NativeIntoFidl<fdecl::Ref> for ExposeSource {
2200    fn native_into_fidl(self) -> fdecl::Ref {
2201        match self {
2202            ExposeSource::Self_ => fdecl::Ref::Self_(fdecl::SelfRef {}),
2203            ExposeSource::Child(name) => fdecl::Ref::Child(fdecl::ChildRef {
2204                name: name.native_into_fidl(),
2205                collection: None,
2206            }),
2207            ExposeSource::Collection(name) => {
2208                fdecl::Ref::Collection(fdecl::CollectionRef { name: name.native_into_fidl() })
2209            }
2210            ExposeSource::Framework => fdecl::Ref::Framework(fdecl::FrameworkRef {}),
2211            ExposeSource::Capability(name) => {
2212                fdecl::Ref::Capability(fdecl::CapabilityRef { name: name.to_string() })
2213            }
2214            ExposeSource::Void => fdecl::Ref::VoidType(fdecl::VoidRef {}),
2215        }
2216    }
2217}
2218
2219#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2220#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2221pub enum ExposeTarget {
2222    Parent,
2223    Framework,
2224}
2225
2226impl std::fmt::Display for ExposeTarget {
2227    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2228        match self {
2229            Self::Framework => write!(f, "framework"),
2230            Self::Parent => write!(f, "parent"),
2231        }
2232    }
2233}
2234
2235impl FidlIntoNative<ExposeTarget> for fdecl::Ref {
2236    fn fidl_into_native(self) -> ExposeTarget {
2237        match self {
2238            fdecl::Ref::Parent(_) => ExposeTarget::Parent,
2239            fdecl::Ref::Framework(_) => ExposeTarget::Framework,
2240            _ => panic!("invalid ExposeTarget variant"),
2241        }
2242    }
2243}
2244
2245impl NativeIntoFidl<fdecl::Ref> for ExposeTarget {
2246    fn native_into_fidl(self) -> fdecl::Ref {
2247        match self {
2248            ExposeTarget::Parent => fdecl::Ref::Parent(fdecl::ParentRef {}),
2249            ExposeTarget::Framework => fdecl::Ref::Framework(fdecl::FrameworkRef {}),
2250        }
2251    }
2252}
2253
2254/// A source for a service.
2255#[derive(Debug, Clone, PartialEq, Eq)]
2256pub struct ServiceSource<T> {
2257    /// The provider of the service, relative to a component.
2258    pub source: T,
2259    /// The name of the service.
2260    pub source_name: Name,
2261}
2262
2263#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2264#[derive(Debug, Clone, PartialEq, Eq)]
2265pub enum StorageDirectorySource {
2266    Parent,
2267    Self_,
2268    Child(String),
2269}
2270
2271impl FidlIntoNative<StorageDirectorySource> for fdecl::Ref {
2272    fn fidl_into_native(self) -> StorageDirectorySource {
2273        match self {
2274            fdecl::Ref::Parent(_) => StorageDirectorySource::Parent,
2275            fdecl::Ref::Self_(_) => StorageDirectorySource::Self_,
2276            fdecl::Ref::Child(c) => StorageDirectorySource::Child(c.name),
2277            _ => panic!("invalid StorageDirectorySource variant"),
2278        }
2279    }
2280}
2281
2282impl NativeIntoFidl<fdecl::Ref> for StorageDirectorySource {
2283    fn native_into_fidl(self) -> fdecl::Ref {
2284        match self {
2285            StorageDirectorySource::Parent => fdecl::Ref::Parent(fdecl::ParentRef {}),
2286            StorageDirectorySource::Self_ => fdecl::Ref::Self_(fdecl::SelfRef {}),
2287            StorageDirectorySource::Child(child_name) => {
2288                fdecl::Ref::Child(fdecl::ChildRef { name: child_name, collection: None })
2289            }
2290        }
2291    }
2292}
2293
2294#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2295#[derive(Debug, Clone, PartialEq, Eq)]
2296pub enum DictionarySource {
2297    Parent,
2298    Self_,
2299    Child(ChildRef),
2300}
2301
2302impl FidlIntoNative<DictionarySource> for fdecl::Ref {
2303    fn fidl_into_native(self) -> DictionarySource {
2304        match self {
2305            Self::Parent(_) => DictionarySource::Parent,
2306            Self::Self_(_) => DictionarySource::Self_,
2307            Self::Child(c) => DictionarySource::Child(c.fidl_into_native()),
2308            _ => panic!("invalid DictionarySource variant"),
2309        }
2310    }
2311}
2312
2313impl NativeIntoFidl<fdecl::Ref> for DictionarySource {
2314    fn native_into_fidl(self) -> fdecl::Ref {
2315        match self {
2316            Self::Parent => fdecl::Ref::Parent(fdecl::ParentRef {}),
2317            Self::Self_ => fdecl::Ref::Self_(fdecl::SelfRef {}),
2318            Self::Child(c) => fdecl::Ref::Child(c.native_into_fidl()),
2319        }
2320    }
2321}
2322
2323#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2324#[derive(Debug, Clone, PartialEq, Eq)]
2325pub enum RegistrationSource {
2326    Parent,
2327    Self_,
2328    Child(String),
2329}
2330
2331impl FidlIntoNative<RegistrationSource> for fdecl::Ref {
2332    fn fidl_into_native(self) -> RegistrationSource {
2333        match self {
2334            fdecl::Ref::Parent(_) => RegistrationSource::Parent,
2335            fdecl::Ref::Self_(_) => RegistrationSource::Self_,
2336            fdecl::Ref::Child(c) => RegistrationSource::Child(c.name),
2337            _ => panic!("invalid RegistrationSource variant"),
2338        }
2339    }
2340}
2341
2342impl NativeIntoFidl<fdecl::Ref> for RegistrationSource {
2343    fn native_into_fidl(self) -> fdecl::Ref {
2344        match self {
2345            RegistrationSource::Parent => fdecl::Ref::Parent(fdecl::ParentRef {}),
2346            RegistrationSource::Self_ => fdecl::Ref::Self_(fdecl::SelfRef {}),
2347            RegistrationSource::Child(child_name) => {
2348                fdecl::Ref::Child(fdecl::ChildRef { name: child_name, collection: None })
2349            }
2350        }
2351    }
2352}
2353
2354/// Converts the contents of a CM-FIDL declaration and produces the equivalent CM-Rust
2355/// struct.
2356/// This function applies cm_fidl_validator to check correctness.
2357impl TryFrom<fdecl::Component> for ComponentDecl {
2358    type Error = Error;
2359
2360    fn try_from(decl: fdecl::Component) -> Result<Self, Self::Error> {
2361        cm_fidl_validator::validate(&decl, &mut DirectedGraph::new())
2362            .map_err(|err| Error::Validate { err })?;
2363        Ok(decl.fidl_into_native())
2364    }
2365}
2366
2367// Converts the contents of a CM-Rust declaration into a CM_FIDL declaration
2368impl From<ComponentDecl> for fdecl::Component {
2369    fn from(decl: ComponentDecl) -> Self {
2370        decl.native_into_fidl()
2371    }
2372}
2373
2374/// Errors produced by cm_rust.
2375#[derive(Debug, Error, Clone)]
2376pub enum Error {
2377    #[error("Fidl validation failed: {}", err)]
2378    Validate {
2379        #[source]
2380        err: cm_fidl_validator::error::ErrorList,
2381    },
2382    #[error("Invalid capability path: {}", raw)]
2383    InvalidCapabilityPath { raw: String },
2384    #[error("Invalid capability type name: {}", raw)]
2385    ParseCapabilityTypeName { raw: String },
2386}
2387
2388/// Push `value` onto the end of `Box<[T]>`. Convenience function for clients that work with
2389/// cm_rust, which uses `Box<[T]>` instead of `Vec<T>` for its list type.
2390pub fn push_box<T>(container: &mut Box<[T]>, value: T) {
2391    let boxed = mem::replace(container, Box::from([]));
2392    let mut new_container: Vec<_> = boxed.into();
2393    new_container.push(value);
2394    *container = new_container.into();
2395}
2396
2397/// Append `other` to the end of `Box<[T]>`. Convenience function for clients that work with
2398/// cm_rust, which uses `Box<[T]>` instead of `Vec<T>` for its list type.
2399pub fn append_box<T>(container: &mut Box<[T]>, other: &mut Vec<T>) {
2400    let boxed = mem::replace(container, Box::from([]));
2401    let mut new_container: Vec<_> = boxed.into();
2402    new_container.append(other);
2403    *container = new_container.into();
2404}
2405
2406#[cfg(test)]
2407mod tests {
2408    use super::*;
2409    use difference::Changeset;
2410    use fidl_fuchsia_component_decl as fdecl;
2411
2412    fn offer_source_static_child(name: &str) -> OfferSource {
2413        OfferSource::Child(ChildRef { name: name.parse().unwrap(), collection: None })
2414    }
2415
2416    fn offer_target_static_child(name: &str) -> OfferTarget {
2417        OfferTarget::Child(ChildRef { name: name.parse().unwrap(), collection: None })
2418    }
2419
2420    macro_rules! test_try_from_decl {
2421        (
2422            $(
2423                $test_name:ident => {
2424                    input = $input:expr,
2425                    result = $result:expr,
2426                },
2427            )+
2428        ) => {
2429            $(
2430                #[test]
2431                fn $test_name() {
2432                    {
2433                        let res = ComponentDecl::try_from($input).expect("try_from failed");
2434                        if res != $result {
2435                            let a = format!("{:#?}", res);
2436                            let e = format!("{:#?}", $result);
2437                            panic!("Conversion from fidl to cm_rust did not yield expected result:\n{}", Changeset::new(&a, &e, "\n"));
2438                        }
2439                    }
2440                    {
2441                        let res = fdecl::Component::try_from($result).expect("try_from failed");
2442                        if res != $input {
2443                            let a = format!("{:#?}", res);
2444                            let e = format!("{:#?}", $input);
2445                            panic!("Conversion from cm_rust to fidl did not yield expected result:\n{}", Changeset::new(&a, &e, "\n"));
2446                        }
2447                    }
2448                }
2449            )+
2450        }
2451    }
2452
2453    macro_rules! test_fidl_into_and_from {
2454        (
2455            $(
2456                $test_name:ident => {
2457                    input = $input:expr,
2458                    input_type = $input_type:ty,
2459                    result = $result:expr,
2460                    result_type = $result_type:ty,
2461                },
2462            )+
2463        ) => {
2464            $(
2465                #[test]
2466                fn $test_name() {
2467                    {
2468                        let res: Vec<$result_type> =
2469                            $input.into_iter().map(|e| e.fidl_into_native()).collect();
2470                        assert_eq!(res, $result);
2471                    }
2472                    {
2473                        let res: Vec<$input_type> =
2474                            $result.into_iter().map(|e| e.native_into_fidl()).collect();
2475                        assert_eq!(res, $input);
2476                    }
2477                }
2478            )+
2479        }
2480    }
2481
2482    macro_rules! test_fidl_into {
2483        (
2484            $(
2485                $test_name:ident => {
2486                    input = $input:expr,
2487                    result = $result:expr,
2488                },
2489            )+
2490        ) => {
2491            $(
2492                #[test]
2493                fn $test_name() {
2494                    test_fidl_into_helper($input, $result);
2495                }
2496            )+
2497        }
2498    }
2499
2500    fn test_fidl_into_helper<T, U>(input: T, expected_res: U)
2501    where
2502        T: FidlIntoNative<U>,
2503        U: std::cmp::PartialEq + std::fmt::Debug,
2504    {
2505        let res: U = input.fidl_into_native();
2506        assert_eq!(res, expected_res);
2507    }
2508
2509    test_try_from_decl! {
2510        try_from_empty => {
2511            input = fdecl::Component {
2512                program: None,
2513                uses: None,
2514                exposes: None,
2515                offers: None,
2516                capabilities: None,
2517                children: None,
2518                collections: None,
2519                facets: None,
2520                environments: None,
2521                ..Default::default()
2522            },
2523            result = ComponentDecl {
2524                program: None,
2525                uses: Box::from([]),
2526                exposes: Box::from([]),
2527                offers: Box::from([]),
2528                capabilities: Box::from([]),
2529                children: Box::from([]),
2530                collections: Box::from([]),
2531                facets: None,
2532                environments: Box::from([]),
2533                config: None,
2534                debug_info: None,
2535            },
2536        },
2537        try_from_all => {
2538            input = fdecl::Component {
2539                program: Some(fdecl::Program {
2540                    runner: Some("elf".to_string()),
2541                    info: Some(fdata::Dictionary {
2542                        entries: Some(vec![
2543                            fdata::DictionaryEntry {
2544                                key: "args".to_string(),
2545                                value: Some(Box::new(fdata::DictionaryValue::StrVec(vec!["foo".to_string(), "bar".to_string()]))),
2546                            },
2547                            fdata::DictionaryEntry {
2548                                key: "binary".to_string(),
2549                                value: Some(Box::new(fdata::DictionaryValue::Str("bin/app".to_string()))),
2550                            },
2551                        ]),
2552                        ..Default::default()
2553                    }),
2554                    ..Default::default()
2555                }),
2556                uses: Some(vec![
2557                    fdecl::Use::Service(fdecl::UseService {
2558                        dependency_type: Some(fdecl::DependencyType::Strong),
2559                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2560                        source_name: Some("netstack".to_string()),
2561                        source_dictionary: Some("in/dict".to_string()),
2562                        target_path: Some("/svc/mynetstack".to_string()),
2563                        availability: Some(fdecl::Availability::Required),
2564                        ..Default::default()
2565                    }),
2566                    fdecl::Use::Protocol(fdecl::UseProtocol {
2567                        dependency_type: Some(fdecl::DependencyType::Strong),
2568                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2569                        source_name: Some("legacy_netstack".to_string()),
2570                        source_dictionary: Some("in/dict".to_string()),
2571                        target_path: None,
2572                        numbered_handle: Some(0xab),
2573                        availability: Some(fdecl::Availability::Optional),
2574                        ..Default::default()
2575                    }),
2576                    fdecl::Use::Protocol(fdecl::UseProtocol {
2577                        dependency_type: Some(fdecl::DependencyType::Strong),
2578                        source: Some(fdecl::Ref::Child(fdecl::ChildRef { name: "echo".to_string(), collection: None})),
2579                        source_name: Some("echo_service".to_string()),
2580                        source_dictionary: Some("in/dict".to_string()),
2581                        target_path: Some("/svc/echo_service".to_string()),
2582                        availability: Some(fdecl::Availability::Required),
2583                        ..Default::default()
2584                    }),
2585                    fdecl::Use::Directory(fdecl::UseDirectory {
2586                        dependency_type: Some(fdecl::DependencyType::Strong),
2587                        source: Some(fdecl::Ref::Self_(fdecl::SelfRef {})),
2588                        source_name: Some("dir".to_string()),
2589                        source_dictionary: Some("dict1/me".to_string()),
2590                        target_path: Some("/data".to_string()),
2591                        rights: Some(fio::Operations::CONNECT),
2592                        subdir: Some("foo/bar".to_string()),
2593                        availability: Some(fdecl::Availability::Required),
2594                        ..Default::default()
2595                    }),
2596                    fdecl::Use::Storage(fdecl::UseStorage {
2597                        source_name: Some("cache".to_string()),
2598                        target_path: Some("/cache".to_string()),
2599                        availability: Some(fdecl::Availability::Required),
2600                        ..Default::default()
2601                    }),
2602                    fdecl::Use::Storage(fdecl::UseStorage {
2603                        source_name: Some("temp".to_string()),
2604                        target_path: Some("/temp".to_string()),
2605                        availability: Some(fdecl::Availability::Optional),
2606                        ..Default::default()
2607                    }),
2608                    fdecl::Use::EventStream(fdecl::UseEventStream {
2609                        source: Some(fdecl::Ref::Child(fdecl::ChildRef {
2610                            collection: None,
2611                            name: "netstack".to_string(),
2612                        })),
2613                        source_name: Some("stopped".to_string()),
2614                        scope: Some(vec![
2615                            fdecl::Ref::Child(fdecl::ChildRef {
2616                                collection: None,
2617                                name:"a".to_string(),
2618                        }), fdecl::Ref::Collection(fdecl::CollectionRef {
2619                            name:"b".to_string(),
2620                        })]),
2621                        target_path: Some("/svc/test".to_string()),
2622                        availability: Some(fdecl::Availability::Optional),
2623                        ..Default::default()
2624                    }),
2625                    fdecl::Use::Runner(fdecl::UseRunner {
2626                        source: Some(fdecl::Ref::Environment(fdecl::EnvironmentRef {})),
2627                        source_name: Some("elf".to_string()),
2628                        source_dictionary: None,
2629                        ..Default::default()
2630                    }),
2631                    fdecl::Use::Config(fdecl::UseConfiguration {
2632                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef)),
2633                        source_name: Some("fuchsia.config.MyConfig".to_string()),
2634                        target_name: Some("my_config".to_string()),
2635                        availability: Some(fdecl::Availability::Required),
2636                        type_: Some(fdecl::ConfigType{
2637                            layout: fdecl::ConfigTypeLayout::Bool,
2638                            parameters: Some(Vec::new()),
2639                            constraints: Vec::new(),
2640                        }),
2641                        ..Default::default()
2642                    }),
2643                    #[cfg(fuchsia_api_level_at_least = "29")]
2644                    fdecl::Use::Dictionary(fdecl::UseDictionary {
2645                        dependency_type: Some(fdecl::DependencyType::Strong),
2646                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2647                        source_name: Some("dictionary".to_string()),
2648                        source_dictionary: Some("other_dictionary".to_string()),
2649                        target_path: Some("/svc".to_string()),
2650                        availability: Some(fdecl::Availability::Optional),
2651                        ..Default::default()
2652                    }),
2653                ]),
2654                exposes: Some(vec![
2655                    fdecl::Expose::Protocol(fdecl::ExposeProtocol {
2656                        source: Some(fdecl::Ref::Child(fdecl::ChildRef {
2657                            name: "netstack".to_string(),
2658                            collection: None,
2659                        })),
2660                        source_name: Some("legacy_netstack".to_string()),
2661                        source_dictionary: Some("in/dict".to_string()),
2662                        target_name: Some("legacy_mynetstack".to_string()),
2663                        target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2664                        availability: Some(fdecl::Availability::Required),
2665                        ..Default::default()
2666                    }),
2667                    fdecl::Expose::Directory(fdecl::ExposeDirectory {
2668                        source: Some(fdecl::Ref::Child(fdecl::ChildRef {
2669                            name: "netstack".to_string(),
2670                            collection: None,
2671                        })),
2672                        source_name: Some("dir".to_string()),
2673                        source_dictionary: Some("in/dict".to_string()),
2674                        target_name: Some("data".to_string()),
2675                        target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2676                        rights: Some(fio::Operations::CONNECT),
2677                        subdir: Some("foo/bar".to_string()),
2678                        availability: Some(fdecl::Availability::Optional),
2679                        ..Default::default()
2680                    }),
2681                    fdecl::Expose::Runner(fdecl::ExposeRunner {
2682                        source: Some(fdecl::Ref::Child(fdecl::ChildRef {
2683                            name: "netstack".to_string(),
2684                            collection: None,
2685                        })),
2686                        source_name: Some("elf".to_string()),
2687                        source_dictionary: Some("in/dict".to_string()),
2688                        target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2689                        target_name: Some("elf".to_string()),
2690                        ..Default::default()
2691                    }),
2692                    fdecl::Expose::Resolver(fdecl::ExposeResolver{
2693                        source: Some(fdecl::Ref::Child(fdecl::ChildRef {
2694                            name: "netstack".to_string(),
2695                            collection: None,
2696                        })),
2697                        source_name: Some("pkg".to_string()),
2698                        source_dictionary: Some("in/dict".to_string()),
2699                        target: Some(fdecl::Ref::Parent(fdecl::ParentRef{})),
2700                        target_name: Some("pkg".to_string()),
2701                        ..Default::default()
2702                    }),
2703                    fdecl::Expose::Service(fdecl::ExposeService {
2704                        source: Some(fdecl::Ref::Child(fdecl::ChildRef {
2705                            name: "netstack".to_string(),
2706                            collection: None,
2707                        })),
2708                        source_name: Some("netstack1".to_string()),
2709                        source_dictionary: Some("in/dict".to_string()),
2710                        target_name: Some("mynetstack".to_string()),
2711                        target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2712                        availability: Some(fdecl::Availability::Required),
2713                        ..Default::default()
2714                    }),
2715                    fdecl::Expose::Service(fdecl::ExposeService {
2716                        source: Some(fdecl::Ref::Collection(fdecl::CollectionRef {
2717                            name: "modular".to_string(),
2718                        })),
2719                        source_name: Some("netstack2".to_string()),
2720                        source_dictionary: None,
2721                        target_name: Some("mynetstack".to_string()),
2722                        target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2723                        availability: Some(fdecl::Availability::Required),
2724                        ..Default::default()
2725                    }),
2726                    fdecl::Expose::Dictionary(fdecl::ExposeDictionary {
2727                        source: Some(fdecl::Ref::Child(fdecl::ChildRef {
2728                            name: "netstack".to_string(),
2729                            collection: None,
2730                        })),
2731                        source_name: Some("bundle".to_string()),
2732                        source_dictionary: Some("in/dict".to_string()),
2733                        target_name: Some("mybundle".to_string()),
2734                        target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2735                        availability: Some(fdecl::Availability::Required),
2736                        ..Default::default()
2737                    }),
2738                ]),
2739                offers: Some(vec![
2740                    fdecl::Offer::Protocol(fdecl::OfferProtocol {
2741                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2742                        source_name: Some("legacy_netstack".to_string()),
2743                        source_dictionary: Some("in/dict".to_string()),
2744                        target: Some(fdecl::Ref::Child(
2745                           fdecl::ChildRef {
2746                               name: "echo".to_string(),
2747                               collection: None,
2748                           }
2749                        )),
2750                        target_name: Some("legacy_mynetstack".to_string()),
2751                        dependency_type: Some(fdecl::DependencyType::Weak),
2752                        availability: Some(fdecl::Availability::Required),
2753                        ..Default::default()
2754                    }),
2755                    fdecl::Offer::Directory(fdecl::OfferDirectory {
2756                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2757                        source_name: Some("dir".to_string()),
2758                        source_dictionary: Some("in/dict".to_string()),
2759                        target: Some(fdecl::Ref::Collection(
2760                            fdecl::CollectionRef { name: "modular".to_string() }
2761                        )),
2762                        target_name: Some("data".to_string()),
2763                        rights: Some(fio::Operations::CONNECT),
2764                        subdir: None,
2765                        dependency_type: Some(fdecl::DependencyType::Strong),
2766                        availability: Some(fdecl::Availability::Optional),
2767                        ..Default::default()
2768                    }),
2769                    fdecl::Offer::Storage(fdecl::OfferStorage {
2770                        source_name: Some("cache".to_string()),
2771                        source: Some(fdecl::Ref::Self_(fdecl::SelfRef {})),
2772                        target: Some(fdecl::Ref::Collection(
2773                            fdecl::CollectionRef { name: "modular".to_string() }
2774                        )),
2775                        target_name: Some("cache".to_string()),
2776                        availability: Some(fdecl::Availability::Required),
2777                        ..Default::default()
2778                    }),
2779                    fdecl::Offer::Runner(fdecl::OfferRunner {
2780                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2781                        source_name: Some("elf".to_string()),
2782                        source_dictionary: Some("in/dict".to_string()),
2783                        target: Some(fdecl::Ref::Child(
2784                           fdecl::ChildRef {
2785                               name: "echo".to_string(),
2786                               collection: None,
2787                           }
2788                        )),
2789                        target_name: Some("elf2".to_string()),
2790                        ..Default::default()
2791                    }),
2792                    fdecl::Offer::Resolver(fdecl::OfferResolver{
2793                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef{})),
2794                        source_name: Some("pkg".to_string()),
2795                        source_dictionary: Some("in/dict".to_string()),
2796                        target: Some(fdecl::Ref::Child(
2797                           fdecl::ChildRef {
2798                              name: "echo".to_string(),
2799                              collection: None,
2800                           }
2801                        )),
2802                        target_name: Some("pkg".to_string()),
2803                        ..Default::default()
2804                    }),
2805                    fdecl::Offer::Service(fdecl::OfferService {
2806                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2807                        source_name: Some("netstack1".to_string()),
2808                        source_dictionary: Some("in/dict".to_string()),
2809                        target: Some(fdecl::Ref::Child(
2810                           fdecl::ChildRef {
2811                               name: "echo".to_string(),
2812                               collection: None,
2813                           }
2814                        )),
2815                        target_name: Some("mynetstack1".to_string()),
2816                        availability: Some(fdecl::Availability::Required),
2817                        dependency_type: Some(fdecl::DependencyType::Strong),
2818                        ..Default::default()
2819                    }),
2820                    fdecl::Offer::Service(fdecl::OfferService {
2821                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2822                        source_name: Some("netstack2".to_string()),
2823                        source_dictionary: None,
2824                        target: Some(fdecl::Ref::Child(
2825                           fdecl::ChildRef {
2826                               name: "echo".to_string(),
2827                               collection: None,
2828                           }
2829                        )),
2830                        target_name: Some("mynetstack2".to_string()),
2831                        availability: Some(fdecl::Availability::Optional),
2832                        dependency_type: Some(fdecl::DependencyType::Strong),
2833                        ..Default::default()
2834                    }),
2835                    fdecl::Offer::Service(fdecl::OfferService {
2836                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2837                        source_name: Some("netstack3".to_string()),
2838                        source_dictionary: None,
2839                        target: Some(fdecl::Ref::Child(
2840                           fdecl::ChildRef {
2841                               name: "echo".to_string(),
2842                               collection: None,
2843                           }
2844                        )),
2845                        target_name: Some("mynetstack3".to_string()),
2846                        source_instance_filter: Some(vec!["allowedinstance".to_string()]),
2847                        renamed_instances: Some(vec![fdecl::NameMapping{source_name: "default".to_string(), target_name: "allowedinstance".to_string()}]),
2848                        availability: Some(fdecl::Availability::Required),
2849                        dependency_type: Some(fdecl::DependencyType::Strong),
2850                        ..Default::default()
2851                    }),
2852                    fdecl::Offer::Dictionary(fdecl::OfferDictionary {
2853                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2854                        source_name: Some("bundle".to_string()),
2855                        source_dictionary: Some("in/dict".to_string()),
2856                        target: Some(fdecl::Ref::Child(
2857                           fdecl::ChildRef {
2858                               name: "echo".to_string(),
2859                               collection: None,
2860                           }
2861                        )),
2862                        target_name: Some("mybundle".to_string()),
2863                        dependency_type: Some(fdecl::DependencyType::Weak),
2864                        availability: Some(fdecl::Availability::Required),
2865                        ..Default::default()
2866                    }),
2867                ]),
2868                capabilities: Some(vec![
2869                    fdecl::Capability::Service(fdecl::Service {
2870                        name: Some("netstack".to_string()),
2871                        source_path: Some("/netstack".to_string()),
2872                        ..Default::default()
2873                    }),
2874                    fdecl::Capability::Protocol(fdecl::Protocol {
2875                        name: Some("netstack2".to_string()),
2876                        source_path: Some("/netstack2".to_string()),
2877                        delivery: Some(fdecl::DeliveryType::Immediate),
2878                        ..Default::default()
2879                    }),
2880                    fdecl::Capability::Directory(fdecl::Directory {
2881                        name: Some("data".to_string()),
2882                        source_path: Some("/data".to_string()),
2883                        rights: Some(fio::Operations::CONNECT),
2884                        ..Default::default()
2885                    }),
2886                    fdecl::Capability::Storage(fdecl::Storage {
2887                        name: Some("cache".to_string()),
2888                        backing_dir: Some("data".to_string()),
2889                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2890                        subdir: Some("cache".to_string()),
2891                        storage_id: Some(fdecl::StorageId::StaticInstanceId),
2892                        ..Default::default()
2893                    }),
2894                    fdecl::Capability::Runner(fdecl::Runner {
2895                        name: Some("elf".to_string()),
2896                        source_path: Some("/elf".to_string()),
2897                        ..Default::default()
2898                    }),
2899                    fdecl::Capability::Resolver(fdecl::Resolver {
2900                        name: Some("pkg".to_string()),
2901                        source_path: Some("/pkg_resolver".to_string()),
2902                        ..Default::default()
2903                    }),
2904                    fdecl::Capability::Dictionary(fdecl::Dictionary {
2905                        name: Some("dict1".to_string()),
2906                        ..Default::default()
2907                    }),
2908                    fdecl::Capability::Dictionary(fdecl::Dictionary {
2909                        name: Some("dict2".to_string()),
2910                        source_path: Some("/in/other".to_string()),
2911                        ..Default::default()
2912                    }),
2913                ]),
2914                children: Some(vec![
2915                     fdecl::Child {
2916                         name: Some("netstack".to_string()),
2917                         url: Some("fuchsia-pkg://fuchsia.com/netstack#meta/netstack.cm"
2918                                   .to_string()),
2919                         startup: Some(fdecl::StartupMode::Lazy),
2920                         on_terminate: None,
2921                         environment: None,
2922                         ..Default::default()
2923                     },
2924                     fdecl::Child {
2925                         name: Some("gtest".to_string()),
2926                         url: Some("fuchsia-pkg://fuchsia.com/gtest#meta/gtest.cm".to_string()),
2927                         startup: Some(fdecl::StartupMode::Lazy),
2928                         on_terminate: Some(fdecl::OnTerminate::None),
2929                         environment: None,
2930                         ..Default::default()
2931                     },
2932                     fdecl::Child {
2933                         name: Some("echo".to_string()),
2934                         url: Some("fuchsia-pkg://fuchsia.com/echo#meta/echo.cm"
2935                                   .to_string()),
2936                         startup: Some(fdecl::StartupMode::Eager),
2937                         on_terminate: Some(fdecl::OnTerminate::Reboot),
2938                         environment: Some("test_env".to_string()),
2939                         ..Default::default()
2940                     },
2941                ]),
2942                collections: Some(vec![
2943                     fdecl::Collection {
2944                         name: Some("modular".to_string()),
2945                         durability: Some(fdecl::Durability::Transient),
2946                         environment: None,
2947                         allowed_offers: Some(fdecl::AllowedOffers::StaticOnly),
2948                         allow_long_names: Some(true),
2949                         persistent_storage: None,
2950                         ..Default::default()
2951                     },
2952                     fdecl::Collection {
2953                         name: Some("tests".to_string()),
2954                         durability: Some(fdecl::Durability::Transient),
2955                         environment: Some("test_env".to_string()),
2956                         allowed_offers: Some(fdecl::AllowedOffers::StaticAndDynamic),
2957                         allow_long_names: Some(true),
2958                         persistent_storage: Some(true),
2959                         ..Default::default()
2960                     },
2961                ]),
2962                facets: Some(fdata::Dictionary {
2963                    entries: Some(vec![
2964                        fdata::DictionaryEntry {
2965                            key: "author".to_string(),
2966                            value: Some(Box::new(fdata::DictionaryValue::Str("Fuchsia".to_string()))),
2967                        },
2968                    ]),
2969                    ..Default::default()
2970                }),
2971                environments: Some(vec![
2972                    fdecl::Environment {
2973                        name: Some("test_env".to_string()),
2974                        extends: Some(fdecl::EnvironmentExtends::Realm),
2975                        runners: Some(vec![
2976                            fdecl::RunnerRegistration {
2977                                source_name: Some("runner".to_string()),
2978                                source: Some(fdecl::Ref::Child(fdecl::ChildRef {
2979                                    name: "gtest".to_string(),
2980                                    collection: None,
2981                                })),
2982                                target_name: Some("gtest-runner".to_string()),
2983                                ..Default::default()
2984                            }
2985                        ]),
2986                        resolvers: Some(vec![
2987                            fdecl::ResolverRegistration {
2988                                resolver: Some("pkg_resolver".to_string()),
2989                                source: Some(fdecl::Ref::Parent(fdecl::ParentRef{})),
2990                                scheme: Some("fuchsia-pkg".to_string()),
2991                                ..Default::default()
2992                            }
2993                        ]),
2994                        debug_capabilities: Some(vec![
2995                         fdecl::DebugRegistration::Protocol(fdecl::DebugProtocolRegistration {
2996                             source_name: Some("some_protocol".to_string()),
2997                             source: Some(fdecl::Ref::Child(fdecl::ChildRef {
2998                                 name: "gtest".to_string(),
2999                                 collection: None,
3000                             })),
3001                             target_name: Some("some_protocol".to_string()),
3002                             ..Default::default()
3003                            })
3004                        ]),
3005                        stop_timeout_ms: Some(4567),
3006                        ..Default::default()
3007                    }
3008                ]),
3009                config: Some(fdecl::ConfigSchema{
3010                    fields: Some(vec![
3011                        fdecl::ConfigField {
3012                            key: Some("enable_logging".to_string()),
3013                            type_: Some(fdecl::ConfigType {
3014                                layout: fdecl::ConfigTypeLayout::Bool,
3015                                parameters: Some(vec![]),
3016                                constraints: vec![],
3017                            }),
3018                            mutability: Some(Default::default()),
3019                            ..Default::default()
3020                        }
3021                    ]),
3022                    checksum: Some(fdecl::ConfigChecksum::Sha256([
3023                        0x64, 0x49, 0x9E, 0x75, 0xF3, 0x37, 0x69, 0x88, 0x74, 0x3B, 0x38, 0x16,
3024                        0xCD, 0x14, 0x70, 0x9F, 0x3D, 0x4A, 0xD3, 0xE2, 0x24, 0x9A, 0x1A, 0x34,
3025                        0x80, 0xB4, 0x9E, 0xB9, 0x63, 0x57, 0xD6, 0xED,
3026                    ])),
3027                    value_source: Some(
3028                        fdecl::ConfigValueSource::PackagePath("fake.cvf".to_string())
3029                    ),
3030                    ..Default::default()
3031                }),
3032                ..Default::default()
3033            },
3034            result = {
3035                ComponentDecl {
3036                    program: Some(ProgramDecl {
3037                        runner: Some("elf".parse().unwrap()),
3038                        info: fdata::Dictionary {
3039                            entries: Some(vec![
3040                                fdata::DictionaryEntry {
3041                                    key: "args".to_string(),
3042                                    value: Some(Box::new(fdata::DictionaryValue::StrVec(vec!["foo".to_string(), "bar".to_string()]))),
3043                                },
3044                                fdata::DictionaryEntry{
3045                                    key: "binary".to_string(),
3046                                    value: Some(Box::new(fdata::DictionaryValue::Str("bin/app".to_string()))),
3047                                },
3048                            ]),
3049                            ..Default::default()
3050                        },
3051                    }),
3052                    uses: Box::from([
3053                        UseDecl::Service(UseServiceDecl {
3054                            dependency_type: DependencyType::Strong,
3055                            source: UseSource::Parent,
3056                            source_name: "netstack".parse().unwrap(),
3057                            source_dictionary: "in/dict".parse().unwrap(),
3058                            target_path: "/svc/mynetstack".parse().unwrap(),
3059                            availability: Availability::Required,
3060                        }),
3061                        UseDecl::Protocol(UseProtocolDecl {
3062                            dependency_type: DependencyType::Strong,
3063                            source: UseSource::Parent,
3064                            source_name: "legacy_netstack".parse().unwrap(),
3065                            source_dictionary: "in/dict".parse().unwrap(),
3066                            target_path: None,
3067                            numbered_handle: Some(HandleType::from(0xab)),
3068                            availability: Availability::Optional,
3069                        }),
3070                        UseDecl::Protocol(UseProtocolDecl {
3071                            dependency_type: DependencyType::Strong,
3072                            source: UseSource::Child("echo".parse().unwrap()),
3073                            source_name: "echo_service".parse().unwrap(),
3074                            source_dictionary: "in/dict".parse().unwrap(),
3075                            target_path: Some("/svc/echo_service".parse().unwrap()),
3076                            numbered_handle: None,
3077                            availability: Availability::Required,
3078                        }),
3079                        UseDecl::Directory(UseDirectoryDecl {
3080                            dependency_type: DependencyType::Strong,
3081                            source: UseSource::Self_,
3082                            source_name: "dir".parse().unwrap(),
3083                            source_dictionary: "dict1/me".parse().unwrap(),
3084                            target_path: "/data".parse().unwrap(),
3085                            rights: fio::Operations::CONNECT,
3086                            subdir: "foo/bar".parse().unwrap(),
3087                            availability: Availability::Required,
3088                        }),
3089                        UseDecl::Storage(UseStorageDecl {
3090                            source_name: "cache".parse().unwrap(),
3091                            target_path: "/cache".parse().unwrap(),
3092                            availability: Availability::Required,
3093                        }),
3094                        UseDecl::Storage(UseStorageDecl {
3095                            source_name: "temp".parse().unwrap(),
3096                            target_path: "/temp".parse().unwrap(),
3097                            availability: Availability::Optional,
3098                        }),
3099                        UseDecl::EventStream(UseEventStreamDecl {
3100                            source: UseSource::Child("netstack".parse().unwrap()),
3101                            scope: Some(Box::from([EventScope::Child(ChildRef{ name: "a".parse().unwrap(), collection: None}), EventScope::Collection("b".parse().unwrap())])),
3102                            source_name: "stopped".parse().unwrap(),
3103                            target_path: "/svc/test".parse().unwrap(),
3104                            filter: None,
3105                            availability: Availability::Optional,
3106                        }),
3107                        UseDecl::Runner(UseRunnerDecl {
3108                            source: UseSource::Environment,
3109                            source_name: "elf".parse().unwrap(),
3110                            source_dictionary: ".".parse().unwrap(),
3111                        }),
3112                        UseDecl::Config(UseConfigurationDecl {
3113                            source: UseSource::Parent,
3114                            source_name: "fuchsia.config.MyConfig".parse().unwrap(),
3115                            target_name: "my_config".parse().unwrap(),
3116                            availability: Availability::Required,
3117                            type_: ConfigValueType::Bool,
3118                            default: None,
3119                            source_dictionary: ".".parse().unwrap(),
3120                        }),
3121                        #[cfg(fuchsia_api_level_at_least = "29")]
3122                        UseDecl::Dictionary(UseDictionaryDecl {
3123                            dependency_type: DependencyType::Strong,
3124                            source: UseSource::Parent,
3125                            source_name: "dictionary".parse().unwrap(),
3126                            source_dictionary: "other_dictionary".parse().unwrap(),
3127                            target_path: "/svc".parse().unwrap(),
3128                            availability: Availability::Optional,
3129                        }),
3130                    ]),
3131                    exposes: Box::from([
3132                        ExposeDecl::Protocol(ExposeProtocolDecl {
3133                            source: ExposeSource::Child("netstack".parse().unwrap()),
3134                            source_name: "legacy_netstack".parse().unwrap(),
3135                            source_dictionary: "in/dict".parse().unwrap(),
3136                            target_name: "legacy_mynetstack".parse().unwrap(),
3137                            target: ExposeTarget::Parent,
3138                            availability: Availability::Required,
3139                        }),
3140                        ExposeDecl::Directory(ExposeDirectoryDecl {
3141                            source: ExposeSource::Child("netstack".parse().unwrap()),
3142                            source_name: "dir".parse().unwrap(),
3143                            source_dictionary: "in/dict".parse().unwrap(),
3144                            target_name: "data".parse().unwrap(),
3145                            target: ExposeTarget::Parent,
3146                            rights: Some(fio::Operations::CONNECT),
3147                            subdir: "foo/bar".parse().unwrap(),
3148                            availability: Availability::Optional,
3149                        }),
3150                        ExposeDecl::Runner(ExposeRunnerDecl {
3151                            source: ExposeSource::Child("netstack".parse().unwrap()),
3152                            source_name: "elf".parse().unwrap(),
3153                            source_dictionary: "in/dict".parse().unwrap(),
3154                            target: ExposeTarget::Parent,
3155                            target_name: "elf".parse().unwrap(),
3156                        }),
3157                        ExposeDecl::Resolver(ExposeResolverDecl {
3158                            source: ExposeSource::Child("netstack".parse().unwrap()),
3159                            source_name: "pkg".parse().unwrap(),
3160                            source_dictionary: "in/dict".parse().unwrap(),
3161                            target: ExposeTarget::Parent,
3162                            target_name: "pkg".parse().unwrap(),
3163                        }),
3164                        ExposeDecl::Service(ExposeServiceDecl {
3165                            source: ExposeSource::Child("netstack".parse().unwrap()),
3166                            source_name: "netstack1".parse().unwrap(),
3167                            source_dictionary: "in/dict".parse().unwrap(),
3168                            target_name: "mynetstack".parse().unwrap(),
3169                            target: ExposeTarget::Parent,
3170                            availability: Availability::Required,
3171                        }),
3172                        ExposeDecl::Service(ExposeServiceDecl {
3173                            source: ExposeSource::Collection("modular".parse().unwrap()),
3174                            source_name: "netstack2".parse().unwrap(),
3175                            source_dictionary: ".".parse().unwrap(),
3176                            target_name: "mynetstack".parse().unwrap(),
3177                            target: ExposeTarget::Parent,
3178                            availability: Availability::Required,
3179                        }),
3180                        ExposeDecl::Dictionary(ExposeDictionaryDecl {
3181                            source: ExposeSource::Child("netstack".parse().unwrap()),
3182                            source_name: "bundle".parse().unwrap(),
3183                            source_dictionary: "in/dict".parse().unwrap(),
3184                            target_name: "mybundle".parse().unwrap(),
3185                            target: ExposeTarget::Parent,
3186                            availability: Availability::Required,
3187                        }),
3188                    ]),
3189                    offers: Box::from([
3190                        OfferDecl::Protocol(OfferProtocolDecl {
3191                            source: OfferSource::Parent,
3192                            source_name: "legacy_netstack".parse().unwrap(),
3193                            source_dictionary: "in/dict".parse().unwrap(),
3194                            target: offer_target_static_child("echo"),
3195                            target_name: "legacy_mynetstack".parse().unwrap(),
3196                            dependency_type: DependencyType::Weak,
3197                            availability: Availability::Required,
3198                        }),
3199                        OfferDecl::Directory(OfferDirectoryDecl {
3200                            source: OfferSource::Parent,
3201                            source_name: "dir".parse().unwrap(),
3202                            source_dictionary: "in/dict".parse().unwrap(),
3203                            target: OfferTarget::Collection("modular".parse().unwrap()),
3204                            target_name: "data".parse().unwrap(),
3205                            rights: Some(fio::Operations::CONNECT),
3206                            subdir: ".".parse().unwrap(),
3207                            dependency_type: DependencyType::Strong,
3208                            availability: Availability::Optional,
3209                        }),
3210                        OfferDecl::Storage(OfferStorageDecl {
3211                            source_name: "cache".parse().unwrap(),
3212                            source: OfferSource::Self_,
3213                            target: OfferTarget::Collection("modular".parse().unwrap()),
3214                            target_name: "cache".parse().unwrap(),
3215                            availability: Availability::Required,
3216                        }),
3217                        OfferDecl::Runner(OfferRunnerDecl {
3218                            source: OfferSource::Parent,
3219                            source_name: "elf".parse().unwrap(),
3220                            source_dictionary: "in/dict".parse().unwrap(),
3221                            target: offer_target_static_child("echo"),
3222                            target_name: "elf2".parse().unwrap(),
3223                        }),
3224                        OfferDecl::Resolver(OfferResolverDecl {
3225                            source: OfferSource::Parent,
3226                            source_name: "pkg".parse().unwrap(),
3227                            source_dictionary: "in/dict".parse().unwrap(),
3228                            target: offer_target_static_child("echo"),
3229                            target_name: "pkg".parse().unwrap(),
3230                        }),
3231                        OfferDecl::Service(OfferServiceDecl {
3232                            source: OfferSource::Parent,
3233                            source_name: "netstack1".parse().unwrap(),
3234                            source_dictionary: "in/dict".parse().unwrap(),
3235                            source_instance_filter: None,
3236                            renamed_instances: None,
3237                            target: offer_target_static_child("echo"),
3238                            target_name: "mynetstack1".parse().unwrap(),
3239                            availability: Availability::Required,
3240                            dependency_type: Default::default(),
3241                        }),
3242                        OfferDecl::Service(OfferServiceDecl {
3243                            source: OfferSource::Parent,
3244                            source_name: "netstack2".parse().unwrap(),
3245                            source_dictionary: ".".parse().unwrap(),
3246                            source_instance_filter: None,
3247                            renamed_instances: None,
3248                            target: offer_target_static_child("echo"),
3249                            target_name: "mynetstack2".parse().unwrap(),
3250                            availability: Availability::Optional,
3251                            dependency_type: Default::default(),
3252                        }),
3253                        OfferDecl::Service(OfferServiceDecl {
3254                            source: OfferSource::Parent,
3255                            source_name: "netstack3".parse().unwrap(),
3256                            source_dictionary: ".".parse().unwrap(),
3257                            source_instance_filter: Some(Box::from(["allowedinstance".parse().unwrap()])),
3258                            renamed_instances: Some(Box::from([NameMapping{source_name: "default".parse().unwrap(), target_name: "allowedinstance".parse().unwrap()}])),
3259                            target: offer_target_static_child("echo"),
3260                            target_name: "mynetstack3".parse().unwrap(),
3261                            availability: Availability::Required,
3262                            dependency_type: Default::default(),
3263                        }),
3264                        OfferDecl::Dictionary(OfferDictionaryDecl {
3265                            source: OfferSource::Parent,
3266                            source_name: "bundle".parse().unwrap(),
3267                            source_dictionary: "in/dict".parse().unwrap(),
3268                            target: offer_target_static_child("echo"),
3269                            target_name: "mybundle".parse().unwrap(),
3270                            dependency_type: DependencyType::Weak,
3271                            availability: Availability::Required,
3272                        }),
3273                    ]),
3274                    capabilities: Box::from([
3275                        CapabilityDecl::Service(ServiceDecl {
3276                            name: "netstack".parse().unwrap(),
3277                            source_path: Some("/netstack".parse().unwrap()),
3278                        }),
3279                        CapabilityDecl::Protocol(ProtocolDecl {
3280                            name: "netstack2".parse().unwrap(),
3281                            source_path: Some("/netstack2".parse().unwrap()),
3282                            delivery: DeliveryType::Immediate,
3283                        }),
3284                        CapabilityDecl::Directory(DirectoryDecl {
3285                            name: "data".parse().unwrap(),
3286                            source_path: Some("/data".parse().unwrap()),
3287                            rights: fio::Operations::CONNECT,
3288                        }),
3289                        CapabilityDecl::Storage(StorageDecl {
3290                            name: "cache".parse().unwrap(),
3291                            backing_dir: "data".parse().unwrap(),
3292                            source: StorageDirectorySource::Parent,
3293                            subdir: "cache".parse().unwrap(),
3294                            storage_id: fdecl::StorageId::StaticInstanceId,
3295                        }),
3296                        CapabilityDecl::Runner(RunnerDecl {
3297                            name: "elf".parse().unwrap(),
3298                            source_path: Some("/elf".parse().unwrap()),
3299                        }),
3300                        CapabilityDecl::Resolver(ResolverDecl {
3301                            name: "pkg".parse().unwrap(),
3302                            source_path: Some("/pkg_resolver".parse().unwrap()),
3303                        }),
3304                        CapabilityDecl::Dictionary(DictionaryDecl {
3305                            name: "dict1".parse().unwrap(),
3306                            source_path: None,
3307                        }),
3308                        CapabilityDecl::Dictionary(DictionaryDecl {
3309                            name: "dict2".parse().unwrap(),
3310                            source_path: Some("/in/other".parse().unwrap()),
3311                        }),
3312                    ]),
3313                    children: Box::from([
3314                        ChildDecl {
3315                            name: "netstack".parse().unwrap(),
3316                            url: "fuchsia-pkg://fuchsia.com/netstack#meta/netstack.cm".parse().unwrap(),
3317                            startup: fdecl::StartupMode::Lazy,
3318                            on_terminate: None,
3319                            environment: None,
3320                            config_overrides: None,
3321                        },
3322                        ChildDecl {
3323                            name: "gtest".parse().unwrap(),
3324                            url: "fuchsia-pkg://fuchsia.com/gtest#meta/gtest.cm".parse().unwrap(),
3325                            startup: fdecl::StartupMode::Lazy,
3326                            on_terminate: Some(fdecl::OnTerminate::None),
3327                            environment: None,
3328                            config_overrides: None,
3329                        },
3330                        ChildDecl {
3331                            name: "echo".parse().unwrap(),
3332                            url: "fuchsia-pkg://fuchsia.com/echo#meta/echo.cm".parse().unwrap(),
3333                            startup: fdecl::StartupMode::Eager,
3334                            on_terminate: Some(fdecl::OnTerminate::Reboot),
3335                            environment: Some("test_env".parse().unwrap()),
3336                            config_overrides: None,
3337                        },
3338                    ]),
3339                    collections: Box::from([
3340                        CollectionDecl {
3341                            name: "modular".parse().unwrap(),
3342                            durability: fdecl::Durability::Transient,
3343                            environment: None,
3344                            allowed_offers: cm_types::AllowedOffers::StaticOnly,
3345                            allow_long_names: true,
3346                            persistent_storage: None,
3347                        },
3348                        CollectionDecl {
3349                            name: "tests".parse().unwrap(),
3350                            durability: fdecl::Durability::Transient,
3351                            environment: Some("test_env".parse().unwrap()),
3352                            allowed_offers: cm_types::AllowedOffers::StaticAndDynamic,
3353                            allow_long_names: true,
3354                            persistent_storage: Some(true),
3355                        },
3356                    ]),
3357                    facets: Some(fdata::Dictionary {
3358                        entries: Some(vec![
3359                            fdata::DictionaryEntry {
3360                                key: "author".to_string(),
3361                                value: Some(Box::new(fdata::DictionaryValue::Str("Fuchsia".to_string()))),
3362                            },
3363                        ]),
3364                        ..Default::default()
3365                    }),
3366                    environments: Box::from([
3367                        EnvironmentDecl {
3368                            name: "test_env".parse().unwrap(),
3369                            extends: fdecl::EnvironmentExtends::Realm,
3370                            runners: Box::from([
3371                                RunnerRegistration {
3372                                    source_name: "runner".parse().unwrap(),
3373                                    source: RegistrationSource::Child("gtest".to_string()),
3374                                    target_name: "gtest-runner".parse().unwrap(),
3375                                }
3376                            ]),
3377                            resolvers: Box::from([
3378                                ResolverRegistration {
3379                                    resolver: "pkg_resolver".parse().unwrap(),
3380                                    source: RegistrationSource::Parent,
3381                                    scheme: "fuchsia-pkg".to_string(),
3382                                }
3383                            ]),
3384                            debug_capabilities: Box::from([
3385                                DebugRegistration::Protocol(DebugProtocolRegistration {
3386                                    source_name: "some_protocol".parse().unwrap(),
3387                                    source: RegistrationSource::Child("gtest".to_string()),
3388                                    target_name: "some_protocol".parse().unwrap(),
3389                                })
3390                            ]),
3391                            stop_timeout_ms: Some(4567),
3392                        }
3393                    ]),
3394                    config: Some(ConfigDecl {
3395                        fields: Box::from([
3396                            ConfigField {
3397                                key: "enable_logging".to_string(),
3398                                type_: ConfigValueType::Bool,
3399                                mutability: ConfigMutability::default(),
3400                            }
3401                        ]),
3402                        checksum: ConfigChecksum::Sha256([
3403                            0x64, 0x49, 0x9E, 0x75, 0xF3, 0x37, 0x69, 0x88, 0x74, 0x3B, 0x38, 0x16,
3404                            0xCD, 0x14, 0x70, 0x9F, 0x3D, 0x4A, 0xD3, 0xE2, 0x24, 0x9A, 0x1A, 0x34,
3405                            0x80, 0xB4, 0x9E, 0xB9, 0x63, 0x57, 0xD6, 0xED,
3406                        ]),
3407                        value_source: ConfigValueSource::PackagePath("fake.cvf".to_string())
3408                    }),
3409                    debug_info: None,
3410                }
3411            },
3412        },
3413    }
3414
3415    test_fidl_into_and_from! {
3416        fidl_into_and_from_use_source => {
3417            input = vec![
3418                fdecl::Ref::Parent(fdecl::ParentRef{}),
3419                fdecl::Ref::Framework(fdecl::FrameworkRef{}),
3420                fdecl::Ref::Debug(fdecl::DebugRef{}),
3421                fdecl::Ref::Capability(fdecl::CapabilityRef {name: "capability".to_string()}),
3422                fdecl::Ref::Child(fdecl::ChildRef {
3423                    name: "foo".into(),
3424                    collection: None,
3425                }),
3426                fdecl::Ref::Environment(fdecl::EnvironmentRef{}),
3427            ],
3428            input_type = fdecl::Ref,
3429            result = vec![
3430                UseSource::Parent,
3431                UseSource::Framework,
3432                UseSource::Debug,
3433                UseSource::Capability("capability".parse().unwrap()),
3434                UseSource::Child("foo".parse().unwrap()),
3435                UseSource::Environment,
3436            ],
3437            result_type = UseSource,
3438        },
3439        fidl_into_and_from_expose_source => {
3440            input = vec![
3441                fdecl::Ref::Self_(fdecl::SelfRef {}),
3442                fdecl::Ref::Child(fdecl::ChildRef {
3443                    name: "foo".into(),
3444                    collection: None,
3445                }),
3446                fdecl::Ref::Framework(fdecl::FrameworkRef {}),
3447                fdecl::Ref::Collection(fdecl::CollectionRef { name: "foo".to_string() }),
3448            ],
3449            input_type = fdecl::Ref,
3450            result = vec![
3451                ExposeSource::Self_,
3452                ExposeSource::Child("foo".parse().unwrap()),
3453                ExposeSource::Framework,
3454                ExposeSource::Collection("foo".parse().unwrap()),
3455            ],
3456            result_type = ExposeSource,
3457        },
3458        fidl_into_and_from_offer_source => {
3459            input = vec![
3460                fdecl::Ref::Self_(fdecl::SelfRef {}),
3461                fdecl::Ref::Child(fdecl::ChildRef {
3462                    name: "foo".into(),
3463                    collection: None,
3464                }),
3465                fdecl::Ref::Framework(fdecl::FrameworkRef {}),
3466                fdecl::Ref::Capability(fdecl::CapabilityRef { name: "foo".to_string() }),
3467                fdecl::Ref::Parent(fdecl::ParentRef {}),
3468                fdecl::Ref::Collection(fdecl::CollectionRef { name: "foo".to_string() }),
3469                fdecl::Ref::VoidType(fdecl::VoidRef {}),
3470            ],
3471            input_type = fdecl::Ref,
3472            result = vec![
3473                OfferSource::Self_,
3474                offer_source_static_child("foo"),
3475                OfferSource::Framework,
3476                OfferSource::Capability("foo".parse().unwrap()),
3477                OfferSource::Parent,
3478                OfferSource::Collection("foo".parse().unwrap()),
3479                OfferSource::Void,
3480            ],
3481            result_type = OfferSource,
3482        },
3483        fidl_into_and_from_dictionary_source => {
3484            input = vec![
3485                fdecl::Ref::Self_(fdecl::SelfRef {}),
3486                fdecl::Ref::Child(fdecl::ChildRef {
3487                    name: "foo".into(),
3488                    collection: None,
3489                }),
3490                fdecl::Ref::Parent(fdecl::ParentRef {}),
3491            ],
3492            input_type = fdecl::Ref,
3493            result = vec![
3494                DictionarySource::Self_,
3495                DictionarySource::Child(ChildRef {
3496                    name: "foo".parse().unwrap(),
3497                    collection: None,
3498                }),
3499                DictionarySource::Parent,
3500            ],
3501            result_type = DictionarySource,
3502        },
3503
3504        fidl_into_and_from_capability_without_path => {
3505            input = vec![
3506                fdecl::Protocol {
3507                    name: Some("foo_protocol".to_string()),
3508                    source_path: None,
3509                    delivery: Some(fdecl::DeliveryType::Immediate),
3510                    ..Default::default()
3511                },
3512            ],
3513            input_type = fdecl::Protocol,
3514            result = vec![
3515                ProtocolDecl {
3516                    name: "foo_protocol".parse().unwrap(),
3517                    source_path: None,
3518                    delivery: DeliveryType::Immediate,
3519                }
3520            ],
3521            result_type = ProtocolDecl,
3522        },
3523        fidl_into_and_from_storage_capability => {
3524            input = vec![
3525                fdecl::Storage {
3526                    name: Some("minfs".to_string()),
3527                    backing_dir: Some("minfs".into()),
3528                    source: Some(fdecl::Ref::Child(fdecl::ChildRef {
3529                        name: "foo".into(),
3530                        collection: None,
3531                    })),
3532                    subdir: None,
3533                    storage_id: Some(fdecl::StorageId::StaticInstanceIdOrMoniker),
3534                    ..Default::default()
3535                },
3536            ],
3537            input_type = fdecl::Storage,
3538            result = vec![
3539                StorageDecl {
3540                    name: "minfs".parse().unwrap(),
3541                    backing_dir: "minfs".parse().unwrap(),
3542                    source: StorageDirectorySource::Child("foo".to_string()),
3543                    subdir: ".".parse().unwrap(),
3544                    storage_id: fdecl::StorageId::StaticInstanceIdOrMoniker,
3545                },
3546            ],
3547            result_type = StorageDecl,
3548        },
3549        fidl_into_and_from_storage_capability_restricted => {
3550            input = vec![
3551                fdecl::Storage {
3552                    name: Some("minfs".to_string()),
3553                    backing_dir: Some("minfs".into()),
3554                    source: Some(fdecl::Ref::Child(fdecl::ChildRef {
3555                        name: "foo".into(),
3556                        collection: None,
3557                    })),
3558                    subdir: None,
3559                    storage_id: Some(fdecl::StorageId::StaticInstanceId),
3560                    ..Default::default()
3561                },
3562            ],
3563            input_type = fdecl::Storage,
3564            result = vec![
3565                StorageDecl {
3566                    name: "minfs".parse().unwrap(),
3567                    backing_dir: "minfs".parse().unwrap(),
3568                    source: StorageDirectorySource::Child("foo".to_string()),
3569                    subdir: ".".parse().unwrap(),
3570                    storage_id: fdecl::StorageId::StaticInstanceId,
3571                },
3572            ],
3573            result_type = StorageDecl,
3574        },
3575    }
3576
3577    test_fidl_into! {
3578        all_with_omitted_defaults => {
3579            input = fdecl::Component {
3580                program: Some(fdecl::Program {
3581                    runner: Some("elf".to_string()),
3582                    info: Some(fdata::Dictionary {
3583                        entries: Some(vec![]),
3584                        ..Default::default()
3585                    }),
3586                    ..Default::default()
3587                }),
3588                uses: Some(vec![]),
3589                exposes: Some(vec![]),
3590                offers: Some(vec![]),
3591                capabilities: Some(vec![]),
3592                children: Some(vec![]),
3593                collections: Some(vec![
3594                     fdecl::Collection {
3595                         name: Some("modular".to_string()),
3596                         durability: Some(fdecl::Durability::Transient),
3597                         environment: None,
3598                         allowed_offers: None,
3599                         allow_long_names: None,
3600                         persistent_storage: None,
3601                         ..Default::default()
3602                     },
3603                     fdecl::Collection {
3604                         name: Some("tests".to_string()),
3605                         durability: Some(fdecl::Durability::Transient),
3606                         environment: Some("test_env".to_string()),
3607                         allowed_offers: Some(fdecl::AllowedOffers::StaticOnly),
3608                         allow_long_names: None,
3609                         persistent_storage: Some(false),
3610                         ..Default::default()
3611                     },
3612                     fdecl::Collection {
3613                         name: Some("dyn_offers".to_string()),
3614                         durability: Some(fdecl::Durability::Transient),
3615                         allowed_offers: Some(fdecl::AllowedOffers::StaticAndDynamic),
3616                         allow_long_names: None,
3617                         persistent_storage: Some(true),
3618                         ..Default::default()
3619                     },
3620                     fdecl::Collection {
3621                         name: Some("long_child_names".to_string()),
3622                         durability: Some(fdecl::Durability::Transient),
3623                         allowed_offers: None,
3624                         allow_long_names: Some(true),
3625                         persistent_storage: None,
3626                         ..Default::default()
3627                     },
3628                ]),
3629                facets: Some(fdata::Dictionary{
3630                    entries: Some(vec![]),
3631                    ..Default::default()
3632                }),
3633                environments: Some(vec![]),
3634                ..Default::default()
3635            },
3636            result = {
3637                ComponentDecl {
3638                    program: Some(ProgramDecl {
3639                        runner: Some("elf".parse().unwrap()),
3640                        info: fdata::Dictionary {
3641                            entries: Some(vec![]),
3642                            ..Default::default()
3643                        },
3644                    }),
3645                    uses: Box::from([]),
3646                    exposes: Box::from([]),
3647                    offers: Box::from([]),
3648                    capabilities: Box::from([]),
3649                    children: Box::from([]),
3650                    collections: Box::from([
3651                        CollectionDecl {
3652                            name: "modular".parse().unwrap(),
3653                            durability: fdecl::Durability::Transient,
3654                            environment: None,
3655                            allowed_offers: cm_types::AllowedOffers::StaticOnly,
3656                            allow_long_names: false,
3657                            persistent_storage: None,
3658                        },
3659                        CollectionDecl {
3660                            name: "tests".parse().unwrap(),
3661                            durability: fdecl::Durability::Transient,
3662                            environment: Some("test_env".parse().unwrap()),
3663                            allowed_offers: cm_types::AllowedOffers::StaticOnly,
3664                            allow_long_names: false,
3665                            persistent_storage: Some(false),
3666                        },
3667                        CollectionDecl {
3668                            name: "dyn_offers".parse().unwrap(),
3669                            durability: fdecl::Durability::Transient,
3670                            environment: None,
3671                            allowed_offers: cm_types::AllowedOffers::StaticAndDynamic,
3672                            allow_long_names: false,
3673                            persistent_storage: Some(true),
3674                        },
3675                        CollectionDecl {
3676                            name: "long_child_names".parse().unwrap(),
3677                            durability: fdecl::Durability::Transient,
3678                            environment: None,
3679                            allowed_offers: cm_types::AllowedOffers::StaticOnly,
3680                            allow_long_names: true,
3681                            persistent_storage: None,
3682                        },
3683                    ]),
3684                    facets: Some(fdata::Dictionary{
3685                        entries: Some(vec![]),
3686                        ..Default::default()
3687                    }),
3688                    environments: Box::from([]),
3689                    config: None,
3690                    debug_info: None,
3691                }
3692            },
3693        },
3694    }
3695
3696    #[test]
3697    fn default_expose_availability() {
3698        let source = fdecl::Ref::Self_(fdecl::SelfRef {});
3699        let source_name = "source";
3700        let target = fdecl::Ref::Parent(fdecl::ParentRef {});
3701        let target_name = "target";
3702        assert_eq!(
3703            *fdecl::ExposeService {
3704                source: Some(source.clone()),
3705                source_name: Some(source_name.into()),
3706                target: Some(target.clone()),
3707                target_name: Some(target_name.into()),
3708                availability: None,
3709                ..Default::default()
3710            }
3711            .fidl_into_native()
3712            .availability(),
3713            Availability::Required
3714        );
3715        assert_eq!(
3716            *fdecl::ExposeProtocol {
3717                source: Some(source.clone()),
3718                source_name: Some(source_name.into()),
3719                target: Some(target.clone()),
3720                target_name: Some(target_name.into()),
3721                ..Default::default()
3722            }
3723            .fidl_into_native()
3724            .availability(),
3725            Availability::Required
3726        );
3727        assert_eq!(
3728            *fdecl::ExposeDirectory {
3729                source: Some(source.clone()),
3730                source_name: Some(source_name.into()),
3731                target: Some(target.clone()),
3732                target_name: Some(target_name.into()),
3733                ..Default::default()
3734            }
3735            .fidl_into_native()
3736            .availability(),
3737            Availability::Required
3738        );
3739        assert_eq!(
3740            *fdecl::ExposeRunner {
3741                source: Some(source.clone()),
3742                source_name: Some(source_name.into()),
3743                target: Some(target.clone()),
3744                target_name: Some(target_name.into()),
3745                ..Default::default()
3746            }
3747            .fidl_into_native()
3748            .availability(),
3749            Availability::Required
3750        );
3751        assert_eq!(
3752            *fdecl::ExposeResolver {
3753                source: Some(source.clone()),
3754                source_name: Some(source_name.into()),
3755                target: Some(target.clone()),
3756                target_name: Some(target_name.into()),
3757                ..Default::default()
3758            }
3759            .fidl_into_native()
3760            .availability(),
3761            Availability::Required
3762        );
3763        assert_eq!(
3764            *fdecl::ExposeDictionary {
3765                source: Some(source.clone()),
3766                source_name: Some(source_name.into()),
3767                target: Some(target.clone()),
3768                target_name: Some(target_name.into()),
3769                ..Default::default()
3770            }
3771            .fidl_into_native()
3772            .availability(),
3773            Availability::Required
3774        );
3775    }
3776
3777    #[test]
3778    fn default_delivery_type() {
3779        assert_eq!(
3780            fdecl::Protocol {
3781                name: Some("foo".to_string()),
3782                source_path: Some("/foo".to_string()),
3783                delivery: None,
3784                ..Default::default()
3785            }
3786            .fidl_into_native()
3787            .delivery,
3788            DeliveryType::Immediate
3789        )
3790    }
3791
3792    #[test]
3793    fn on_readable_delivery_type() {
3794        assert_eq!(
3795            fdecl::Protocol {
3796                name: Some("foo".to_string()),
3797                source_path: Some("/foo".to_string()),
3798                delivery: Some(fdecl::DeliveryType::OnReadable),
3799                ..Default::default()
3800            }
3801            .fidl_into_native()
3802            .delivery,
3803            DeliveryType::OnReadable
3804        )
3805    }
3806
3807    #[test]
3808    fn config_value_matches_type() {
3809        let bool_true = ConfigValue::Single(ConfigSingleValue::Bool(true));
3810        let bool_false = ConfigValue::Single(ConfigSingleValue::Bool(false));
3811        let uint8_zero = ConfigValue::Single(ConfigSingleValue::Uint8(0));
3812        let vec_bool_true = ConfigValue::Vector(ConfigVectorValue::BoolVector(Box::from([true])));
3813        let vec_bool_false = ConfigValue::Vector(ConfigVectorValue::BoolVector(Box::from([false])));
3814
3815        assert!(bool_true.matches_type(&bool_false));
3816        assert!(vec_bool_true.matches_type(&vec_bool_false));
3817
3818        assert!(!bool_true.matches_type(&uint8_zero));
3819        assert!(!bool_true.matches_type(&vec_bool_true));
3820    }
3821}