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