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