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