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