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 = "NEXT")]
313pub use cm_types::HandleType;
314
315#[cfg(fuchsia_api_level_at_least = "NEXT")]
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 = "NEXT")]
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 = "NEXT")]
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 = "NEXT")]
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 = "NEXT")]
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 = "NEXT")]
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 = "NEXT")]
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#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
1941#[fidl_decl(fidl_table = "fdecl::DebugProtocolRegistration")]
1942pub struct DebugProtocolRegistration {
1943    pub source_name: Name,
1944    pub source: RegistrationSource,
1945    pub target_name: Name,
1946}
1947
1948#[derive(FidlDecl, Debug, Clone, PartialEq)]
1949#[fidl_decl(fidl_table = "fdecl::Program")]
1950pub struct ProgramDecl {
1951    pub runner: Option<Name>,
1952    pub info: fdata::Dictionary,
1953}
1954
1955impl Default for ProgramDecl {
1956    fn default() -> Self {
1957        Self { runner: None, info: fdata::Dictionary::default() }
1958    }
1959}
1960
1961fidl_translations_identical!([u8; 32]);
1962fidl_translations_identical!(u8);
1963fidl_translations_identical!(u16);
1964fidl_translations_identical!(u32);
1965fidl_translations_identical!(u64);
1966fidl_translations_identical!(i8);
1967fidl_translations_identical!(i16);
1968fidl_translations_identical!(i32);
1969fidl_translations_identical!(i64);
1970fidl_translations_identical!(bool);
1971fidl_translations_identical!(String);
1972fidl_translations_identical!(Vec<Name>);
1973fidl_translations_identical!(fdecl::StartupMode);
1974fidl_translations_identical!(fdecl::OnTerminate);
1975fidl_translations_identical!(fdecl::Durability);
1976fidl_translations_identical!(fdata::Dictionary);
1977fidl_translations_identical!(fio::Operations);
1978fidl_translations_identical!(fdecl::EnvironmentExtends);
1979fidl_translations_identical!(fdecl::StorageId);
1980fidl_translations_identical!(Vec<fprocess::HandleInfo>);
1981fidl_translations_identical!(fsys::ServiceInstance);
1982fidl_translations_from_into!(cm_types::AllowedOffers, fdecl::AllowedOffers);
1983
1984#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
1985#[derive(Debug, Clone, PartialEq, Eq)]
1986pub enum DependencyType {
1987    Strong,
1988    Weak,
1989}
1990
1991impl Default for DependencyType {
1992    fn default() -> Self {
1993        Self::Strong
1994    }
1995}
1996
1997fidl_translations_symmetrical_enums!(fdecl::DependencyType, DependencyType, Strong, Weak);
1998
1999impl UseDecl {
2000    pub fn path(&self) -> Option<&Path> {
2001        match self {
2002            UseDecl::Service(d) => Some(&d.target_path),
2003            UseDecl::Protocol(d) => d.target_path.as_ref(),
2004            UseDecl::Directory(d) => Some(&d.target_path),
2005            UseDecl::Storage(d) => Some(&d.target_path),
2006            UseDecl::EventStream(d) => Some(&d.target_path),
2007            #[cfg(fuchsia_api_level_at_least = "HEAD")]
2008            UseDecl::Runner(_) => None,
2009            UseDecl::Config(_) => None,
2010            #[cfg(fuchsia_api_level_at_least = "NEXT")]
2011            UseDecl::Dictionary(d) => Some(&d.target_path),
2012        }
2013    }
2014
2015    pub fn name(&self) -> Option<&Name> {
2016        match self {
2017            UseDecl::Storage(storage_decl) => Some(&storage_decl.source_name),
2018            UseDecl::EventStream(_) => None,
2019            UseDecl::Service(_) | UseDecl::Protocol(_) | UseDecl::Directory(_) => None,
2020            #[cfg(fuchsia_api_level_at_least = "HEAD")]
2021            UseDecl::Runner(_) => None,
2022            UseDecl::Config(_) => None,
2023            #[cfg(fuchsia_api_level_at_least = "NEXT")]
2024            UseDecl::Dictionary(_) => None,
2025        }
2026    }
2027}
2028
2029impl SourceName for UseDecl {
2030    fn source_name(&self) -> &Name {
2031        match self {
2032            UseDecl::Storage(storage_decl) => &storage_decl.source_name,
2033            UseDecl::Service(service_decl) => &service_decl.source_name,
2034            UseDecl::Protocol(protocol_decl) => &protocol_decl.source_name,
2035            UseDecl::Directory(directory_decl) => &directory_decl.source_name,
2036            UseDecl::EventStream(event_stream_decl) => &event_stream_decl.source_name,
2037            #[cfg(fuchsia_api_level_at_least = "HEAD")]
2038            UseDecl::Runner(runner_decl) => &runner_decl.source_name,
2039            UseDecl::Config(u) => &u.source_name,
2040            #[cfg(fuchsia_api_level_at_least = "NEXT")]
2041            UseDecl::Dictionary(dictionary_decl) => &dictionary_decl.source_name,
2042        }
2043    }
2044}
2045
2046impl SourcePath for UseDecl {
2047    fn source_path(&self) -> BorrowedSeparatedPath<'_> {
2048        match self {
2049            UseDecl::Service(u) => u.source_path(),
2050            UseDecl::Protocol(u) => u.source_path(),
2051            UseDecl::Directory(u) => u.source_path(),
2052            UseDecl::Storage(u) => u.source_path(),
2053            UseDecl::EventStream(u) => u.source_path(),
2054            #[cfg(fuchsia_api_level_at_least = "HEAD")]
2055            UseDecl::Runner(u) => u.source_path(),
2056            UseDecl::Config(u) => u.source_path(),
2057            #[cfg(fuchsia_api_level_at_least = "NEXT")]
2058            UseDecl::Dictionary(u) => u.source_path(),
2059        }
2060    }
2061}
2062
2063/// The trait for all declarations that have a source name.
2064pub trait SourceName {
2065    fn source_name(&self) -> &Name;
2066}
2067
2068/// The common properties of a [Use](fdecl::Use) declaration.
2069pub trait UseDeclCommon: SourceName + SourcePath + Send + Sync {
2070    fn source(&self) -> &UseSource;
2071    fn availability(&self) -> &Availability;
2072}
2073
2074/// The common properties of a Registration-with-environment declaration.
2075pub trait RegistrationDeclCommon: SourceName + Send + Sync {
2076    /// The name of the registration type, for error messages.
2077    const TYPE: &'static str;
2078    fn source(&self) -> &RegistrationSource;
2079}
2080
2081/// The common properties of an [Offer](fdecl::Offer) declaration.
2082pub trait OfferDeclCommon: SourceName + SourcePath + fmt::Debug + Send + Sync {
2083    fn target_name(&self) -> &Name;
2084    fn target(&self) -> &OfferTarget;
2085    fn source(&self) -> &OfferSource;
2086    fn availability(&self) -> &Availability;
2087}
2088
2089/// The common properties of an [Expose](fdecl::Expose) declaration.
2090pub trait ExposeDeclCommon: SourceName + SourcePath + fmt::Debug + Send + Sync {
2091    fn target_name(&self) -> &Name;
2092    fn target(&self) -> &ExposeTarget;
2093    fn source(&self) -> &ExposeSource;
2094    fn availability(&self) -> &Availability;
2095}
2096
2097/// A named capability type.
2098///
2099/// `CapabilityTypeName` provides a user friendly type encoding for a capability.
2100#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2101#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)]
2102pub enum CapabilityTypeName {
2103    Directory,
2104    EventStream,
2105    Protocol,
2106    Resolver,
2107    Runner,
2108    Service,
2109    Storage,
2110    Dictionary,
2111    Config,
2112}
2113
2114impl std::str::FromStr for CapabilityTypeName {
2115    type Err = Error;
2116
2117    fn from_str(s: &str) -> Result<Self, Self::Err> {
2118        match s {
2119            "directory" => Ok(CapabilityTypeName::Directory),
2120            "event_stream" => Ok(CapabilityTypeName::EventStream),
2121            "protocol" => Ok(CapabilityTypeName::Protocol),
2122            "resolver" => Ok(CapabilityTypeName::Resolver),
2123            "runner" => Ok(CapabilityTypeName::Runner),
2124            "service" => Ok(CapabilityTypeName::Service),
2125            "storage" => Ok(CapabilityTypeName::Storage),
2126            "dictionary" => Ok(CapabilityTypeName::Dictionary),
2127            "configuration" => Ok(CapabilityTypeName::Config),
2128            _ => Err(Error::ParseCapabilityTypeName { raw: s.to_string() }),
2129        }
2130    }
2131}
2132
2133impl FidlIntoNative<CapabilityTypeName> for String {
2134    fn fidl_into_native(self) -> CapabilityTypeName {
2135        self.parse().unwrap()
2136    }
2137}
2138
2139impl NativeIntoFidl<String> for CapabilityTypeName {
2140    fn native_into_fidl(self) -> String {
2141        self.to_string()
2142    }
2143}
2144
2145impl fmt::Display for CapabilityTypeName {
2146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2147        let display_name = match &self {
2148            CapabilityTypeName::Directory => "directory",
2149            CapabilityTypeName::EventStream => "event_stream",
2150            CapabilityTypeName::Protocol => "protocol",
2151            CapabilityTypeName::Resolver => "resolver",
2152            CapabilityTypeName::Runner => "runner",
2153            CapabilityTypeName::Service => "service",
2154            CapabilityTypeName::Storage => "storage",
2155            CapabilityTypeName::Dictionary => "dictionary",
2156            CapabilityTypeName::Config => "configuration",
2157        };
2158        write!(f, "{}", display_name)
2159    }
2160}
2161
2162impl From<&UseDecl> for CapabilityTypeName {
2163    fn from(use_decl: &UseDecl) -> Self {
2164        match use_decl {
2165            UseDecl::Service(_) => Self::Service,
2166            UseDecl::Protocol(_) => Self::Protocol,
2167            UseDecl::Directory(_) => Self::Directory,
2168            UseDecl::Storage(_) => Self::Storage,
2169            UseDecl::EventStream(_) => Self::EventStream,
2170            #[cfg(fuchsia_api_level_at_least = "HEAD")]
2171            UseDecl::Runner(_) => Self::Runner,
2172            UseDecl::Config(_) => Self::Config,
2173            #[cfg(fuchsia_api_level_at_least = "NEXT")]
2174            UseDecl::Dictionary(_) => Self::Dictionary,
2175        }
2176    }
2177}
2178
2179impl From<&OfferDecl> for CapabilityTypeName {
2180    fn from(offer_decl: &OfferDecl) -> Self {
2181        match offer_decl {
2182            OfferDecl::Service(_) => Self::Service,
2183            OfferDecl::Protocol(_) => Self::Protocol,
2184            OfferDecl::Directory(_) => Self::Directory,
2185            OfferDecl::Storage(_) => Self::Storage,
2186            OfferDecl::Runner(_) => Self::Runner,
2187            OfferDecl::Resolver(_) => Self::Resolver,
2188            OfferDecl::EventStream(_) => Self::EventStream,
2189            OfferDecl::Dictionary(_) => Self::Dictionary,
2190            OfferDecl::Config(_) => Self::Config,
2191        }
2192    }
2193}
2194
2195impl From<&ExposeDecl> for CapabilityTypeName {
2196    fn from(expose_decl: &ExposeDecl) -> Self {
2197        match expose_decl {
2198            ExposeDecl::Service(_) => Self::Service,
2199            ExposeDecl::Protocol(_) => Self::Protocol,
2200            ExposeDecl::Directory(_) => Self::Directory,
2201            ExposeDecl::Runner(_) => Self::Runner,
2202            ExposeDecl::Resolver(_) => Self::Resolver,
2203            ExposeDecl::Dictionary(_) => Self::Dictionary,
2204            ExposeDecl::Config(_) => Self::Config,
2205        }
2206    }
2207}
2208
2209impl From<&CapabilityDecl> for CapabilityTypeName {
2210    fn from(capability: &CapabilityDecl) -> Self {
2211        match capability {
2212            CapabilityDecl::Service(_) => Self::Service,
2213            CapabilityDecl::Protocol(_) => Self::Protocol,
2214            CapabilityDecl::Directory(_) => Self::Directory,
2215            CapabilityDecl::Storage(_) => Self::Storage,
2216            CapabilityDecl::Runner(_) => Self::Runner,
2217            CapabilityDecl::Resolver(_) => Self::Resolver,
2218            CapabilityDecl::EventStream(_) => Self::EventStream,
2219            CapabilityDecl::Dictionary(_) => Self::Dictionary,
2220            CapabilityDecl::Config(_) => Self::Config,
2221        }
2222    }
2223}
2224
2225impl From<CapabilityTypeName> for fio::DirentType {
2226    fn from(value: CapabilityTypeName) -> Self {
2227        match value {
2228            CapabilityTypeName::Directory => fio::DirentType::Directory,
2229            CapabilityTypeName::EventStream => fio::DirentType::Service,
2230            CapabilityTypeName::Protocol => fio::DirentType::Service,
2231            CapabilityTypeName::Service => fio::DirentType::Directory,
2232            CapabilityTypeName::Storage => fio::DirentType::Directory,
2233            CapabilityTypeName::Dictionary => fio::DirentType::Directory,
2234            CapabilityTypeName::Resolver => fio::DirentType::Service,
2235            CapabilityTypeName::Runner => fio::DirentType::Service,
2236            // Config capabilities don't appear in exposed or used dir
2237            CapabilityTypeName::Config => fio::DirentType::Unknown,
2238        }
2239    }
2240}
2241
2242// TODO: Runners and third parties can use this to parse `facets`.
2243impl FidlIntoNative<HashMap<String, DictionaryValue>> for fdata::Dictionary {
2244    fn fidl_into_native(self) -> HashMap<String, DictionaryValue> {
2245        from_fidl_dict(self)
2246    }
2247}
2248
2249impl NativeIntoFidl<fdata::Dictionary> for HashMap<String, DictionaryValue> {
2250    fn native_into_fidl(self) -> fdata::Dictionary {
2251        to_fidl_dict(self)
2252    }
2253}
2254
2255impl FidlIntoNative<BTreeMap<String, DictionaryValue>> for fdata::Dictionary {
2256    fn fidl_into_native(self) -> BTreeMap<String, DictionaryValue> {
2257        from_fidl_dict_btree(self)
2258    }
2259}
2260
2261impl NativeIntoFidl<fdata::Dictionary> for BTreeMap<String, DictionaryValue> {
2262    fn native_into_fidl(self) -> fdata::Dictionary {
2263        to_fidl_dict_btree(self)
2264    }
2265}
2266
2267#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2268pub enum DictionaryValue {
2269    Str(String),
2270    StrVec(Vec<String>),
2271    Null,
2272}
2273
2274impl FidlIntoNative<DictionaryValue> for Option<Box<fdata::DictionaryValue>> {
2275    fn fidl_into_native(self) -> DictionaryValue {
2276        match self {
2277            Some(v) => match *v {
2278                fdata::DictionaryValue::Str(s) => DictionaryValue::Str(s),
2279                fdata::DictionaryValue::StrVec(ss) => DictionaryValue::StrVec(ss),
2280                _ => DictionaryValue::Null,
2281            },
2282            None => DictionaryValue::Null,
2283        }
2284    }
2285}
2286
2287impl NativeIntoFidl<Option<Box<fdata::DictionaryValue>>> for DictionaryValue {
2288    fn native_into_fidl(self) -> Option<Box<fdata::DictionaryValue>> {
2289        match self {
2290            DictionaryValue::Str(s) => Some(Box::new(fdata::DictionaryValue::Str(s))),
2291            DictionaryValue::StrVec(ss) => Some(Box::new(fdata::DictionaryValue::StrVec(ss))),
2292            DictionaryValue::Null => None,
2293        }
2294    }
2295}
2296
2297fn from_fidl_dict(dict: fdata::Dictionary) -> HashMap<String, DictionaryValue> {
2298    match dict.entries {
2299        Some(entries) => entries.into_iter().map(|e| (e.key, e.value.fidl_into_native())).collect(),
2300        _ => HashMap::new(),
2301    }
2302}
2303
2304fn to_fidl_dict(dict: HashMap<String, DictionaryValue>) -> fdata::Dictionary {
2305    fdata::Dictionary {
2306        entries: Some(
2307            dict.into_iter()
2308                .map(|(key, value)| fdata::DictionaryEntry { key, value: value.native_into_fidl() })
2309                .collect(),
2310        ),
2311        ..Default::default()
2312    }
2313}
2314
2315fn from_fidl_dict_btree(dict: fdata::Dictionary) -> BTreeMap<String, DictionaryValue> {
2316    match dict.entries {
2317        Some(entries) => entries.into_iter().map(|e| (e.key, e.value.fidl_into_native())).collect(),
2318        _ => BTreeMap::new(),
2319    }
2320}
2321
2322fn to_fidl_dict_btree(dict: BTreeMap<String, DictionaryValue>) -> fdata::Dictionary {
2323    fdata::Dictionary {
2324        entries: Some(
2325            dict.into_iter()
2326                .map(|(key, value)| fdata::DictionaryEntry { key, value: value.native_into_fidl() })
2327                .collect(),
2328        ),
2329        ..Default::default()
2330    }
2331}
2332
2333#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2334#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2335pub enum UseSource {
2336    Parent,
2337    Framework,
2338    Debug,
2339    Self_,
2340    Capability(Name),
2341    Child(Name),
2342    Collection(Name),
2343    #[cfg(fuchsia_api_level_at_least = "HEAD")]
2344    Environment,
2345}
2346
2347impl std::fmt::Display for UseSource {
2348    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2349        match self {
2350            Self::Framework => write!(f, "framework"),
2351            Self::Parent => write!(f, "parent"),
2352            Self::Debug => write!(f, "debug environment"),
2353            Self::Self_ => write!(f, "self"),
2354            Self::Capability(c) => write!(f, "capability `{}`", c),
2355            Self::Child(c) => write!(f, "child `#{}`", c),
2356            Self::Collection(c) => write!(f, "collection `#{}`", c),
2357            #[cfg(fuchsia_api_level_at_least = "HEAD")]
2358            Self::Environment => write!(f, "environment"),
2359        }
2360    }
2361}
2362
2363impl FidlIntoNative<UseSource> for fdecl::Ref {
2364    fn fidl_into_native(self) -> UseSource {
2365        match self {
2366            fdecl::Ref::Parent(_) => UseSource::Parent,
2367            fdecl::Ref::Framework(_) => UseSource::Framework,
2368            fdecl::Ref::Debug(_) => UseSource::Debug,
2369            fdecl::Ref::Self_(_) => UseSource::Self_,
2370            // cm_fidl_validator should have already validated this
2371            fdecl::Ref::Capability(c) => UseSource::Capability(c.name.parse().unwrap()),
2372            fdecl::Ref::Child(c) => UseSource::Child(c.name.parse().unwrap()),
2373            fdecl::Ref::Collection(c) => UseSource::Collection(c.name.parse().unwrap()),
2374            #[cfg(fuchsia_api_level_at_least = "HEAD")]
2375            fdecl::Ref::Environment(_) => UseSource::Environment,
2376            _ => panic!("invalid UseSource variant"),
2377        }
2378    }
2379}
2380
2381impl NativeIntoFidl<fdecl::Ref> for UseSource {
2382    fn native_into_fidl(self) -> fdecl::Ref {
2383        match self {
2384            UseSource::Parent => fdecl::Ref::Parent(fdecl::ParentRef {}),
2385            UseSource::Framework => fdecl::Ref::Framework(fdecl::FrameworkRef {}),
2386            UseSource::Debug => fdecl::Ref::Debug(fdecl::DebugRef {}),
2387            UseSource::Self_ => fdecl::Ref::Self_(fdecl::SelfRef {}),
2388            UseSource::Capability(name) => {
2389                fdecl::Ref::Capability(fdecl::CapabilityRef { name: name.to_string() })
2390            }
2391            UseSource::Child(name) => {
2392                fdecl::Ref::Child(fdecl::ChildRef { name: name.to_string(), collection: None })
2393            }
2394            UseSource::Collection(name) => {
2395                fdecl::Ref::Collection(fdecl::CollectionRef { name: name.to_string() })
2396            }
2397            #[cfg(fuchsia_api_level_at_least = "HEAD")]
2398            UseSource::Environment => fdecl::Ref::Environment(fdecl::EnvironmentRef {}),
2399        }
2400    }
2401}
2402
2403#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2404#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2405pub enum EventScope {
2406    Child(ChildRef),
2407    Collection(Name),
2408}
2409
2410impl FidlIntoNative<EventScope> for fdecl::Ref {
2411    fn fidl_into_native(self) -> EventScope {
2412        match self {
2413            fdecl::Ref::Child(c) => {
2414                if let Some(_) = c.collection {
2415                    panic!("Dynamic children scopes are not supported for EventStreams");
2416                } else {
2417                    EventScope::Child(ChildRef { name: c.name.parse().unwrap(), collection: None })
2418                }
2419            }
2420            fdecl::Ref::Collection(collection) => {
2421                // cm_fidl_validator should have already validated this
2422                EventScope::Collection(collection.name.parse().unwrap())
2423            }
2424            _ => panic!("invalid EventScope variant"),
2425        }
2426    }
2427}
2428
2429impl NativeIntoFidl<fdecl::Ref> for EventScope {
2430    fn native_into_fidl(self) -> fdecl::Ref {
2431        match self {
2432            EventScope::Child(child) => fdecl::Ref::Child(child.native_into_fidl()),
2433            EventScope::Collection(name) => {
2434                fdecl::Ref::Collection(fdecl::CollectionRef { name: name.native_into_fidl() })
2435            }
2436        }
2437    }
2438}
2439
2440#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2441#[derive(Debug, Clone, PartialEq, Eq)]
2442pub enum OfferSource {
2443    Framework,
2444    Parent,
2445    Child(ChildRef),
2446    Collection(Name),
2447    Self_,
2448    Capability(Name),
2449    Void,
2450}
2451
2452impl std::fmt::Display for OfferSource {
2453    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2454        match self {
2455            Self::Framework => write!(f, "framework"),
2456            Self::Parent => write!(f, "parent"),
2457            Self::Child(c) => write!(f, "child `#{}`", c),
2458            Self::Collection(c) => write!(f, "collection `#{}`", c),
2459            Self::Self_ => write!(f, "self"),
2460            Self::Capability(c) => write!(f, "capability `{}`", c),
2461            Self::Void => write!(f, "void"),
2462        }
2463    }
2464}
2465
2466impl FidlIntoNative<OfferSource> for fdecl::Ref {
2467    fn fidl_into_native(self) -> OfferSource {
2468        match self {
2469            fdecl::Ref::Parent(_) => OfferSource::Parent,
2470            fdecl::Ref::Self_(_) => OfferSource::Self_,
2471            fdecl::Ref::Child(c) => OfferSource::Child(c.fidl_into_native()),
2472            // cm_fidl_validator should have already validated this
2473            fdecl::Ref::Collection(c) => OfferSource::Collection(c.name.parse().unwrap()),
2474            fdecl::Ref::Framework(_) => OfferSource::Framework,
2475            // cm_fidl_validator should have already validated this
2476            fdecl::Ref::Capability(c) => OfferSource::Capability(c.name.parse().unwrap()),
2477            fdecl::Ref::VoidType(_) => OfferSource::Void,
2478            _ => panic!("invalid OfferSource variant"),
2479        }
2480    }
2481}
2482
2483impl NativeIntoFidl<fdecl::Ref> for OfferSource {
2484    fn native_into_fidl(self) -> fdecl::Ref {
2485        match self {
2486            OfferSource::Parent => fdecl::Ref::Parent(fdecl::ParentRef {}),
2487            OfferSource::Self_ => fdecl::Ref::Self_(fdecl::SelfRef {}),
2488            OfferSource::Child(c) => fdecl::Ref::Child(c.native_into_fidl()),
2489            OfferSource::Collection(name) => {
2490                fdecl::Ref::Collection(fdecl::CollectionRef { name: name.native_into_fidl() })
2491            }
2492            OfferSource::Framework => fdecl::Ref::Framework(fdecl::FrameworkRef {}),
2493            OfferSource::Capability(name) => {
2494                fdecl::Ref::Capability(fdecl::CapabilityRef { name: name.to_string() })
2495            }
2496            OfferSource::Void => fdecl::Ref::VoidType(fdecl::VoidRef {}),
2497        }
2498    }
2499}
2500
2501#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2502#[derive(Debug, Clone, PartialEq, Eq)]
2503pub enum ExposeSource {
2504    Self_,
2505    Child(Name),
2506    Collection(Name),
2507    Framework,
2508    Capability(Name),
2509    Void,
2510}
2511
2512impl std::fmt::Display for ExposeSource {
2513    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2514        match self {
2515            Self::Framework => write!(f, "framework"),
2516            Self::Child(c) => write!(f, "child `#{}`", c),
2517            Self::Collection(c) => write!(f, "collection `#{}`", c),
2518            Self::Self_ => write!(f, "self"),
2519            Self::Capability(c) => write!(f, "capability `{}`", c),
2520            Self::Void => write!(f, "void"),
2521        }
2522    }
2523}
2524
2525impl FidlIntoNative<ExposeSource> for fdecl::Ref {
2526    fn fidl_into_native(self) -> ExposeSource {
2527        match self {
2528            fdecl::Ref::Self_(_) => ExposeSource::Self_,
2529            // cm_fidl_validator should have already validated this
2530            fdecl::Ref::Child(c) => ExposeSource::Child(c.name.parse().unwrap()),
2531            // cm_fidl_validator should have already validated this
2532            fdecl::Ref::Collection(c) => ExposeSource::Collection(c.name.parse().unwrap()),
2533            fdecl::Ref::Framework(_) => ExposeSource::Framework,
2534            // cm_fidl_validator should have already validated this
2535            fdecl::Ref::Capability(c) => ExposeSource::Capability(c.name.parse().unwrap()),
2536            fdecl::Ref::VoidType(_) => ExposeSource::Void,
2537            _ => panic!("invalid ExposeSource variant"),
2538        }
2539    }
2540}
2541
2542impl NativeIntoFidl<fdecl::Ref> for ExposeSource {
2543    fn native_into_fidl(self) -> fdecl::Ref {
2544        match self {
2545            ExposeSource::Self_ => fdecl::Ref::Self_(fdecl::SelfRef {}),
2546            ExposeSource::Child(name) => fdecl::Ref::Child(fdecl::ChildRef {
2547                name: name.native_into_fidl(),
2548                collection: None,
2549            }),
2550            ExposeSource::Collection(name) => {
2551                fdecl::Ref::Collection(fdecl::CollectionRef { name: name.native_into_fidl() })
2552            }
2553            ExposeSource::Framework => fdecl::Ref::Framework(fdecl::FrameworkRef {}),
2554            ExposeSource::Capability(name) => {
2555                fdecl::Ref::Capability(fdecl::CapabilityRef { name: name.to_string() })
2556            }
2557            ExposeSource::Void => fdecl::Ref::VoidType(fdecl::VoidRef {}),
2558        }
2559    }
2560}
2561
2562#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2563#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2564pub enum ExposeTarget {
2565    Parent,
2566    Framework,
2567}
2568
2569impl std::fmt::Display for ExposeTarget {
2570    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2571        match self {
2572            Self::Framework => write!(f, "framework"),
2573            Self::Parent => write!(f, "parent"),
2574        }
2575    }
2576}
2577
2578impl FidlIntoNative<ExposeTarget> for fdecl::Ref {
2579    fn fidl_into_native(self) -> ExposeTarget {
2580        match self {
2581            fdecl::Ref::Parent(_) => ExposeTarget::Parent,
2582            fdecl::Ref::Framework(_) => ExposeTarget::Framework,
2583            _ => panic!("invalid ExposeTarget variant"),
2584        }
2585    }
2586}
2587
2588impl NativeIntoFidl<fdecl::Ref> for ExposeTarget {
2589    fn native_into_fidl(self) -> fdecl::Ref {
2590        match self {
2591            ExposeTarget::Parent => fdecl::Ref::Parent(fdecl::ParentRef {}),
2592            ExposeTarget::Framework => fdecl::Ref::Framework(fdecl::FrameworkRef {}),
2593        }
2594    }
2595}
2596
2597/// A source for a service.
2598#[derive(Debug, Clone, PartialEq, Eq)]
2599pub struct ServiceSource<T> {
2600    /// The provider of the service, relative to a component.
2601    pub source: T,
2602    /// The name of the service.
2603    pub source_name: Name,
2604}
2605
2606#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2607#[derive(Debug, Clone, PartialEq, Eq)]
2608pub enum StorageDirectorySource {
2609    Parent,
2610    Self_,
2611    Child(String),
2612}
2613
2614impl FidlIntoNative<StorageDirectorySource> for fdecl::Ref {
2615    fn fidl_into_native(self) -> StorageDirectorySource {
2616        match self {
2617            fdecl::Ref::Parent(_) => StorageDirectorySource::Parent,
2618            fdecl::Ref::Self_(_) => StorageDirectorySource::Self_,
2619            fdecl::Ref::Child(c) => StorageDirectorySource::Child(c.name),
2620            _ => panic!("invalid OfferDirectorySource variant"),
2621        }
2622    }
2623}
2624
2625impl NativeIntoFidl<fdecl::Ref> for StorageDirectorySource {
2626    fn native_into_fidl(self) -> fdecl::Ref {
2627        match self {
2628            StorageDirectorySource::Parent => fdecl::Ref::Parent(fdecl::ParentRef {}),
2629            StorageDirectorySource::Self_ => fdecl::Ref::Self_(fdecl::SelfRef {}),
2630            StorageDirectorySource::Child(child_name) => {
2631                fdecl::Ref::Child(fdecl::ChildRef { name: child_name, collection: None })
2632            }
2633        }
2634    }
2635}
2636
2637#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2638#[derive(Debug, Clone, PartialEq, Eq)]
2639pub enum DictionarySource {
2640    Parent,
2641    Self_,
2642    Child(ChildRef),
2643}
2644
2645impl FidlIntoNative<DictionarySource> for fdecl::Ref {
2646    fn fidl_into_native(self) -> DictionarySource {
2647        match self {
2648            Self::Parent(_) => DictionarySource::Parent,
2649            Self::Self_(_) => DictionarySource::Self_,
2650            Self::Child(c) => DictionarySource::Child(c.fidl_into_native()),
2651            _ => panic!("invalid DictionarySource variant"),
2652        }
2653    }
2654}
2655
2656impl NativeIntoFidl<fdecl::Ref> for DictionarySource {
2657    fn native_into_fidl(self) -> fdecl::Ref {
2658        match self {
2659            Self::Parent => fdecl::Ref::Parent(fdecl::ParentRef {}),
2660            Self::Self_ => fdecl::Ref::Self_(fdecl::SelfRef {}),
2661            Self::Child(c) => fdecl::Ref::Child(c.native_into_fidl()),
2662        }
2663    }
2664}
2665
2666#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2667#[derive(Debug, Clone, PartialEq, Eq)]
2668pub enum RegistrationSource {
2669    Parent,
2670    Self_,
2671    Child(String),
2672}
2673
2674impl FidlIntoNative<RegistrationSource> for fdecl::Ref {
2675    fn fidl_into_native(self) -> RegistrationSource {
2676        match self {
2677            fdecl::Ref::Parent(_) => RegistrationSource::Parent,
2678            fdecl::Ref::Self_(_) => RegistrationSource::Self_,
2679            fdecl::Ref::Child(c) => RegistrationSource::Child(c.name),
2680            _ => panic!("invalid RegistrationSource variant"),
2681        }
2682    }
2683}
2684
2685impl NativeIntoFidl<fdecl::Ref> for RegistrationSource {
2686    fn native_into_fidl(self) -> fdecl::Ref {
2687        match self {
2688            RegistrationSource::Parent => fdecl::Ref::Parent(fdecl::ParentRef {}),
2689            RegistrationSource::Self_ => fdecl::Ref::Self_(fdecl::SelfRef {}),
2690            RegistrationSource::Child(child_name) => {
2691                fdecl::Ref::Child(fdecl::ChildRef { name: child_name, collection: None })
2692            }
2693        }
2694    }
2695}
2696
2697#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
2698#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2699pub enum OfferTarget {
2700    Child(ChildRef),
2701    Collection(Name),
2702    Capability(Name),
2703}
2704
2705impl std::fmt::Display for OfferTarget {
2706    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2707        match self {
2708            Self::Child(c) => write!(f, "child `#{}`", c),
2709            Self::Collection(c) => write!(f, "collection `#{}`", c),
2710            Self::Capability(c) => write!(f, "capability `#{}`", c),
2711        }
2712    }
2713}
2714
2715impl FidlIntoNative<OfferTarget> for fdecl::Ref {
2716    fn fidl_into_native(self) -> OfferTarget {
2717        match self {
2718            fdecl::Ref::Child(c) => OfferTarget::Child(c.fidl_into_native()),
2719            // cm_fidl_validator should have already validated this
2720            fdecl::Ref::Collection(c) => OfferTarget::Collection(c.name.parse().unwrap()),
2721            fdecl::Ref::Capability(c) => OfferTarget::Capability(c.name.parse().unwrap()),
2722            _ => panic!("invalid OfferTarget variant"),
2723        }
2724    }
2725}
2726
2727impl NativeIntoFidl<fdecl::Ref> for OfferTarget {
2728    fn native_into_fidl(self) -> fdecl::Ref {
2729        match self {
2730            OfferTarget::Child(c) => fdecl::Ref::Child(c.native_into_fidl()),
2731            OfferTarget::Collection(collection_name) => {
2732                fdecl::Ref::Collection(fdecl::CollectionRef {
2733                    name: collection_name.native_into_fidl(),
2734                })
2735            }
2736            OfferTarget::Capability(capability_name) => {
2737                fdecl::Ref::Capability(fdecl::CapabilityRef {
2738                    name: capability_name.native_into_fidl(),
2739                })
2740            }
2741        }
2742    }
2743}
2744
2745/// Converts the contents of a CM-FIDL declaration and produces the equivalent CM-Rust
2746/// struct.
2747/// This function applies cm_fidl_validator to check correctness.
2748impl TryFrom<fdecl::Component> for ComponentDecl {
2749    type Error = Error;
2750
2751    fn try_from(decl: fdecl::Component) -> Result<Self, Self::Error> {
2752        cm_fidl_validator::validate(&decl, &mut DirectedGraph::new())
2753            .map_err(|err| Error::Validate { err })?;
2754        Ok(decl.fidl_into_native())
2755    }
2756}
2757
2758// Converts the contents of a CM-Rust declaration into a CM_FIDL declaration
2759impl From<ComponentDecl> for fdecl::Component {
2760    fn from(decl: ComponentDecl) -> Self {
2761        decl.native_into_fidl()
2762    }
2763}
2764
2765/// Errors produced by cm_rust.
2766#[derive(Debug, Error, Clone)]
2767pub enum Error {
2768    #[error("Fidl validation failed: {}", err)]
2769    Validate {
2770        #[source]
2771        err: cm_fidl_validator::error::ErrorList,
2772    },
2773    #[error("Invalid capability path: {}", raw)]
2774    InvalidCapabilityPath { raw: String },
2775    #[error("Invalid capability type name: {}", raw)]
2776    ParseCapabilityTypeName { raw: String },
2777}
2778
2779/// Push `value` onto the end of `Box<[T]>`. Convenience function for clients that work with
2780/// cm_rust, which uses `Box<[T]>` instead of `Vec<T>` for its list type.
2781pub fn push_box<T>(container: &mut Box<[T]>, value: T) {
2782    let boxed = mem::replace(container, Box::from([]));
2783    let mut new_container: Vec<_> = boxed.into();
2784    new_container.push(value);
2785    *container = new_container.into();
2786}
2787
2788/// Append `other` to the end of `Box<[T]>`. Convenience function for clients that work with
2789/// cm_rust, which uses `Box<[T]>` instead of `Vec<T>` for its list type.
2790pub fn append_box<T>(container: &mut Box<[T]>, other: &mut Vec<T>) {
2791    let boxed = mem::replace(container, Box::from([]));
2792    let mut new_container: Vec<_> = boxed.into();
2793    new_container.append(other);
2794    *container = new_container.into();
2795}
2796
2797#[cfg(test)]
2798mod tests {
2799    use super::*;
2800    use difference::Changeset;
2801    use fidl_fuchsia_component_decl as fdecl;
2802
2803    fn offer_source_static_child(name: &str) -> OfferSource {
2804        OfferSource::Child(ChildRef { name: name.parse().unwrap(), collection: None })
2805    }
2806
2807    fn offer_target_static_child(name: &str) -> OfferTarget {
2808        OfferTarget::Child(ChildRef { name: name.parse().unwrap(), collection: None })
2809    }
2810
2811    macro_rules! test_try_from_decl {
2812        (
2813            $(
2814                $test_name:ident => {
2815                    input = $input:expr,
2816                    result = $result:expr,
2817                },
2818            )+
2819        ) => {
2820            $(
2821                #[test]
2822                fn $test_name() {
2823                    {
2824                        let res = ComponentDecl::try_from($input).expect("try_from failed");
2825                        if res != $result {
2826                            let a = format!("{:#?}", res);
2827                            let e = format!("{:#?}", $result);
2828                            panic!("Conversion from fidl to cm_rust did not yield expected result:\n{}", Changeset::new(&a, &e, "\n"));
2829                        }
2830                    }
2831                    {
2832                        let res = fdecl::Component::try_from($result).expect("try_from failed");
2833                        if res != $input {
2834                            let a = format!("{:#?}", res);
2835                            let e = format!("{:#?}", $input);
2836                            panic!("Conversion from cm_rust to fidl did not yield expected result:\n{}", Changeset::new(&a, &e, "\n"));
2837                        }
2838                    }
2839                }
2840            )+
2841        }
2842    }
2843
2844    macro_rules! test_fidl_into_and_from {
2845        (
2846            $(
2847                $test_name:ident => {
2848                    input = $input:expr,
2849                    input_type = $input_type:ty,
2850                    result = $result:expr,
2851                    result_type = $result_type:ty,
2852                },
2853            )+
2854        ) => {
2855            $(
2856                #[test]
2857                fn $test_name() {
2858                    {
2859                        let res: Vec<$result_type> =
2860                            $input.into_iter().map(|e| e.fidl_into_native()).collect();
2861                        assert_eq!(res, $result);
2862                    }
2863                    {
2864                        let res: Vec<$input_type> =
2865                            $result.into_iter().map(|e| e.native_into_fidl()).collect();
2866                        assert_eq!(res, $input);
2867                    }
2868                }
2869            )+
2870        }
2871    }
2872
2873    macro_rules! test_fidl_into {
2874        (
2875            $(
2876                $test_name:ident => {
2877                    input = $input:expr,
2878                    result = $result:expr,
2879                },
2880            )+
2881        ) => {
2882            $(
2883                #[test]
2884                fn $test_name() {
2885                    test_fidl_into_helper($input, $result);
2886                }
2887            )+
2888        }
2889    }
2890
2891    fn test_fidl_into_helper<T, U>(input: T, expected_res: U)
2892    where
2893        T: FidlIntoNative<U>,
2894        U: std::cmp::PartialEq + std::fmt::Debug,
2895    {
2896        let res: U = input.fidl_into_native();
2897        assert_eq!(res, expected_res);
2898    }
2899
2900    test_try_from_decl! {
2901        try_from_empty => {
2902            input = fdecl::Component {
2903                program: None,
2904                uses: None,
2905                exposes: None,
2906                offers: None,
2907                capabilities: None,
2908                children: None,
2909                collections: None,
2910                facets: None,
2911                environments: None,
2912                ..Default::default()
2913            },
2914            result = ComponentDecl {
2915                program: None,
2916                uses: Box::from([]),
2917                exposes: Box::from([]),
2918                offers: Box::from([]),
2919                capabilities: Box::from([]),
2920                children: Box::from([]),
2921                collections: Box::from([]),
2922                facets: None,
2923                environments: Box::from([]),
2924                config: None,
2925            },
2926        },
2927        try_from_all => {
2928            input = fdecl::Component {
2929                program: Some(fdecl::Program {
2930                    runner: Some("elf".to_string()),
2931                    info: Some(fdata::Dictionary {
2932                        entries: Some(vec![
2933                            fdata::DictionaryEntry {
2934                                key: "args".to_string(),
2935                                value: Some(Box::new(fdata::DictionaryValue::StrVec(vec!["foo".to_string(), "bar".to_string()]))),
2936                            },
2937                            fdata::DictionaryEntry {
2938                                key: "binary".to_string(),
2939                                value: Some(Box::new(fdata::DictionaryValue::Str("bin/app".to_string()))),
2940                            },
2941                        ]),
2942                        ..Default::default()
2943                    }),
2944                    ..Default::default()
2945                }),
2946                uses: Some(vec![
2947                    fdecl::Use::Service(fdecl::UseService {
2948                        dependency_type: Some(fdecl::DependencyType::Strong),
2949                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2950                        source_name: Some("netstack".to_string()),
2951                        source_dictionary: Some("in/dict".to_string()),
2952                        target_path: Some("/svc/mynetstack".to_string()),
2953                        availability: Some(fdecl::Availability::Required),
2954                        ..Default::default()
2955                    }),
2956                    fdecl::Use::Protocol(fdecl::UseProtocol {
2957                        dependency_type: Some(fdecl::DependencyType::Strong),
2958                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
2959                        source_name: Some("legacy_netstack".to_string()),
2960                        source_dictionary: Some("in/dict".to_string()),
2961                        target_path: None,
2962                        numbered_handle: Some(0xab),
2963                        availability: Some(fdecl::Availability::Optional),
2964                        ..Default::default()
2965                    }),
2966                    fdecl::Use::Protocol(fdecl::UseProtocol {
2967                        dependency_type: Some(fdecl::DependencyType::Strong),
2968                        source: Some(fdecl::Ref::Child(fdecl::ChildRef { name: "echo".to_string(), collection: None})),
2969                        source_name: Some("echo_service".to_string()),
2970                        source_dictionary: Some("in/dict".to_string()),
2971                        target_path: Some("/svc/echo_service".to_string()),
2972                        availability: Some(fdecl::Availability::Required),
2973                        ..Default::default()
2974                    }),
2975                    fdecl::Use::Directory(fdecl::UseDirectory {
2976                        dependency_type: Some(fdecl::DependencyType::Strong),
2977                        source: Some(fdecl::Ref::Self_(fdecl::SelfRef {})),
2978                        source_name: Some("dir".to_string()),
2979                        source_dictionary: Some("dict1/me".to_string()),
2980                        target_path: Some("/data".to_string()),
2981                        rights: Some(fio::Operations::CONNECT),
2982                        subdir: Some("foo/bar".to_string()),
2983                        availability: Some(fdecl::Availability::Required),
2984                        ..Default::default()
2985                    }),
2986                    fdecl::Use::Storage(fdecl::UseStorage {
2987                        source_name: Some("cache".to_string()),
2988                        target_path: Some("/cache".to_string()),
2989                        availability: Some(fdecl::Availability::Required),
2990                        ..Default::default()
2991                    }),
2992                    fdecl::Use::Storage(fdecl::UseStorage {
2993                        source_name: Some("temp".to_string()),
2994                        target_path: Some("/temp".to_string()),
2995                        availability: Some(fdecl::Availability::Optional),
2996                        ..Default::default()
2997                    }),
2998                    fdecl::Use::EventStream(fdecl::UseEventStream {
2999                        source: Some(fdecl::Ref::Child(fdecl::ChildRef {
3000                            collection: None,
3001                            name: "netstack".to_string(),
3002                        })),
3003                        source_name: Some("stopped".to_string()),
3004                        scope: Some(vec![
3005                            fdecl::Ref::Child(fdecl::ChildRef {
3006                                collection: None,
3007                                name:"a".to_string(),
3008                        }), fdecl::Ref::Collection(fdecl::CollectionRef {
3009                            name:"b".to_string(),
3010                        })]),
3011                        target_path: Some("/svc/test".to_string()),
3012                        availability: Some(fdecl::Availability::Optional),
3013                        ..Default::default()
3014                    }),
3015                    fdecl::Use::Runner(fdecl::UseRunner {
3016                        source: Some(fdecl::Ref::Environment(fdecl::EnvironmentRef {})),
3017                        source_name: Some("elf".to_string()),
3018                        source_dictionary: None,
3019                        ..Default::default()
3020                    }),
3021                    fdecl::Use::Config(fdecl::UseConfiguration {
3022                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef)),
3023                        source_name: Some("fuchsia.config.MyConfig".to_string()),
3024                        target_name: Some("my_config".to_string()),
3025                        availability: Some(fdecl::Availability::Required),
3026                        type_: Some(fdecl::ConfigType{
3027                            layout: fdecl::ConfigTypeLayout::Bool,
3028                            parameters: Some(Vec::new()),
3029                            constraints: Vec::new(),
3030                        }),
3031                        ..Default::default()
3032                    }),
3033                    #[cfg(fuchsia_api_level_at_least = "NEXT")]
3034                    fdecl::Use::Dictionary(fdecl::UseDictionary {
3035                        dependency_type: Some(fdecl::DependencyType::Strong),
3036                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
3037                        source_name: Some("dictionary".to_string()),
3038                        source_dictionary: Some("other_dictionary".to_string()),
3039                        target_path: Some("/svc".to_string()),
3040                        availability: Some(fdecl::Availability::Optional),
3041                        ..Default::default()
3042                    }),
3043                ]),
3044                exposes: Some(vec![
3045                    fdecl::Expose::Protocol(fdecl::ExposeProtocol {
3046                        source: Some(fdecl::Ref::Child(fdecl::ChildRef {
3047                            name: "netstack".to_string(),
3048                            collection: None,
3049                        })),
3050                        source_name: Some("legacy_netstack".to_string()),
3051                        source_dictionary: Some("in/dict".to_string()),
3052                        target_name: Some("legacy_mynetstack".to_string()),
3053                        target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
3054                        availability: Some(fdecl::Availability::Required),
3055                        ..Default::default()
3056                    }),
3057                    fdecl::Expose::Directory(fdecl::ExposeDirectory {
3058                        source: Some(fdecl::Ref::Child(fdecl::ChildRef {
3059                            name: "netstack".to_string(),
3060                            collection: None,
3061                        })),
3062                        source_name: Some("dir".to_string()),
3063                        source_dictionary: Some("in/dict".to_string()),
3064                        target_name: Some("data".to_string()),
3065                        target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
3066                        rights: Some(fio::Operations::CONNECT),
3067                        subdir: Some("foo/bar".to_string()),
3068                        availability: Some(fdecl::Availability::Optional),
3069                        ..Default::default()
3070                    }),
3071                    fdecl::Expose::Runner(fdecl::ExposeRunner {
3072                        source: Some(fdecl::Ref::Child(fdecl::ChildRef {
3073                            name: "netstack".to_string(),
3074                            collection: None,
3075                        })),
3076                        source_name: Some("elf".to_string()),
3077                        source_dictionary: Some("in/dict".to_string()),
3078                        target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
3079                        target_name: Some("elf".to_string()),
3080                        ..Default::default()
3081                    }),
3082                    fdecl::Expose::Resolver(fdecl::ExposeResolver{
3083                        source: Some(fdecl::Ref::Child(fdecl::ChildRef {
3084                            name: "netstack".to_string(),
3085                            collection: None,
3086                        })),
3087                        source_name: Some("pkg".to_string()),
3088                        source_dictionary: Some("in/dict".to_string()),
3089                        target: Some(fdecl::Ref::Parent(fdecl::ParentRef{})),
3090                        target_name: Some("pkg".to_string()),
3091                        ..Default::default()
3092                    }),
3093                    fdecl::Expose::Service(fdecl::ExposeService {
3094                        source: Some(fdecl::Ref::Child(fdecl::ChildRef {
3095                            name: "netstack".to_string(),
3096                            collection: None,
3097                        })),
3098                        source_name: Some("netstack1".to_string()),
3099                        source_dictionary: Some("in/dict".to_string()),
3100                        target_name: Some("mynetstack".to_string()),
3101                        target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
3102                        availability: Some(fdecl::Availability::Required),
3103                        ..Default::default()
3104                    }),
3105                    fdecl::Expose::Service(fdecl::ExposeService {
3106                        source: Some(fdecl::Ref::Collection(fdecl::CollectionRef {
3107                            name: "modular".to_string(),
3108                        })),
3109                        source_name: Some("netstack2".to_string()),
3110                        source_dictionary: None,
3111                        target_name: Some("mynetstack".to_string()),
3112                        target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
3113                        availability: Some(fdecl::Availability::Required),
3114                        ..Default::default()
3115                    }),
3116                    fdecl::Expose::Dictionary(fdecl::ExposeDictionary {
3117                        source: Some(fdecl::Ref::Child(fdecl::ChildRef {
3118                            name: "netstack".to_string(),
3119                            collection: None,
3120                        })),
3121                        source_name: Some("bundle".to_string()),
3122                        source_dictionary: Some("in/dict".to_string()),
3123                        target_name: Some("mybundle".to_string()),
3124                        target: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
3125                        availability: Some(fdecl::Availability::Required),
3126                        ..Default::default()
3127                    }),
3128                ]),
3129                offers: Some(vec![
3130                    fdecl::Offer::Protocol(fdecl::OfferProtocol {
3131                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
3132                        source_name: Some("legacy_netstack".to_string()),
3133                        source_dictionary: Some("in/dict".to_string()),
3134                        target: Some(fdecl::Ref::Child(
3135                           fdecl::ChildRef {
3136                               name: "echo".to_string(),
3137                               collection: None,
3138                           }
3139                        )),
3140                        target_name: Some("legacy_mynetstack".to_string()),
3141                        dependency_type: Some(fdecl::DependencyType::Weak),
3142                        availability: Some(fdecl::Availability::Required),
3143                        ..Default::default()
3144                    }),
3145                    fdecl::Offer::Directory(fdecl::OfferDirectory {
3146                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
3147                        source_name: Some("dir".to_string()),
3148                        source_dictionary: Some("in/dict".to_string()),
3149                        target: Some(fdecl::Ref::Collection(
3150                            fdecl::CollectionRef { name: "modular".to_string() }
3151                        )),
3152                        target_name: Some("data".to_string()),
3153                        rights: Some(fio::Operations::CONNECT),
3154                        subdir: None,
3155                        dependency_type: Some(fdecl::DependencyType::Strong),
3156                        availability: Some(fdecl::Availability::Optional),
3157                        ..Default::default()
3158                    }),
3159                    fdecl::Offer::Storage(fdecl::OfferStorage {
3160                        source_name: Some("cache".to_string()),
3161                        source: Some(fdecl::Ref::Self_(fdecl::SelfRef {})),
3162                        target: Some(fdecl::Ref::Collection(
3163                            fdecl::CollectionRef { name: "modular".to_string() }
3164                        )),
3165                        target_name: Some("cache".to_string()),
3166                        availability: Some(fdecl::Availability::Required),
3167                        ..Default::default()
3168                    }),
3169                    fdecl::Offer::Runner(fdecl::OfferRunner {
3170                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
3171                        source_name: Some("elf".to_string()),
3172                        source_dictionary: Some("in/dict".to_string()),
3173                        target: Some(fdecl::Ref::Child(
3174                           fdecl::ChildRef {
3175                               name: "echo".to_string(),
3176                               collection: None,
3177                           }
3178                        )),
3179                        target_name: Some("elf2".to_string()),
3180                        ..Default::default()
3181                    }),
3182                    fdecl::Offer::Resolver(fdecl::OfferResolver{
3183                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef{})),
3184                        source_name: Some("pkg".to_string()),
3185                        source_dictionary: Some("in/dict".to_string()),
3186                        target: Some(fdecl::Ref::Child(
3187                           fdecl::ChildRef {
3188                              name: "echo".to_string(),
3189                              collection: None,
3190                           }
3191                        )),
3192                        target_name: Some("pkg".to_string()),
3193                        ..Default::default()
3194                    }),
3195                    fdecl::Offer::Service(fdecl::OfferService {
3196                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
3197                        source_name: Some("netstack1".to_string()),
3198                        source_dictionary: Some("in/dict".to_string()),
3199                        target: Some(fdecl::Ref::Child(
3200                           fdecl::ChildRef {
3201                               name: "echo".to_string(),
3202                               collection: None,
3203                           }
3204                        )),
3205                        target_name: Some("mynetstack1".to_string()),
3206                        availability: Some(fdecl::Availability::Required),
3207                        dependency_type: Some(fdecl::DependencyType::Strong),
3208                        ..Default::default()
3209                    }),
3210                    fdecl::Offer::Service(fdecl::OfferService {
3211                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
3212                        source_name: Some("netstack2".to_string()),
3213                        source_dictionary: None,
3214                        target: Some(fdecl::Ref::Child(
3215                           fdecl::ChildRef {
3216                               name: "echo".to_string(),
3217                               collection: None,
3218                           }
3219                        )),
3220                        target_name: Some("mynetstack2".to_string()),
3221                        availability: Some(fdecl::Availability::Optional),
3222                        dependency_type: Some(fdecl::DependencyType::Strong),
3223                        ..Default::default()
3224                    }),
3225                    fdecl::Offer::Service(fdecl::OfferService {
3226                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
3227                        source_name: Some("netstack3".to_string()),
3228                        source_dictionary: None,
3229                        target: Some(fdecl::Ref::Child(
3230                           fdecl::ChildRef {
3231                               name: "echo".to_string(),
3232                               collection: None,
3233                           }
3234                        )),
3235                        target_name: Some("mynetstack3".to_string()),
3236                        source_instance_filter: Some(vec!["allowedinstance".to_string()]),
3237                        renamed_instances: Some(vec![fdecl::NameMapping{source_name: "default".to_string(), target_name: "allowedinstance".to_string()}]),
3238                        availability: Some(fdecl::Availability::Required),
3239                        dependency_type: Some(fdecl::DependencyType::Strong),
3240                        ..Default::default()
3241                    }),
3242                    fdecl::Offer::Dictionary(fdecl::OfferDictionary {
3243                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
3244                        source_name: Some("bundle".to_string()),
3245                        source_dictionary: Some("in/dict".to_string()),
3246                        target: Some(fdecl::Ref::Child(
3247                           fdecl::ChildRef {
3248                               name: "echo".to_string(),
3249                               collection: None,
3250                           }
3251                        )),
3252                        target_name: Some("mybundle".to_string()),
3253                        dependency_type: Some(fdecl::DependencyType::Weak),
3254                        availability: Some(fdecl::Availability::Required),
3255                        ..Default::default()
3256                    }),
3257                ]),
3258                capabilities: Some(vec![
3259                    fdecl::Capability::Service(fdecl::Service {
3260                        name: Some("netstack".to_string()),
3261                        source_path: Some("/netstack".to_string()),
3262                        ..Default::default()
3263                    }),
3264                    fdecl::Capability::Protocol(fdecl::Protocol {
3265                        name: Some("netstack2".to_string()),
3266                        source_path: Some("/netstack2".to_string()),
3267                        delivery: Some(fdecl::DeliveryType::Immediate),
3268                        ..Default::default()
3269                    }),
3270                    fdecl::Capability::Directory(fdecl::Directory {
3271                        name: Some("data".to_string()),
3272                        source_path: Some("/data".to_string()),
3273                        rights: Some(fio::Operations::CONNECT),
3274                        ..Default::default()
3275                    }),
3276                    fdecl::Capability::Storage(fdecl::Storage {
3277                        name: Some("cache".to_string()),
3278                        backing_dir: Some("data".to_string()),
3279                        source: Some(fdecl::Ref::Parent(fdecl::ParentRef {})),
3280                        subdir: Some("cache".to_string()),
3281                        storage_id: Some(fdecl::StorageId::StaticInstanceId),
3282                        ..Default::default()
3283                    }),
3284                    fdecl::Capability::Runner(fdecl::Runner {
3285                        name: Some("elf".to_string()),
3286                        source_path: Some("/elf".to_string()),
3287                        ..Default::default()
3288                    }),
3289                    fdecl::Capability::Resolver(fdecl::Resolver {
3290                        name: Some("pkg".to_string()),
3291                        source_path: Some("/pkg_resolver".to_string()),
3292                        ..Default::default()
3293                    }),
3294                    fdecl::Capability::Dictionary(fdecl::Dictionary {
3295                        name: Some("dict1".to_string()),
3296                        ..Default::default()
3297                    }),
3298                    fdecl::Capability::Dictionary(fdecl::Dictionary {
3299                        name: Some("dict2".to_string()),
3300                        source_path: Some("/in/other".to_string()),
3301                        ..Default::default()
3302                    }),
3303                ]),
3304                children: Some(vec![
3305                     fdecl::Child {
3306                         name: Some("netstack".to_string()),
3307                         url: Some("fuchsia-pkg://fuchsia.com/netstack#meta/netstack.cm"
3308                                   .to_string()),
3309                         startup: Some(fdecl::StartupMode::Lazy),
3310                         on_terminate: None,
3311                         environment: None,
3312                         ..Default::default()
3313                     },
3314                     fdecl::Child {
3315                         name: Some("gtest".to_string()),
3316                         url: Some("fuchsia-pkg://fuchsia.com/gtest#meta/gtest.cm".to_string()),
3317                         startup: Some(fdecl::StartupMode::Lazy),
3318                         on_terminate: Some(fdecl::OnTerminate::None),
3319                         environment: None,
3320                         ..Default::default()
3321                     },
3322                     fdecl::Child {
3323                         name: Some("echo".to_string()),
3324                         url: Some("fuchsia-pkg://fuchsia.com/echo#meta/echo.cm"
3325                                   .to_string()),
3326                         startup: Some(fdecl::StartupMode::Eager),
3327                         on_terminate: Some(fdecl::OnTerminate::Reboot),
3328                         environment: Some("test_env".to_string()),
3329                         ..Default::default()
3330                     },
3331                ]),
3332                collections: Some(vec![
3333                     fdecl::Collection {
3334                         name: Some("modular".to_string()),
3335                         durability: Some(fdecl::Durability::Transient),
3336                         environment: None,
3337                         allowed_offers: Some(fdecl::AllowedOffers::StaticOnly),
3338                         allow_long_names: Some(true),
3339                         persistent_storage: None,
3340                         ..Default::default()
3341                     },
3342                     fdecl::Collection {
3343                         name: Some("tests".to_string()),
3344                         durability: Some(fdecl::Durability::Transient),
3345                         environment: Some("test_env".to_string()),
3346                         allowed_offers: Some(fdecl::AllowedOffers::StaticAndDynamic),
3347                         allow_long_names: Some(true),
3348                         persistent_storage: Some(true),
3349                         ..Default::default()
3350                     },
3351                ]),
3352                facets: Some(fdata::Dictionary {
3353                    entries: Some(vec![
3354                        fdata::DictionaryEntry {
3355                            key: "author".to_string(),
3356                            value: Some(Box::new(fdata::DictionaryValue::Str("Fuchsia".to_string()))),
3357                        },
3358                    ]),
3359                    ..Default::default()
3360                }),
3361                environments: Some(vec![
3362                    fdecl::Environment {
3363                        name: Some("test_env".to_string()),
3364                        extends: Some(fdecl::EnvironmentExtends::Realm),
3365                        runners: Some(vec![
3366                            fdecl::RunnerRegistration {
3367                                source_name: Some("runner".to_string()),
3368                                source: Some(fdecl::Ref::Child(fdecl::ChildRef {
3369                                    name: "gtest".to_string(),
3370                                    collection: None,
3371                                })),
3372                                target_name: Some("gtest-runner".to_string()),
3373                                ..Default::default()
3374                            }
3375                        ]),
3376                        resolvers: Some(vec![
3377                            fdecl::ResolverRegistration {
3378                                resolver: Some("pkg_resolver".to_string()),
3379                                source: Some(fdecl::Ref::Parent(fdecl::ParentRef{})),
3380                                scheme: Some("fuchsia-pkg".to_string()),
3381                                ..Default::default()
3382                            }
3383                        ]),
3384                        debug_capabilities: Some(vec![
3385                         fdecl::DebugRegistration::Protocol(fdecl::DebugProtocolRegistration {
3386                             source_name: Some("some_protocol".to_string()),
3387                             source: Some(fdecl::Ref::Child(fdecl::ChildRef {
3388                                 name: "gtest".to_string(),
3389                                 collection: None,
3390                             })),
3391                             target_name: Some("some_protocol".to_string()),
3392                             ..Default::default()
3393                            })
3394                        ]),
3395                        stop_timeout_ms: Some(4567),
3396                        ..Default::default()
3397                    }
3398                ]),
3399                config: Some(fdecl::ConfigSchema{
3400                    fields: Some(vec![
3401                        fdecl::ConfigField {
3402                            key: Some("enable_logging".to_string()),
3403                            type_: Some(fdecl::ConfigType {
3404                                layout: fdecl::ConfigTypeLayout::Bool,
3405                                parameters: Some(vec![]),
3406                                constraints: vec![],
3407                            }),
3408                            mutability: Some(Default::default()),
3409                            ..Default::default()
3410                        }
3411                    ]),
3412                    checksum: Some(fdecl::ConfigChecksum::Sha256([
3413                        0x64, 0x49, 0x9E, 0x75, 0xF3, 0x37, 0x69, 0x88, 0x74, 0x3B, 0x38, 0x16,
3414                        0xCD, 0x14, 0x70, 0x9F, 0x3D, 0x4A, 0xD3, 0xE2, 0x24, 0x9A, 0x1A, 0x34,
3415                        0x80, 0xB4, 0x9E, 0xB9, 0x63, 0x57, 0xD6, 0xED,
3416                    ])),
3417                    value_source: Some(
3418                        fdecl::ConfigValueSource::PackagePath("fake.cvf".to_string())
3419                    ),
3420                    ..Default::default()
3421                }),
3422                ..Default::default()
3423            },
3424            result = {
3425                ComponentDecl {
3426                    program: Some(ProgramDecl {
3427                        runner: Some("elf".parse().unwrap()),
3428                        info: fdata::Dictionary {
3429                            entries: Some(vec![
3430                                fdata::DictionaryEntry {
3431                                    key: "args".to_string(),
3432                                    value: Some(Box::new(fdata::DictionaryValue::StrVec(vec!["foo".to_string(), "bar".to_string()]))),
3433                                },
3434                                fdata::DictionaryEntry{
3435                                    key: "binary".to_string(),
3436                                    value: Some(Box::new(fdata::DictionaryValue::Str("bin/app".to_string()))),
3437                                },
3438                            ]),
3439                            ..Default::default()
3440                        },
3441                    }),
3442                    uses: Box::from([
3443                        UseDecl::Service(UseServiceDecl {
3444                            dependency_type: DependencyType::Strong,
3445                            source: UseSource::Parent,
3446                            source_name: "netstack".parse().unwrap(),
3447                            source_dictionary: "in/dict".parse().unwrap(),
3448                            target_path: "/svc/mynetstack".parse().unwrap(),
3449                            availability: Availability::Required,
3450                        }),
3451                        UseDecl::Protocol(UseProtocolDecl {
3452                            dependency_type: DependencyType::Strong,
3453                            source: UseSource::Parent,
3454                            source_name: "legacy_netstack".parse().unwrap(),
3455                            source_dictionary: "in/dict".parse().unwrap(),
3456                            target_path: None,
3457                            numbered_handle: Some(HandleType::from(0xab)),
3458                            availability: Availability::Optional,
3459                        }),
3460                        UseDecl::Protocol(UseProtocolDecl {
3461                            dependency_type: DependencyType::Strong,
3462                            source: UseSource::Child("echo".parse().unwrap()),
3463                            source_name: "echo_service".parse().unwrap(),
3464                            source_dictionary: "in/dict".parse().unwrap(),
3465                            target_path: Some("/svc/echo_service".parse().unwrap()),
3466                            numbered_handle: None,
3467                            availability: Availability::Required,
3468                        }),
3469                        UseDecl::Directory(UseDirectoryDecl {
3470                            dependency_type: DependencyType::Strong,
3471                            source: UseSource::Self_,
3472                            source_name: "dir".parse().unwrap(),
3473                            source_dictionary: "dict1/me".parse().unwrap(),
3474                            target_path: "/data".parse().unwrap(),
3475                            rights: fio::Operations::CONNECT,
3476                            subdir: "foo/bar".parse().unwrap(),
3477                            availability: Availability::Required,
3478                        }),
3479                        UseDecl::Storage(UseStorageDecl {
3480                            source_name: "cache".parse().unwrap(),
3481                            target_path: "/cache".parse().unwrap(),
3482                            availability: Availability::Required,
3483                        }),
3484                        UseDecl::Storage(UseStorageDecl {
3485                            source_name: "temp".parse().unwrap(),
3486                            target_path: "/temp".parse().unwrap(),
3487                            availability: Availability::Optional,
3488                        }),
3489                        UseDecl::EventStream(UseEventStreamDecl {
3490                            source: UseSource::Child("netstack".parse().unwrap()),
3491                            scope: Some(Box::from([EventScope::Child(ChildRef{ name: "a".parse().unwrap(), collection: None}), EventScope::Collection("b".parse().unwrap())])),
3492                            source_name: "stopped".parse().unwrap(),
3493                            target_path: "/svc/test".parse().unwrap(),
3494                            filter: None,
3495                            availability: Availability::Optional,
3496                        }),
3497                        UseDecl::Runner(UseRunnerDecl {
3498                            source: UseSource::Environment,
3499                            source_name: "elf".parse().unwrap(),
3500                            source_dictionary: ".".parse().unwrap(),
3501                        }),
3502                        UseDecl::Config(UseConfigurationDecl {
3503                            source: UseSource::Parent,
3504                            source_name: "fuchsia.config.MyConfig".parse().unwrap(),
3505                            target_name: "my_config".parse().unwrap(),
3506                            availability: Availability::Required,
3507                            type_: ConfigValueType::Bool,
3508                            default: None,
3509                            source_dictionary: ".".parse().unwrap(),
3510                        }),
3511                        #[cfg(fuchsia_api_level_at_least = "NEXT")]
3512                        UseDecl::Dictionary(UseDictionaryDecl {
3513                            dependency_type: DependencyType::Strong,
3514                            source: UseSource::Parent,
3515                            source_name: "dictionary".parse().unwrap(),
3516                            source_dictionary: "other_dictionary".parse().unwrap(),
3517                            target_path: "/svc".parse().unwrap(),
3518                            availability: Availability::Optional,
3519                        }),
3520                    ]),
3521                    exposes: Box::from([
3522                        ExposeDecl::Protocol(ExposeProtocolDecl {
3523                            source: ExposeSource::Child("netstack".parse().unwrap()),
3524                            source_name: "legacy_netstack".parse().unwrap(),
3525                            source_dictionary: "in/dict".parse().unwrap(),
3526                            target_name: "legacy_mynetstack".parse().unwrap(),
3527                            target: ExposeTarget::Parent,
3528                            availability: Availability::Required,
3529                        }),
3530                        ExposeDecl::Directory(ExposeDirectoryDecl {
3531                            source: ExposeSource::Child("netstack".parse().unwrap()),
3532                            source_name: "dir".parse().unwrap(),
3533                            source_dictionary: "in/dict".parse().unwrap(),
3534                            target_name: "data".parse().unwrap(),
3535                            target: ExposeTarget::Parent,
3536                            rights: Some(fio::Operations::CONNECT),
3537                            subdir: "foo/bar".parse().unwrap(),
3538                            availability: Availability::Optional,
3539                        }),
3540                        ExposeDecl::Runner(ExposeRunnerDecl {
3541                            source: ExposeSource::Child("netstack".parse().unwrap()),
3542                            source_name: "elf".parse().unwrap(),
3543                            source_dictionary: "in/dict".parse().unwrap(),
3544                            target: ExposeTarget::Parent,
3545                            target_name: "elf".parse().unwrap(),
3546                        }),
3547                        ExposeDecl::Resolver(ExposeResolverDecl {
3548                            source: ExposeSource::Child("netstack".parse().unwrap()),
3549                            source_name: "pkg".parse().unwrap(),
3550                            source_dictionary: "in/dict".parse().unwrap(),
3551                            target: ExposeTarget::Parent,
3552                            target_name: "pkg".parse().unwrap(),
3553                        }),
3554                        ExposeDecl::Service(ExposeServiceDecl {
3555                            source: ExposeSource::Child("netstack".parse().unwrap()),
3556                            source_name: "netstack1".parse().unwrap(),
3557                            source_dictionary: "in/dict".parse().unwrap(),
3558                            target_name: "mynetstack".parse().unwrap(),
3559                            target: ExposeTarget::Parent,
3560                            availability: Availability::Required,
3561                        }),
3562                        ExposeDecl::Service(ExposeServiceDecl {
3563                            source: ExposeSource::Collection("modular".parse().unwrap()),
3564                            source_name: "netstack2".parse().unwrap(),
3565                            source_dictionary: ".".parse().unwrap(),
3566                            target_name: "mynetstack".parse().unwrap(),
3567                            target: ExposeTarget::Parent,
3568                            availability: Availability::Required,
3569                        }),
3570                        ExposeDecl::Dictionary(ExposeDictionaryDecl {
3571                            source: ExposeSource::Child("netstack".parse().unwrap()),
3572                            source_name: "bundle".parse().unwrap(),
3573                            source_dictionary: "in/dict".parse().unwrap(),
3574                            target_name: "mybundle".parse().unwrap(),
3575                            target: ExposeTarget::Parent,
3576                            availability: Availability::Required,
3577                        }),
3578                    ]),
3579                    offers: Box::from([
3580                        OfferDecl::Protocol(OfferProtocolDecl {
3581                            source: OfferSource::Parent,
3582                            source_name: "legacy_netstack".parse().unwrap(),
3583                            source_dictionary: "in/dict".parse().unwrap(),
3584                            target: offer_target_static_child("echo"),
3585                            target_name: "legacy_mynetstack".parse().unwrap(),
3586                            dependency_type: DependencyType::Weak,
3587                            availability: Availability::Required,
3588                        }),
3589                        OfferDecl::Directory(OfferDirectoryDecl {
3590                            source: OfferSource::Parent,
3591                            source_name: "dir".parse().unwrap(),
3592                            source_dictionary: "in/dict".parse().unwrap(),
3593                            target: OfferTarget::Collection("modular".parse().unwrap()),
3594                            target_name: "data".parse().unwrap(),
3595                            rights: Some(fio::Operations::CONNECT),
3596                            subdir: ".".parse().unwrap(),
3597                            dependency_type: DependencyType::Strong,
3598                            availability: Availability::Optional,
3599                        }),
3600                        OfferDecl::Storage(OfferStorageDecl {
3601                            source_name: "cache".parse().unwrap(),
3602                            source: OfferSource::Self_,
3603                            target: OfferTarget::Collection("modular".parse().unwrap()),
3604                            target_name: "cache".parse().unwrap(),
3605                            availability: Availability::Required,
3606                        }),
3607                        OfferDecl::Runner(OfferRunnerDecl {
3608                            source: OfferSource::Parent,
3609                            source_name: "elf".parse().unwrap(),
3610                            source_dictionary: "in/dict".parse().unwrap(),
3611                            target: offer_target_static_child("echo"),
3612                            target_name: "elf2".parse().unwrap(),
3613                        }),
3614                        OfferDecl::Resolver(OfferResolverDecl {
3615                            source: OfferSource::Parent,
3616                            source_name: "pkg".parse().unwrap(),
3617                            source_dictionary: "in/dict".parse().unwrap(),
3618                            target: offer_target_static_child("echo"),
3619                            target_name: "pkg".parse().unwrap(),
3620                        }),
3621                        OfferDecl::Service(OfferServiceDecl {
3622                            source: OfferSource::Parent,
3623                            source_name: "netstack1".parse().unwrap(),
3624                            source_dictionary: "in/dict".parse().unwrap(),
3625                            source_instance_filter: None,
3626                            renamed_instances: None,
3627                            target: offer_target_static_child("echo"),
3628                            target_name: "mynetstack1".parse().unwrap(),
3629                            availability: Availability::Required,
3630                            dependency_type: Default::default(),
3631                        }),
3632                        OfferDecl::Service(OfferServiceDecl {
3633                            source: OfferSource::Parent,
3634                            source_name: "netstack2".parse().unwrap(),
3635                            source_dictionary: ".".parse().unwrap(),
3636                            source_instance_filter: None,
3637                            renamed_instances: None,
3638                            target: offer_target_static_child("echo"),
3639                            target_name: "mynetstack2".parse().unwrap(),
3640                            availability: Availability::Optional,
3641                            dependency_type: Default::default(),
3642                        }),
3643                        OfferDecl::Service(OfferServiceDecl {
3644                            source: OfferSource::Parent,
3645                            source_name: "netstack3".parse().unwrap(),
3646                            source_dictionary: ".".parse().unwrap(),
3647                            source_instance_filter: Some(Box::from(["allowedinstance".parse().unwrap()])),
3648                            renamed_instances: Some(Box::from([NameMapping{source_name: "default".parse().unwrap(), target_name: "allowedinstance".parse().unwrap()}])),
3649                            target: offer_target_static_child("echo"),
3650                            target_name: "mynetstack3".parse().unwrap(),
3651                            availability: Availability::Required,
3652                            dependency_type: Default::default(),
3653                        }),
3654                        OfferDecl::Dictionary(OfferDictionaryDecl {
3655                            source: OfferSource::Parent,
3656                            source_name: "bundle".parse().unwrap(),
3657                            source_dictionary: "in/dict".parse().unwrap(),
3658                            target: offer_target_static_child("echo"),
3659                            target_name: "mybundle".parse().unwrap(),
3660                            dependency_type: DependencyType::Weak,
3661                            availability: Availability::Required,
3662                        }),
3663                    ]),
3664                    capabilities: Box::from([
3665                        CapabilityDecl::Service(ServiceDecl {
3666                            name: "netstack".parse().unwrap(),
3667                            source_path: Some("/netstack".parse().unwrap()),
3668                        }),
3669                        CapabilityDecl::Protocol(ProtocolDecl {
3670                            name: "netstack2".parse().unwrap(),
3671                            source_path: Some("/netstack2".parse().unwrap()),
3672                            delivery: DeliveryType::Immediate,
3673                        }),
3674                        CapabilityDecl::Directory(DirectoryDecl {
3675                            name: "data".parse().unwrap(),
3676                            source_path: Some("/data".parse().unwrap()),
3677                            rights: fio::Operations::CONNECT,
3678                        }),
3679                        CapabilityDecl::Storage(StorageDecl {
3680                            name: "cache".parse().unwrap(),
3681                            backing_dir: "data".parse().unwrap(),
3682                            source: StorageDirectorySource::Parent,
3683                            subdir: "cache".parse().unwrap(),
3684                            storage_id: fdecl::StorageId::StaticInstanceId,
3685                        }),
3686                        CapabilityDecl::Runner(RunnerDecl {
3687                            name: "elf".parse().unwrap(),
3688                            source_path: Some("/elf".parse().unwrap()),
3689                        }),
3690                        CapabilityDecl::Resolver(ResolverDecl {
3691                            name: "pkg".parse().unwrap(),
3692                            source_path: Some("/pkg_resolver".parse().unwrap()),
3693                        }),
3694                        CapabilityDecl::Dictionary(DictionaryDecl {
3695                            name: "dict1".parse().unwrap(),
3696                            source_path: None,
3697                        }),
3698                        CapabilityDecl::Dictionary(DictionaryDecl {
3699                            name: "dict2".parse().unwrap(),
3700                            source_path: Some("/in/other".parse().unwrap()),
3701                        }),
3702                    ]),
3703                    children: Box::from([
3704                        ChildDecl {
3705                            name: "netstack".parse().unwrap(),
3706                            url: "fuchsia-pkg://fuchsia.com/netstack#meta/netstack.cm".parse().unwrap(),
3707                            startup: fdecl::StartupMode::Lazy,
3708                            on_terminate: None,
3709                            environment: None,
3710                            config_overrides: None,
3711                        },
3712                        ChildDecl {
3713                            name: "gtest".parse().unwrap(),
3714                            url: "fuchsia-pkg://fuchsia.com/gtest#meta/gtest.cm".parse().unwrap(),
3715                            startup: fdecl::StartupMode::Lazy,
3716                            on_terminate: Some(fdecl::OnTerminate::None),
3717                            environment: None,
3718                            config_overrides: None,
3719                        },
3720                        ChildDecl {
3721                            name: "echo".parse().unwrap(),
3722                            url: "fuchsia-pkg://fuchsia.com/echo#meta/echo.cm".parse().unwrap(),
3723                            startup: fdecl::StartupMode::Eager,
3724                            on_terminate: Some(fdecl::OnTerminate::Reboot),
3725                            environment: Some("test_env".parse().unwrap()),
3726                            config_overrides: None,
3727                        },
3728                    ]),
3729                    collections: Box::from([
3730                        CollectionDecl {
3731                            name: "modular".parse().unwrap(),
3732                            durability: fdecl::Durability::Transient,
3733                            environment: None,
3734                            allowed_offers: cm_types::AllowedOffers::StaticOnly,
3735                            allow_long_names: true,
3736                            persistent_storage: None,
3737                        },
3738                        CollectionDecl {
3739                            name: "tests".parse().unwrap(),
3740                            durability: fdecl::Durability::Transient,
3741                            environment: Some("test_env".parse().unwrap()),
3742                            allowed_offers: cm_types::AllowedOffers::StaticAndDynamic,
3743                            allow_long_names: true,
3744                            persistent_storage: Some(true),
3745                        },
3746                    ]),
3747                    facets: Some(fdata::Dictionary {
3748                        entries: Some(vec![
3749                            fdata::DictionaryEntry {
3750                                key: "author".to_string(),
3751                                value: Some(Box::new(fdata::DictionaryValue::Str("Fuchsia".to_string()))),
3752                            },
3753                        ]),
3754                        ..Default::default()
3755                    }),
3756                    environments: Box::from([
3757                        EnvironmentDecl {
3758                            name: "test_env".parse().unwrap(),
3759                            extends: fdecl::EnvironmentExtends::Realm,
3760                            runners: Box::from([
3761                                RunnerRegistration {
3762                                    source_name: "runner".parse().unwrap(),
3763                                    source: RegistrationSource::Child("gtest".to_string()),
3764                                    target_name: "gtest-runner".parse().unwrap(),
3765                                }
3766                            ]),
3767                            resolvers: Box::from([
3768                                ResolverRegistration {
3769                                    resolver: "pkg_resolver".parse().unwrap(),
3770                                    source: RegistrationSource::Parent,
3771                                    scheme: "fuchsia-pkg".to_string(),
3772                                }
3773                            ]),
3774                            debug_capabilities: Box::from([
3775                                DebugRegistration::Protocol(DebugProtocolRegistration {
3776                                    source_name: "some_protocol".parse().unwrap(),
3777                                    source: RegistrationSource::Child("gtest".to_string()),
3778                                    target_name: "some_protocol".parse().unwrap(),
3779                                })
3780                            ]),
3781                            stop_timeout_ms: Some(4567),
3782                        }
3783                    ]),
3784                    config: Some(ConfigDecl {
3785                        fields: Box::from([
3786                            ConfigField {
3787                                key: "enable_logging".to_string(),
3788                                type_: ConfigValueType::Bool,
3789                                mutability: ConfigMutability::default(),
3790                            }
3791                        ]),
3792                        checksum: ConfigChecksum::Sha256([
3793                            0x64, 0x49, 0x9E, 0x75, 0xF3, 0x37, 0x69, 0x88, 0x74, 0x3B, 0x38, 0x16,
3794                            0xCD, 0x14, 0x70, 0x9F, 0x3D, 0x4A, 0xD3, 0xE2, 0x24, 0x9A, 0x1A, 0x34,
3795                            0x80, 0xB4, 0x9E, 0xB9, 0x63, 0x57, 0xD6, 0xED,
3796                        ]),
3797                        value_source: ConfigValueSource::PackagePath("fake.cvf".to_string())
3798                    }),
3799                }
3800            },
3801        },
3802    }
3803
3804    test_fidl_into_and_from! {
3805        fidl_into_and_from_use_source => {
3806            input = vec![
3807                fdecl::Ref::Parent(fdecl::ParentRef{}),
3808                fdecl::Ref::Framework(fdecl::FrameworkRef{}),
3809                fdecl::Ref::Debug(fdecl::DebugRef{}),
3810                fdecl::Ref::Capability(fdecl::CapabilityRef {name: "capability".to_string()}),
3811                fdecl::Ref::Child(fdecl::ChildRef {
3812                    name: "foo".into(),
3813                    collection: None,
3814                }),
3815                fdecl::Ref::Environment(fdecl::EnvironmentRef{}),
3816            ],
3817            input_type = fdecl::Ref,
3818            result = vec![
3819                UseSource::Parent,
3820                UseSource::Framework,
3821                UseSource::Debug,
3822                UseSource::Capability("capability".parse().unwrap()),
3823                UseSource::Child("foo".parse().unwrap()),
3824                UseSource::Environment,
3825            ],
3826            result_type = UseSource,
3827        },
3828        fidl_into_and_from_expose_source => {
3829            input = vec![
3830                fdecl::Ref::Self_(fdecl::SelfRef {}),
3831                fdecl::Ref::Child(fdecl::ChildRef {
3832                    name: "foo".into(),
3833                    collection: None,
3834                }),
3835                fdecl::Ref::Framework(fdecl::FrameworkRef {}),
3836                fdecl::Ref::Collection(fdecl::CollectionRef { name: "foo".to_string() }),
3837            ],
3838            input_type = fdecl::Ref,
3839            result = vec![
3840                ExposeSource::Self_,
3841                ExposeSource::Child("foo".parse().unwrap()),
3842                ExposeSource::Framework,
3843                ExposeSource::Collection("foo".parse().unwrap()),
3844            ],
3845            result_type = ExposeSource,
3846        },
3847        fidl_into_and_from_offer_source => {
3848            input = vec![
3849                fdecl::Ref::Self_(fdecl::SelfRef {}),
3850                fdecl::Ref::Child(fdecl::ChildRef {
3851                    name: "foo".into(),
3852                    collection: None,
3853                }),
3854                fdecl::Ref::Framework(fdecl::FrameworkRef {}),
3855                fdecl::Ref::Capability(fdecl::CapabilityRef { name: "foo".to_string() }),
3856                fdecl::Ref::Parent(fdecl::ParentRef {}),
3857                fdecl::Ref::Collection(fdecl::CollectionRef { name: "foo".to_string() }),
3858                fdecl::Ref::VoidType(fdecl::VoidRef {}),
3859            ],
3860            input_type = fdecl::Ref,
3861            result = vec![
3862                OfferSource::Self_,
3863                offer_source_static_child("foo"),
3864                OfferSource::Framework,
3865                OfferSource::Capability("foo".parse().unwrap()),
3866                OfferSource::Parent,
3867                OfferSource::Collection("foo".parse().unwrap()),
3868                OfferSource::Void,
3869            ],
3870            result_type = OfferSource,
3871        },
3872        fidl_into_and_from_dictionary_source => {
3873            input = vec![
3874                fdecl::Ref::Self_(fdecl::SelfRef {}),
3875                fdecl::Ref::Child(fdecl::ChildRef {
3876                    name: "foo".into(),
3877                    collection: None,
3878                }),
3879                fdecl::Ref::Parent(fdecl::ParentRef {}),
3880            ],
3881            input_type = fdecl::Ref,
3882            result = vec![
3883                DictionarySource::Self_,
3884                DictionarySource::Child(ChildRef {
3885                    name: "foo".parse().unwrap(),
3886                    collection: None,
3887                }),
3888                DictionarySource::Parent,
3889            ],
3890            result_type = DictionarySource,
3891        },
3892
3893        fidl_into_and_from_capability_without_path => {
3894            input = vec![
3895                fdecl::Protocol {
3896                    name: Some("foo_protocol".to_string()),
3897                    source_path: None,
3898                    delivery: Some(fdecl::DeliveryType::Immediate),
3899                    ..Default::default()
3900                },
3901            ],
3902            input_type = fdecl::Protocol,
3903            result = vec![
3904                ProtocolDecl {
3905                    name: "foo_protocol".parse().unwrap(),
3906                    source_path: None,
3907                    delivery: DeliveryType::Immediate,
3908                }
3909            ],
3910            result_type = ProtocolDecl,
3911        },
3912        fidl_into_and_from_storage_capability => {
3913            input = vec![
3914                fdecl::Storage {
3915                    name: Some("minfs".to_string()),
3916                    backing_dir: Some("minfs".into()),
3917                    source: Some(fdecl::Ref::Child(fdecl::ChildRef {
3918                        name: "foo".into(),
3919                        collection: None,
3920                    })),
3921                    subdir: None,
3922                    storage_id: Some(fdecl::StorageId::StaticInstanceIdOrMoniker),
3923                    ..Default::default()
3924                },
3925            ],
3926            input_type = fdecl::Storage,
3927            result = vec![
3928                StorageDecl {
3929                    name: "minfs".parse().unwrap(),
3930                    backing_dir: "minfs".parse().unwrap(),
3931                    source: StorageDirectorySource::Child("foo".to_string()),
3932                    subdir: ".".parse().unwrap(),
3933                    storage_id: fdecl::StorageId::StaticInstanceIdOrMoniker,
3934                },
3935            ],
3936            result_type = StorageDecl,
3937        },
3938        fidl_into_and_from_storage_capability_restricted => {
3939            input = vec![
3940                fdecl::Storage {
3941                    name: Some("minfs".to_string()),
3942                    backing_dir: Some("minfs".into()),
3943                    source: Some(fdecl::Ref::Child(fdecl::ChildRef {
3944                        name: "foo".into(),
3945                        collection: None,
3946                    })),
3947                    subdir: None,
3948                    storage_id: Some(fdecl::StorageId::StaticInstanceId),
3949                    ..Default::default()
3950                },
3951            ],
3952            input_type = fdecl::Storage,
3953            result = vec![
3954                StorageDecl {
3955                    name: "minfs".parse().unwrap(),
3956                    backing_dir: "minfs".parse().unwrap(),
3957                    source: StorageDirectorySource::Child("foo".to_string()),
3958                    subdir: ".".parse().unwrap(),
3959                    storage_id: fdecl::StorageId::StaticInstanceId,
3960                },
3961            ],
3962            result_type = StorageDecl,
3963        },
3964    }
3965
3966    test_fidl_into! {
3967        all_with_omitted_defaults => {
3968            input = fdecl::Component {
3969                program: Some(fdecl::Program {
3970                    runner: Some("elf".to_string()),
3971                    info: Some(fdata::Dictionary {
3972                        entries: Some(vec![]),
3973                        ..Default::default()
3974                    }),
3975                    ..Default::default()
3976                }),
3977                uses: Some(vec![]),
3978                exposes: Some(vec![]),
3979                offers: Some(vec![]),
3980                capabilities: Some(vec![]),
3981                children: Some(vec![]),
3982                collections: Some(vec![
3983                     fdecl::Collection {
3984                         name: Some("modular".to_string()),
3985                         durability: Some(fdecl::Durability::Transient),
3986                         environment: None,
3987                         allowed_offers: None,
3988                         allow_long_names: None,
3989                         persistent_storage: None,
3990                         ..Default::default()
3991                     },
3992                     fdecl::Collection {
3993                         name: Some("tests".to_string()),
3994                         durability: Some(fdecl::Durability::Transient),
3995                         environment: Some("test_env".to_string()),
3996                         allowed_offers: Some(fdecl::AllowedOffers::StaticOnly),
3997                         allow_long_names: None,
3998                         persistent_storage: Some(false),
3999                         ..Default::default()
4000                     },
4001                     fdecl::Collection {
4002                         name: Some("dyn_offers".to_string()),
4003                         durability: Some(fdecl::Durability::Transient),
4004                         allowed_offers: Some(fdecl::AllowedOffers::StaticAndDynamic),
4005                         allow_long_names: None,
4006                         persistent_storage: Some(true),
4007                         ..Default::default()
4008                     },
4009                     fdecl::Collection {
4010                         name: Some("long_child_names".to_string()),
4011                         durability: Some(fdecl::Durability::Transient),
4012                         allowed_offers: None,
4013                         allow_long_names: Some(true),
4014                         persistent_storage: None,
4015                         ..Default::default()
4016                     },
4017                ]),
4018                facets: Some(fdata::Dictionary{
4019                    entries: Some(vec![]),
4020                    ..Default::default()
4021                }),
4022                environments: Some(vec![]),
4023                ..Default::default()
4024            },
4025            result = {
4026                ComponentDecl {
4027                    program: Some(ProgramDecl {
4028                        runner: Some("elf".parse().unwrap()),
4029                        info: fdata::Dictionary {
4030                            entries: Some(vec![]),
4031                            ..Default::default()
4032                        },
4033                    }),
4034                    uses: Box::from([]),
4035                    exposes: Box::from([]),
4036                    offers: Box::from([]),
4037                    capabilities: Box::from([]),
4038                    children: Box::from([]),
4039                    collections: Box::from([
4040                        CollectionDecl {
4041                            name: "modular".parse().unwrap(),
4042                            durability: fdecl::Durability::Transient,
4043                            environment: None,
4044                            allowed_offers: cm_types::AllowedOffers::StaticOnly,
4045                            allow_long_names: false,
4046                            persistent_storage: None,
4047                        },
4048                        CollectionDecl {
4049                            name: "tests".parse().unwrap(),
4050                            durability: fdecl::Durability::Transient,
4051                            environment: Some("test_env".parse().unwrap()),
4052                            allowed_offers: cm_types::AllowedOffers::StaticOnly,
4053                            allow_long_names: false,
4054                            persistent_storage: Some(false),
4055                        },
4056                        CollectionDecl {
4057                            name: "dyn_offers".parse().unwrap(),
4058                            durability: fdecl::Durability::Transient,
4059                            environment: None,
4060                            allowed_offers: cm_types::AllowedOffers::StaticAndDynamic,
4061                            allow_long_names: false,
4062                            persistent_storage: Some(true),
4063                        },
4064                        CollectionDecl {
4065                            name: "long_child_names".parse().unwrap(),
4066                            durability: fdecl::Durability::Transient,
4067                            environment: None,
4068                            allowed_offers: cm_types::AllowedOffers::StaticOnly,
4069                            allow_long_names: true,
4070                            persistent_storage: None,
4071                        },
4072                    ]),
4073                    facets: Some(fdata::Dictionary{
4074                        entries: Some(vec![]),
4075                        ..Default::default()
4076                    }),
4077                    environments: Box::from([]),
4078                    config: None,
4079                }
4080            },
4081        },
4082    }
4083
4084    #[test]
4085    fn default_expose_availability() {
4086        let source = fdecl::Ref::Self_(fdecl::SelfRef {});
4087        let source_name = "source";
4088        let target = fdecl::Ref::Parent(fdecl::ParentRef {});
4089        let target_name = "target";
4090        assert_eq!(
4091            *fdecl::ExposeService {
4092                source: Some(source.clone()),
4093                source_name: Some(source_name.into()),
4094                target: Some(target.clone()),
4095                target_name: Some(target_name.into()),
4096                availability: None,
4097                ..Default::default()
4098            }
4099            .fidl_into_native()
4100            .availability(),
4101            Availability::Required
4102        );
4103        assert_eq!(
4104            *fdecl::ExposeProtocol {
4105                source: Some(source.clone()),
4106                source_name: Some(source_name.into()),
4107                target: Some(target.clone()),
4108                target_name: Some(target_name.into()),
4109                ..Default::default()
4110            }
4111            .fidl_into_native()
4112            .availability(),
4113            Availability::Required
4114        );
4115        assert_eq!(
4116            *fdecl::ExposeDirectory {
4117                source: Some(source.clone()),
4118                source_name: Some(source_name.into()),
4119                target: Some(target.clone()),
4120                target_name: Some(target_name.into()),
4121                ..Default::default()
4122            }
4123            .fidl_into_native()
4124            .availability(),
4125            Availability::Required
4126        );
4127        assert_eq!(
4128            *fdecl::ExposeRunner {
4129                source: Some(source.clone()),
4130                source_name: Some(source_name.into()),
4131                target: Some(target.clone()),
4132                target_name: Some(target_name.into()),
4133                ..Default::default()
4134            }
4135            .fidl_into_native()
4136            .availability(),
4137            Availability::Required
4138        );
4139        assert_eq!(
4140            *fdecl::ExposeResolver {
4141                source: Some(source.clone()),
4142                source_name: Some(source_name.into()),
4143                target: Some(target.clone()),
4144                target_name: Some(target_name.into()),
4145                ..Default::default()
4146            }
4147            .fidl_into_native()
4148            .availability(),
4149            Availability::Required
4150        );
4151        assert_eq!(
4152            *fdecl::ExposeDictionary {
4153                source: Some(source.clone()),
4154                source_name: Some(source_name.into()),
4155                target: Some(target.clone()),
4156                target_name: Some(target_name.into()),
4157                ..Default::default()
4158            }
4159            .fidl_into_native()
4160            .availability(),
4161            Availability::Required
4162        );
4163    }
4164
4165    #[test]
4166    fn default_delivery_type() {
4167        assert_eq!(
4168            fdecl::Protocol {
4169                name: Some("foo".to_string()),
4170                source_path: Some("/foo".to_string()),
4171                delivery: None,
4172                ..Default::default()
4173            }
4174            .fidl_into_native()
4175            .delivery,
4176            DeliveryType::Immediate
4177        )
4178    }
4179
4180    #[test]
4181    fn on_readable_delivery_type() {
4182        assert_eq!(
4183            fdecl::Protocol {
4184                name: Some("foo".to_string()),
4185                source_path: Some("/foo".to_string()),
4186                delivery: Some(fdecl::DeliveryType::OnReadable),
4187                ..Default::default()
4188            }
4189            .fidl_into_native()
4190            .delivery,
4191            DeliveryType::OnReadable
4192        )
4193    }
4194
4195    #[test]
4196    fn config_value_matches_type() {
4197        let bool_true = ConfigValue::Single(ConfigSingleValue::Bool(true));
4198        let bool_false = ConfigValue::Single(ConfigSingleValue::Bool(false));
4199        let uint8_zero = ConfigValue::Single(ConfigSingleValue::Uint8(0));
4200        let vec_bool_true = ConfigValue::Vector(ConfigVectorValue::BoolVector(Box::from([true])));
4201        let vec_bool_false = ConfigValue::Vector(ConfigVectorValue::BoolVector(Box::from([false])));
4202
4203        assert!(bool_true.matches_type(&bool_false));
4204        assert!(vec_bool_true.matches_type(&vec_bool_false));
4205
4206        assert!(!bool_true.matches_type(&uint8_zero));
4207        assert!(!bool_true.matches_type(&vec_bool_true));
4208    }
4209}