cml/
lib.rs

1// Copyright 2023 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
5//! A library of common utilities used by `cmc` and related tools.
6//! To manually regenerate reference documentation from doc comments in
7//! this file, see the instructions at:
8//!
9//!   tools/lib/reference_doc/macro/derive-reference-doc-tests/src/test_data/README.md
10
11pub mod error;
12pub mod features;
13pub mod one_or_many;
14pub(crate) mod validate;
15
16#[allow(unused)] // A test-only macro is defined outside of a test builds.
17pub mod translate;
18
19use crate::error::Error;
20use cml_macro::{CheckedVec, OneOrMany, Reference};
21use fidl_fuchsia_io as fio;
22use indexmap::IndexMap;
23use itertools::Itertools;
24use json5format::{FormatOptions, PathOption};
25use lazy_static::lazy_static;
26use maplit::{hashmap, hashset};
27use reference_doc::ReferenceDoc;
28use serde::{de, ser, Deserialize, Serialize};
29use serde_json::{Map, Value};
30use std::collections::{BTreeMap, HashMap, HashSet};
31use std::fmt::Write;
32use std::hash::Hash;
33use std::num::NonZeroU32;
34use std::str::FromStr;
35use std::{cmp, fmt, path};
36use validate::offer_to_all_from_offer;
37
38pub use cm_types::{
39    AllowedOffers, Availability, DeliveryType, DependencyType, Durability, Name, NamespacePath,
40    OnTerminate, ParseError, Path, RelativePath, StartupMode, StorageId, Url,
41};
42use error::Location;
43
44pub use crate::one_or_many::OneOrMany;
45pub use crate::translate::{compile, CompileOptions};
46pub use crate::validate::{CapabilityRequirements, MustUseRequirement, OfferToAllCapability};
47
48lazy_static! {
49    static ref DEFAULT_EVENT_STREAM_NAME: Name = "EventStream".parse().unwrap();
50}
51
52/// Parses a string `buffer` into a [Document]. `file` is used for error reporting.
53pub fn parse_one_document(buffer: &String, file: &std::path::Path) -> Result<Document, Error> {
54    serde_json5::from_str(&buffer).map_err(|e| {
55        let serde_json5::Error::Message { location, msg } = e;
56        let location = location.map(|l| Location { line: l.line, column: l.column });
57        Error::parse(msg, location, Some(file))
58    })
59}
60
61/// Parses a string `buffer` into a vector of [Document]. `file` is used for error reporting.
62/// Supports JSON encoded as an array of Document JSON objects.
63pub fn parse_many_documents(
64    buffer: &String,
65    file: &std::path::Path,
66) -> Result<Vec<Document>, Error> {
67    let res: Result<Vec<Document>, _> = serde_json5::from_str(&buffer);
68    match res {
69        Err(_) => {
70            let d = parse_one_document(buffer, file)?;
71            Ok(vec![d])
72        }
73        Ok(docs) => Ok(docs),
74    }
75}
76
77/// A name/identity of a capability exposed/offered to another component.
78///
79/// Exposed or offered capabilities have an identifier whose format
80/// depends on the capability type. For directories and services this is
81/// a path, while for storage this is a storage name. Paths and storage
82/// names, however, are in different conceptual namespaces, and can't
83/// collide with each other.
84///
85/// This enum allows such names to be specified disambiguating what
86/// namespace they are in.
87#[derive(Debug, PartialEq, Eq, Hash, Clone)]
88pub enum CapabilityId<'a> {
89    Service(&'a Name),
90    Protocol(&'a Name),
91    Directory(&'a Name),
92    // A service in a `use` declaration has a target path in the component's namespace.
93    UsedService(Path),
94    // A protocol in a `use` declaration has a target path in the component's namespace.
95    UsedProtocol(Path),
96    // A directory in a `use` declaration has a target path in the component's namespace.
97    UsedDirectory(Path),
98    // A storage in a `use` declaration has a target path in the component's namespace.
99    UsedStorage(Path),
100    // An event stream in a `use` declaration has a target path in the component's namespace.
101    UsedEventStream(Path),
102    // A configuration in a `use` declaration has a target name that matches a config.
103    UsedConfiguration(&'a Name),
104    UsedRunner(&'a Name),
105    Storage(&'a Name),
106    Runner(&'a Name),
107    Resolver(&'a Name),
108    EventStream(&'a Name),
109    Dictionary(&'a Name),
110    Configuration(&'a Name),
111}
112
113/// Generates a `Vec<Name>` -> `Vec<CapabilityId>` conversion function.
114macro_rules! capability_ids_from_names {
115    ($name:ident, $variant:expr) => {
116        fn $name(names: Vec<&'a Name>) -> Vec<Self> {
117            names.into_iter().map(|n| $variant(n)).collect()
118        }
119    };
120}
121
122/// Generates a `Vec<Path>` -> `Vec<CapabilityId>` conversion function.
123macro_rules! capability_ids_from_paths {
124    ($name:ident, $variant:expr) => {
125        fn $name(paths: Vec<Path>) -> Vec<Self> {
126            paths.into_iter().map(|p| $variant(p)).collect()
127        }
128    };
129}
130
131impl<'a> CapabilityId<'a> {
132    /// Human readable description of this capability type.
133    pub fn type_str(&self) -> &'static str {
134        match self {
135            CapabilityId::Service(_) => "service",
136            CapabilityId::Protocol(_) => "protocol",
137            CapabilityId::Directory(_) => "directory",
138            CapabilityId::UsedService(_) => "service",
139            CapabilityId::UsedProtocol(_) => "protocol",
140            CapabilityId::UsedDirectory(_) => "directory",
141            CapabilityId::UsedStorage(_) => "storage",
142            CapabilityId::UsedEventStream(_) => "event_stream",
143            CapabilityId::UsedRunner(_) => "runner",
144            CapabilityId::UsedConfiguration(_) => "config",
145            CapabilityId::Storage(_) => "storage",
146            CapabilityId::Runner(_) => "runner",
147            CapabilityId::Resolver(_) => "resolver",
148            CapabilityId::EventStream(_) => "event_stream",
149            CapabilityId::Dictionary(_) => "dictionary",
150            CapabilityId::Configuration(_) => "config",
151        }
152    }
153
154    /// Return the directory containing the capability, if this capability takes a target path.
155    pub fn get_dir_path(&self) -> Option<NamespacePath> {
156        match self {
157            CapabilityId::UsedService(p)
158            | CapabilityId::UsedProtocol(p)
159            | CapabilityId::UsedEventStream(p) => Some(p.parent()),
160            CapabilityId::UsedDirectory(p) | CapabilityId::UsedStorage(p) => Some(p.clone().into()),
161            _ => None,
162        }
163    }
164
165    /// Given a Use clause, return the set of target identifiers.
166    ///
167    /// When only one capability identifier is specified, the target identifier name is derived
168    /// using the "path" clause. If a "path" clause is not specified, the target identifier is the
169    /// same name as the source.
170    ///
171    /// When multiple capability identifiers are specified, the target names are the same as the
172    /// source names.
173    pub fn from_use(use_: &'a Use) -> Result<Vec<Self>, Error> {
174        // TODO: Validate that exactly one of these is set.
175        let alias = use_.path.as_ref();
176        if let Some(n) = use_.service() {
177            return Ok(Self::used_services_from(Self::get_one_or_many_svc_paths(
178                n,
179                alias,
180                use_.capability_type().unwrap(),
181            )?));
182        } else if let Some(n) = use_.protocol() {
183            return Ok(Self::used_protocols_from(Self::get_one_or_many_svc_paths(
184                n,
185                alias,
186                use_.capability_type().unwrap(),
187            )?));
188        } else if let Some(_) = use_.directory.as_ref() {
189            if use_.path.is_none() {
190                return Err(Error::validate("\"path\" should be present for `use directory`."));
191            }
192            return Ok(vec![CapabilityId::UsedDirectory(use_.path.as_ref().unwrap().clone())]);
193        } else if let Some(_) = use_.storage.as_ref() {
194            if use_.path.is_none() {
195                return Err(Error::validate("\"path\" should be present for `use storage`."));
196            }
197            return Ok(vec![CapabilityId::UsedStorage(use_.path.as_ref().unwrap().clone())]);
198        } else if let Some(_) = use_.event_stream() {
199            if let Some(path) = use_.path() {
200                return Ok(vec![CapabilityId::UsedEventStream(path.clone())]);
201            }
202            return Ok(vec![CapabilityId::UsedEventStream(Path::new(
203                "/svc/fuchsia.component.EventStream",
204            )?)]);
205        } else if let Some(n) = use_.runner() {
206            match n {
207                OneOrMany::One(name) => {
208                    return Ok(vec![CapabilityId::UsedRunner(name)]);
209                }
210                OneOrMany::Many(_) => {
211                    return Err(Error::validate("`use runner` should occur at most once."));
212                }
213            }
214        } else if let Some(_) = use_.config() {
215            return match &use_.key {
216                None => Err(Error::validate("\"key\" should be present for `use config`.")),
217                Some(name) => Ok(vec![CapabilityId::UsedConfiguration(name)]),
218            };
219        }
220        // Unsupported capability type.
221        let supported_keywords = use_
222            .supported()
223            .into_iter()
224            .map(|k| format!("\"{}\"", k))
225            .collect::<Vec<_>>()
226            .join(", ");
227        Err(Error::validate(format!(
228            "`{}` declaration is missing a capability keyword, one of: {}",
229            use_.decl_type(),
230            supported_keywords,
231        )))
232    }
233
234    pub fn from_capability(capability: &'a Capability) -> Result<Vec<Self>, Error> {
235        // TODO: Validate that exactly one of these is set.
236        if let Some(n) = capability.service() {
237            if n.is_many() && capability.path.is_some() {
238                return Err(Error::validate(
239                    "\"path\" can only be specified when one `service` is supplied.",
240                ));
241            }
242            return Ok(Self::services_from(Self::get_one_or_many_names(
243                n,
244                None,
245                capability.capability_type().unwrap(),
246            )?));
247        } else if let Some(n) = capability.protocol() {
248            if n.is_many() && capability.path.is_some() {
249                return Err(Error::validate(
250                    "\"path\" can only be specified when one `protocol` is supplied.",
251                ));
252            }
253            return Ok(Self::protocols_from(Self::get_one_or_many_names(
254                n,
255                None,
256                capability.capability_type().unwrap(),
257            )?));
258        } else if let Some(n) = capability.directory() {
259            return Ok(Self::directories_from(Self::get_one_or_many_names(
260                n,
261                None,
262                capability.capability_type().unwrap(),
263            )?));
264        } else if let Some(n) = capability.storage() {
265            if capability.storage_id.is_none() {
266                return Err(Error::validate(
267                    "Storage declaration is missing \"storage_id\", but is required.",
268                ));
269            }
270            return Ok(Self::storages_from(Self::get_one_or_many_names(
271                n,
272                None,
273                capability.capability_type().unwrap(),
274            )?));
275        } else if let Some(n) = capability.runner() {
276            return Ok(Self::runners_from(Self::get_one_or_many_names(
277                n,
278                None,
279                capability.capability_type().unwrap(),
280            )?));
281        } else if let Some(n) = capability.resolver() {
282            return Ok(Self::resolvers_from(Self::get_one_or_many_names(
283                n,
284                None,
285                capability.capability_type().unwrap(),
286            )?));
287        } else if let Some(n) = capability.event_stream() {
288            return Ok(Self::event_streams_from(Self::get_one_or_many_names(
289                n,
290                None,
291                capability.capability_type().unwrap(),
292            )?));
293        } else if let Some(n) = capability.dictionary() {
294            return Ok(Self::dictionaries_from(Self::get_one_or_many_names(
295                n,
296                None,
297                capability.capability_type().unwrap(),
298            )?));
299        } else if let Some(n) = capability.config() {
300            return Ok(Self::configurations_from(Self::get_one_or_many_names(
301                n,
302                None,
303                capability.capability_type().unwrap(),
304            )?));
305        }
306
307        // Unsupported capability type.
308        let supported_keywords = capability
309            .supported()
310            .into_iter()
311            .map(|k| format!("\"{}\"", k))
312            .collect::<Vec<_>>()
313            .join(", ");
314        Err(Error::validate(format!(
315            "`{}` declaration is missing a capability keyword, one of: {}",
316            capability.decl_type(),
317            supported_keywords,
318        )))
319    }
320
321    /// Given an Offer or Expose clause, return the set of target identifiers.
322    ///
323    /// When only one capability identifier is specified, the target identifier name is derived
324    /// using the "as" clause. If an "as" clause is not specified, the target identifier is the
325    /// same name as the source.
326    ///
327    /// When multiple capability identifiers are specified, the target names are the same as the
328    /// source names.
329    pub fn from_offer_expose<T>(clause: &'a T) -> Result<Vec<Self>, Error>
330    where
331        T: CapabilityClause + AsClause + fmt::Debug,
332    {
333        // TODO: Validate that exactly one of these is set.
334        let alias = clause.r#as();
335        if let Some(n) = clause.service() {
336            return Ok(Self::services_from(Self::get_one_or_many_names(
337                n,
338                alias,
339                clause.capability_type().unwrap(),
340            )?));
341        } else if let Some(n) = clause.protocol() {
342            return Ok(Self::protocols_from(Self::get_one_or_many_names(
343                n,
344                alias,
345                clause.capability_type().unwrap(),
346            )?));
347        } else if let Some(n) = clause.directory() {
348            return Ok(Self::directories_from(Self::get_one_or_many_names(
349                n,
350                alias,
351                clause.capability_type().unwrap(),
352            )?));
353        } else if let Some(n) = clause.storage() {
354            return Ok(Self::storages_from(Self::get_one_or_many_names(
355                n,
356                alias,
357                clause.capability_type().unwrap(),
358            )?));
359        } else if let Some(n) = clause.runner() {
360            return Ok(Self::runners_from(Self::get_one_or_many_names(
361                n,
362                alias,
363                clause.capability_type().unwrap(),
364            )?));
365        } else if let Some(n) = clause.resolver() {
366            return Ok(Self::resolvers_from(Self::get_one_or_many_names(
367                n,
368                alias,
369                clause.capability_type().unwrap(),
370            )?));
371        } else if let Some(event_stream) = clause.event_stream() {
372            return Ok(Self::event_streams_from(Self::get_one_or_many_names(
373                event_stream,
374                alias,
375                clause.capability_type().unwrap(),
376            )?));
377        } else if let Some(n) = clause.dictionary() {
378            return Ok(Self::dictionaries_from(Self::get_one_or_many_names(
379                n,
380                alias,
381                clause.capability_type().unwrap(),
382            )?));
383        } else if let Some(n) = clause.config() {
384            return Ok(Self::configurations_from(Self::get_one_or_many_names(
385                n,
386                alias,
387                clause.capability_type().unwrap(),
388            )?));
389        }
390
391        // Unsupported capability type.
392        let supported_keywords = clause
393            .supported()
394            .into_iter()
395            .map(|k| format!("\"{}\"", k))
396            .collect::<Vec<_>>()
397            .join(", ");
398        Err(Error::validate(format!(
399            "`{}` declaration is missing a capability keyword, one of: {}",
400            clause.decl_type(),
401            supported_keywords,
402        )))
403    }
404
405    /// Returns the target names as a `Vec`  from a declaration with `names` and `alias` as a `Vec`.
406    fn get_one_or_many_names<'b>(
407        names: OneOrMany<&'b Name>,
408        alias: Option<&'b Name>,
409        capability_type: &str,
410    ) -> Result<Vec<&'b Name>, Error> {
411        let names: Vec<&Name> = names.into_iter().collect();
412        if names.len() == 1 {
413            Ok(vec![alias_or_name(alias, &names[0])])
414        } else {
415            if alias.is_some() {
416                return Err(Error::validate(format!(
417                    "\"as\" can only be specified when one `{}` is supplied.",
418                    capability_type,
419                )));
420            }
421            Ok(names)
422        }
423    }
424
425    /// Returns the target paths as a `Vec` from a `use` declaration with `names` and `alias`.
426    fn get_one_or_many_svc_paths(
427        names: OneOrMany<&Name>,
428        alias: Option<&Path>,
429        capability_type: &str,
430    ) -> Result<Vec<Path>, Error> {
431        let names: Vec<_> = names.into_iter().collect();
432        match (names.len(), alias) {
433            (_, None) => {
434                Ok(names.into_iter().map(|n| format!("/svc/{}", n).parse().unwrap()).collect())
435            }
436            (1, Some(alias)) => Ok(vec![alias.clone()]),
437            (_, Some(_)) => {
438                return Err(Error::validate(format!(
439                    "\"path\" can only be specified when one `{}` is supplied.",
440                    capability_type,
441                )));
442            }
443        }
444    }
445
446    capability_ids_from_names!(services_from, CapabilityId::Service);
447    capability_ids_from_names!(protocols_from, CapabilityId::Protocol);
448    capability_ids_from_names!(directories_from, CapabilityId::Directory);
449    capability_ids_from_names!(storages_from, CapabilityId::Storage);
450    capability_ids_from_names!(runners_from, CapabilityId::Runner);
451    capability_ids_from_names!(resolvers_from, CapabilityId::Resolver);
452    capability_ids_from_names!(event_streams_from, CapabilityId::EventStream);
453    capability_ids_from_names!(dictionaries_from, CapabilityId::Dictionary);
454    capability_ids_from_names!(configurations_from, CapabilityId::Configuration);
455    capability_ids_from_paths!(used_services_from, CapabilityId::UsedService);
456    capability_ids_from_paths!(used_protocols_from, CapabilityId::UsedProtocol);
457}
458
459impl fmt::Display for CapabilityId<'_> {
460    /// Return the string ID of this clause.
461    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
462        match self {
463            CapabilityId::Service(n)
464            | CapabilityId::Storage(n)
465            | CapabilityId::Runner(n)
466            | CapabilityId::UsedRunner(n)
467            | CapabilityId::Resolver(n)
468            | CapabilityId::EventStream(n)
469            | CapabilityId::Configuration(n)
470            | CapabilityId::UsedConfiguration(n)
471            | CapabilityId::Dictionary(n) => write!(f, "{}", n),
472            CapabilityId::UsedService(p)
473            | CapabilityId::UsedProtocol(p)
474            | CapabilityId::UsedDirectory(p)
475            | CapabilityId::UsedStorage(p)
476            | CapabilityId::UsedEventStream(p) => write!(f, "{}", p),
477            CapabilityId::Protocol(p) | CapabilityId::Directory(p) => write!(f, "{}", p),
478        }
479    }
480}
481
482/// A list of rights.
483#[derive(CheckedVec, Debug, PartialEq, Clone)]
484#[checked_vec(
485    expected = "a nonempty array of rights, with unique elements",
486    min_length = 1,
487    unique_items = true
488)]
489pub struct Rights(pub Vec<Right>);
490
491/// Generates deserializer for `OneOrMany<Name>`.
492#[derive(OneOrMany, Debug, Clone)]
493#[one_or_many(
494    expected = "a name or nonempty array of names, with unique elements",
495    inner_type = "Name",
496    min_length = 1,
497    unique_items = true
498)]
499pub struct OneOrManyNames;
500
501/// Generates deserializer for `OneOrMany<Path>`.
502#[derive(OneOrMany, Debug, Clone)]
503#[one_or_many(
504    expected = "a path or nonempty array of paths, with unique elements",
505    inner_type = "Path",
506    min_length = 1,
507    unique_items = true
508)]
509pub struct OneOrManyPaths;
510
511/// Generates deserializer for `OneOrMany<ExposeFromRef>`.
512#[derive(OneOrMany, Debug, Clone)]
513#[one_or_many(
514    expected = "one or an array of \"framework\", \"self\", \"#<child-name>\", or a dictionary path",
515    inner_type = "ExposeFromRef",
516    min_length = 1,
517    unique_items = true
518)]
519pub struct OneOrManyExposeFromRefs;
520
521/// Generates deserializer for `OneOrMany<OfferToRef>`.
522#[derive(OneOrMany, Debug, Clone)]
523#[one_or_many(
524    expected = "one or an array of \"#<child-name>\", \"#<collection-name>\", or \"self/<dictionary>\", with unique elements",
525    inner_type = "OfferToRef",
526    min_length = 1,
527    unique_items = true
528)]
529pub struct OneOrManyOfferToRefs;
530
531/// Generates deserializer for `OneOrMany<OfferFromRef>`.
532#[derive(OneOrMany, Debug, Clone)]
533#[one_or_many(
534    expected = "one or an array of \"parent\", \"framework\", \"self\", \"#<child-name>\", \"#<collection-name>\", or a dictionary path",
535    inner_type = "OfferFromRef",
536    min_length = 1,
537    unique_items = true
538)]
539pub struct OneOrManyOfferFromRefs;
540
541/// Generates deserializer for `OneOrMany<UseFromRef>`.
542#[derive(OneOrMany, Debug, Clone)]
543#[one_or_many(
544    expected = "one or an array of \"#<collection-name>\", or \"#<child-name>\"",
545    inner_type = "EventScope",
546    min_length = 1,
547    unique_items = true
548)]
549pub struct OneOrManyEventScope;
550
551/// The stop timeout configured in an environment.
552#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
553pub struct StopTimeoutMs(pub u32);
554
555impl<'de> de::Deserialize<'de> for StopTimeoutMs {
556    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
557    where
558        D: de::Deserializer<'de>,
559    {
560        struct Visitor;
561
562        impl<'de> de::Visitor<'de> for Visitor {
563            type Value = StopTimeoutMs;
564
565            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
566                f.write_str("an unsigned 32-bit integer")
567            }
568
569            fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
570            where
571                E: de::Error,
572            {
573                if v < 0 || v > i64::from(u32::max_value()) {
574                    return Err(E::invalid_value(
575                        de::Unexpected::Signed(v),
576                        &"an unsigned 32-bit integer",
577                    ));
578                }
579                Ok(StopTimeoutMs(v as u32))
580            }
581
582            fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
583            where
584                E: de::Error,
585            {
586                self.visit_i64(value as i64)
587            }
588        }
589
590        deserializer.deserialize_i64(Visitor)
591    }
592}
593
594/// A relative reference to another object. This is a generic type that can encode any supported
595/// reference subtype. For named references, it holds a reference to the name instead of the name
596/// itself.
597///
598/// Objects of this type are usually derived from conversions of context-specific reference
599/// types that `#[derive(Reference)]`. This type makes it easy to write helper functions that operate on
600/// generic references.
601#[derive(Debug, PartialEq, Eq, Hash, Clone)]
602pub enum AnyRef<'a> {
603    /// A named reference. Parsed as `#name`.
604    Named(&'a Name),
605    /// A reference to the parent. Parsed as `parent`.
606    Parent,
607    /// A reference to the framework (component manager). Parsed as `framework`.
608    Framework,
609    /// A reference to the debug. Parsed as `debug`.
610    Debug,
611    /// A reference to this component. Parsed as `self`.
612    Self_,
613    /// An intentionally omitted reference.
614    Void,
615    /// A reference to a dictionary. Parsed as a dictionary path.
616    Dictionary(&'a DictionaryRef),
617    /// A reference to a dictionary defined by this component. Parsed as
618    /// `self/<dictionary>`.
619    OwnDictionary(&'a Name),
620}
621
622/// Format an `AnyRef` as a string.
623impl fmt::Display for AnyRef<'_> {
624    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
625        match self {
626            Self::Named(name) => write!(f, "#{}", name),
627            Self::Parent => write!(f, "parent"),
628            Self::Framework => write!(f, "framework"),
629            Self::Debug => write!(f, "debug"),
630            Self::Self_ => write!(f, "self"),
631            Self::Void => write!(f, "void"),
632            Self::Dictionary(d) => write!(f, "{}", d),
633            Self::OwnDictionary(name) => write!(f, "self/{}", name),
634        }
635    }
636}
637
638/// A reference in a `use from`.
639#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
640#[reference(
641    expected = "\"parent\", \"framework\", \"debug\", \"self\", \"#<capability-name>\", \"#<child-name>\", \"#<collection-name>\", dictionary path, or none"
642)]
643pub enum UseFromRef {
644    /// A reference to the parent.
645    Parent,
646    /// A reference to the framework.
647    Framework,
648    /// A reference to debug.
649    Debug,
650    /// A reference to a child, collection, or a capability declared on self.
651    ///
652    /// A reference to a capability must be one of the following:
653    /// - A dictionary capability.
654    /// - A protocol that references a storage capability declared in the same component,
655    ///   which will cause the framework to host a fuchsia.sys2.StorageAdmin protocol for the
656    ///   component.
657    ///
658    /// A reference to a collection must be a service capability.
659    ///
660    /// This cannot be used to directly access capabilities that a component itself declares.
661    Named(Name),
662    /// A reference to this component.
663    Self_,
664    /// A reference to a dictionary.
665    Dictionary(DictionaryRef),
666}
667
668/// The scope of an event.
669#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference, Ord, PartialOrd)]
670#[reference(expected = "\"#<collection-name>\", \"#<child-name>\", or none")]
671pub enum EventScope {
672    /// A reference to a child or a collection.
673    Named(Name),
674}
675
676/// A reference in an `expose from`.
677#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
678#[reference(expected = "\"framework\", \"self\", \"void\", or \"#<child-name>\"")]
679pub enum ExposeFromRef {
680    /// A reference to a child or collection.
681    Named(Name),
682    /// A reference to the framework.
683    Framework,
684    /// A reference to this component.
685    Self_,
686    /// An intentionally omitted source.
687    Void,
688    /// A reference to a dictionary.
689    Dictionary(DictionaryRef),
690}
691
692/// A reference in an `expose to`.
693#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
694#[reference(expected = "\"parent\", \"framework\", or none")]
695pub enum ExposeToRef {
696    /// A reference to the parent.
697    Parent,
698    /// A reference to the framework.
699    Framework,
700}
701
702/// A reference in an `offer from`.
703#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
704#[reference(
705    expected = "\"parent\", \"framework\", \"self\", \"void\", \"#<child-name>\", or a dictionary path"
706)]
707pub enum OfferFromRef {
708    /// A reference to a child or collection.
709    Named(Name),
710    /// A reference to the parent.
711    Parent,
712    /// A reference to the framework.
713    Framework,
714    /// A reference to this component.
715    Self_,
716    /// An intentionally omitted source.
717    Void,
718    /// A reference to a dictionary.
719    Dictionary(DictionaryRef),
720}
721
722impl OfferFromRef {
723    pub fn is_named(&self) -> bool {
724        match self {
725            OfferFromRef::Named(_) => true,
726            _ => false,
727        }
728    }
729}
730
731/// A reference in an `offer to`.
732#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
733#[reference(expected = "\"#<child-name>\", \"#<collection-name>\", or \"self/<dictionary>\"")]
734pub enum OfferToRef {
735    /// A reference to a child or collection.
736    Named(Name),
737
738    /// Syntax sugar that results in the offer decl applying to all children and collections
739    All,
740
741    /// A reference to a dictionary defined by this component, the form "self/<dictionary>".
742    OwnDictionary(Name),
743}
744
745/// A reference in an `offer to`.
746#[derive(Debug, Deserialize, PartialEq, Eq, Hash, Clone, Serialize)]
747#[serde(rename_all = "snake_case")]
748pub enum SourceAvailability {
749    Required,
750    Unknown,
751}
752
753impl Default for SourceAvailability {
754    fn default() -> Self {
755        Self::Required
756    }
757}
758
759/// A reference in an environment.
760#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
761#[reference(expected = "\"#<environment-name>\"")]
762pub enum EnvironmentRef {
763    /// A reference to an environment defined in this component.
764    Named(Name),
765}
766
767/// A reference in a `storage from`.
768#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
769#[reference(expected = "\"parent\", \"self\", or \"#<child-name>\"")]
770pub enum CapabilityFromRef {
771    /// A reference to a child.
772    Named(Name),
773    /// A reference to the parent.
774    Parent,
775    /// A reference to this component.
776    Self_,
777}
778
779/// A reference to a (possibly nested) dictionary.
780#[derive(Debug, PartialEq, Eq, Hash, Clone)]
781pub struct DictionaryRef {
782    /// Path to the dictionary relative to `root_dictionary`.
783    pub path: RelativePath,
784    pub root: RootDictionaryRef,
785}
786
787impl<'a> From<&'a DictionaryRef> for AnyRef<'a> {
788    fn from(r: &'a DictionaryRef) -> Self {
789        Self::Dictionary(r)
790    }
791}
792
793impl FromStr for DictionaryRef {
794    type Err = ParseError;
795
796    fn from_str(path: &str) -> Result<Self, ParseError> {
797        match path.find('/') {
798            Some(n) => {
799                let root = path[..n].parse().map_err(|_| ParseError::InvalidValue)?;
800                let path = RelativePath::new(&path[n + 1..])?;
801                Ok(Self { root, path })
802            }
803            None => Err(ParseError::InvalidValue),
804        }
805    }
806}
807
808impl fmt::Display for DictionaryRef {
809    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
810        write!(f, "{}/{}", self.root, self.path)
811    }
812}
813
814impl ser::Serialize for DictionaryRef {
815    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
816    where
817        S: serde::ser::Serializer,
818    {
819        format!("{}", self).serialize(serializer)
820    }
821}
822
823const DICTIONARY_REF_EXPECT_STR: &str = "a path to a dictionary no more \
824    than 4095 characters in length";
825
826impl<'de> de::Deserialize<'de> for DictionaryRef {
827    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
828    where
829        D: de::Deserializer<'de>,
830    {
831        struct Visitor;
832
833        impl<'de> de::Visitor<'de> for Visitor {
834            type Value = DictionaryRef;
835
836            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
837                f.write_str(DICTIONARY_REF_EXPECT_STR)
838            }
839
840            fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
841            where
842                E: de::Error,
843            {
844                s.parse().map_err(|err| match err {
845                    ParseError::InvalidValue => {
846                        E::invalid_value(de::Unexpected::Str(s), &DICTIONARY_REF_EXPECT_STR)
847                    }
848                    ParseError::TooLong | ParseError::Empty => {
849                        E::invalid_length(s.len(), &DICTIONARY_REF_EXPECT_STR)
850                    }
851                    e => {
852                        panic!("unexpected parse error: {:?}", e);
853                    }
854                })
855            }
856        }
857
858        deserializer.deserialize_string(Visitor)
859    }
860}
861
862/// A reference to a root dictionary.
863#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
864#[reference(expected = "\"parent\", \"self\", \"#<child-name>\"")]
865pub enum RootDictionaryRef {
866    /// A reference to a child.
867    Named(Name),
868    /// A reference to the parent.
869    Parent,
870    /// A reference to this component.
871    Self_,
872}
873
874/// A reference in an environment registration.
875#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
876#[reference(expected = "\"parent\", \"self\", or \"#<child-name>\"")]
877pub enum RegistrationRef {
878    /// A reference to a child.
879    Named(Name),
880    /// A reference to the parent.
881    Parent,
882    /// A reference to this component.
883    Self_,
884}
885
886/// A right or bundle of rights to apply to a directory.
887#[derive(Deserialize, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
888#[serde(rename_all = "snake_case")]
889pub enum Right {
890    // Individual
891    Connect,
892    Enumerate,
893    Execute,
894    GetAttributes,
895    ModifyDirectory,
896    ReadBytes,
897    Traverse,
898    UpdateAttributes,
899    WriteBytes,
900
901    // Aliass
902    #[serde(rename = "r*")]
903    ReadAlias,
904    #[serde(rename = "w*")]
905    WriteAlias,
906    #[serde(rename = "x*")]
907    ExecuteAlias,
908    #[serde(rename = "rw*")]
909    ReadWriteAlias,
910    #[serde(rename = "rx*")]
911    ReadExecuteAlias,
912}
913
914impl fmt::Display for Right {
915    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
916        let s = match self {
917            Self::Connect => "connect",
918            Self::Enumerate => "enumerate",
919            Self::Execute => "execute",
920            Self::GetAttributes => "get_attributes",
921            Self::ModifyDirectory => "modify_directory",
922            Self::ReadBytes => "read_bytes",
923            Self::Traverse => "traverse",
924            Self::UpdateAttributes => "update_attributes",
925            Self::WriteBytes => "write_bytes",
926            Self::ReadAlias => "r*",
927            Self::WriteAlias => "w*",
928            Self::ExecuteAlias => "x*",
929            Self::ReadWriteAlias => "rw*",
930            Self::ReadExecuteAlias => "rx*",
931        };
932        write!(f, "{}", s)
933    }
934}
935
936impl Right {
937    /// Expands this right or bundle or rights into a list of `fio::Operations`.
938    pub fn expand(&self) -> Vec<fio::Operations> {
939        match self {
940            Self::Connect => vec![fio::Operations::CONNECT],
941            Self::Enumerate => vec![fio::Operations::ENUMERATE],
942            Self::Execute => vec![fio::Operations::EXECUTE],
943            Self::GetAttributes => vec![fio::Operations::GET_ATTRIBUTES],
944            Self::ModifyDirectory => vec![fio::Operations::MODIFY_DIRECTORY],
945            Self::ReadBytes => vec![fio::Operations::READ_BYTES],
946            Self::Traverse => vec![fio::Operations::TRAVERSE],
947            Self::UpdateAttributes => vec![fio::Operations::UPDATE_ATTRIBUTES],
948            Self::WriteBytes => vec![fio::Operations::WRITE_BYTES],
949            Self::ReadAlias => vec![
950                fio::Operations::CONNECT,
951                fio::Operations::ENUMERATE,
952                fio::Operations::TRAVERSE,
953                fio::Operations::READ_BYTES,
954                fio::Operations::GET_ATTRIBUTES,
955            ],
956            Self::WriteAlias => vec![
957                fio::Operations::CONNECT,
958                fio::Operations::ENUMERATE,
959                fio::Operations::TRAVERSE,
960                fio::Operations::WRITE_BYTES,
961                fio::Operations::MODIFY_DIRECTORY,
962                fio::Operations::UPDATE_ATTRIBUTES,
963            ],
964            Self::ExecuteAlias => vec![
965                fio::Operations::CONNECT,
966                fio::Operations::ENUMERATE,
967                fio::Operations::TRAVERSE,
968                fio::Operations::EXECUTE,
969            ],
970            Self::ReadWriteAlias => vec![
971                fio::Operations::CONNECT,
972                fio::Operations::ENUMERATE,
973                fio::Operations::TRAVERSE,
974                fio::Operations::READ_BYTES,
975                fio::Operations::WRITE_BYTES,
976                fio::Operations::MODIFY_DIRECTORY,
977                fio::Operations::GET_ATTRIBUTES,
978                fio::Operations::UPDATE_ATTRIBUTES,
979            ],
980            Self::ReadExecuteAlias => vec![
981                fio::Operations::CONNECT,
982                fio::Operations::ENUMERATE,
983                fio::Operations::TRAVERSE,
984                fio::Operations::READ_BYTES,
985                fio::Operations::GET_ATTRIBUTES,
986                fio::Operations::EXECUTE,
987            ],
988        }
989    }
990}
991
992/// # Component manifest (`.cml`) reference
993///
994/// A `.cml` file contains a single json5 object literal with the keys below.
995///
996/// Where string values are expected, a list of valid values is generally documented.
997/// The following string value types are reused and must follow specific rules.
998///
999/// The `.cml` file is compiled into a FIDL wire format (`.cm`) file.
1000///
1001/// ## String types
1002///
1003/// ### Names {#names}
1004///
1005/// Both capabilities and a component's children are named. A name string may
1006/// consist of one or more of the following characters: `A-Z`, `a-z`, `0-9`,
1007/// `_`, `.`, `-`. It must not exceed 255 characters in length and may not start
1008/// with `.` or `-`.
1009///
1010/// ### Paths {#paths}
1011///
1012/// Paths are sequences of [names](#names) delimited by the `/` character. A path
1013/// must not exceed 4095 characters in length. Throughout the document,
1014///
1015/// - Relative paths cannot start with the `/` character.
1016/// - Namespace and outgoing directory paths must start with the `/` character.
1017///
1018/// ### References {#references}
1019///
1020/// A reference string takes the form of `#<name>`, where `<name>` refers to the name of a child:
1021///
1022/// - A [static child instance][doc-static-children] whose name is
1023///     `<name>`, or
1024/// - A [collection][doc-collections] whose name is `<name>`.
1025///
1026/// [doc-static-children]: /docs/concepts/components/v2/realms.md#static-children
1027/// [doc-collections]: /docs/concepts/components/v2/realms.md#collections
1028/// [doc-protocol]: /docs/concepts/components/v2/capabilities/protocol.md
1029/// [doc-dictionaries]: /reference/fidl/fuchsia.component.decl#Dictionary
1030/// [doc-directory]: /docs/concepts/components/v2/capabilities/directory.md
1031/// [doc-storage]: /docs/concepts/components/v2/capabilities/storage.md
1032/// [doc-resolvers]: /docs/concepts/components/v2/capabilities/resolver.md
1033/// [doc-runners]: /docs/concepts/components/v2/capabilities/runner.md
1034/// [doc-event]: /docs/concepts/components/v2/capabilities/event.md
1035/// [doc-service]: /docs/concepts/components/v2/capabilities/service.md
1036/// [doc-directory-rights]: /docs/concepts/components/v2/capabilities/directory.md#directory-capability-rights
1037///
1038/// ## Top-level keys {#document}
1039#[derive(ReferenceDoc, Deserialize, Debug, Default, PartialEq, Serialize)]
1040#[serde(deny_unknown_fields)]
1041pub struct Document {
1042    /// The optional `include` property describes zero or more other component manifest
1043    /// files to be merged into this component manifest. For example:
1044    ///
1045    /// ```json5
1046    /// include: [ "syslog/client.shard.cml" ]
1047    /// ```
1048    ///
1049    /// In the example given above, the component manifest is including contents from a
1050    /// manifest shard provided by the `syslog` library, thus ensuring that the
1051    /// component functions correctly at runtime if it attempts to write to `syslog`. By
1052    /// convention such files are called "manifest shards" and end with `.shard.cml`.
1053    ///
1054    /// Include paths prepended with `//` are relative to the source root of the Fuchsia
1055    /// checkout. However, include paths not prepended with `//`, as in the example
1056    /// above, are resolved from Fuchsia SDK libraries (`//sdk/lib`) that export
1057    /// component manifest shards.
1058    ///
1059    /// For reference, inside the Fuchsia checkout these two include paths are
1060    /// equivalent:
1061    ///
1062    /// * `syslog/client.shard.cml`
1063    /// * `//sdk/lib/syslog/client.shard.cml`
1064    ///
1065    /// You can review the outcome of merging any and all includes into a component
1066    /// manifest file by invoking the following command:
1067    ///
1068    /// Note: The `fx` command below is for developers working in a Fuchsia source
1069    /// checkout environment.
1070    ///
1071    /// ```sh
1072    /// fx cmc include {{ "<var>" }}cml_file{{ "</var>" }} --includeroot $FUCHSIA_DIR --includepath $FUCHSIA_DIR/sdk/lib
1073    /// ```
1074    ///
1075    /// Includes can cope with duplicate [`use`], [`offer`], [`expose`], or [`capabilities`]
1076    /// declarations referencing the same capability, as long as the properties are the same. For
1077    /// example:
1078    ///
1079    /// ```json5
1080    /// // my_component.cml
1081    /// include: [ "syslog.client.shard.cml" ]
1082    /// use: [
1083    ///     {
1084    ///         protocol: [
1085    ///             "fuchsia.posix.socket.Provider",
1086    ///         ],
1087    ///     },
1088    /// ],
1089    ///
1090    /// // syslog.client.shard.cml
1091    /// use: [
1092    ///     { protocol: "fuchsia.logger.LogSink", from: "parent/diagnostics" },
1093    /// ],
1094    /// ```
1095    ///
1096    /// In this example, the contents of the merged file will be the same as my_component.cml --
1097    /// `fuchsia.logger.LogSink` is deduped.
1098    ///
1099    /// However, this would fail to compile:
1100    ///
1101    /// ```json5
1102    /// // my_component.cml
1103    /// include: [ "syslog.client.shard.cml" ]
1104    /// use: [
1105    ///     {
1106    ///         protocol: "fuchsia.logger.LogSink",
1107    ///         // properties for fuchsia.logger.LogSink don't match
1108    ///         from: "#archivist",
1109    ///     },
1110    /// ],
1111    ///
1112    /// // syslog.client.shard.cml
1113    /// use: [
1114    ///     { protocol: "fuchsia.logger.LogSink" },
1115    /// ],
1116    /// ```
1117    ///
1118    /// An exception to this constraint is the `availability` property. If two routing declarations
1119    /// are identical, and one availability is stronger than the other, the availability will be
1120    /// "promoted" to the stronger value (if `availability` is missing, it defaults to `required`).
1121    /// For example:
1122    ///
1123    /// ```json5
1124    /// // my_component.cml
1125    /// include: [ "syslog.client.shard.cml" ]
1126    /// use: [
1127    ///     {
1128    ///         protocol: [
1129    ///             "fuchsia.logger.LogSink",
1130    ///             "fuchsia.posix.socket.Provider",
1131    ///         ],
1132    ///         from: "parent/diagnostics",
1133    ///         availability: "optional",
1134    ///     },
1135    /// ],
1136    ///
1137    /// // syslog.client.shard.cml
1138    /// use: [
1139    ///     {
1140    ///         protocol: "fuchsia.logger.LogSink"
1141    ///         availability: "required",  // This is the default
1142    ///         from: "parent/diagnostics",
1143    ///     },
1144    /// ],
1145    /// ```
1146    ///
1147    /// Becomes:
1148    ///
1149    /// ```json5
1150    /// use: [
1151    ///     {
1152    ///         protocol: "fuchsia.posix.socket.Provider",
1153    ///         availability: "optional",
1154    ///     },
1155    ///     {
1156    ///         protocol: "fuchsia.logger.LogSink",
1157    ///         availability: "required",
1158    ///         from: "parent/diagnostics",
1159    ///     },
1160    /// ],
1161    /// ```
1162    ///
1163    /// Includes are transitive, meaning that shards can have their own includes.
1164    ///
1165    /// Include paths can have diamond dependencies. For instance this is valid:
1166    /// A includes B, A includes C, B includes D, C includes D.
1167    /// In this case A will transitively include B, C, D.
1168    ///
1169    /// Include paths cannot have cycles. For instance this is invalid:
1170    /// A includes B, B includes A.
1171    /// A cycle such as the above will result in a compile-time error.
1172    ///
1173    /// [`use`]: #use
1174    /// [`offer`]: #offer
1175    /// [`expose`]: #expose
1176    /// [`capabilities`]: #capabilities
1177    #[serde(skip_serializing_if = "Option::is_none")]
1178    pub include: Option<Vec<String>>,
1179
1180    /// Components that are executable include a `program` section. The `program`
1181    /// section must set the `runner` property to select a [runner][doc-runners] to run
1182    /// the component. The format of the rest of the `program` section is determined by
1183    /// that particular runner.
1184    ///
1185    /// # ELF runners {#elf-runners}
1186    ///
1187    /// If the component uses the ELF runner, `program` must include the following
1188    /// properties, at a minimum:
1189    ///
1190    /// - `runner`: must be set to `"elf"`
1191    /// - `binary`: Package-relative path to the executable binary
1192    /// - `args` _(optional)_: List of arguments
1193    ///
1194    /// Example:
1195    ///
1196    /// ```json5
1197    /// program: {
1198    ///     runner: "elf",
1199    ///     binary: "bin/hippo",
1200    ///     args: [ "Hello", "hippos!" ],
1201    /// },
1202    /// ```
1203    ///
1204    /// For a complete list of properties, see: [ELF Runner](/docs/concepts/components/v2/elf_runner.md)
1205    ///
1206    /// # Other runners {#other-runners}
1207    ///
1208    /// If a component uses a custom runner, values inside the `program` stanza other
1209    /// than `runner` are specific to the runner. The runner receives the arguments as a
1210    /// dictionary of key and value pairs. Refer to the specific runner being used to
1211    /// determine what keys it expects to receive, and how it interprets them.
1212    ///
1213    /// [doc-runners]: /docs/concepts/components/v2/capabilities/runner.md
1214    #[reference_doc(json_type = "object")]
1215    #[serde(skip_serializing_if = "Option::is_none")]
1216    pub program: Option<Program>,
1217
1218    /// The `children` section declares child component instances as described in
1219    /// [Child component instances][doc-children].
1220    ///
1221    /// [doc-children]: /docs/concepts/components/v2/realms.md#child-component-instances
1222    #[reference_doc(recurse)]
1223    #[serde(skip_serializing_if = "Option::is_none")]
1224    pub children: Option<Vec<Child>>,
1225
1226    /// The `collections` section declares collections as described in
1227    /// [Component collections][doc-collections].
1228    #[reference_doc(recurse)]
1229    #[serde(skip_serializing_if = "Option::is_none")]
1230    pub collections: Option<Vec<Collection>>,
1231
1232    /// The `environments` section declares environments as described in
1233    /// [Environments][doc-environments].
1234    ///
1235    /// [doc-environments]: /docs/concepts/components/v2/environments.md
1236    #[reference_doc(recurse)]
1237    #[serde(skip_serializing_if = "Option::is_none")]
1238    pub environments: Option<Vec<Environment>>,
1239
1240    /// The `capabilities` section defines capabilities that are provided by this component.
1241    /// Capabilities that are [offered](#offer) or [exposed](#expose) from `self` must be declared
1242    /// here.
1243    ///
1244    /// # Capability fields
1245    ///
1246    /// This supports the following capability keys. Exactly one of these must be set:
1247    ///
1248    /// - `protocol`: (_optional `string or array of strings`_)
1249    /// - `service`: (_optional `string or array of strings`_)
1250    /// - `directory`: (_optional `string`_)
1251    /// - `storage`: (_optional `string`_)
1252    /// - `runner`: (_optional `string`_)
1253    /// - `resolver`: (_optional `string`_)
1254    /// - `event_stream`: (_optional `string or array of strings`_)
1255    /// - `dictionary`: (_optional `string`_)
1256    /// - `config`: (_optional `string`_)
1257    ///
1258    /// # Additional fields
1259    ///
1260    /// This supports the following additional fields:
1261    /// [glossary.outgoing directory]: /docs/glossary/README.md#outgoing-directory
1262    #[reference_doc(recurse)]
1263    #[serde(skip_serializing_if = "Option::is_none")]
1264    pub capabilities: Option<Vec<Capability>>,
1265
1266    /// For executable components, declares capabilities that this
1267    /// component requires in its [namespace][glossary.namespace] at runtime.
1268    /// Capabilities are routed from the `parent` unless otherwise specified,
1269    /// and each capability must have a valid route through all components between
1270    /// this component and the capability's source.
1271    ///
1272    /// # Capability fields
1273    ///
1274    /// This supports the following capability keys. Exactly one of these must be set:
1275    ///
1276    /// - `service`: (_optional `string or array of strings`_)
1277    /// - `directory`: (_optional `string`_)
1278    /// - `protocol`: (_optional `string or array of strings`_)
1279    /// - `dictionary`: (_optional `string`_)
1280    /// - `storage`: (_optional `string`_)
1281    /// - `event_stream`: (_optional `string or array of strings`_)
1282    /// - `runner`: (_optional `string`_)
1283    /// - `config`: (_optional `string`_)
1284    ///
1285    /// # Additional fields
1286    ///
1287    /// This supports the following additional fields:
1288    /// [glossary.namespace]: /docs/glossary/README.md#namespace
1289    #[reference_doc(recurse)]
1290    #[serde(skip_serializing_if = "Option::is_none")]
1291    pub r#use: Option<Vec<Use>>,
1292
1293    /// Declares the capabilities that are made available to the parent component or to the
1294    /// framework. It is valid to `expose` from `self` or from a child component.
1295    ///
1296    /// # Capability fields
1297    ///
1298    /// This supports the following capability keys. Exactly one of these must be set:
1299    ///
1300    /// - `service`: (_optional `string or array of strings`_)
1301    /// - `protocol`: (_optional `string or array of strings`_)
1302    /// - `directory`: (_optional `string`_)
1303    /// - `runner`: (_optional `string`_)
1304    /// - `resolver`: (_optional `string`_)
1305    /// - `dictionary`: (_optional `string`_)
1306    /// - `config`: (_optional `string`_)
1307    ///
1308    /// # Additional fields
1309    ///
1310    /// This supports the following additional fields:
1311    #[reference_doc(recurse)]
1312    #[serde(skip_serializing_if = "Option::is_none")]
1313    pub expose: Option<Vec<Expose>>,
1314
1315    /// Declares the capabilities that are made available to a [child component][doc-children]
1316    /// instance or a [child collection][doc-collections].
1317    ///
1318    /// # Capability fields
1319    ///
1320    /// This supports the following capability keys. Exactly one of these must be set:
1321    ///
1322    /// - `protocol`: (_optional `string or array of strings`_)
1323    /// - `service`: (_optional `string or array of strings`_)
1324    /// - `directory`: (_optional `string`_)
1325    /// - `storage`: (_optional `string`_)
1326    /// - `runner`: (_optional `string`_)
1327    /// - `resolver`: (_optional `string`_)
1328    /// - `event_stream`: (_optional `string or array of strings`_)
1329    /// - `dictionary`: (_optional `string`_)
1330    /// - `config`: (_optional `string`_)
1331    ///
1332    /// # Additional fields
1333    ///
1334    /// This supports the following additional fields:
1335    #[reference_doc(recurse)]
1336    #[serde(skip_serializing_if = "Option::is_none")]
1337    pub offer: Option<Vec<Offer>>,
1338
1339    /// Contains metadata that components may interpret for their own purposes. The component
1340    /// framework enforces no schema for this section, but third parties may expect their facets to
1341    /// adhere to a particular schema.
1342    #[serde(skip_serializing_if = "Option::is_none")]
1343    pub facets: Option<IndexMap<String, Value>>,
1344
1345    /// The configuration schema as defined by a component. Each key represents a single field
1346    /// in the schema.
1347    ///
1348    /// Configuration fields are JSON objects and must define a `type` which can be one of the
1349    /// following strings:
1350    /// `bool`, `uint8`, `int8`, `uint16`, `int16`, `uint32`, `int32`, `uint64`, `int64`,
1351    /// `string`, `vector`
1352    ///
1353    /// Example:
1354    ///
1355    /// ```json5
1356    /// config: {
1357    ///     debug_mode: {
1358    ///         type: "bool"
1359    ///     },
1360    /// }
1361    /// ```
1362    ///
1363    /// Fields are resolved from a component's package by default. To be able to change the values
1364    /// at runtime a `mutability` specifier is required.
1365    ///
1366    /// Example:
1367    ///
1368    /// ```json5
1369    /// config: {
1370    ///     verbose: {
1371    ///         type: "bool",
1372    ///         mutability: [ "parent" ],
1373    ///     },
1374    /// },
1375    /// ```
1376    ///
1377    /// Currently `"parent"` is the only mutability specifier supported.
1378    ///
1379    /// Strings must define the `max_size` property as a non-zero integer.
1380    ///
1381    /// Example:
1382    ///
1383    /// ```json5
1384    /// config: {
1385    ///     verbosity: {
1386    ///         type: "string",
1387    ///         max_size: 20,
1388    ///     }
1389    /// }
1390    /// ```
1391    ///
1392    /// Vectors must set the `max_count` property as a non-zero integer. Vectors must also set the
1393    /// `element` property as a JSON object which describes the element being contained in the
1394    /// vector. Vectors can contain booleans, integers, and strings but cannot contain other
1395    /// vectors.
1396    ///
1397    /// Example:
1398    ///
1399    /// ```json5
1400    /// config: {
1401    ///     tags: {
1402    ///         type: "vector",
1403    ///         max_count: 20,
1404    ///         element: {
1405    ///             type: "string",
1406    ///             max_size: 50,
1407    ///         }
1408    ///     }
1409    /// }
1410    /// ```
1411    #[reference_doc(json_type = "object")]
1412    #[serde(skip_serializing_if = "Option::is_none")]
1413    // NB: Unlike other maps the order of these fields matters for the ABI of generated config
1414    // libraries. Rather than insertion order, we explicitly sort the fields here to dissuade
1415    // developers from taking a dependency on the source ordering in their manifest. In the future
1416    // this will hopefully make it easier to pursue layout size optimizations.
1417    pub config: Option<BTreeMap<ConfigKey, ConfigValueType>>,
1418}
1419
1420impl<T> Canonicalize for Vec<T>
1421where
1422    T: Canonicalize + CapabilityClause + PathClause,
1423{
1424    fn canonicalize(&mut self) {
1425        // Collapse like-entries into one. Like entries are those that are equal in all fields
1426        // but their capability names. Accomplish this by collecting all the names into a vector
1427        // keyed by an instance of T with its names removed.
1428        let mut to_merge: Vec<(T, Vec<Name>)> = vec![];
1429        let mut to_keep: Vec<T> = vec![];
1430        self.iter().for_each(|c| {
1431            // Any entry with a `path` set cannot be merged with another.
1432            if !c.are_many_names_allowed() || c.path().is_some() {
1433                to_keep.push(c.clone());
1434                return;
1435            }
1436            let mut names = c.names().into_iter().cloned().collect();
1437            let mut copy = c.clone();
1438            copy.set_names(vec![Name::from_str("a").unwrap()]); // The name here is arbitrary.
1439            let r = to_merge.iter().position(|(t, _)| t == &copy);
1440            match r {
1441                Some(i) => to_merge[i].1.append(&mut names),
1442                None => to_merge.push((copy, names)),
1443            };
1444        });
1445        let mut merged = to_merge
1446            .into_iter()
1447            .map(|(mut t, names)| {
1448                t.set_names(names);
1449                t
1450            })
1451            .collect::<Vec<_>>();
1452        to_keep.append(&mut merged);
1453        *self = to_keep;
1454
1455        self.iter_mut().for_each(|c| c.canonicalize());
1456        self.sort_by(|a, b| {
1457            // Sort by capability type, then by the name of the first entry for
1458            // that type.
1459            let a_type = a.capability_type().unwrap();
1460            let b_type = b.capability_type().unwrap();
1461            a_type.cmp(b_type).then_with(|| {
1462                let a_names = a.names();
1463                let b_names = b.names();
1464                let a_first_name = a_names.first().unwrap();
1465                let b_first_name = b_names.first().unwrap();
1466                a_first_name.cmp(b_first_name)
1467            })
1468        });
1469    }
1470}
1471
1472/// Merges `us` into `other` according to the rules documented for [`include`].
1473/// [`include`]: #include
1474fn merge_from_capability_field<T: CapabilityClause>(
1475    us: &mut Option<Vec<T>>,
1476    other: &mut Option<Vec<T>>,
1477) -> Result<(), Error> {
1478    // Empty entries are an error, and merging removes empty entries so we first need to check
1479    // for them.
1480    for entry in us.iter().flatten().chain(other.iter().flatten()) {
1481        if entry.names().is_empty() {
1482            return Err(Error::Validate {
1483                err: format!("{}: Missing type name: {:#?}", entry.decl_type(), entry),
1484                filename: None,
1485            });
1486        }
1487    }
1488
1489    if let Some(all_ours) = us.as_mut() {
1490        if let Some(all_theirs) = other.take() {
1491            for mut theirs in all_theirs {
1492                for ours in &mut *all_ours {
1493                    compute_diff(ours, &mut theirs);
1494                }
1495                all_ours.push(theirs);
1496            }
1497        }
1498        // Post-filter step: remove empty entries.
1499        all_ours.retain(|ours| !ours.names().is_empty())
1500    } else if let Some(theirs) = other.take() {
1501        us.replace(theirs);
1502    }
1503    Ok(())
1504}
1505
1506/// Merges `us` into `other` according to the rules documented for [`include`].
1507/// [`include`]: #include
1508fn merge_from_other_field<T: std::cmp::PartialEq>(
1509    us: &mut Option<Vec<T>>,
1510    other: &mut Option<Vec<T>>,
1511) {
1512    if let Some(ref mut ours) = us {
1513        if let Some(theirs) = other.take() {
1514            // Add their elements, ignoring dupes with ours
1515            for t in theirs {
1516                if !ours.contains(&t) {
1517                    ours.push(t);
1518                }
1519            }
1520        }
1521    } else if let Some(theirs) = other.take() {
1522        us.replace(theirs);
1523    }
1524}
1525
1526/// Subtracts the capabilities in `ours` from `theirs` if the declarations match in their type and
1527/// other fields, resulting in the removal of duplicates between `ours` and `theirs`. Stores the
1528/// result in `theirs`.
1529///
1530/// Inexact matches on `availability` are allowed if there is a partial order between them. The
1531/// stronger availability is chosen.
1532fn compute_diff<T: CapabilityClause>(ours: &mut T, theirs: &mut T) {
1533    // Return early if one is empty.
1534    if ours.names().is_empty() || theirs.names().is_empty() {
1535        return;
1536    }
1537
1538    // Return early if the types don't match.
1539    if ours.capability_type().unwrap() != theirs.capability_type().unwrap() {
1540        return;
1541    }
1542
1543    // Check if the non-capability fields match before proceeding.
1544    let mut ours_partial = ours.clone();
1545    let mut theirs_partial = theirs.clone();
1546    for e in [&mut ours_partial, &mut theirs_partial] {
1547        e.set_names(Vec::new());
1548        // Availability is allowed to differ (see merge algorithm below)
1549        e.set_availability(None);
1550    }
1551    if ours_partial != theirs_partial {
1552        // The fields other than `availability` do not match, nothing to remove.
1553        return;
1554    }
1555
1556    // Compare the availabilities.
1557    let Some(avail_cmp) = ours
1558        .availability()
1559        .unwrap_or_default()
1560        .partial_cmp(&theirs.availability().unwrap_or_default())
1561    else {
1562        // The availabilities are incompatible (no partial order).
1563        return;
1564    };
1565
1566    let mut our_names: Vec<_> = ours.names().into_iter().cloned().collect();
1567    let mut their_names: Vec<_> = theirs.names().into_iter().cloned().collect();
1568
1569    let mut our_entries_to_remove = HashSet::new();
1570    let mut their_entries_to_remove = HashSet::new();
1571    for e in &their_names {
1572        if !our_names.contains(e) {
1573            // Not a duplicate, so keep.
1574            continue;
1575        }
1576        match avail_cmp {
1577            cmp::Ordering::Less => {
1578                // Their availability is stronger, meaning theirs should take
1579                // priority. Keep `e` in theirs, and remove it from ours.
1580                our_entries_to_remove.insert(e.clone());
1581            }
1582            cmp::Ordering::Greater => {
1583                // Our availability is stronger, meaning ours should take
1584                // priority. Remove `e` from theirs.
1585                their_entries_to_remove.insert(e.clone());
1586            }
1587            cmp::Ordering::Equal => {
1588                // The availabilities are equal, so `e` is a duplicate.
1589                their_entries_to_remove.insert(e.clone());
1590            }
1591        }
1592    }
1593    our_names.retain(|e| !our_entries_to_remove.contains(e));
1594    their_names.retain(|e| !their_entries_to_remove.contains(e));
1595
1596    ours.set_names(our_names);
1597    theirs.set_names(their_names);
1598}
1599
1600impl Document {
1601    pub fn merge_from(
1602        &mut self,
1603        other: &mut Document,
1604        include_path: &path::Path,
1605    ) -> Result<(), Error> {
1606        // Flatten the mergable fields that may contain a
1607        // list of capabilities in one clause.
1608        merge_from_capability_field(&mut self.r#use, &mut other.r#use)?;
1609        merge_from_capability_field(&mut self.expose, &mut other.expose)?;
1610        merge_from_capability_field(&mut self.offer, &mut other.offer)?;
1611        merge_from_capability_field(&mut self.capabilities, &mut other.capabilities)?;
1612        merge_from_other_field(&mut self.include, &mut other.include);
1613        merge_from_other_field(&mut self.children, &mut other.children);
1614        merge_from_other_field(&mut self.collections, &mut other.collections);
1615        self.merge_environment(other, include_path)?;
1616        self.merge_program(other, include_path)?;
1617        self.merge_facets(other, include_path)?;
1618        self.merge_config(other, include_path)?;
1619
1620        Ok(())
1621    }
1622
1623    pub fn canonicalize(&mut self) {
1624        // Don't sort `include` - the order there matters.
1625        if let Some(children) = &mut self.children {
1626            children.sort_by(|a, b| a.name.cmp(&b.name));
1627        }
1628        if let Some(collections) = &mut self.collections {
1629            collections.sort_by(|a, b| a.name.cmp(&b.name));
1630        }
1631        if let Some(environments) = &mut self.environments {
1632            environments.sort_by(|a, b| a.name.cmp(&b.name));
1633        }
1634        if let Some(capabilities) = &mut self.capabilities {
1635            capabilities.canonicalize();
1636        }
1637        if let Some(offers) = &mut self.offer {
1638            offers.canonicalize();
1639        }
1640        if let Some(expose) = &mut self.expose {
1641            expose.canonicalize();
1642        }
1643        if let Some(r#use) = &mut self.r#use {
1644            r#use.canonicalize();
1645        }
1646    }
1647
1648    fn merge_program(
1649        &mut self,
1650        other: &mut Document,
1651        include_path: &path::Path,
1652    ) -> Result<(), Error> {
1653        if let None = other.program {
1654            return Ok(());
1655        }
1656        if let None = self.program {
1657            self.program = Some(Program::default());
1658        }
1659        let my_program = self.program.as_mut().unwrap();
1660        let other_program = other.program.as_mut().unwrap();
1661        if let Some(other_runner) = other_program.runner.take() {
1662            my_program.runner = match &my_program.runner {
1663                Some(runner) if *runner != other_runner => {
1664                    return Err(Error::validate(format!(
1665                        "manifest include had a conflicting `program.runner`: {}",
1666                        include_path.display()
1667                    )))
1668                }
1669                _ => Some(other_runner),
1670            }
1671        }
1672
1673        Self::merge_maps_with_options(
1674            &mut my_program.info,
1675            &other_program.info,
1676            "program",
1677            include_path,
1678            Some(vec!["environ", "features"]),
1679        )
1680    }
1681
1682    fn merge_environment(
1683        &mut self,
1684        other: &mut Document,
1685        _include_path: &path::Path,
1686    ) -> Result<(), Error> {
1687        if let None = other.environments {
1688            return Ok(());
1689        }
1690        if let None = self.environments {
1691            self.environments = Some(vec![]);
1692        }
1693
1694        let my_environments = self.environments.as_mut().unwrap();
1695        let other_environments = other.environments.as_mut().unwrap();
1696        my_environments.sort_by(|x, y| x.name.cmp(&y.name));
1697        other_environments.sort_by(|x, y| x.name.cmp(&y.name));
1698
1699        let all_environments =
1700            my_environments.into_iter().merge_by(other_environments, |x, y| x.name <= y.name);
1701        let groups = all_environments.group_by(|e| e.name.clone());
1702
1703        let mut merged_environments = vec![];
1704        for (name, group) in groups.into_iter() {
1705            let mut merged_environment = Environment {
1706                name: name.clone(),
1707                extends: None,
1708                runners: None,
1709                resolvers: None,
1710                debug: None,
1711                stop_timeout_ms: None,
1712            };
1713            for e in group {
1714                merged_environment.merge_from(e)?;
1715            }
1716            merged_environments.push(merged_environment);
1717        }
1718
1719        self.environments = Some(merged_environments);
1720        Ok(())
1721    }
1722
1723    fn merge_maps<'s, Source, Dest>(
1724        self_map: &mut Dest,
1725        include_map: Source,
1726        outer_key: &str,
1727        include_path: &path::Path,
1728    ) -> Result<(), Error>
1729    where
1730        Source: IntoIterator<Item = (&'s String, &'s Value)>,
1731        Dest: ValueMap,
1732    {
1733        Self::merge_maps_with_options(self_map, include_map, outer_key, include_path, None)
1734    }
1735
1736    /// If `allow_array_concatenation_keys` is None, all arrays present in both
1737    /// `self_map` and `include_map` will be concatenated in the result. If it
1738    /// is set to Some(vec), only those keys specified will allow concatenation,
1739    /// with any others returning an error.
1740    fn merge_maps_with_options<'s, Source, Dest>(
1741        self_map: &mut Dest,
1742        include_map: Source,
1743        outer_key: &str,
1744        include_path: &path::Path,
1745        allow_array_concatenation_keys: Option<Vec<&str>>,
1746    ) -> Result<(), Error>
1747    where
1748        Source: IntoIterator<Item = (&'s String, &'s Value)>,
1749        Dest: ValueMap,
1750    {
1751        for (key, value) in include_map {
1752            match self_map.get_mut(key) {
1753                None => {
1754                    // Key not present in self map, insert it from include map.
1755                    self_map.insert(key.clone(), value.clone());
1756                }
1757                // Self and include maps share the same key
1758                Some(Value::Object(self_nested_map)) => match value {
1759                    // The include value is an object and can be recursively merged
1760                    Value::Object(include_nested_map) => {
1761                        let combined_key = format!("{}.{}", outer_key, key);
1762
1763                        // Recursively merge maps
1764                        Self::merge_maps(
1765                            self_nested_map,
1766                            include_nested_map,
1767                            &combined_key,
1768                            include_path,
1769                        )?;
1770                    }
1771                    _ => {
1772                        // Cannot merge object and non-object
1773                        return Err(Error::validate(format!(
1774                            "manifest include had a conflicting `{}.{}`: {}",
1775                            outer_key,
1776                            key,
1777                            include_path.display()
1778                        )));
1779                    }
1780                },
1781                Some(Value::Array(self_nested_vec)) => match value {
1782                    // The include value is an array and can be merged, unless
1783                    // `allow_array_concatenation_keys` is used and the key is not included.
1784                    Value::Array(include_nested_vec) => {
1785                        if let Some(allowed_keys) = &allow_array_concatenation_keys {
1786                            if !allowed_keys.contains(&key.as_str()) {
1787                                // This key wasn't present in `allow_array_concatenation_keys` and so
1788                                // merging is disallowed.
1789                                return Err(Error::validate(format!(
1790                                    "manifest include had a conflicting `{}.{}`: {}",
1791                                    outer_key,
1792                                    key,
1793                                    include_path.display()
1794                                )));
1795                            }
1796                        }
1797                        let mut new_values = include_nested_vec.clone();
1798                        self_nested_vec.append(&mut new_values);
1799                    }
1800                    _ => {
1801                        // Cannot merge array and non-array
1802                        return Err(Error::validate(format!(
1803                            "manifest include had a conflicting `{}.{}`: {}",
1804                            outer_key,
1805                            key,
1806                            include_path.display()
1807                        )));
1808                    }
1809                },
1810                _ => {
1811                    // Cannot merge object and non-object
1812                    return Err(Error::validate(format!(
1813                        "manifest include had a conflicting `{}.{}`: {}",
1814                        outer_key,
1815                        key,
1816                        include_path.display()
1817                    )));
1818                }
1819            }
1820        }
1821        Ok(())
1822    }
1823
1824    fn merge_facets(
1825        &mut self,
1826        other: &mut Document,
1827        include_path: &path::Path,
1828    ) -> Result<(), Error> {
1829        if let None = other.facets {
1830            return Ok(());
1831        }
1832        if let None = self.facets {
1833            self.facets = Some(Default::default());
1834        }
1835        let my_facets = self.facets.as_mut().unwrap();
1836        let other_facets = other.facets.as_ref().unwrap();
1837
1838        Self::merge_maps(my_facets, other_facets, "facets", include_path)
1839    }
1840
1841    fn merge_config(
1842        &mut self,
1843        other: &mut Document,
1844        include_path: &path::Path,
1845    ) -> Result<(), Error> {
1846        if let Some(other_config) = other.config.as_mut() {
1847            if let Some(self_config) = self.config.as_mut() {
1848                for (key, field) in other_config {
1849                    match self_config.entry(key.clone()) {
1850                        std::collections::btree_map::Entry::Vacant(v) => {
1851                            v.insert(field.clone());
1852                        }
1853                        std::collections::btree_map::Entry::Occupied(o) => {
1854                            if o.get() != field {
1855                                let msg = format!(
1856                                    "Found conflicting entry for config key `{key}` in `{}`.",
1857                                    include_path.display()
1858                                );
1859                                return Err(Error::validate(&msg));
1860                            }
1861                        }
1862                    }
1863                }
1864            } else {
1865                self.config.replace(std::mem::take(other_config));
1866            }
1867        }
1868        Ok(())
1869    }
1870
1871    pub fn includes(&self) -> Vec<String> {
1872        self.include.clone().unwrap_or_default()
1873    }
1874
1875    pub fn all_children_names(&self) -> Vec<&Name> {
1876        if let Some(children) = self.children.as_ref() {
1877            children.iter().map(|c| &c.name).collect()
1878        } else {
1879            vec![]
1880        }
1881    }
1882
1883    pub fn all_collection_names(&self) -> Vec<&Name> {
1884        if let Some(collections) = self.collections.as_ref() {
1885            collections.iter().map(|c| &c.name).collect()
1886        } else {
1887            vec![]
1888        }
1889    }
1890
1891    pub fn all_storage_names(&self) -> Vec<&Name> {
1892        if let Some(capabilities) = self.capabilities.as_ref() {
1893            capabilities.iter().filter_map(|c| c.storage.as_ref()).collect()
1894        } else {
1895            vec![]
1896        }
1897    }
1898
1899    pub fn all_storage_with_sources<'a>(&'a self) -> HashMap<&'a Name, &'a CapabilityFromRef> {
1900        if let Some(capabilities) = self.capabilities.as_ref() {
1901            capabilities
1902                .iter()
1903                .filter_map(|c| match (c.storage.as_ref(), c.from.as_ref()) {
1904                    (Some(s), Some(f)) => Some((s, f)),
1905                    _ => None,
1906                })
1907                .collect()
1908        } else {
1909            HashMap::new()
1910        }
1911    }
1912
1913    pub fn all_service_names(&self) -> Vec<&Name> {
1914        self.capabilities
1915            .as_ref()
1916            .map(|c| {
1917                c.iter().filter_map(|c| c.service.as_ref()).map(|p| p.iter()).flatten().collect()
1918            })
1919            .unwrap_or_else(|| vec![])
1920    }
1921
1922    pub fn all_protocol_names(&self) -> Vec<&Name> {
1923        self.capabilities
1924            .as_ref()
1925            .map(|c| {
1926                c.iter().filter_map(|c| c.protocol.as_ref()).map(|p| p.iter()).flatten().collect()
1927            })
1928            .unwrap_or_else(|| vec![])
1929    }
1930
1931    pub fn all_directory_names(&self) -> Vec<&Name> {
1932        self.capabilities
1933            .as_ref()
1934            .map(|c| c.iter().filter_map(|c| c.directory.as_ref()).collect())
1935            .unwrap_or_else(|| vec![])
1936    }
1937
1938    pub fn all_runner_names(&self) -> Vec<&Name> {
1939        self.capabilities
1940            .as_ref()
1941            .map(|c| c.iter().filter_map(|c| c.runner.as_ref()).collect())
1942            .unwrap_or_else(|| vec![])
1943    }
1944
1945    pub fn all_resolver_names(&self) -> Vec<&Name> {
1946        self.capabilities
1947            .as_ref()
1948            .map(|c| c.iter().filter_map(|c| c.resolver.as_ref()).collect())
1949            .unwrap_or_else(|| vec![])
1950    }
1951
1952    pub fn all_dictionary_names(&self) -> Vec<&Name> {
1953        if let Some(capabilities) = self.capabilities.as_ref() {
1954            capabilities.iter().filter_map(|c| c.dictionary.as_ref()).collect()
1955        } else {
1956            vec![]
1957        }
1958    }
1959
1960    pub fn all_dictionaries<'a>(&'a self) -> HashMap<&'a Name, &'a Capability> {
1961        if let Some(capabilities) = self.capabilities.as_ref() {
1962            capabilities
1963                .iter()
1964                .filter_map(|c| match c.dictionary.as_ref() {
1965                    Some(s) => Some((s, c)),
1966                    _ => None,
1967                })
1968                .collect()
1969        } else {
1970            HashMap::new()
1971        }
1972    }
1973
1974    pub fn all_config_names(&self) -> Vec<&Name> {
1975        self.capabilities
1976            .as_ref()
1977            .map(|c| c.iter().filter_map(|c| c.config.as_ref()).collect())
1978            .unwrap_or_else(|| vec![])
1979    }
1980
1981    pub fn all_environment_names(&self) -> Vec<&Name> {
1982        self.environments
1983            .as_ref()
1984            .map(|c| c.iter().map(|s| &s.name).collect())
1985            .unwrap_or_else(|| vec![])
1986    }
1987
1988    pub fn all_capability_names(&self) -> HashSet<&Name> {
1989        self.capabilities
1990            .as_ref()
1991            .map(|c| {
1992                c.iter().fold(HashSet::new(), |mut acc, capability| {
1993                    acc.extend(capability.names());
1994                    acc
1995                })
1996            })
1997            .unwrap_or_default()
1998    }
1999}
2000
2001/// Trait that allows us to merge `serde_json::Map`s into `indexmap::IndexMap`s and vice versa.
2002trait ValueMap {
2003    fn get_mut(&mut self, key: &str) -> Option<&mut Value>;
2004    fn insert(&mut self, key: String, val: Value);
2005}
2006
2007impl ValueMap for Map<String, Value> {
2008    fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
2009        self.get_mut(key)
2010    }
2011
2012    fn insert(&mut self, key: String, val: Value) {
2013        self.insert(key, val);
2014    }
2015}
2016
2017impl ValueMap for IndexMap<String, Value> {
2018    fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
2019        self.get_mut(key)
2020    }
2021
2022    fn insert(&mut self, key: String, val: Value) {
2023        self.insert(key, val);
2024    }
2025}
2026
2027#[derive(Deserialize, Debug, PartialEq, Serialize)]
2028#[serde(rename_all = "lowercase")]
2029pub enum EnvironmentExtends {
2030    Realm,
2031    None,
2032}
2033
2034/// Example:
2035///
2036/// ```json5
2037/// environments: [
2038///     {
2039///         name: "test-env",
2040///         extends: "realm",
2041///         runners: [
2042///             {
2043///                 runner: "gtest-runner",
2044///                 from: "#gtest",
2045///             },
2046///         ],
2047///         resolvers: [
2048///             {
2049///                 resolver: "full-resolver",
2050///                 from: "parent",
2051///                 scheme: "fuchsia-pkg",
2052///             },
2053///         ],
2054///     },
2055/// ],
2056/// ```
2057#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
2058#[serde(deny_unknown_fields)]
2059#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
2060pub struct Environment {
2061    /// The name of the environment, which is a string of one or more of the
2062    /// following characters: `a-z`, `0-9`, `_`, `.`, `-`. The name identifies this
2063    /// environment when used in a [reference](#references).
2064    pub name: Name,
2065
2066    /// How the environment should extend this realm's environment.
2067    /// - `realm`: Inherit all properties from this component's environment.
2068    /// - `none`: Start with an empty environment, do not inherit anything.
2069    #[serde(skip_serializing_if = "Option::is_none")]
2070    pub extends: Option<EnvironmentExtends>,
2071
2072    /// The runners registered in the environment. An array of objects
2073    /// with the following properties:
2074    #[reference_doc(recurse)]
2075    #[serde(skip_serializing_if = "Option::is_none")]
2076    pub runners: Option<Vec<RunnerRegistration>>,
2077
2078    /// The resolvers registered in the environment. An array of
2079    /// objects with the following properties:
2080    #[reference_doc(recurse)]
2081    #[serde(skip_serializing_if = "Option::is_none")]
2082    pub resolvers: Option<Vec<ResolverRegistration>>,
2083
2084    /// Debug protocols available to any component in this environment acquired
2085    /// through `use from debug`.
2086    #[reference_doc(recurse)]
2087    #[serde(skip_serializing_if = "Option::is_none")]
2088    pub debug: Option<Vec<DebugRegistration>>,
2089
2090    /// The number of milliseconds to wait, after notifying a component in this environment that it
2091    /// should terminate, before forcibly killing it. This field is required if the environment
2092    /// extends from `none`.
2093    #[serde(rename = "__stop_timeout_ms")]
2094    #[reference_doc(json_type = "number", rename = "__stop_timeout_ms")]
2095    #[serde(skip_serializing_if = "Option::is_none")]
2096    pub stop_timeout_ms: Option<StopTimeoutMs>,
2097}
2098
2099impl Environment {
2100    pub fn merge_from(&mut self, other: &mut Self) -> Result<(), Error> {
2101        if self.extends.is_none() {
2102            self.extends = other.extends.take();
2103        } else if other.extends.is_some() && other.extends != self.extends {
2104            return Err(Error::validate(
2105                "cannot merge `environments` that declare conflicting `extends`",
2106            ));
2107        }
2108
2109        if self.stop_timeout_ms.is_none() {
2110            self.stop_timeout_ms = other.stop_timeout_ms;
2111        } else if other.stop_timeout_ms.is_some() && other.stop_timeout_ms != self.stop_timeout_ms {
2112            return Err(Error::validate(
2113                "cannot merge `environments` that declare conflicting `stop_timeout_ms`",
2114            ));
2115        }
2116
2117        // Perform naive vector concatenation and rely on later validation to ensure
2118        // no conflicting entries.
2119        match &mut self.runners {
2120            Some(r) => {
2121                if let Some(o) = &mut other.runners {
2122                    r.append(o);
2123                }
2124            }
2125            None => self.runners = other.runners.take(),
2126        }
2127
2128        match &mut self.resolvers {
2129            Some(r) => {
2130                if let Some(o) = &mut other.resolvers {
2131                    r.append(o);
2132                }
2133            }
2134            None => self.resolvers = other.resolvers.take(),
2135        }
2136
2137        match &mut self.debug {
2138            Some(r) => {
2139                if let Some(o) = &mut other.debug {
2140                    r.append(o);
2141                }
2142            }
2143            None => self.debug = other.debug.take(),
2144        }
2145        Ok(())
2146    }
2147}
2148
2149#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
2150#[serde(rename_all = "snake_case")]
2151pub enum ConfigType {
2152    Bool,
2153    Uint8,
2154    Uint16,
2155    Uint32,
2156    Uint64,
2157    Int8,
2158    Int16,
2159    Int32,
2160    Int64,
2161    String,
2162    Vector,
2163}
2164
2165impl From<&cm_rust::ConfigValueType> for ConfigType {
2166    fn from(value: &cm_rust::ConfigValueType) -> Self {
2167        match value {
2168            cm_rust::ConfigValueType::Bool => ConfigType::Bool,
2169            cm_rust::ConfigValueType::Uint8 => ConfigType::Uint8,
2170            cm_rust::ConfigValueType::Int8 => ConfigType::Int8,
2171            cm_rust::ConfigValueType::Uint16 => ConfigType::Uint16,
2172            cm_rust::ConfigValueType::Int16 => ConfigType::Int16,
2173            cm_rust::ConfigValueType::Uint32 => ConfigType::Uint32,
2174            cm_rust::ConfigValueType::Int32 => ConfigType::Int32,
2175            cm_rust::ConfigValueType::Uint64 => ConfigType::Uint64,
2176            cm_rust::ConfigValueType::Int64 => ConfigType::Int64,
2177            cm_rust::ConfigValueType::String { .. } => ConfigType::String,
2178            cm_rust::ConfigValueType::Vector { .. } => ConfigType::Vector,
2179        }
2180    }
2181}
2182
2183#[derive(Clone, Hash, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize)]
2184pub struct ConfigKey(String);
2185
2186impl ConfigKey {
2187    pub fn as_str(&self) -> &str {
2188        self.0.as_str()
2189    }
2190}
2191
2192impl std::fmt::Display for ConfigKey {
2193    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2194        write!(f, "{}", self.0)
2195    }
2196}
2197
2198impl FromStr for ConfigKey {
2199    type Err = ParseError;
2200
2201    fn from_str(s: &str) -> Result<Self, ParseError> {
2202        let length = s.len();
2203        if length == 0 {
2204            return Err(ParseError::Empty);
2205        }
2206        if length > 64 {
2207            return Err(ParseError::TooLong);
2208        }
2209
2210        // identifiers must start with a letter
2211        let first_is_letter = s.chars().next().expect("non-empty string").is_ascii_lowercase();
2212        // can contain letters, numbers, and underscores
2213        let contains_invalid_chars =
2214            s.chars().any(|c| !(c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_'));
2215        // cannot end with an underscore
2216        let last_is_underscore = s.chars().next_back().expect("non-empty string") == '_';
2217
2218        if !first_is_letter || contains_invalid_chars || last_is_underscore {
2219            return Err(ParseError::InvalidValue);
2220        }
2221
2222        Ok(Self(s.to_string()))
2223    }
2224}
2225
2226impl<'de> de::Deserialize<'de> for ConfigKey {
2227    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2228    where
2229        D: de::Deserializer<'de>,
2230    {
2231        struct Visitor;
2232
2233        impl<'de> de::Visitor<'de> for Visitor {
2234            type Value = ConfigKey;
2235
2236            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2237                f.write_str(
2238                    "a non-empty string no more than 64 characters in length, which must \
2239                    start with a letter, can contain letters, numbers, and underscores, \
2240                    but cannot end with an underscore",
2241                )
2242            }
2243
2244            fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
2245            where
2246                E: de::Error,
2247            {
2248                s.parse().map_err(|err| match err {
2249                    ParseError::InvalidValue => E::invalid_value(
2250                        de::Unexpected::Str(s),
2251                        &"a name which must start with a letter, can contain letters, \
2252                        numbers, and underscores, but cannot end with an underscore",
2253                    ),
2254                    ParseError::TooLong | ParseError::Empty => E::invalid_length(
2255                        s.len(),
2256                        &"a non-empty name no more than 64 characters in length",
2257                    ),
2258                    e => {
2259                        panic!("unexpected parse error: {:?}", e);
2260                    }
2261                })
2262            }
2263        }
2264        deserializer.deserialize_string(Visitor)
2265    }
2266}
2267
2268#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
2269#[serde(deny_unknown_fields, rename_all = "lowercase")]
2270pub enum ConfigRuntimeSource {
2271    Parent,
2272}
2273
2274#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
2275#[serde(tag = "type", deny_unknown_fields, rename_all = "lowercase")]
2276pub enum ConfigValueType {
2277    Bool {
2278        mutability: Option<Vec<ConfigRuntimeSource>>,
2279    },
2280    Uint8 {
2281        mutability: Option<Vec<ConfigRuntimeSource>>,
2282    },
2283    Uint16 {
2284        mutability: Option<Vec<ConfigRuntimeSource>>,
2285    },
2286    Uint32 {
2287        mutability: Option<Vec<ConfigRuntimeSource>>,
2288    },
2289    Uint64 {
2290        mutability: Option<Vec<ConfigRuntimeSource>>,
2291    },
2292    Int8 {
2293        mutability: Option<Vec<ConfigRuntimeSource>>,
2294    },
2295    Int16 {
2296        mutability: Option<Vec<ConfigRuntimeSource>>,
2297    },
2298    Int32 {
2299        mutability: Option<Vec<ConfigRuntimeSource>>,
2300    },
2301    Int64 {
2302        mutability: Option<Vec<ConfigRuntimeSource>>,
2303    },
2304    String {
2305        max_size: NonZeroU32,
2306        mutability: Option<Vec<ConfigRuntimeSource>>,
2307    },
2308    Vector {
2309        max_count: NonZeroU32,
2310        element: ConfigNestedValueType,
2311        mutability: Option<Vec<ConfigRuntimeSource>>,
2312    },
2313}
2314
2315impl ConfigValueType {
2316    /// Update the hasher by digesting the ConfigValueType enum value
2317    pub fn update_digest(&self, hasher: &mut impl sha2::Digest) {
2318        let val = match self {
2319            ConfigValueType::Bool { .. } => 0u8,
2320            ConfigValueType::Uint8 { .. } => 1u8,
2321            ConfigValueType::Uint16 { .. } => 2u8,
2322            ConfigValueType::Uint32 { .. } => 3u8,
2323            ConfigValueType::Uint64 { .. } => 4u8,
2324            ConfigValueType::Int8 { .. } => 5u8,
2325            ConfigValueType::Int16 { .. } => 6u8,
2326            ConfigValueType::Int32 { .. } => 7u8,
2327            ConfigValueType::Int64 { .. } => 8u8,
2328            ConfigValueType::String { max_size, .. } => {
2329                hasher.update(max_size.get().to_le_bytes());
2330                9u8
2331            }
2332            ConfigValueType::Vector { max_count, element, .. } => {
2333                hasher.update(max_count.get().to_le_bytes());
2334                element.update_digest(hasher);
2335                10u8
2336            }
2337        };
2338        hasher.update([val])
2339    }
2340}
2341
2342impl From<ConfigValueType> for cm_rust::ConfigValueType {
2343    fn from(value: ConfigValueType) -> Self {
2344        match value {
2345            ConfigValueType::Bool { .. } => cm_rust::ConfigValueType::Bool,
2346            ConfigValueType::Uint8 { .. } => cm_rust::ConfigValueType::Uint8,
2347            ConfigValueType::Uint16 { .. } => cm_rust::ConfigValueType::Uint16,
2348            ConfigValueType::Uint32 { .. } => cm_rust::ConfigValueType::Uint32,
2349            ConfigValueType::Uint64 { .. } => cm_rust::ConfigValueType::Uint64,
2350            ConfigValueType::Int8 { .. } => cm_rust::ConfigValueType::Int8,
2351            ConfigValueType::Int16 { .. } => cm_rust::ConfigValueType::Int16,
2352            ConfigValueType::Int32 { .. } => cm_rust::ConfigValueType::Int32,
2353            ConfigValueType::Int64 { .. } => cm_rust::ConfigValueType::Int64,
2354            ConfigValueType::String { max_size, .. } => {
2355                cm_rust::ConfigValueType::String { max_size: max_size.into() }
2356            }
2357            ConfigValueType::Vector { max_count, element, .. } => {
2358                cm_rust::ConfigValueType::Vector {
2359                    max_count: max_count.into(),
2360                    nested_type: element.into(),
2361                }
2362            }
2363        }
2364    }
2365}
2366
2367#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
2368#[serde(tag = "type", deny_unknown_fields, rename_all = "lowercase")]
2369pub enum ConfigNestedValueType {
2370    Bool {},
2371    Uint8 {},
2372    Uint16 {},
2373    Uint32 {},
2374    Uint64 {},
2375    Int8 {},
2376    Int16 {},
2377    Int32 {},
2378    Int64 {},
2379    String { max_size: NonZeroU32 },
2380}
2381
2382impl ConfigNestedValueType {
2383    /// Update the hasher by digesting the ConfigVectorElementType enum value
2384    pub fn update_digest(&self, hasher: &mut impl sha2::Digest) {
2385        let val = match self {
2386            ConfigNestedValueType::Bool {} => 0u8,
2387            ConfigNestedValueType::Uint8 {} => 1u8,
2388            ConfigNestedValueType::Uint16 {} => 2u8,
2389            ConfigNestedValueType::Uint32 {} => 3u8,
2390            ConfigNestedValueType::Uint64 {} => 4u8,
2391            ConfigNestedValueType::Int8 {} => 5u8,
2392            ConfigNestedValueType::Int16 {} => 6u8,
2393            ConfigNestedValueType::Int32 {} => 7u8,
2394            ConfigNestedValueType::Int64 {} => 8u8,
2395            ConfigNestedValueType::String { max_size } => {
2396                hasher.update(max_size.get().to_le_bytes());
2397                9u8
2398            }
2399        };
2400        hasher.update([val])
2401    }
2402}
2403
2404impl From<ConfigNestedValueType> for cm_rust::ConfigNestedValueType {
2405    fn from(value: ConfigNestedValueType) -> Self {
2406        match value {
2407            ConfigNestedValueType::Bool {} => cm_rust::ConfigNestedValueType::Bool,
2408            ConfigNestedValueType::Uint8 {} => cm_rust::ConfigNestedValueType::Uint8,
2409            ConfigNestedValueType::Uint16 {} => cm_rust::ConfigNestedValueType::Uint16,
2410            ConfigNestedValueType::Uint32 {} => cm_rust::ConfigNestedValueType::Uint32,
2411            ConfigNestedValueType::Uint64 {} => cm_rust::ConfigNestedValueType::Uint64,
2412            ConfigNestedValueType::Int8 {} => cm_rust::ConfigNestedValueType::Int8,
2413            ConfigNestedValueType::Int16 {} => cm_rust::ConfigNestedValueType::Int16,
2414            ConfigNestedValueType::Int32 {} => cm_rust::ConfigNestedValueType::Int32,
2415            ConfigNestedValueType::Int64 {} => cm_rust::ConfigNestedValueType::Int64,
2416            ConfigNestedValueType::String { max_size } => {
2417                cm_rust::ConfigNestedValueType::String { max_size: max_size.into() }
2418            }
2419        }
2420    }
2421}
2422
2423impl TryFrom<&cm_rust::ConfigNestedValueType> for ConfigNestedValueType {
2424    type Error = ();
2425    fn try_from(nested: &cm_rust::ConfigNestedValueType) -> Result<Self, ()> {
2426        Ok(match nested {
2427            cm_rust::ConfigNestedValueType::Bool => ConfigNestedValueType::Bool {},
2428            cm_rust::ConfigNestedValueType::Uint8 => ConfigNestedValueType::Uint8 {},
2429            cm_rust::ConfigNestedValueType::Int8 => ConfigNestedValueType::Int8 {},
2430            cm_rust::ConfigNestedValueType::Uint16 => ConfigNestedValueType::Uint16 {},
2431            cm_rust::ConfigNestedValueType::Int16 => ConfigNestedValueType::Int16 {},
2432            cm_rust::ConfigNestedValueType::Uint32 => ConfigNestedValueType::Uint32 {},
2433            cm_rust::ConfigNestedValueType::Int32 => ConfigNestedValueType::Int32 {},
2434            cm_rust::ConfigNestedValueType::Uint64 => ConfigNestedValueType::Uint64 {},
2435            cm_rust::ConfigNestedValueType::Int64 => ConfigNestedValueType::Int64 {},
2436            cm_rust::ConfigNestedValueType::String { max_size } => {
2437                ConfigNestedValueType::String { max_size: NonZeroU32::new(*max_size).ok_or(())? }
2438            }
2439        })
2440    }
2441}
2442
2443#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
2444#[serde(deny_unknown_fields)]
2445#[reference_doc(fields_as = "list")]
2446pub struct RunnerRegistration {
2447    /// The [name](#name) of a runner capability, whose source is specified in `from`.
2448    pub runner: Name,
2449
2450    /// The source of the runner capability, one of:
2451    /// - `parent`: The component's parent.
2452    /// - `self`: This component.
2453    /// - `#<child-name>`: A [reference](#references) to a child component
2454    ///     instance.
2455    pub from: RegistrationRef,
2456
2457    /// An explicit name for the runner as it will be known in
2458    /// this environment. If omitted, defaults to `runner`.
2459    #[serde(skip_serializing_if = "Option::is_none")]
2460    pub r#as: Option<Name>,
2461}
2462
2463#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
2464#[serde(deny_unknown_fields)]
2465#[reference_doc(fields_as = "list")]
2466pub struct ResolverRegistration {
2467    /// The [name](#name) of a resolver capability,
2468    /// whose source is specified in `from`.
2469    pub resolver: Name,
2470
2471    /// The source of the resolver capability, one of:
2472    /// - `parent`: The component's parent.
2473    /// - `self`: This component.
2474    /// - `#<child-name>`: A [reference](#references) to a child component
2475    ///     instance.
2476    pub from: RegistrationRef,
2477
2478    /// The URL scheme for which the resolver should handle
2479    /// resolution.
2480    pub scheme: cm_types::UrlScheme,
2481}
2482
2483#[derive(Deserialize, Debug, PartialEq, Clone, ReferenceDoc, Serialize, Default)]
2484#[serde(deny_unknown_fields)]
2485#[reference_doc(fields_as = "list")]
2486pub struct Capability {
2487    /// The [name](#name) for this service capability. Specifying `path` is valid
2488    /// only when this value is a string.
2489    #[serde(skip_serializing_if = "Option::is_none")]
2490    #[reference_doc(skip = true)]
2491    pub service: Option<OneOrMany<Name>>,
2492
2493    /// The [name](#name) for this protocol capability. Specifying `path` is valid
2494    /// only when this value is a string.
2495    #[serde(skip_serializing_if = "Option::is_none")]
2496    #[reference_doc(skip = true)]
2497    pub protocol: Option<OneOrMany<Name>>,
2498
2499    /// The [name](#name) for this directory capability.
2500    #[serde(skip_serializing_if = "Option::is_none")]
2501    #[reference_doc(skip = true)]
2502    pub directory: Option<Name>,
2503
2504    /// The [name](#name) for this storage capability.
2505    #[serde(skip_serializing_if = "Option::is_none")]
2506    #[reference_doc(skip = true)]
2507    pub storage: Option<Name>,
2508
2509    /// The [name](#name) for this runner capability.
2510    #[serde(skip_serializing_if = "Option::is_none")]
2511    #[reference_doc(skip = true)]
2512    pub runner: Option<Name>,
2513
2514    /// The [name](#name) for this resolver capability.
2515    #[serde(skip_serializing_if = "Option::is_none")]
2516    #[reference_doc(skip = true)]
2517    pub resolver: Option<Name>,
2518
2519    /// The [name](#name) for this event_stream capability.
2520    #[serde(skip_serializing_if = "Option::is_none")]
2521    #[reference_doc(skip = true)]
2522    pub event_stream: Option<OneOrMany<Name>>,
2523
2524    /// The [name](#name) for this dictionary capability.
2525    #[serde(skip_serializing_if = "Option::is_none")]
2526    #[reference_doc(skip = true)]
2527    pub dictionary: Option<Name>,
2528
2529    /// The [name](#name) for this configuration capability.
2530    #[serde(skip_serializing_if = "Option::is_none")]
2531    #[reference_doc(skip = true)]
2532    pub config: Option<Name>,
2533
2534    /// The path within the [outgoing directory][glossary.outgoing directory] of the component's
2535    /// program to source the capability.
2536    ///
2537    /// For `protocol` and `service`, defaults to `/svc/${protocol}`, otherwise required.
2538    ///
2539    /// For `protocol`, the target of the path MUST be a channel, which tends to speak
2540    /// the protocol matching the name of this capability.
2541    ///
2542    /// For `service`, `directory`, the target of the path MUST be a directory.
2543    ///
2544    /// For `runner`, the target of the path MUST be a channel and MUST speak
2545    /// the protocol `fuchsia.component.runner.ComponentRunner`.
2546    ///
2547    /// For `resolver`, the target of the path MUST be a channel and MUST speak
2548    /// the protocol `fuchsia.component.resolution.Resolver`.
2549    ///
2550    /// For `dictionary`, this is optional. If provided, it is a path to a
2551    /// `fuchsia.component.sandbox/DictionaryRouter` served by the program which should return a
2552    /// `fuchsia.component.sandbox/DictionaryRef`, by which the program may dynamically provide
2553    /// a dictionary from itself. If this is set for `dictionary`, `offer` to this dictionary
2554    /// is not allowed.
2555    #[serde(skip_serializing_if = "Option::is_none")]
2556    pub path: Option<Path>,
2557
2558    /// (`directory` only) The maximum [directory rights][doc-directory-rights] that may be set
2559    /// when using this directory.
2560    #[serde(skip_serializing_if = "Option::is_none")]
2561    #[reference_doc(json_type = "array of string")]
2562    pub rights: Option<Rights>,
2563
2564    /// (`storage` only) The source component of an existing directory capability backing this
2565    /// storage capability, one of:
2566    /// - `parent`: The component's parent.
2567    /// - `self`: This component.
2568    /// - `#<child-name>`: A [reference](#references) to a child component
2569    ///     instance.
2570    #[serde(skip_serializing_if = "Option::is_none")]
2571    pub from: Option<CapabilityFromRef>,
2572
2573    /// (`storage` only) The [name](#name) of the directory capability backing the storage. The
2574    /// capability must be available from the component referenced in `from`.
2575    #[serde(skip_serializing_if = "Option::is_none")]
2576    pub backing_dir: Option<Name>,
2577
2578    /// (`storage` only) A subdirectory within `backing_dir` where per-component isolated storage
2579    /// directories are created
2580    #[serde(skip_serializing_if = "Option::is_none")]
2581    pub subdir: Option<RelativePath>,
2582
2583    /// (`storage` only) The identifier used to isolated storage for a component, one of:
2584    /// - `static_instance_id`: The instance ID in the component ID index is used
2585    ///     as the key for a component's storage. Components which are not listed in
2586    ///     the component ID index will not be able to use this storage capability.
2587    /// - `static_instance_id_or_moniker`: If the component is listed in the
2588    ///     component ID index, the instance ID is used as the key for a component's
2589    ///     storage. Otherwise, the component's moniker from the storage
2590    ///     capability is used.
2591    #[serde(skip_serializing_if = "Option::is_none")]
2592    pub storage_id: Option<StorageId>,
2593
2594    /// (`configuration` only) The type of configuration, one of:
2595    /// - `bool`: Boolean type.
2596    /// - `uint8`: Unsigned 8 bit type.
2597    /// - `uint16`: Unsigned 16 bit type.
2598    /// - `uint32`: Unsigned 32 bit type.
2599    /// - `uint64`: Unsigned 64 bit type.
2600    /// - `int8`: Signed 8 bit type.
2601    /// - `int16`: Signed 16 bit type.
2602    /// - `int32`: Signed 32 bit type.
2603    /// - `int64`: Signed 64 bit type.
2604    /// - `string`: ASCII string type.
2605    /// - `vector`: Vector type. See `element` for the type of the element within the vector.
2606    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
2607    #[reference_doc(rename = "type")]
2608    pub config_type: Option<ConfigType>,
2609
2610    /// (`configuration` only) Only supported if this configuration `type` is 'string'.
2611    /// This is the max size of the string.
2612    #[serde(rename = "max_size", skip_serializing_if = "Option::is_none")]
2613    #[reference_doc(rename = "max_size")]
2614    pub config_max_size: Option<NonZeroU32>,
2615
2616    /// (`configuration` only) Only supported if this configuration `type` is 'vector'.
2617    /// This is the max number of elements in the vector.
2618    #[serde(rename = "max_count", skip_serializing_if = "Option::is_none")]
2619    #[reference_doc(rename = "max_count")]
2620    pub config_max_count: Option<NonZeroU32>,
2621
2622    /// (`configuration` only) Only supported if this configuration `type` is 'vector'.
2623    /// This is the type of the elements in the configuration vector.
2624    ///
2625    /// Example (simple type):
2626    ///
2627    /// ```json5
2628    /// { type: "uint8" }
2629    /// ```
2630    ///
2631    /// Example (string type):
2632    ///
2633    /// ```json5
2634    /// {
2635    ///   type: "string",
2636    ///   max_size: 100,
2637    /// }
2638    /// ```
2639    #[serde(rename = "element", skip_serializing_if = "Option::is_none")]
2640    #[reference_doc(rename = "element", json_type = "object")]
2641    pub config_element_type: Option<ConfigNestedValueType>,
2642
2643    /// (`configuration` only) The value of the configuration.
2644    #[serde(skip_serializing_if = "Option::is_none")]
2645    pub value: Option<serde_json::Value>,
2646
2647    /// (`protocol` only) Specifies when the framework will open the protocol
2648    /// from this component's outgoing directory when someone requests the
2649    /// capability. Allowed values are:
2650    ///
2651    /// - `eager`: (default) the framework will open the capability as soon as
2652    ///   some consumer component requests it.
2653    /// - `on_readable`: the framework will open the capability when the server
2654    ///   endpoint pipelined in a connection request becomes readable.
2655    ///
2656    #[serde(skip_serializing_if = "Option::is_none")]
2657    pub delivery: Option<DeliveryType>,
2658}
2659
2660#[derive(Deserialize, Debug, Clone, PartialEq, ReferenceDoc, Serialize)]
2661#[serde(deny_unknown_fields)]
2662#[reference_doc(fields_as = "list")]
2663pub struct DebugRegistration {
2664    /// The name(s) of the protocol(s) to make available.
2665    pub protocol: Option<OneOrMany<Name>>,
2666
2667    /// The source of the capability(s), one of:
2668    /// - `parent`: The component's parent.
2669    /// - `self`: This component.
2670    /// - `#<child-name>`: A [reference](#references) to a child component
2671    ///     instance.
2672    pub from: OfferFromRef,
2673
2674    /// If specified, the name that the capability in `protocol` should be made
2675    /// available as to clients. Disallowed if `protocol` is an array.
2676    #[serde(skip_serializing_if = "Option::is_none")]
2677    pub r#as: Option<Name>,
2678}
2679
2680#[derive(Debug, PartialEq, Default, Serialize)]
2681pub struct Program {
2682    #[serde(skip_serializing_if = "Option::is_none")]
2683    pub runner: Option<Name>,
2684    #[serde(flatten)]
2685    pub info: IndexMap<String, Value>,
2686}
2687
2688impl<'de> de::Deserialize<'de> for Program {
2689    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2690    where
2691        D: de::Deserializer<'de>,
2692    {
2693        struct Visitor;
2694
2695        const EXPECTED_PROGRAM: &'static str =
2696            "a JSON object that includes a `runner` string property";
2697        const EXPECTED_RUNNER: &'static str =
2698            "a non-empty `runner` string property no more than 255 characters in length \
2699            that consists of [A-Za-z0-9_.-] and starts with [A-Za-z0-9_]";
2700
2701        impl<'de> de::Visitor<'de> for Visitor {
2702            type Value = Program;
2703
2704            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2705                f.write_str(EXPECTED_PROGRAM)
2706            }
2707
2708            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
2709            where
2710                A: de::MapAccess<'de>,
2711            {
2712                let mut info = IndexMap::new();
2713                let mut runner = None;
2714                while let Some(e) = map.next_entry::<String, Value>()? {
2715                    let (k, v) = e;
2716                    if &k == "runner" {
2717                        if let Value::String(s) = v {
2718                            runner = Some(s);
2719                        } else {
2720                            return Err(de::Error::invalid_value(
2721                                de::Unexpected::Map,
2722                                &EXPECTED_RUNNER,
2723                            ));
2724                        }
2725                    } else {
2726                        info.insert(k, v);
2727                    }
2728                }
2729                let runner = runner
2730                    .map(|r| {
2731                        Name::new(r.clone()).map_err(|e| match e {
2732                            ParseError::InvalidValue => de::Error::invalid_value(
2733                                serde::de::Unexpected::Str(&r),
2734                                &EXPECTED_RUNNER,
2735                            ),
2736                            ParseError::TooLong | ParseError::Empty => {
2737                                de::Error::invalid_length(r.len(), &EXPECTED_RUNNER)
2738                            }
2739                            _ => {
2740                                panic!("unexpected parse error: {:?}", e);
2741                            }
2742                        })
2743                    })
2744                    .transpose()?;
2745                Ok(Program { runner, info })
2746            }
2747        }
2748
2749        deserializer.deserialize_map(Visitor)
2750    }
2751}
2752
2753/// Example:
2754///
2755/// ```json5
2756/// use: [
2757///     {
2758///         protocol: [
2759///             "fuchsia.ui.scenic.Scenic",
2760///             "fuchsia.accessibility.Manager",
2761///         ]
2762///     },
2763///     {
2764///         directory: "themes",
2765///         path: "/data/themes",
2766///         rights: [ "r*" ],
2767///     },
2768///     {
2769///         storage: "persistent",
2770///         path: "/data",
2771///     },
2772///     {
2773///         event_stream: [
2774///             "started",
2775///             "stopped",
2776///         ],
2777///         from: "framework",
2778///     },
2779///     {
2780///         runner: "own_test_runner".
2781///         from: "#test_runner",
2782///     },
2783/// ],
2784/// ```
2785#[derive(Deserialize, Debug, Default, PartialEq, Clone, ReferenceDoc, Serialize)]
2786#[serde(deny_unknown_fields)]
2787#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
2788pub struct Use {
2789    /// When using a service capability, the [name](#name) of a [service capability][doc-service].
2790    #[serde(skip_serializing_if = "Option::is_none")]
2791    #[reference_doc(skip = true)]
2792    pub service: Option<OneOrMany<Name>>,
2793
2794    /// When using a protocol capability, the [name](#name) of a [protocol capability][doc-protocol].
2795    #[serde(skip_serializing_if = "Option::is_none")]
2796    #[reference_doc(skip = true)]
2797    pub protocol: Option<OneOrMany<Name>>,
2798
2799    /// When using a directory capability, the [name](#name) of a [directory capability][doc-directory].
2800    #[serde(skip_serializing_if = "Option::is_none")]
2801    #[reference_doc(skip = true)]
2802    pub directory: Option<Name>,
2803
2804    /// When using a storage capability, the [name](#name) of a [storage capability][doc-storage].
2805    #[serde(skip_serializing_if = "Option::is_none")]
2806    #[reference_doc(skip = true)]
2807    pub storage: Option<Name>,
2808
2809    /// When using an event stream capability, the [name](#name) of an [event stream capability][doc-event].
2810    #[serde(skip_serializing_if = "Option::is_none")]
2811    #[reference_doc(skip = true)]
2812    pub event_stream: Option<OneOrMany<Name>>,
2813
2814    /// When using a runner capability, the [name](#name) of a [runner capability][doc-runners].
2815    #[serde(skip_serializing_if = "Option::is_none")]
2816    #[reference_doc(skip = true)]
2817    pub runner: Option<Name>,
2818
2819    /// When using a configuration capability, the [name](#name) of a [configuration capability][doc-configuration].
2820    #[serde(skip_serializing_if = "Option::is_none")]
2821    #[reference_doc(skip = true)]
2822    pub config: Option<Name>,
2823
2824    /// The source of the capability. Defaults to `parent`.  One of:
2825    /// - `parent`: The component's parent.
2826    /// - `debug`: One of [`debug_capabilities`][fidl-environment-decl] in the
2827    ///     environment assigned to this component.
2828    /// - `framework`: The Component Framework runtime.
2829    /// - `self`: This component.
2830    /// - `#<capability-name>`: The name of another capability from which the
2831    ///     requested capability is derived.
2832    /// - `#<child-name>`: A [reference](#references) to a child component
2833    ///     instance.
2834    ///
2835    /// [fidl-environment-decl]: /reference/fidl/fuchsia.component.decl#Environment
2836    #[serde(skip_serializing_if = "Option::is_none")]
2837    pub from: Option<UseFromRef>,
2838
2839    /// The path at which to install the capability in the component's namespace. For protocols,
2840    /// defaults to `/svc/${protocol}`.  Required for `directory` and `storage`. This property is
2841    /// disallowed for declarations with arrays of capability names and for runner capabilities.
2842    #[serde(skip_serializing_if = "Option::is_none")]
2843    pub path: Option<Path>,
2844
2845    /// (`directory` only) the maximum [directory rights][doc-directory-rights] to apply to
2846    /// the directory in the component's namespace.
2847    #[serde(skip_serializing_if = "Option::is_none")]
2848    #[reference_doc(json_type = "array of string")]
2849    pub rights: Option<Rights>,
2850
2851    /// (`directory` only) A subdirectory within the directory capability to provide in the
2852    /// component's namespace.
2853    #[serde(skip_serializing_if = "Option::is_none")]
2854    pub subdir: Option<RelativePath>,
2855
2856    /// (`event_stream` only) When defined the event stream will contain events about only the
2857    /// components defined in the scope.
2858    #[serde(skip_serializing_if = "Option::is_none")]
2859    pub scope: Option<OneOrMany<EventScope>>,
2860
2861    /// (`event_stream` only) Capability requested event streams require specifying a filter
2862    /// referring to the protocol to which the events in the event stream apply. The content of the
2863    /// filter will be an object mapping from "name" to the "protocol name".
2864    #[serde(skip_serializing_if = "Option::is_none")]
2865    pub filter: Option<Map<String, Value>>,
2866
2867    /// The type of dependency between the source and
2868    /// this component, one of:
2869    /// - `strong`: a strong dependency, which is used to determine shutdown
2870    ///     ordering. Component manager is guaranteed to stop the target before the
2871    ///     source. This is the default.
2872    /// - `weak`: a weak dependency, which is ignored during shutdown. When component manager
2873    ///     stops the parent realm, the source may stop before the clients. Clients of weak
2874    ///     dependencies must be able to handle these dependencies becoming unavailable.
2875    /// This property is disallowed for runner capabilities, which are always a `strong` dependency.
2876    #[serde(skip_serializing_if = "Option::is_none")]
2877    pub dependency: Option<DependencyType>,
2878
2879    /// The expectations around this capability's availability. One
2880    /// of:
2881    /// - `required` (default): a required dependency, the component is unable to perform its
2882    ///     work without this capability.
2883    /// - `optional`: an optional dependency, the component will be able to function without this
2884    ///     capability (although if the capability is unavailable some functionality may be
2885    ///     disabled).
2886    /// - `transitional`: the source may omit the route completely without even having to route
2887    ///     from `void`. Used for soft transitions that introduce new capabilities.
2888    /// This property is disallowed for runner capabilities, which are always `required`.
2889    ///
2890    /// For more information, see the
2891    /// [availability](/docs/concepts/components/v2/capabilities/availability.md) documentation.
2892    #[serde(skip_serializing_if = "Option::is_none")]
2893    pub availability: Option<Availability>,
2894
2895    /// (`config` only) The configuration key in the component's `config` block that this capability
2896    /// will set.
2897    #[serde(skip_serializing_if = "Option::is_none")]
2898    pub key: Option<Name>,
2899
2900    /// (`config` only) The type of configuration, one of:
2901    /// - `bool`: Boolean type.
2902    /// - `uint8`: Unsigned 8 bit type.
2903    /// - `uint16`: Unsigned 16 bit type.
2904    /// - `uint32`: Unsigned 32 bit type.
2905    /// - `uint64`: Unsigned 64 bit type.
2906    /// - `int8`: Signed 8 bit type.
2907    /// - `int16`: Signed 16 bit type.
2908    /// - `int32`: Signed 32 bit type.
2909    /// - `int64`: Signed 64 bit type.
2910    /// - `string`: ASCII string type.
2911    /// - `vector`: Vector type. See `element` for the type of the element within the vector
2912    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
2913    #[reference_doc(rename = "type")]
2914    pub config_type: Option<ConfigType>,
2915
2916    /// (`configuration` only) Only supported if this configuration `type` is 'string'.
2917    /// This is the max size of the string.
2918    #[serde(rename = "max_size", skip_serializing_if = "Option::is_none")]
2919    #[reference_doc(rename = "max_size")]
2920    pub config_max_size: Option<NonZeroU32>,
2921
2922    /// (`configuration` only) Only supported if this configuration `type` is 'vector'.
2923    /// This is the max number of elements in the vector.
2924    #[serde(rename = "max_count", skip_serializing_if = "Option::is_none")]
2925    #[reference_doc(rename = "max_count")]
2926    pub config_max_count: Option<NonZeroU32>,
2927
2928    /// (`configuration` only) Only supported if this configuration `type` is 'vector'.
2929    /// This is the type of the elements in the configuration vector.
2930    ///
2931    /// Example (simple type):
2932    ///
2933    /// ```json5
2934    /// { type: "uint8" }
2935    /// ```
2936    ///
2937    /// Example (string type):
2938    ///
2939    /// ```json5
2940    /// {
2941    ///   type: "string",
2942    ///   max_size: 100,
2943    /// }
2944    /// ```
2945    #[serde(rename = "element", skip_serializing_if = "Option::is_none")]
2946    #[reference_doc(rename = "element", json_type = "object")]
2947    pub config_element_type: Option<ConfigNestedValueType>,
2948
2949    /// (`configuration` only) The default value of this configuration.
2950    /// Default values are used if the capability is optional and routed from `void`.
2951    /// This is only supported if `availability` is not `required``.
2952    #[serde(rename = "default", skip_serializing_if = "Option::is_none")]
2953    #[reference_doc(rename = "default")]
2954    pub config_default: Option<serde_json::Value>,
2955}
2956
2957/// Example:
2958///
2959/// ```json5
2960/// expose: [
2961///     {
2962///         directory: "themes",
2963///         from: "self",
2964///     },
2965///     {
2966///         protocol: "pkg.Cache",
2967///         from: "#pkg_cache",
2968///         as: "fuchsia.pkg.PackageCache",
2969///     },
2970///     {
2971///         protocol: [
2972///             "fuchsia.ui.app.ViewProvider",
2973///             "fuchsia.fonts.Provider",
2974///         ],
2975///         from: "self",
2976///     },
2977///     {
2978///         runner: "web-chromium",
2979///         from: "#web_runner",
2980///         as: "web",
2981///     },
2982///     {
2983///         resolver: "full-resolver",
2984///         from: "#full-resolver",
2985///     },
2986/// ],
2987/// ```
2988#[derive(Deserialize, Debug, PartialEq, Clone, ReferenceDoc, Serialize)]
2989#[serde(deny_unknown_fields)]
2990#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
2991pub struct Expose {
2992    /// When routing a service, the [name](#name) of a [service capability][doc-service].
2993    #[serde(skip_serializing_if = "Option::is_none")]
2994    #[reference_doc(skip = true)]
2995    pub service: Option<OneOrMany<Name>>,
2996
2997    /// When routing a protocol, the [name](#name) of a [protocol capability][doc-protocol].
2998    #[serde(skip_serializing_if = "Option::is_none")]
2999    #[reference_doc(skip = true)]
3000    pub protocol: Option<OneOrMany<Name>>,
3001
3002    /// When routing a directory, the [name](#name) of a [directory capability][doc-directory].
3003    #[serde(skip_serializing_if = "Option::is_none")]
3004    #[reference_doc(skip = true)]
3005    pub directory: Option<OneOrMany<Name>>,
3006
3007    /// When routing a runner, the [name](#name) of a [runner capability][doc-runners].
3008    #[serde(skip_serializing_if = "Option::is_none")]
3009    #[reference_doc(skip = true)]
3010    pub runner: Option<OneOrMany<Name>>,
3011
3012    /// When routing a resolver, the [name](#name) of a [resolver capability][doc-resolvers].
3013    #[serde(skip_serializing_if = "Option::is_none")]
3014    #[reference_doc(skip = true)]
3015    pub resolver: Option<OneOrMany<Name>>,
3016
3017    /// When routing a dictionary, the [name](#name) of a [dictionary capability][doc-dictionaries].
3018    #[serde(skip_serializing_if = "Option::is_none")]
3019    #[reference_doc(skip = true)]
3020    pub dictionary: Option<OneOrMany<Name>>,
3021
3022    /// When routing a config, the [name](#name) of a configuration capability.
3023    #[serde(skip_serializing_if = "Option::is_none")]
3024    #[reference_doc(skip = true)]
3025    pub config: Option<OneOrMany<Name>>,
3026
3027    /// `from`: The source of the capability, one of:
3028    /// - `self`: This component. Requires a corresponding
3029    ///     [`capability`](#capabilities) declaration.
3030    /// - `framework`: The Component Framework runtime.
3031    /// - `#<child-name>`: A [reference](#references) to a child component
3032    ///     instance.
3033    pub from: OneOrMany<ExposeFromRef>,
3034
3035    /// The [name](#name) for the capability as it will be known by the target. If omitted,
3036    /// defaults to the original name. `as` cannot be used when an array of multiple capability
3037    /// names is provided.
3038    #[serde(skip_serializing_if = "Option::is_none")]
3039    pub r#as: Option<Name>,
3040
3041    /// The capability target. Either `parent` or `framework`. Defaults to `parent`.
3042    #[serde(skip_serializing_if = "Option::is_none")]
3043    pub to: Option<ExposeToRef>,
3044
3045    /// (`directory` only) the maximum [directory rights][doc-directory-rights] to apply to
3046    /// the exposed directory capability.
3047    #[serde(skip_serializing_if = "Option::is_none")]
3048    #[reference_doc(json_type = "array of string")]
3049    pub rights: Option<Rights>,
3050
3051    /// (`directory` only) the relative path of a subdirectory within the source directory
3052    /// capability to route.
3053    #[serde(skip_serializing_if = "Option::is_none")]
3054    pub subdir: Option<RelativePath>,
3055
3056    /// (`event_stream` only) the name(s) of the event streams being exposed.
3057    #[serde(skip_serializing_if = "Option::is_none")]
3058    pub event_stream: Option<OneOrMany<Name>>,
3059
3060    /// (`event_stream` only) the scope(s) of the event streams being exposed. This is used to
3061    /// downscope the range of components to which an event stream refers and make it refer only to
3062    /// the components defined in the scope.
3063    #[serde(skip_serializing_if = "Option::is_none")]
3064    pub scope: Option<OneOrMany<EventScope>>,
3065
3066    /// `availability` _(optional)_: The expectations around this capability's availability. Affects
3067    /// build-time and runtime route validation. One of:
3068    /// - `required` (default): a required dependency, the source must exist and provide it. Use
3069    ///     this when the target of this expose requires this capability to function properly.
3070    /// - `optional`: an optional dependency. Use this when the target of the expose can function
3071    ///     with or without this capability. The target must not have a `required` dependency on the
3072    ///     capability. The ultimate source of this expose must be `void` or an actual component.
3073    /// - `same_as_target`: the availability expectations of this capability will match the
3074    ///     target's. If the target requires the capability, then this field is set to `required`.
3075    ///     If the target has an optional dependency on the capability, then the field is set to
3076    ///     `optional`.
3077    /// - `transitional`: like `optional`, but will tolerate a missing source. Use this
3078    ///     only to avoid validation errors during transitional periods of multi-step code changes.
3079    ///
3080    /// For more information, see the
3081    /// [availability](/docs/concepts/components/v2/capabilities/availability.md) documentation.
3082    #[serde(skip_serializing_if = "Option::is_none")]
3083    pub availability: Option<Availability>,
3084
3085    /// Whether or not the source of this offer must exist. One of:
3086    /// - `required` (default): the source (`from`) must be defined in this manifest.
3087    /// - `unknown`: the source of this offer will be rewritten to `void` if its source (`from`)
3088    ///     is not defined in this manifest after includes are processed.
3089    #[serde(skip_serializing_if = "Option::is_none")]
3090    pub source_availability: Option<SourceAvailability>,
3091}
3092
3093impl Expose {
3094    pub fn new_from(from: OneOrMany<ExposeFromRef>) -> Self {
3095        Self {
3096            from,
3097            service: None,
3098            protocol: None,
3099            directory: None,
3100            config: None,
3101            runner: None,
3102            resolver: None,
3103            dictionary: None,
3104            r#as: None,
3105            to: None,
3106            rights: None,
3107            subdir: None,
3108            event_stream: None,
3109            scope: None,
3110            availability: None,
3111            source_availability: None,
3112        }
3113    }
3114}
3115
3116/// Example:
3117///
3118/// ```json5
3119/// offer: [
3120///     {
3121///         protocol: "fuchsia.logger.LogSink",
3122///         from: "#logger",
3123///         to: [ "#fshost", "#pkg_cache" ],
3124///         dependency: "weak",
3125///     },
3126///     {
3127///         protocol: [
3128///             "fuchsia.ui.app.ViewProvider",
3129///             "fuchsia.fonts.Provider",
3130///         ],
3131///         from: "#session",
3132///         to: [ "#ui_shell" ],
3133///         dependency: "strong",
3134///     },
3135///     {
3136///         directory: "blobfs",
3137///         from: "self",
3138///         to: [ "#pkg_cache" ],
3139///     },
3140///     {
3141///         directory: "fshost-config",
3142///         from: "parent",
3143///         to: [ "#fshost" ],
3144///         as: "config",
3145///     },
3146///     {
3147///         storage: "cache",
3148///         from: "parent",
3149///         to: [ "#logger" ],
3150///     },
3151///     {
3152///         runner: "web",
3153///         from: "parent",
3154///         to: [ "#user-shell" ],
3155///     },
3156///     {
3157///         resolver: "full-resolver",
3158///         from: "parent",
3159///         to: [ "#user-shell" ],
3160///     },
3161///     {
3162///         event_stream: "stopped",
3163///         from: "framework",
3164///         to: [ "#logger" ],
3165///     },
3166/// ],
3167/// ```
3168#[derive(Deserialize, Debug, PartialEq, Clone, ReferenceDoc, Serialize)]
3169#[serde(deny_unknown_fields)]
3170#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
3171pub struct Offer {
3172    /// When routing a service, the [name](#name) of a [service capability][doc-service].
3173    #[serde(skip_serializing_if = "Option::is_none")]
3174    pub service: Option<OneOrMany<Name>>,
3175
3176    /// When routing a protocol, the [name](#name) of a [protocol capability][doc-protocol].
3177    #[serde(skip_serializing_if = "Option::is_none")]
3178    pub protocol: Option<OneOrMany<Name>>,
3179
3180    /// When routing a directory, the [name](#name) of a [directory capability][doc-directory].
3181    #[serde(skip_serializing_if = "Option::is_none")]
3182    pub directory: Option<OneOrMany<Name>>,
3183
3184    /// When routing a runner, the [name](#name) of a [runner capability][doc-runners].
3185    #[serde(skip_serializing_if = "Option::is_none")]
3186    pub runner: Option<OneOrMany<Name>>,
3187
3188    /// When routing a resolver, the [name](#name) of a [resolver capability][doc-resolvers].
3189    #[serde(skip_serializing_if = "Option::is_none")]
3190    pub resolver: Option<OneOrMany<Name>>,
3191
3192    /// When routing a storage capability, the [name](#name) of a [storage capability][doc-storage].
3193    #[serde(skip_serializing_if = "Option::is_none")]
3194    pub storage: Option<OneOrMany<Name>>,
3195
3196    /// When routing a dictionary, the [name](#name) of a [dictionary capability][doc-dictionaries].
3197    #[serde(skip_serializing_if = "Option::is_none")]
3198    pub dictionary: Option<OneOrMany<Name>>,
3199
3200    /// When routing a config, the [name](#name) of a configuration capability.
3201    #[serde(skip_serializing_if = "Option::is_none")]
3202    pub config: Option<OneOrMany<Name>>,
3203
3204    /// `from`: The source of the capability, one of:
3205    /// - `parent`: The component's parent. This source can be used for all
3206    ///     capability types.
3207    /// - `self`: This component. Requires a corresponding
3208    ///     [`capability`](#capabilities) declaration.
3209    /// - `framework`: The Component Framework runtime.
3210    /// - `#<child-name>`: A [reference](#references) to a child component
3211    ///     instance. This source can only be used when offering protocol,
3212    ///     directory, or runner capabilities.
3213    /// - `void`: The source is intentionally omitted. Only valid when `availability` is
3214    ///     `optional` or `transitional`.
3215    pub from: OneOrMany<OfferFromRef>,
3216
3217    /// Capability target(s). One of:
3218    /// - `#<target-name>` or \[`#name1`, ...\]: A [reference](#references) to a child or collection,
3219    ///   or an array of references.
3220    /// - `all`: Short-hand for an `offer` clause containing all child [references](#references).
3221    pub to: OneOrMany<OfferToRef>,
3222
3223    /// An explicit [name](#name) for the capability as it will be known by the target. If omitted,
3224    /// defaults to the original name. `as` cannot be used when an array of multiple names is
3225    /// provided.
3226    #[serde(skip_serializing_if = "Option::is_none")]
3227    pub r#as: Option<Name>,
3228
3229    /// The type of dependency between the source and
3230    /// targets, one of:
3231    /// - `strong`: a strong dependency, which is used to determine shutdown
3232    ///     ordering. Component manager is guaranteed to stop the target before the
3233    ///     source. This is the default.
3234    /// - `weak`: a weak dependency, which is ignored during
3235    ///     shutdown. When component manager stops the parent realm, the source may
3236    ///     stop before the clients. Clients of weak dependencies must be able to
3237    ///     handle these dependencies becoming unavailable.
3238    #[serde(skip_serializing_if = "Option::is_none")]
3239    pub dependency: Option<DependencyType>,
3240
3241    /// (`directory` only) the maximum [directory rights][doc-directory-rights] to apply to
3242    /// the offered directory capability.
3243    #[serde(skip_serializing_if = "Option::is_none")]
3244    #[reference_doc(json_type = "array of string")]
3245    pub rights: Option<Rights>,
3246
3247    /// (`directory` only) the relative path of a subdirectory within the source directory
3248    /// capability to route.
3249    #[serde(skip_serializing_if = "Option::is_none")]
3250    pub subdir: Option<RelativePath>,
3251
3252    /// (`event_stream` only) the name(s) of the event streams being offered.
3253    #[serde(skip_serializing_if = "Option::is_none")]
3254    pub event_stream: Option<OneOrMany<Name>>,
3255
3256    /// (`event_stream` only) When defined the event stream will contain events about only the
3257    /// components defined in the scope.
3258    #[serde(skip_serializing_if = "Option::is_none")]
3259    pub scope: Option<OneOrMany<EventScope>>,
3260
3261    /// `availability` _(optional)_: The expectations around this capability's availability. Affects
3262    /// build-time and runtime route validation. One of:
3263    /// - `required` (default): a required dependency, the source must exist and provide it. Use
3264    ///     this when the target of this offer requires this capability to function properly.
3265    /// - `optional`: an optional dependency. Use this when the target of the offer can function
3266    ///     with or without this capability. The target must not have a `required` dependency on the
3267    ///     capability. The ultimate source of this offer must be `void` or an actual component.
3268    /// - `same_as_target`: the availability expectations of this capability will match the
3269    ///     target's. If the target requires the capability, then this field is set to `required`.
3270    ///     If the target has an optional dependency on the capability, then the field is set to
3271    ///     `optional`.
3272    /// - `transitional`: like `optional`, but will tolerate a missing source. Use this
3273    ///     only to avoid validation errors during transitional periods of multi-step code changes.
3274    ///
3275    /// For more information, see the
3276    /// [availability](/docs/concepts/components/v2/capabilities/availability.md) documentation.
3277    #[serde(skip_serializing_if = "Option::is_none")]
3278    pub availability: Option<Availability>,
3279
3280    /// Whether or not the source of this offer must exist. One of:
3281    /// - `required` (default): the source (`from`) must be defined in this manifest.
3282    /// - `unknown`: the source of this offer will be rewritten to `void` if its source (`from`)
3283    ///     is not defined in this manifest after includes are processed.
3284    #[serde(skip_serializing_if = "Option::is_none")]
3285    pub source_availability: Option<SourceAvailability>,
3286}
3287
3288/// Example:
3289///
3290/// ```json5
3291/// children: [
3292///     {
3293///         name: "logger",
3294///         url: "fuchsia-pkg://fuchsia.com/logger#logger.cm",
3295///     },
3296///     {
3297///         name: "pkg_cache",
3298///         url: "fuchsia-pkg://fuchsia.com/pkg_cache#meta/pkg_cache.cm",
3299///         startup: "eager",
3300///     },
3301///     {
3302///         name: "child",
3303///         url: "#meta/child.cm",
3304///     }
3305/// ],
3306/// ```
3307///
3308/// [component-url]: /docs/reference/components/url.md
3309/// [doc-eager]: /docs/development/components/connect.md#eager
3310/// [doc-reboot-on-terminate]: /docs/development/components/connect.md#reboot-on-terminate
3311#[derive(ReferenceDoc, Deserialize, Debug, PartialEq, Serialize)]
3312#[serde(deny_unknown_fields)]
3313#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
3314pub struct Child {
3315    /// The name of the child component instance, which is a string of one
3316    /// or more of the following characters: `a-z`, `0-9`, `_`, `.`, `-`. The name
3317    /// identifies this component when used in a [reference](#references).
3318    pub name: Name,
3319
3320    /// The [component URL][component-url] for the child component instance.
3321    pub url: Url,
3322
3323    /// The component instance's startup mode. One of:
3324    /// - `lazy` _(default)_: Start the component instance only if another
3325    ///     component instance binds to it.
3326    /// - [`eager`][doc-eager]: Start the component instance as soon as its parent
3327    ///     starts.
3328    #[serde(default)]
3329    #[serde(skip_serializing_if = "StartupMode::is_lazy")]
3330    pub startup: StartupMode,
3331
3332    /// Determines the fault recovery policy to apply if this component terminates.
3333    /// - `none` _(default)_: Do nothing.
3334    /// - `reboot`: Gracefully reboot the system if the component terminates for
3335    ///     any reason other than graceful exit. This is a special feature for use only by a narrow
3336    ///     set of components; see [Termination policies][doc-reboot-on-terminate] for more
3337    ///     information.
3338    #[serde(skip_serializing_if = "Option::is_none")]
3339    pub on_terminate: Option<OnTerminate>,
3340
3341    /// If present, the name of the environment to be assigned to the child component instance, one
3342    /// of [`environments`](#environments). If omitted, the child will inherit the same environment
3343    /// assigned to this component.
3344    #[serde(skip_serializing_if = "Option::is_none")]
3345    pub environment: Option<EnvironmentRef>,
3346}
3347
3348#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
3349#[serde(deny_unknown_fields)]
3350#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
3351/// Example:
3352///
3353/// ```json5
3354/// collections: [
3355///     {
3356///         name: "tests",
3357///         durability: "transient",
3358///     },
3359/// ],
3360/// ```
3361pub struct Collection {
3362    /// The name of the component collection, which is a string of one or
3363    /// more of the following characters: `a-z`, `0-9`, `_`, `.`, `-`. The name
3364    /// identifies this collection when used in a [reference](#references).
3365    pub name: Name,
3366
3367    /// The duration of child component instances in the collection.
3368    /// - `transient`: The instance exists until its parent is stopped or it is
3369    ///     explicitly destroyed.
3370    /// - `single_run`: The instance is started when it is created, and destroyed
3371    ///     when it is stopped.
3372    pub durability: Durability,
3373
3374    /// If present, the environment that will be
3375    /// assigned to instances in this collection, one of
3376    /// [`environments`](#environments). If omitted, instances in this collection
3377    /// will inherit the same environment assigned to this component.
3378    pub environment: Option<EnvironmentRef>,
3379
3380    /// Constraints on the dynamic offers that target the components in this collection.
3381    /// Dynamic offers are specified when calling `fuchsia.component.Realm/CreateChild`.
3382    /// - `static_only`: Only those specified in this `.cml` file. No dynamic offers.
3383    ///     This is the default.
3384    /// - `static_and_dynamic`: Both static offers and those specified at runtime
3385    ///     with `CreateChild` are allowed.
3386    pub allowed_offers: Option<AllowedOffers>,
3387
3388    /// Allow child names up to 1024 characters long instead of the usual 255 character limit.
3389    /// Default is false.
3390    pub allow_long_names: Option<bool>,
3391
3392    /// If set to `true`, the data in isolated storage used by dynamic child instances and
3393    /// their descendants will persist after the instances are destroyed. A new child instance
3394    /// created with the same name will share the same storage path as the previous instance.
3395    pub persistent_storage: Option<bool>,
3396}
3397
3398pub trait FromClause {
3399    fn from_(&self) -> OneOrMany<AnyRef<'_>>;
3400}
3401
3402pub trait CapabilityClause: Clone + PartialEq + std::fmt::Debug {
3403    fn service(&self) -> Option<OneOrMany<&Name>>;
3404    fn protocol(&self) -> Option<OneOrMany<&Name>>;
3405    fn directory(&self) -> Option<OneOrMany<&Name>>;
3406    fn storage(&self) -> Option<OneOrMany<&Name>>;
3407    fn runner(&self) -> Option<OneOrMany<&Name>>;
3408    fn resolver(&self) -> Option<OneOrMany<&Name>>;
3409    fn event_stream(&self) -> Option<OneOrMany<&Name>>;
3410    fn dictionary(&self) -> Option<OneOrMany<&Name>>;
3411    fn config(&self) -> Option<OneOrMany<&Name>>;
3412    fn set_service(&mut self, o: Option<OneOrMany<Name>>);
3413    fn set_protocol(&mut self, o: Option<OneOrMany<Name>>);
3414    fn set_directory(&mut self, o: Option<OneOrMany<Name>>);
3415    fn set_storage(&mut self, o: Option<OneOrMany<Name>>);
3416    fn set_runner(&mut self, o: Option<OneOrMany<Name>>);
3417    fn set_resolver(&mut self, o: Option<OneOrMany<Name>>);
3418    fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>);
3419    fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>);
3420    fn set_config(&mut self, o: Option<OneOrMany<Name>>);
3421
3422    fn availability(&self) -> Option<Availability>;
3423    fn set_availability(&mut self, a: Option<Availability>);
3424
3425    /// Returns the name of the capability for display purposes.
3426    /// If `service()` returns `Some`, the capability name must be "service", etc.
3427    ///
3428    /// Returns an error if the capability name is not set, or if there is more than one.
3429    fn capability_type(&self) -> Result<&'static str, Error> {
3430        let mut types = Vec::new();
3431        if self.service().is_some() {
3432            types.push("service");
3433        }
3434        if self.protocol().is_some() {
3435            types.push("protocol");
3436        }
3437        if self.directory().is_some() {
3438            types.push("directory");
3439        }
3440        if self.storage().is_some() {
3441            types.push("storage");
3442        }
3443        if self.event_stream().is_some() {
3444            types.push("event_stream");
3445        }
3446        if self.runner().is_some() {
3447            types.push("runner");
3448        }
3449        if self.config().is_some() {
3450            types.push("config");
3451        }
3452        if self.resolver().is_some() {
3453            types.push("resolver");
3454        }
3455        if self.dictionary().is_some() {
3456            types.push("dictionary");
3457        }
3458        match types.len() {
3459            0 => {
3460                let supported_keywords = self
3461                    .supported()
3462                    .into_iter()
3463                    .map(|k| format!("\"{}\"", k))
3464                    .collect::<Vec<_>>()
3465                    .join(", ");
3466                Err(Error::validate(format!(
3467                    "`{}` declaration is missing a capability keyword, one of: {}",
3468                    self.decl_type(),
3469                    supported_keywords,
3470                )))
3471            }
3472            1 => Ok(types[0]),
3473            _ => Err(Error::validate(format!(
3474                "{} declaration has multiple capability types defined: {:?}",
3475                self.decl_type(),
3476                types
3477            ))),
3478        }
3479    }
3480
3481    /// Returns true if this capability type allows the ::Many variant of OneOrMany.
3482    fn are_many_names_allowed(&self) -> bool;
3483
3484    fn decl_type(&self) -> &'static str;
3485    fn supported(&self) -> &[&'static str];
3486
3487    /// Returns the names of the capabilities in this clause.
3488    /// If `protocol()` returns `Some(OneOrMany::Many(vec!["a", "b"]))`, this returns!["a", "b"].
3489    fn names(&self) -> Vec<&Name> {
3490        let res = vec![
3491            self.service(),
3492            self.protocol(),
3493            self.directory(),
3494            self.storage(),
3495            self.runner(),
3496            self.config(),
3497            self.resolver(),
3498            self.event_stream(),
3499            self.dictionary(),
3500        ];
3501        res.into_iter()
3502            .map(|o| o.map(|o| o.into_iter().collect::<Vec<&Name>>()).unwrap_or(vec![]))
3503            .flatten()
3504            .collect()
3505    }
3506
3507    fn set_names(&mut self, names: Vec<Name>) {
3508        let names = match names.len() {
3509            0 => None,
3510            1 => Some(OneOrMany::One(names.first().unwrap().clone())),
3511            _ => Some(OneOrMany::Many(names)),
3512        };
3513
3514        let cap_type = self.capability_type().unwrap();
3515        if cap_type == "protocol" {
3516            self.set_protocol(names);
3517        } else if cap_type == "service" {
3518            self.set_service(names);
3519        } else if cap_type == "directory" {
3520            self.set_directory(names);
3521        } else if cap_type == "storage" {
3522            self.set_storage(names);
3523        } else if cap_type == "runner" {
3524            self.set_runner(names);
3525        } else if cap_type == "resolver" {
3526            self.set_resolver(names);
3527        } else if cap_type == "event_stream" {
3528            self.set_event_stream(names);
3529        } else if cap_type == "dictionary" {
3530            self.set_dictionary(names);
3531        } else if cap_type == "config" {
3532            self.set_config(names);
3533        } else {
3534            panic!("Unknown capability type {}", cap_type);
3535        }
3536    }
3537}
3538
3539trait Canonicalize {
3540    fn canonicalize(&mut self);
3541}
3542
3543pub trait AsClause {
3544    fn r#as(&self) -> Option<&Name>;
3545}
3546
3547pub trait PathClause {
3548    fn path(&self) -> Option<&Path>;
3549}
3550
3551pub trait FilterClause {
3552    fn filter(&self) -> Option<&Map<String, Value>>;
3553}
3554
3555pub trait RightsClause {
3556    fn rights(&self) -> Option<&Rights>;
3557}
3558
3559fn always_one<T>(o: Option<OneOrMany<T>>) -> Option<T> {
3560    o.map(|o| match o {
3561        OneOrMany::One(o) => o,
3562        OneOrMany::Many(_) => panic!("many is impossible"),
3563    })
3564}
3565
3566impl Canonicalize for Capability {
3567    fn canonicalize(&mut self) {
3568        // Sort the names of the capabilities. Only capabilities with OneOrMany values are included here.
3569        if let Some(service) = &mut self.service {
3570            service.canonicalize()
3571        } else if let Some(protocol) = &mut self.protocol {
3572            protocol.canonicalize()
3573        } else if let Some(event_stream) = &mut self.event_stream {
3574            event_stream.canonicalize()
3575        }
3576    }
3577}
3578
3579fn option_one_or_many_as_ref<T>(o: &Option<OneOrMany<T>>) -> Option<OneOrMany<&T>> {
3580    o.as_ref().map(|o| o.as_ref())
3581}
3582
3583impl CapabilityClause for Capability {
3584    fn service(&self) -> Option<OneOrMany<&Name>> {
3585        option_one_or_many_as_ref(&self.service)
3586    }
3587    fn protocol(&self) -> Option<OneOrMany<&Name>> {
3588        option_one_or_many_as_ref(&self.protocol)
3589    }
3590    fn directory(&self) -> Option<OneOrMany<&Name>> {
3591        self.directory.as_ref().map(|n| OneOrMany::One(n))
3592    }
3593    fn storage(&self) -> Option<OneOrMany<&Name>> {
3594        self.storage.as_ref().map(|n| OneOrMany::One(n))
3595    }
3596    fn runner(&self) -> Option<OneOrMany<&Name>> {
3597        self.runner.as_ref().map(|n| OneOrMany::One(n))
3598    }
3599    fn resolver(&self) -> Option<OneOrMany<&Name>> {
3600        self.resolver.as_ref().map(|n| OneOrMany::One(n))
3601    }
3602    fn event_stream(&self) -> Option<OneOrMany<&Name>> {
3603        option_one_or_many_as_ref(&self.event_stream)
3604    }
3605    fn dictionary(&self) -> Option<OneOrMany<&Name>> {
3606        self.dictionary.as_ref().map(|n| OneOrMany::One(n))
3607    }
3608    fn config(&self) -> Option<OneOrMany<&Name>> {
3609        self.config.as_ref().map(|n| OneOrMany::One(n))
3610    }
3611
3612    fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
3613        self.service = o;
3614    }
3615    fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
3616        self.protocol = o;
3617    }
3618    fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
3619        self.directory = always_one(o);
3620    }
3621    fn set_storage(&mut self, o: Option<OneOrMany<Name>>) {
3622        self.storage = always_one(o);
3623    }
3624    fn set_runner(&mut self, o: Option<OneOrMany<Name>>) {
3625        self.runner = always_one(o);
3626    }
3627    fn set_resolver(&mut self, o: Option<OneOrMany<Name>>) {
3628        self.resolver = always_one(o);
3629    }
3630    fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
3631        self.event_stream = o;
3632    }
3633    fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>) {
3634        self.dictionary = always_one(o);
3635    }
3636
3637    fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
3638        self.config = always_one(o);
3639    }
3640
3641    fn availability(&self) -> Option<Availability> {
3642        None
3643    }
3644    fn set_availability(&mut self, _a: Option<Availability>) {}
3645
3646    fn decl_type(&self) -> &'static str {
3647        "capability"
3648    }
3649    fn supported(&self) -> &[&'static str] {
3650        &[
3651            "service",
3652            "protocol",
3653            "directory",
3654            "storage",
3655            "runner",
3656            "resolver",
3657            "event_stream",
3658            "dictionary",
3659            "config",
3660        ]
3661    }
3662    fn are_many_names_allowed(&self) -> bool {
3663        ["service", "protocol", "event_stream"].contains(&self.capability_type().unwrap())
3664    }
3665}
3666
3667impl AsClause for Capability {
3668    fn r#as(&self) -> Option<&Name> {
3669        None
3670    }
3671}
3672
3673impl PathClause for Capability {
3674    fn path(&self) -> Option<&Path> {
3675        self.path.as_ref()
3676    }
3677}
3678
3679impl FilterClause for Capability {
3680    fn filter(&self) -> Option<&Map<String, Value>> {
3681        None
3682    }
3683}
3684
3685impl RightsClause for Capability {
3686    fn rights(&self) -> Option<&Rights> {
3687        self.rights.as_ref()
3688    }
3689}
3690
3691impl CapabilityClause for DebugRegistration {
3692    fn service(&self) -> Option<OneOrMany<&Name>> {
3693        None
3694    }
3695    fn protocol(&self) -> Option<OneOrMany<&Name>> {
3696        option_one_or_many_as_ref(&self.protocol)
3697    }
3698    fn directory(&self) -> Option<OneOrMany<&Name>> {
3699        None
3700    }
3701    fn storage(&self) -> Option<OneOrMany<&Name>> {
3702        None
3703    }
3704    fn runner(&self) -> Option<OneOrMany<&Name>> {
3705        None
3706    }
3707    fn resolver(&self) -> Option<OneOrMany<&Name>> {
3708        None
3709    }
3710    fn event_stream(&self) -> Option<OneOrMany<&Name>> {
3711        None
3712    }
3713    fn dictionary(&self) -> Option<OneOrMany<&Name>> {
3714        None
3715    }
3716    fn config(&self) -> Option<OneOrMany<&Name>> {
3717        None
3718    }
3719
3720    fn set_service(&mut self, _o: Option<OneOrMany<Name>>) {}
3721    fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
3722        self.protocol = o;
3723    }
3724    fn set_directory(&mut self, _o: Option<OneOrMany<Name>>) {}
3725    fn set_storage(&mut self, _o: Option<OneOrMany<Name>>) {}
3726    fn set_runner(&mut self, _o: Option<OneOrMany<Name>>) {}
3727    fn set_resolver(&mut self, _o: Option<OneOrMany<Name>>) {}
3728    fn set_event_stream(&mut self, _o: Option<OneOrMany<Name>>) {}
3729    fn set_dictionary(&mut self, _o: Option<OneOrMany<Name>>) {}
3730    fn set_config(&mut self, _o: Option<OneOrMany<Name>>) {}
3731
3732    fn availability(&self) -> Option<Availability> {
3733        None
3734    }
3735    fn set_availability(&mut self, _a: Option<Availability>) {}
3736
3737    fn decl_type(&self) -> &'static str {
3738        "debug"
3739    }
3740    fn supported(&self) -> &[&'static str] {
3741        &["service", "protocol"]
3742    }
3743    fn are_many_names_allowed(&self) -> bool {
3744        ["protocol"].contains(&self.capability_type().unwrap())
3745    }
3746}
3747
3748impl AsClause for DebugRegistration {
3749    fn r#as(&self) -> Option<&Name> {
3750        self.r#as.as_ref()
3751    }
3752}
3753
3754impl PathClause for DebugRegistration {
3755    fn path(&self) -> Option<&Path> {
3756        None
3757    }
3758}
3759
3760impl FromClause for DebugRegistration {
3761    fn from_(&self) -> OneOrMany<AnyRef<'_>> {
3762        OneOrMany::One(AnyRef::from(&self.from))
3763    }
3764}
3765
3766impl Canonicalize for Use {
3767    fn canonicalize(&mut self) {
3768        // Sort the names of the capabilities. Only capabilities with OneOrMany values are included here.
3769        if let Some(service) = &mut self.service {
3770            service.canonicalize();
3771        } else if let Some(protocol) = &mut self.protocol {
3772            protocol.canonicalize();
3773        } else if let Some(event_stream) = &mut self.event_stream {
3774            event_stream.canonicalize();
3775            if let Some(scope) = &mut self.scope {
3776                scope.canonicalize();
3777            }
3778        }
3779    }
3780}
3781
3782impl CapabilityClause for Use {
3783    fn service(&self) -> Option<OneOrMany<&Name>> {
3784        option_one_or_many_as_ref(&self.service)
3785    }
3786    fn protocol(&self) -> Option<OneOrMany<&Name>> {
3787        option_one_or_many_as_ref(&self.protocol)
3788    }
3789    fn directory(&self) -> Option<OneOrMany<&Name>> {
3790        self.directory.as_ref().map(|n| OneOrMany::One(n))
3791    }
3792    fn storage(&self) -> Option<OneOrMany<&Name>> {
3793        self.storage.as_ref().map(|n| OneOrMany::One(n))
3794    }
3795    fn runner(&self) -> Option<OneOrMany<&Name>> {
3796        self.runner.as_ref().map(|n| OneOrMany::One(n))
3797    }
3798    fn resolver(&self) -> Option<OneOrMany<&Name>> {
3799        None
3800    }
3801    fn event_stream(&self) -> Option<OneOrMany<&Name>> {
3802        option_one_or_many_as_ref(&self.event_stream)
3803    }
3804    fn dictionary(&self) -> Option<OneOrMany<&Name>> {
3805        None
3806    }
3807    fn config(&self) -> Option<OneOrMany<&Name>> {
3808        self.config.as_ref().map(|n| OneOrMany::One(n))
3809    }
3810
3811    fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
3812        self.service = o;
3813    }
3814    fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
3815        self.protocol = o;
3816    }
3817    fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
3818        self.directory = always_one(o);
3819    }
3820    fn set_storage(&mut self, o: Option<OneOrMany<Name>>) {
3821        self.storage = always_one(o);
3822    }
3823    fn set_runner(&mut self, _o: Option<OneOrMany<Name>>) {}
3824    fn set_resolver(&mut self, _o: Option<OneOrMany<Name>>) {}
3825    fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
3826        self.event_stream = o;
3827    }
3828    fn set_dictionary(&mut self, _o: Option<OneOrMany<Name>>) {}
3829    fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
3830        self.config = always_one(o);
3831    }
3832
3833    fn availability(&self) -> Option<Availability> {
3834        self.availability
3835    }
3836    fn set_availability(&mut self, a: Option<Availability>) {
3837        self.availability = a;
3838    }
3839
3840    fn decl_type(&self) -> &'static str {
3841        "use"
3842    }
3843    fn supported(&self) -> &[&'static str] {
3844        &["service", "protocol", "directory", "storage", "event_stream", "runner", "config"]
3845    }
3846    fn are_many_names_allowed(&self) -> bool {
3847        ["service", "protocol", "event_stream"].contains(&self.capability_type().unwrap())
3848    }
3849}
3850
3851impl FilterClause for Use {
3852    fn filter(&self) -> Option<&Map<String, Value>> {
3853        self.filter.as_ref()
3854    }
3855}
3856
3857impl PathClause for Use {
3858    fn path(&self) -> Option<&Path> {
3859        self.path.as_ref()
3860    }
3861}
3862
3863impl FromClause for Use {
3864    fn from_(&self) -> OneOrMany<AnyRef<'_>> {
3865        let one = match &self.from {
3866            Some(from) => AnyRef::from(from),
3867            // Default for `use`.
3868            None => AnyRef::Parent,
3869        };
3870        OneOrMany::One(one)
3871    }
3872}
3873
3874impl FromClause for Expose {
3875    fn from_(&self) -> OneOrMany<AnyRef<'_>> {
3876        one_or_many_from_impl(&self.from)
3877    }
3878}
3879
3880impl RightsClause for Use {
3881    fn rights(&self) -> Option<&Rights> {
3882        self.rights.as_ref()
3883    }
3884}
3885
3886impl Canonicalize for Expose {
3887    fn canonicalize(&mut self) {
3888        // Sort the names of the capabilities. Only capabilities with OneOrMany values are included here.
3889        if let Some(service) = &mut self.service {
3890            service.canonicalize();
3891        } else if let Some(protocol) = &mut self.protocol {
3892            protocol.canonicalize();
3893        } else if let Some(directory) = &mut self.directory {
3894            directory.canonicalize();
3895        } else if let Some(runner) = &mut self.runner {
3896            runner.canonicalize();
3897        } else if let Some(resolver) = &mut self.resolver {
3898            resolver.canonicalize();
3899        } else if let Some(event_stream) = &mut self.event_stream {
3900            event_stream.canonicalize();
3901            if let Some(scope) = &mut self.scope {
3902                scope.canonicalize();
3903            }
3904        }
3905        // TODO(https://fxbug.dev/300500098): canonicalize dictionaries
3906    }
3907}
3908
3909impl CapabilityClause for Expose {
3910    fn service(&self) -> Option<OneOrMany<&Name>> {
3911        option_one_or_many_as_ref(&self.service)
3912    }
3913    fn protocol(&self) -> Option<OneOrMany<&Name>> {
3914        option_one_or_many_as_ref(&self.protocol)
3915    }
3916    fn directory(&self) -> Option<OneOrMany<&Name>> {
3917        option_one_or_many_as_ref(&self.directory)
3918    }
3919    fn storage(&self) -> Option<OneOrMany<&Name>> {
3920        None
3921    }
3922    fn runner(&self) -> Option<OneOrMany<&Name>> {
3923        option_one_or_many_as_ref(&self.runner)
3924    }
3925    fn resolver(&self) -> Option<OneOrMany<&Name>> {
3926        option_one_or_many_as_ref(&self.resolver)
3927    }
3928    fn event_stream(&self) -> Option<OneOrMany<&Name>> {
3929        option_one_or_many_as_ref(&self.event_stream)
3930    }
3931    fn dictionary(&self) -> Option<OneOrMany<&Name>> {
3932        option_one_or_many_as_ref(&self.dictionary)
3933    }
3934    fn config(&self) -> Option<OneOrMany<&Name>> {
3935        option_one_or_many_as_ref(&self.config)
3936    }
3937
3938    fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
3939        self.service = o;
3940    }
3941    fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
3942        self.protocol = o;
3943    }
3944    fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
3945        self.directory = o;
3946    }
3947    fn set_storage(&mut self, _o: Option<OneOrMany<Name>>) {}
3948    fn set_runner(&mut self, o: Option<OneOrMany<Name>>) {
3949        self.runner = o;
3950    }
3951    fn set_resolver(&mut self, o: Option<OneOrMany<Name>>) {
3952        self.resolver = o;
3953    }
3954    fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
3955        self.event_stream = o;
3956    }
3957    fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>) {
3958        self.dictionary = o;
3959    }
3960    fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
3961        self.config = o;
3962    }
3963
3964    fn availability(&self) -> Option<Availability> {
3965        None
3966    }
3967    fn set_availability(&mut self, _a: Option<Availability>) {}
3968
3969    fn decl_type(&self) -> &'static str {
3970        "expose"
3971    }
3972    fn supported(&self) -> &[&'static str] {
3973        &[
3974            "service",
3975            "protocol",
3976            "directory",
3977            "runner",
3978            "resolver",
3979            "event_stream",
3980            "dictionary",
3981            "config",
3982        ]
3983    }
3984    fn are_many_names_allowed(&self) -> bool {
3985        [
3986            "service",
3987            "protocol",
3988            "directory",
3989            "runner",
3990            "resolver",
3991            "event_stream",
3992            "dictionary",
3993            "config",
3994        ]
3995        .contains(&self.capability_type().unwrap())
3996    }
3997}
3998
3999impl AsClause for Expose {
4000    fn r#as(&self) -> Option<&Name> {
4001        self.r#as.as_ref()
4002    }
4003}
4004
4005impl PathClause for Expose {
4006    fn path(&self) -> Option<&Path> {
4007        None
4008    }
4009}
4010
4011impl FilterClause for Expose {
4012    fn filter(&self) -> Option<&Map<String, Value>> {
4013        None
4014    }
4015}
4016
4017impl RightsClause for Expose {
4018    fn rights(&self) -> Option<&Rights> {
4019        self.rights.as_ref()
4020    }
4021}
4022
4023impl FromClause for Offer {
4024    fn from_(&self) -> OneOrMany<AnyRef<'_>> {
4025        one_or_many_from_impl(&self.from)
4026    }
4027}
4028
4029impl Canonicalize for Offer {
4030    fn canonicalize(&mut self) {
4031        // Sort the names of the capabilities. Only capabilities with OneOrMany values are included here.
4032        if let Some(service) = &mut self.service {
4033            service.canonicalize();
4034        } else if let Some(protocol) = &mut self.protocol {
4035            protocol.canonicalize();
4036        } else if let Some(directory) = &mut self.directory {
4037            directory.canonicalize();
4038        } else if let Some(runner) = &mut self.runner {
4039            runner.canonicalize();
4040        } else if let Some(resolver) = &mut self.resolver {
4041            resolver.canonicalize();
4042        } else if let Some(storage) = &mut self.storage {
4043            storage.canonicalize();
4044        } else if let Some(event_stream) = &mut self.event_stream {
4045            event_stream.canonicalize();
4046            if let Some(scope) = &mut self.scope {
4047                scope.canonicalize();
4048            }
4049        }
4050    }
4051}
4052
4053impl CapabilityClause for Offer {
4054    fn service(&self) -> Option<OneOrMany<&Name>> {
4055        option_one_or_many_as_ref(&self.service)
4056    }
4057    fn protocol(&self) -> Option<OneOrMany<&Name>> {
4058        option_one_or_many_as_ref(&self.protocol)
4059    }
4060    fn directory(&self) -> Option<OneOrMany<&Name>> {
4061        option_one_or_many_as_ref(&self.directory)
4062    }
4063    fn storage(&self) -> Option<OneOrMany<&Name>> {
4064        option_one_or_many_as_ref(&self.storage)
4065    }
4066    fn runner(&self) -> Option<OneOrMany<&Name>> {
4067        option_one_or_many_as_ref(&self.runner)
4068    }
4069    fn resolver(&self) -> Option<OneOrMany<&Name>> {
4070        option_one_or_many_as_ref(&self.resolver)
4071    }
4072    fn event_stream(&self) -> Option<OneOrMany<&Name>> {
4073        option_one_or_many_as_ref(&self.event_stream)
4074    }
4075    fn dictionary(&self) -> Option<OneOrMany<&Name>> {
4076        option_one_or_many_as_ref(&self.dictionary)
4077    }
4078    fn config(&self) -> Option<OneOrMany<&Name>> {
4079        option_one_or_many_as_ref(&self.config)
4080    }
4081
4082    fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
4083        self.service = o;
4084    }
4085    fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
4086        self.protocol = o;
4087    }
4088    fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
4089        self.directory = o;
4090    }
4091    fn set_storage(&mut self, o: Option<OneOrMany<Name>>) {
4092        self.storage = o;
4093    }
4094    fn set_runner(&mut self, o: Option<OneOrMany<Name>>) {
4095        self.runner = o;
4096    }
4097    fn set_resolver(&mut self, o: Option<OneOrMany<Name>>) {
4098        self.resolver = o;
4099    }
4100    fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
4101        self.event_stream = o;
4102    }
4103    fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>) {
4104        self.dictionary = o;
4105    }
4106    fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
4107        self.config = o
4108    }
4109
4110    fn availability(&self) -> Option<Availability> {
4111        self.availability
4112    }
4113    fn set_availability(&mut self, a: Option<Availability>) {
4114        self.availability = a;
4115    }
4116
4117    fn decl_type(&self) -> &'static str {
4118        "offer"
4119    }
4120    fn supported(&self) -> &[&'static str] {
4121        &[
4122            "service",
4123            "protocol",
4124            "directory",
4125            "storage",
4126            "runner",
4127            "resolver",
4128            "event_stream",
4129            "config",
4130        ]
4131    }
4132    fn are_many_names_allowed(&self) -> bool {
4133        [
4134            "service",
4135            "protocol",
4136            "directory",
4137            "storage",
4138            "runner",
4139            "resolver",
4140            "event_stream",
4141            "config",
4142        ]
4143        .contains(&self.capability_type().unwrap())
4144    }
4145}
4146
4147impl AsClause for Offer {
4148    fn r#as(&self) -> Option<&Name> {
4149        self.r#as.as_ref()
4150    }
4151}
4152
4153impl PathClause for Offer {
4154    fn path(&self) -> Option<&Path> {
4155        None
4156    }
4157}
4158
4159impl RightsClause for Offer {
4160    fn rights(&self) -> Option<&Rights> {
4161        self.rights.as_ref()
4162    }
4163}
4164
4165impl FromClause for RunnerRegistration {
4166    fn from_(&self) -> OneOrMany<AnyRef<'_>> {
4167        OneOrMany::One(AnyRef::from(&self.from))
4168    }
4169}
4170
4171impl FromClause for ResolverRegistration {
4172    fn from_(&self) -> OneOrMany<AnyRef<'_>> {
4173        OneOrMany::One(AnyRef::from(&self.from))
4174    }
4175}
4176
4177fn one_or_many_from_impl<'a, T>(from: &'a OneOrMany<T>) -> OneOrMany<AnyRef<'a>>
4178where
4179    AnyRef<'a>: From<&'a T>,
4180    T: 'a,
4181{
4182    let r = match from {
4183        OneOrMany::One(r) => OneOrMany::One(r.into()),
4184        OneOrMany::Many(v) => OneOrMany::Many(v.into_iter().map(|r| r.into()).collect()),
4185    };
4186    r.into()
4187}
4188
4189pub fn alias_or_name<'a>(alias: Option<&'a Name>, name: &'a Name) -> &'a Name {
4190    alias.unwrap_or(name)
4191}
4192
4193pub fn alias_or_path<'a>(alias: Option<&'a Path>, path: &'a Path) -> &'a Path {
4194    alias.unwrap_or(path)
4195}
4196
4197pub fn format_cml(buffer: &str, file: Option<&std::path::Path>) -> Result<Vec<u8>, Error> {
4198    let general_order = PathOption::PropertyNameOrder(vec![
4199        "name",
4200        "url",
4201        "startup",
4202        "environment",
4203        "config",
4204        "dictionary",
4205        "durability",
4206        "service",
4207        "protocol",
4208        "directory",
4209        "storage",
4210        "runner",
4211        "resolver",
4212        "event",
4213        "event_stream",
4214        "from",
4215        "as",
4216        "to",
4217        "rights",
4218        "path",
4219        "subdir",
4220        "filter",
4221        "dependency",
4222        "extends",
4223        "runners",
4224        "resolvers",
4225        "debug",
4226    ]);
4227    let options = FormatOptions {
4228        collapse_containers_of_one: true,
4229        sort_array_items: true, // but use options_by_path to turn this off for program args
4230        options_by_path: hashmap! {
4231            "/*" => hashset! {
4232                PathOption::PropertyNameOrder(vec![
4233                    "include",
4234                    "program",
4235                    "children",
4236                    "collections",
4237                    "capabilities",
4238                    "use",
4239                    "offer",
4240                    "expose",
4241                    "environments",
4242                    "facets",
4243                ])
4244            },
4245            "/*/program" => hashset! {
4246                PathOption::CollapseContainersOfOne(false),
4247                PathOption::PropertyNameOrder(vec![
4248                    "runner",
4249                    "binary",
4250                    "args",
4251                ]),
4252            },
4253            "/*/program/*" => hashset! {
4254                PathOption::SortArrayItems(false),
4255            },
4256            "/*/*/*" => hashset! {
4257                general_order.clone()
4258            },
4259            "/*/*/*/*/*" => hashset! {
4260                general_order
4261            },
4262        },
4263        ..Default::default()
4264    };
4265
4266    json5format::format(buffer, file.map(|f| f.to_string_lossy().to_string()), Some(options))
4267        .map_err(|e| Error::json5(e, file))
4268}
4269
4270pub fn offer_to_all_and_component_diff_sources_message<'a>(
4271    capability: impl Iterator<Item = OfferToAllCapability<'a>>,
4272    component: &str,
4273) -> String {
4274    let mut output = String::new();
4275    let mut capability = capability.peekable();
4276    write!(&mut output, "{} ", capability.peek().unwrap().offer_type()).unwrap();
4277    for (i, capability) in capability.enumerate() {
4278        if i > 0 {
4279            write!(&mut output, ", ").unwrap();
4280        }
4281        write!(&mut output, "{}", capability.name()).unwrap();
4282    }
4283    write!(
4284        &mut output,
4285        r#" is offered to both "all" and child component "{}" with different sources"#,
4286        component
4287    )
4288    .unwrap();
4289    output
4290}
4291
4292pub fn offer_to_all_and_component_diff_capabilities_message<'a>(
4293    capability: impl Iterator<Item = OfferToAllCapability<'a>>,
4294    component: &str,
4295) -> String {
4296    let mut output = String::new();
4297    let mut capability_peek = capability.peekable();
4298
4299    // Clone is needed so the iterator can be moved forward.
4300    // This doesn't actually allocate memory or copy a string, as only the reference
4301    // held by the OfferToAllCapability<'a> is copied.
4302    let first_offer_to_all = capability_peek.peek().unwrap().clone();
4303    write!(&mut output, "{} ", first_offer_to_all.offer_type()).unwrap();
4304    for (i, capability) in capability_peek.enumerate() {
4305        if i > 0 {
4306            write!(&mut output, ", ").unwrap();
4307        }
4308        write!(&mut output, "{}", capability.name()).unwrap();
4309    }
4310    write!(&mut output, r#" is aliased to "{}" with the same name as an offer to "all", but from different source {}"#, component, first_offer_to_all.offer_type_plural()).unwrap();
4311    output
4312}
4313
4314/// Returns `Ok(true)` if desugaring the `offer_to_all` using `name` duplicates
4315/// `specific_offer`. Returns `Ok(false)` if not a duplicate.
4316///
4317/// Returns Err if there is a validation error.
4318pub fn offer_to_all_would_duplicate(
4319    offer_to_all: &Offer,
4320    specific_offer: &Offer,
4321    target: &cm_types::Name,
4322) -> Result<bool, Error> {
4323    // Only protocols and dictionaries may be offered to all
4324    assert!(offer_to_all.protocol.is_some() || offer_to_all.dictionary.is_some());
4325
4326    // If none of the pairs of the cross products of the two offer's protocols
4327    // match, then the offer is certainly not a duplicate
4328    if CapabilityId::from_offer_expose(specific_offer).iter().flatten().all(
4329        |specific_offer_cap_id| {
4330            CapabilityId::from_offer_expose(offer_to_all)
4331                .iter()
4332                .flatten()
4333                .all(|offer_to_all_cap_id| offer_to_all_cap_id != specific_offer_cap_id)
4334        },
4335    ) {
4336        return Ok(false);
4337    }
4338
4339    let to_field_matches = specific_offer
4340        .to
4341        .iter()
4342        .any(|specific_offer_to| matches!(specific_offer_to, OfferToRef::Named(c) if c == target));
4343
4344    if !to_field_matches {
4345        return Ok(false);
4346    }
4347
4348    if offer_to_all.from != specific_offer.from {
4349        return Err(Error::validate(offer_to_all_and_component_diff_sources_message(
4350            offer_to_all_from_offer(offer_to_all),
4351            target.as_str(),
4352        )));
4353    }
4354
4355    // Since the capability ID's match, the underlying protocol must also match
4356    if offer_to_all_from_offer(offer_to_all).all(|to_all_protocol| {
4357        offer_to_all_from_offer(specific_offer)
4358            .all(|to_specific_protocol| to_all_protocol != to_specific_protocol)
4359    }) {
4360        return Err(Error::validate(offer_to_all_and_component_diff_capabilities_message(
4361            offer_to_all_from_offer(offer_to_all),
4362            target.as_str(),
4363        )));
4364    }
4365
4366    Ok(true)
4367}
4368
4369impl Offer {
4370    /// Creates a new empty offer. This offer just has the `from` and `to` fields set, so to make
4371    /// it useful it needs at least the capability name set in the necesssary attribute.
4372    pub fn empty(from: OneOrMany<OfferFromRef>, to: OneOrMany<OfferToRef>) -> Offer {
4373        Self {
4374            protocol: None,
4375            from,
4376            to,
4377            r#as: None,
4378            service: None,
4379            directory: None,
4380            config: None,
4381            runner: None,
4382            resolver: None,
4383            storage: None,
4384            dictionary: None,
4385            dependency: None,
4386            rights: None,
4387            subdir: None,
4388            event_stream: None,
4389            scope: None,
4390            availability: None,
4391            source_availability: None,
4392        }
4393    }
4394}
4395
4396#[cfg(test)]
4397pub fn create_offer(
4398    protocol_name: &str,
4399    from: OneOrMany<OfferFromRef>,
4400    to: OneOrMany<OfferToRef>,
4401) -> Offer {
4402    Offer {
4403        protocol: Some(OneOrMany::One(Name::from_str(protocol_name).unwrap())),
4404        ..Offer::empty(from, to)
4405    }
4406}
4407
4408#[cfg(test)]
4409mod tests {
4410    use super::*;
4411    use assert_matches::assert_matches;
4412    use difference::Changeset;
4413    use serde_json::{json, to_string_pretty, to_value};
4414    use std::path::Path;
4415    use test_case::test_case;
4416
4417    macro_rules! assert_json_eq {
4418        ($a:expr, $e:expr) => {{
4419            if $a != $e {
4420                let expected = to_string_pretty(&$e).unwrap();
4421                let actual = to_string_pretty(&$a).unwrap();
4422                assert_eq!(
4423                    $a,
4424                    $e,
4425                    "JSON actual != expected. Diffs:\n\n{}",
4426                    Changeset::new(&actual, &expected, "\n")
4427                );
4428            }
4429        }};
4430    }
4431
4432    // Exercise reference parsing tests on `OfferFromRef` because it contains every reference
4433    // subtype.
4434
4435    #[test]
4436    fn test_parse_named_reference() {
4437        assert_matches!("#some-child".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "some-child");
4438        assert_matches!("#A".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "A");
4439        assert_matches!("#7".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "7");
4440        assert_matches!("#_".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "_");
4441
4442        assert_matches!("#-".parse::<OfferFromRef>(), Err(_));
4443        assert_matches!("#.".parse::<OfferFromRef>(), Err(_));
4444        assert_matches!("#".parse::<OfferFromRef>(), Err(_));
4445        assert_matches!("some-child".parse::<OfferFromRef>(), Err(_));
4446    }
4447
4448    #[test]
4449    fn test_parse_reference_test() {
4450        assert_matches!("parent".parse::<OfferFromRef>(), Ok(OfferFromRef::Parent));
4451        assert_matches!("framework".parse::<OfferFromRef>(), Ok(OfferFromRef::Framework));
4452        assert_matches!("self".parse::<OfferFromRef>(), Ok(OfferFromRef::Self_));
4453        assert_matches!("#child".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "child");
4454
4455        assert_matches!("invalid".parse::<OfferFromRef>(), Err(_));
4456        assert_matches!("#invalid-child^".parse::<OfferFromRef>(), Err(_));
4457    }
4458
4459    fn json_value_from_str(json: &str, filename: &Path) -> Result<Value, Error> {
4460        serde_json::from_str(json).map_err(|e| {
4461            Error::parse(
4462                format!("Couldn't read input as JSON: {}", e),
4463                Some(Location { line: e.line(), column: e.column() }),
4464                Some(filename),
4465            )
4466        })
4467    }
4468
4469    fn parse_as_ref(input: &str) -> Result<OfferFromRef, Error> {
4470        serde_json::from_value::<OfferFromRef>(json_value_from_str(input, &Path::new("test.cml"))?)
4471            .map_err(|e| Error::parse(format!("{}", e), None, None))
4472    }
4473
4474    #[test]
4475    fn test_deserialize_ref() -> Result<(), Error> {
4476        assert_matches!(parse_as_ref("\"self\""), Ok(OfferFromRef::Self_));
4477        assert_matches!(parse_as_ref("\"parent\""), Ok(OfferFromRef::Parent));
4478        assert_matches!(parse_as_ref("\"#child\""), Ok(OfferFromRef::Named(name)) if name == "child");
4479
4480        assert_matches!(parse_as_ref(r#""invalid""#), Err(_));
4481
4482        Ok(())
4483    }
4484
4485    macro_rules! test_parse_rights {
4486        (
4487            $(
4488                ($input:expr, $expected:expr),
4489            )+
4490        ) => {
4491            #[test]
4492            fn parse_rights() {
4493                $(
4494                    parse_rights_test($input, $expected);
4495                )+
4496            }
4497        }
4498    }
4499
4500    fn parse_rights_test(input: &str, expected: Right) {
4501        let r: Right = serde_json5::from_str(&format!("\"{}\"", input)).expect("invalid json");
4502        assert_eq!(r, expected);
4503    }
4504
4505    test_parse_rights! {
4506        ("connect", Right::Connect),
4507        ("enumerate", Right::Enumerate),
4508        ("execute", Right::Execute),
4509        ("get_attributes", Right::GetAttributes),
4510        ("modify_directory", Right::ModifyDirectory),
4511        ("read_bytes", Right::ReadBytes),
4512        ("traverse", Right::Traverse),
4513        ("update_attributes", Right::UpdateAttributes),
4514        ("write_bytes", Right::WriteBytes),
4515        ("r*", Right::ReadAlias),
4516        ("w*", Right::WriteAlias),
4517        ("x*", Right::ExecuteAlias),
4518        ("rw*", Right::ReadWriteAlias),
4519        ("rx*", Right::ReadExecuteAlias),
4520    }
4521
4522    macro_rules! test_expand_rights {
4523        (
4524            $(
4525                ($input:expr, $expected:expr),
4526            )+
4527        ) => {
4528            #[test]
4529            fn expand_rights() {
4530                $(
4531                    expand_rights_test($input, $expected);
4532                )+
4533            }
4534        }
4535    }
4536
4537    fn expand_rights_test(input: Right, expected: Vec<fio::Operations>) {
4538        assert_eq!(input.expand(), expected);
4539    }
4540
4541    test_expand_rights! {
4542        (Right::Connect, vec![fio::Operations::CONNECT]),
4543        (Right::Enumerate, vec![fio::Operations::ENUMERATE]),
4544        (Right::Execute, vec![fio::Operations::EXECUTE]),
4545        (Right::GetAttributes, vec![fio::Operations::GET_ATTRIBUTES]),
4546        (Right::ModifyDirectory, vec![fio::Operations::MODIFY_DIRECTORY]),
4547        (Right::ReadBytes, vec![fio::Operations::READ_BYTES]),
4548        (Right::Traverse, vec![fio::Operations::TRAVERSE]),
4549        (Right::UpdateAttributes, vec![fio::Operations::UPDATE_ATTRIBUTES]),
4550        (Right::WriteBytes, vec![fio::Operations::WRITE_BYTES]),
4551        (Right::ReadAlias, vec![
4552            fio::Operations::CONNECT,
4553            fio::Operations::ENUMERATE,
4554            fio::Operations::TRAVERSE,
4555            fio::Operations::READ_BYTES,
4556            fio::Operations::GET_ATTRIBUTES,
4557        ]),
4558        (Right::WriteAlias, vec![
4559            fio::Operations::CONNECT,
4560            fio::Operations::ENUMERATE,
4561            fio::Operations::TRAVERSE,
4562            fio::Operations::WRITE_BYTES,
4563            fio::Operations::MODIFY_DIRECTORY,
4564            fio::Operations::UPDATE_ATTRIBUTES,
4565        ]),
4566        (Right::ExecuteAlias, vec![
4567            fio::Operations::CONNECT,
4568            fio::Operations::ENUMERATE,
4569            fio::Operations::TRAVERSE,
4570            fio::Operations::EXECUTE,
4571        ]),
4572        (Right::ReadWriteAlias, vec![
4573            fio::Operations::CONNECT,
4574            fio::Operations::ENUMERATE,
4575            fio::Operations::TRAVERSE,
4576            fio::Operations::READ_BYTES,
4577            fio::Operations::WRITE_BYTES,
4578            fio::Operations::MODIFY_DIRECTORY,
4579            fio::Operations::GET_ATTRIBUTES,
4580            fio::Operations::UPDATE_ATTRIBUTES,
4581        ]),
4582        (Right::ReadExecuteAlias, vec![
4583            fio::Operations::CONNECT,
4584            fio::Operations::ENUMERATE,
4585            fio::Operations::TRAVERSE,
4586            fio::Operations::READ_BYTES,
4587            fio::Operations::GET_ATTRIBUTES,
4588            fio::Operations::EXECUTE,
4589        ]),
4590    }
4591
4592    #[test]
4593    fn test_deny_unknown_fields() {
4594        assert_matches!(serde_json5::from_str::<Document>("{ unknown: \"\" }"), Err(_));
4595        assert_matches!(serde_json5::from_str::<Environment>("{ unknown: \"\" }"), Err(_));
4596        assert_matches!(serde_json5::from_str::<RunnerRegistration>("{ unknown: \"\" }"), Err(_));
4597        assert_matches!(serde_json5::from_str::<ResolverRegistration>("{ unknown: \"\" }"), Err(_));
4598        assert_matches!(serde_json5::from_str::<Use>("{ unknown: \"\" }"), Err(_));
4599        assert_matches!(serde_json5::from_str::<Expose>("{ unknown: \"\" }"), Err(_));
4600        assert_matches!(serde_json5::from_str::<Offer>("{ unknown: \"\" }"), Err(_));
4601        assert_matches!(serde_json5::from_str::<Capability>("{ unknown: \"\" }"), Err(_));
4602        assert_matches!(serde_json5::from_str::<Child>("{ unknown: \"\" }"), Err(_));
4603        assert_matches!(serde_json5::from_str::<Collection>("{ unknown: \"\" }"), Err(_));
4604    }
4605
4606    // TODO: Use Default::default() instead
4607
4608    fn empty_offer() -> Offer {
4609        Offer {
4610            service: None,
4611            protocol: None,
4612            directory: None,
4613            storage: None,
4614            runner: None,
4615            resolver: None,
4616            dictionary: None,
4617            config: None,
4618            from: OneOrMany::One(OfferFromRef::Self_),
4619            to: OneOrMany::Many(vec![]),
4620            r#as: None,
4621            rights: None,
4622            subdir: None,
4623            dependency: None,
4624            event_stream: None,
4625            scope: None,
4626            availability: None,
4627            source_availability: None,
4628        }
4629    }
4630
4631    fn empty_use() -> Use {
4632        Use {
4633            service: None,
4634            protocol: None,
4635            scope: None,
4636            directory: None,
4637            storage: None,
4638            config: None,
4639            key: None,
4640            from: None,
4641            path: None,
4642            rights: None,
4643            subdir: None,
4644            event_stream: None,
4645            runner: None,
4646            filter: None,
4647            dependency: None,
4648            availability: None,
4649            config_element_type: None,
4650            config_max_count: None,
4651            config_max_size: None,
4652            config_type: None,
4653            config_default: None,
4654        }
4655    }
4656
4657    #[test]
4658    fn test_capability_id() -> Result<(), Error> {
4659        // service
4660        let a: Name = "a".parse().unwrap();
4661        let b: Name = "b".parse().unwrap();
4662        assert_eq!(
4663            CapabilityId::from_offer_expose(&Offer {
4664                service: Some(OneOrMany::One(a.clone())),
4665                ..empty_offer()
4666            },)?,
4667            vec![CapabilityId::Service(&a)]
4668        );
4669        assert_eq!(
4670            CapabilityId::from_offer_expose(&Offer {
4671                service: Some(OneOrMany::Many(vec![a.clone(), b.clone()],)),
4672                ..empty_offer()
4673            },)?,
4674            vec![CapabilityId::Service(&a), CapabilityId::Service(&b)]
4675        );
4676        assert_eq!(
4677            CapabilityId::from_use(&Use {
4678                service: Some(OneOrMany::One(a.clone())),
4679                ..empty_use()
4680            },)?,
4681            vec![CapabilityId::UsedService("/svc/a".parse().unwrap())]
4682        );
4683        assert_eq!(
4684            CapabilityId::from_use(&Use {
4685                service: Some(OneOrMany::Many(vec![a.clone(), b.clone(),],)),
4686                ..empty_use()
4687            },)?,
4688            vec![
4689                CapabilityId::UsedService("/svc/a".parse().unwrap()),
4690                CapabilityId::UsedService("/svc/b".parse().unwrap())
4691            ]
4692        );
4693        assert_eq!(
4694            CapabilityId::from_use(&Use {
4695                event_stream: Some(OneOrMany::One(Name::new("test".to_string()).unwrap())),
4696                path: Some(cm_types::Path::new("/svc/myevent".to_string()).unwrap()),
4697                ..empty_use()
4698            },)?,
4699            vec![CapabilityId::UsedEventStream("/svc/myevent".parse().unwrap()),]
4700        );
4701        assert_eq!(
4702            CapabilityId::from_use(&Use {
4703                event_stream: Some(OneOrMany::One(Name::new("test".to_string()).unwrap())),
4704                ..empty_use()
4705            },)?,
4706            vec![CapabilityId::UsedEventStream(
4707                "/svc/fuchsia.component.EventStream".parse().unwrap()
4708            ),]
4709        );
4710        assert_eq!(
4711            CapabilityId::from_use(&Use {
4712                service: Some(OneOrMany::One(a.clone())),
4713                path: Some("/b".parse().unwrap()),
4714                ..empty_use()
4715            },)?,
4716            vec![CapabilityId::UsedService("/b".parse().unwrap())]
4717        );
4718
4719        // protocol
4720        assert_eq!(
4721            CapabilityId::from_offer_expose(&Offer {
4722                protocol: Some(OneOrMany::One(a.clone())),
4723                ..empty_offer()
4724            },)?,
4725            vec![CapabilityId::Protocol(&a)]
4726        );
4727        assert_eq!(
4728            CapabilityId::from_offer_expose(&Offer {
4729                protocol: Some(OneOrMany::Many(vec![a.clone(), b.clone()],)),
4730                ..empty_offer()
4731            },)?,
4732            vec![CapabilityId::Protocol(&a), CapabilityId::Protocol(&b)]
4733        );
4734        assert_eq!(
4735            CapabilityId::from_use(&Use {
4736                protocol: Some(OneOrMany::One(a.clone())),
4737                ..empty_use()
4738            },)?,
4739            vec![CapabilityId::UsedProtocol("/svc/a".parse().unwrap())]
4740        );
4741        assert_eq!(
4742            CapabilityId::from_use(&Use {
4743                protocol: Some(OneOrMany::Many(vec![a.clone(), b.clone(),],)),
4744                ..empty_use()
4745            },)?,
4746            vec![
4747                CapabilityId::UsedProtocol("/svc/a".parse().unwrap()),
4748                CapabilityId::UsedProtocol("/svc/b".parse().unwrap())
4749            ]
4750        );
4751        assert_eq!(
4752            CapabilityId::from_use(&Use {
4753                protocol: Some(OneOrMany::One(a.clone())),
4754                path: Some("/b".parse().unwrap()),
4755                ..empty_use()
4756            },)?,
4757            vec![CapabilityId::UsedProtocol("/b".parse().unwrap())]
4758        );
4759
4760        // directory
4761        assert_eq!(
4762            CapabilityId::from_offer_expose(&Offer {
4763                directory: Some(OneOrMany::One(a.clone())),
4764                ..empty_offer()
4765            },)?,
4766            vec![CapabilityId::Directory(&a)]
4767        );
4768        assert_eq!(
4769            CapabilityId::from_offer_expose(&Offer {
4770                directory: Some(OneOrMany::Many(vec![a.clone(), b.clone()])),
4771                ..empty_offer()
4772            },)?,
4773            vec![CapabilityId::Directory(&a), CapabilityId::Directory(&b),]
4774        );
4775        assert_eq!(
4776            CapabilityId::from_use(&Use {
4777                directory: Some(a.clone()),
4778                path: Some("/b".parse().unwrap()),
4779                ..empty_use()
4780            },)?,
4781            vec![CapabilityId::UsedDirectory("/b".parse().unwrap())]
4782        );
4783
4784        // storage
4785        assert_eq!(
4786            CapabilityId::from_offer_expose(&Offer {
4787                storage: Some(OneOrMany::One(a.clone())),
4788                ..empty_offer()
4789            },)?,
4790            vec![CapabilityId::Storage(&a)]
4791        );
4792        assert_eq!(
4793            CapabilityId::from_offer_expose(&Offer {
4794                storage: Some(OneOrMany::Many(vec![a.clone(), b.clone()])),
4795                ..empty_offer()
4796            },)?,
4797            vec![CapabilityId::Storage(&a), CapabilityId::Storage(&b),]
4798        );
4799        assert_eq!(
4800            CapabilityId::from_use(&Use {
4801                storage: Some(a.clone()),
4802                path: Some("/b".parse().unwrap()),
4803                ..empty_use()
4804            },)?,
4805            vec![CapabilityId::UsedStorage("/b".parse().unwrap())]
4806        );
4807
4808        // runner
4809        assert_eq!(
4810            CapabilityId::from_use(&Use { runner: Some("elf".parse().unwrap()), ..empty_use() },)?,
4811            vec![CapabilityId::UsedRunner(&"elf".parse().unwrap())]
4812        );
4813
4814        // "as" aliasing.
4815        assert_eq!(
4816            CapabilityId::from_offer_expose(&Offer {
4817                service: Some(OneOrMany::One(a.clone())),
4818                r#as: Some(b.clone()),
4819                ..empty_offer()
4820            },)?,
4821            vec![CapabilityId::Service(&b)]
4822        );
4823
4824        // Error case.
4825        assert_matches!(CapabilityId::from_offer_expose(&empty_offer()), Err(_));
4826
4827        Ok(())
4828    }
4829
4830    fn document(contents: serde_json::Value) -> Document {
4831        serde_json5::from_str::<Document>(&contents.to_string()).unwrap()
4832    }
4833
4834    #[test]
4835    fn test_includes() {
4836        assert_eq!(document(json!({})).includes(), Vec::<String>::new());
4837        assert_eq!(document(json!({ "include": []})).includes(), Vec::<String>::new());
4838        assert_eq!(
4839            document(json!({ "include": [ "foo.cml", "bar.cml" ]})).includes(),
4840            vec!["foo.cml", "bar.cml"]
4841        );
4842    }
4843
4844    #[test]
4845    fn test_merge_same_section() {
4846        let mut some = document(json!({ "use": [{ "protocol": "foo" }] }));
4847        let mut other = document(json!({ "use": [{ "protocol": "bar" }] }));
4848        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
4849        let uses = some.r#use.as_ref().unwrap();
4850        assert_eq!(uses.len(), 2);
4851        assert_eq!(
4852            uses[0].protocol.as_ref().unwrap(),
4853            &OneOrMany::One("foo".parse::<Name>().unwrap())
4854        );
4855        assert_eq!(
4856            uses[1].protocol.as_ref().unwrap(),
4857            &OneOrMany::One("bar".parse::<Name>().unwrap())
4858        );
4859    }
4860
4861    #[test]
4862    fn test_merge_upgraded_availability() {
4863        let mut some =
4864            document(json!({ "use": [{ "protocol": "foo", "availability": "optional" }] }));
4865        let mut other1 = document(json!({ "use": [{ "protocol": "foo" }] }));
4866        let mut other2 =
4867            document(json!({ "use": [{ "protocol": "foo", "availability": "transitional" }] }));
4868        let mut other3 =
4869            document(json!({ "use": [{ "protocol": "foo", "availability": "same_as_target" }] }));
4870        some.merge_from(&mut other1, &Path::new("some/path")).unwrap();
4871        some.merge_from(&mut other2, &Path::new("some/path")).unwrap();
4872        some.merge_from(&mut other3, &Path::new("some/path")).unwrap();
4873        let uses = some.r#use.as_ref().unwrap();
4874        assert_eq!(uses.len(), 2);
4875        assert_eq!(
4876            uses[0].protocol.as_ref().unwrap(),
4877            &OneOrMany::One("foo".parse::<Name>().unwrap())
4878        );
4879        assert!(uses[0].availability.is_none());
4880        assert_eq!(
4881            uses[1].protocol.as_ref().unwrap(),
4882            &OneOrMany::One("foo".parse::<Name>().unwrap())
4883        );
4884        assert_eq!(uses[1].availability.as_ref().unwrap(), &Availability::SameAsTarget,);
4885    }
4886
4887    #[test]
4888    fn test_merge_different_sections() {
4889        let mut some = document(json!({ "use": [{ "protocol": "foo" }] }));
4890        let mut other = document(json!({ "expose": [{ "protocol": "bar", "from": "self" }] }));
4891        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
4892        let uses = some.r#use.as_ref().unwrap();
4893        let exposes = some.expose.as_ref().unwrap();
4894        assert_eq!(uses.len(), 1);
4895        assert_eq!(exposes.len(), 1);
4896        assert_eq!(
4897            uses[0].protocol.as_ref().unwrap(),
4898            &OneOrMany::One("foo".parse::<Name>().unwrap())
4899        );
4900        assert_eq!(
4901            exposes[0].protocol.as_ref().unwrap(),
4902            &OneOrMany::One("bar".parse::<Name>().unwrap())
4903        );
4904    }
4905
4906    #[test]
4907    fn test_merge_environments() {
4908        let mut some = document(json!({ "environments": [
4909            {
4910                "name": "one",
4911                "extends": "realm",
4912            },
4913            {
4914                "name": "two",
4915                "extends": "none",
4916                "runners": [
4917                    {
4918                        "runner": "r1",
4919                        "from": "#c1",
4920                    },
4921                    {
4922                        "runner": "r2",
4923                        "from": "#c2",
4924                    },
4925                ],
4926                "resolvers": [
4927                    {
4928                        "resolver": "res1",
4929                        "from": "#c1",
4930                        "scheme": "foo",
4931                    },
4932                ],
4933                "debug": [
4934                    {
4935                        "protocol": "baz",
4936                        "from": "#c2"
4937                    }
4938                ]
4939            },
4940        ]}));
4941        let mut other = document(json!({ "environments": [
4942            {
4943                "name": "two",
4944                "__stop_timeout_ms": 100,
4945                "runners": [
4946                    {
4947                        "runner": "r3",
4948                        "from": "#c3",
4949                    },
4950                ],
4951                "resolvers": [
4952                    {
4953                        "resolver": "res2",
4954                        "from": "#c1",
4955                        "scheme": "bar",
4956                    },
4957                ],
4958                "debug": [
4959                    {
4960                        "protocol": "faz",
4961                        "from": "#c2"
4962                    }
4963                ]
4964            },
4965            {
4966                "name": "three",
4967                "__stop_timeout_ms": 1000,
4968            },
4969        ]}));
4970        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
4971        assert_eq!(
4972            to_value(some).unwrap(),
4973            json!({"environments": [
4974                {
4975                    "name": "one",
4976                    "extends": "realm",
4977                },
4978                {
4979                    "name": "three",
4980                    "__stop_timeout_ms": 1000,
4981                },
4982                {
4983                    "name": "two",
4984                    "extends": "none",
4985                    "__stop_timeout_ms": 100,
4986                    "runners": [
4987                        {
4988                            "runner": "r1",
4989                            "from": "#c1",
4990                        },
4991                        {
4992                            "runner": "r2",
4993                            "from": "#c2",
4994                        },
4995                        {
4996                            "runner": "r3",
4997                            "from": "#c3",
4998                        },
4999                    ],
5000                    "resolvers": [
5001                        {
5002                            "resolver": "res1",
5003                            "from": "#c1",
5004                            "scheme": "foo",
5005                        },
5006                        {
5007                            "resolver": "res2",
5008                            "from": "#c1",
5009                            "scheme": "bar",
5010                        },
5011                    ],
5012                    "debug": [
5013                        {
5014                            "protocol": "baz",
5015                            "from": "#c2"
5016                        },
5017                        {
5018                            "protocol": "faz",
5019                            "from": "#c2"
5020                        }
5021                    ]
5022                },
5023            ]})
5024        );
5025    }
5026
5027    #[test]
5028    fn test_merge_environments_errors() {
5029        {
5030            let mut some = document(json!({"environments": [{"name": "one", "extends": "realm"}]}));
5031            let mut other = document(json!({"environments": [{"name": "one", "extends": "none"}]}));
5032            assert!(some.merge_from(&mut other, &Path::new("some/path")).is_err());
5033        }
5034        {
5035            let mut some =
5036                document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]}));
5037            let mut other =
5038                document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 20}]}));
5039            assert!(some.merge_from(&mut other, &Path::new("some/path")).is_err());
5040        }
5041
5042        // It's ok if the values match.
5043        {
5044            let mut some = document(json!({"environments": [{"name": "one", "extends": "realm"}]}));
5045            let mut other =
5046                document(json!({"environments": [{"name": "one", "extends": "realm"}]}));
5047            some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5048            assert_eq!(
5049                to_value(some).unwrap(),
5050                json!({"environments": [{"name": "one", "extends": "realm"}]})
5051            );
5052        }
5053        {
5054            let mut some =
5055                document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]}));
5056            let mut other =
5057                document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]}));
5058            some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5059            assert_eq!(
5060                to_value(some).unwrap(),
5061                json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]})
5062            );
5063        }
5064    }
5065
5066    #[test]
5067    fn test_merge_from_other_config() {
5068        let mut some = document(json!({}));
5069        let mut other = document(json!({ "config": { "bar": { "type": "bool" } } }));
5070
5071        some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5072        let expected = document(json!({ "config": { "bar": { "type": "bool" } } }));
5073        assert_eq!(some.config, expected.config);
5074    }
5075
5076    #[test]
5077    fn test_merge_from_some_config() {
5078        let mut some = document(json!({ "config": { "bar": { "type": "bool" } } }));
5079        let mut other = document(json!({}));
5080
5081        some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5082        let expected = document(json!({ "config": { "bar": { "type": "bool" } } }));
5083        assert_eq!(some.config, expected.config);
5084    }
5085
5086    #[test]
5087    fn test_merge_from_config() {
5088        let mut some = document(json!({ "config": { "foo": { "type": "bool" } } }));
5089        let mut other = document(json!({ "config": { "bar": { "type": "bool" } } }));
5090        some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5091
5092        assert_eq!(
5093            some,
5094            document(json!({
5095                "config": {
5096                    "foo": { "type": "bool" },
5097                    "bar": { "type": "bool" },
5098                }
5099            })),
5100        );
5101    }
5102
5103    #[test]
5104    fn test_merge_from_config_dedupe_identical_fields() {
5105        let mut some = document(json!({ "config": { "foo": { "type": "bool" } } }));
5106        let mut other = document(json!({ "config": { "foo": { "type": "bool" } } }));
5107        some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5108
5109        assert_eq!(some, document(json!({ "config": { "foo": { "type": "bool" } } })));
5110    }
5111
5112    #[test]
5113    fn test_merge_from_config_conflicting_keys() {
5114        let mut some = document(json!({ "config": { "foo": { "type": "bool" } } }));
5115        let mut other = document(json!({ "config": { "foo": { "type": "uint8" } } }));
5116
5117        assert_matches::assert_matches!(
5118            some.merge_from(&mut other, &path::Path::new("some/path")),
5119            Err(Error::Validate { err, .. })
5120                if err == "Found conflicting entry for config key `foo` in `some/path`."
5121        );
5122    }
5123
5124    #[test]
5125    fn test_canonicalize() {
5126        let mut some = document(json!({
5127            "children": [
5128                // Will be sorted by name
5129                { "name": "b_child", "url": "http://foo/b" },
5130                { "name": "a_child", "url": "http://foo/a" },
5131            ],
5132            "environments": [
5133                // Will be sorted by name
5134                { "name": "b_env" },
5135                { "name": "a_env" },
5136            ],
5137            "collections": [
5138                // Will be sorted by name
5139                { "name": "b_coll", "durability": "transient" },
5140                { "name": "a_coll", "durability": "transient" },
5141            ],
5142            // Will have entries sorted by capability type, then
5143            // by capability name (using the first entry in Many cases).
5144            "capabilities": [
5145                // Will be merged with "bar"
5146                { "protocol": ["foo"] },
5147                { "protocol": "bar" },
5148                // Will not be merged, but will be sorted before "bar"
5149                { "protocol": "arg", "path": "/arg" },
5150                // Will have list of names sorted
5151                { "service": ["b", "a"] },
5152                // Will have list of names sorted
5153                { "event_stream": ["b", "a"] },
5154                { "runner": "myrunner" },
5155                // The following two will *not* be merged, because they have a `path`.
5156                { "runner": "mypathrunner1", "path": "/foo" },
5157                { "runner": "mypathrunner2", "path": "/foo" },
5158            ],
5159            // Same rules as for "capabilities".
5160            "offer": [
5161                // Will be sorted after "bar"
5162                { "protocol": "baz", "from": "#a_child", "to": "#c_child"  },
5163                // The following two entries will be merged
5164                { "protocol": ["foo"], "from": "#a_child", "to": "#b_child"  },
5165                { "protocol": "bar", "from": "#a_child", "to": "#b_child"  },
5166                // Will have list of names sorted
5167                { "service": ["b", "a"], "from": "#a_child", "to": "#b_child"  },
5168                // Will have list of names sorted
5169                {
5170                    "event_stream": ["b", "a"],
5171                    "from": "#a_child",
5172                    "to": "#b_child",
5173                    "scope": ["#b", "#c", "#a"]  // Also gets sorted
5174                },
5175                { "runner": [ "myrunner", "a" ], "from": "#a_child", "to": "#b_child"  },
5176                { "runner": [ "b" ], "from": "#a_child", "to": "#b_child"  },
5177                { "directory": [ "b" ], "from": "#a_child", "to": "#b_child"  },
5178            ],
5179            "expose": [
5180                { "protocol": ["foo"], "from": "#a_child" },
5181                { "protocol": "bar", "from": "#a_child" },  // Will appear before protocol: foo
5182                // Will have list of names sorted
5183                { "service": ["b", "a"], "from": "#a_child" },
5184                // Will have list of names sorted
5185                {
5186                    "event_stream": ["b", "a"],
5187                    "from": "#a_child",
5188                    "scope": ["#b", "#c", "#a"]  // Also gets sorted
5189                },
5190                { "runner": [ "myrunner", "a" ], "from": "#a_child" },
5191                { "runner": [ "b" ], "from": "#a_child" },
5192                { "directory": [ "b" ], "from": "#a_child" },
5193            ],
5194            "use": [
5195                // Will be sorted after "baz"
5196                { "protocol": ["zazzle"], "path": "/zazbaz" },
5197                // These will be merged
5198                { "protocol": ["foo"] },
5199                { "protocol": "bar" },
5200                // Will have list of names sorted
5201                { "service": ["b", "a"] },
5202                // Will have list of names sorted
5203                { "event_stream": ["b", "a"], "scope": ["#b", "#a"] },
5204            ],
5205        }));
5206        some.canonicalize();
5207
5208        assert_json_eq!(
5209            some,
5210            document(json!({
5211                "children": [
5212                    { "name": "a_child", "url": "http://foo/a" },
5213                    { "name": "b_child", "url": "http://foo/b" },
5214                ],
5215                "collections": [
5216                    { "name": "a_coll", "durability": "transient" },
5217                    { "name": "b_coll", "durability": "transient" },
5218                ],
5219                "environments": [
5220                    { "name": "a_env" },
5221                    { "name": "b_env" },
5222                ],
5223                "capabilities": [
5224                    { "event_stream": ["a", "b"] },
5225                    { "protocol": "arg", "path": "/arg" },
5226                    { "protocol": ["bar", "foo"] },
5227                    { "runner": "mypathrunner1", "path": "/foo" },
5228                    { "runner": "mypathrunner2", "path": "/foo" },
5229                    { "runner": "myrunner" },
5230                    { "service": ["a", "b"] },
5231                ],
5232                "use": [
5233                    { "event_stream": ["a", "b"], "scope": ["#a", "#b"] },
5234                    { "protocol": ["bar", "foo"] },
5235                    { "protocol": "zazzle", "path": "/zazbaz" },
5236                    { "service": ["a", "b"] },
5237                ],
5238                "offer": [
5239                    { "directory": "b", "from": "#a_child", "to": "#b_child" },
5240                    {
5241                        "event_stream": ["a", "b"],
5242                        "from": "#a_child",
5243                        "to": "#b_child",
5244                        "scope": ["#a", "#b", "#c"],
5245                    },
5246                    { "protocol": ["bar", "foo"], "from": "#a_child", "to": "#b_child" },
5247                    { "protocol": "baz", "from": "#a_child", "to": "#c_child"  },
5248                    { "runner": [ "a", "b", "myrunner" ], "from": "#a_child", "to": "#b_child" },
5249                    { "service": ["a", "b"], "from": "#a_child", "to": "#b_child" },
5250                ],
5251                "expose": [
5252                    { "directory": "b", "from": "#a_child" },
5253                    {
5254                        "event_stream": ["a", "b"],
5255                        "from": "#a_child",
5256                        "scope": ["#a", "#b", "#c"],
5257                    },
5258                    { "protocol": ["bar", "foo"], "from": "#a_child" },
5259                    { "runner": [ "a", "b", "myrunner" ], "from": "#a_child" },
5260                    { "service": ["a", "b"], "from": "#a_child" },
5261                ],
5262            }))
5263        )
5264    }
5265
5266    #[test]
5267    fn deny_unknown_config_type_fields() {
5268        let input = json!({ "config": { "foo": { "type": "bool", "unknown": "should error" } } });
5269        serde_json5::from_str::<Document>(&input.to_string())
5270            .expect_err("must reject unknown config field attributes");
5271    }
5272
5273    #[test]
5274    fn deny_unknown_config_nested_type_fields() {
5275        let input = json!({
5276            "config": {
5277                "foo": {
5278                    "type": "vector",
5279                    "max_count": 10,
5280                    "element": {
5281                        "type": "bool",
5282                        "unknown": "should error"
5283                    },
5284
5285                }
5286            }
5287        });
5288        serde_json5::from_str::<Document>(&input.to_string())
5289            .expect_err("must reject unknown config field attributes");
5290    }
5291
5292    #[test]
5293    fn test_merge_from_program() {
5294        let mut some = document(json!({ "program": { "binary": "bin/hello_world" } }));
5295        let mut other = document(json!({ "program": { "runner": "elf" } }));
5296        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5297        let expected =
5298            document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5299        assert_eq!(some.program, expected.program);
5300    }
5301
5302    #[test]
5303    fn test_merge_from_program_without_runner() {
5304        let mut some =
5305            document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5306        // https://fxbug.dev/42160240: merging with a document that doesn't have a runner doesn't override the
5307        // runner that we already have assigned.
5308        let mut other = document(json!({ "program": {} }));
5309        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5310        let expected =
5311            document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5312        assert_eq!(some.program, expected.program);
5313    }
5314
5315    #[test]
5316    fn test_merge_from_program_overlapping_environ() {
5317        // It's ok to merge `program.environ` by concatenating the arrays together.
5318        let mut some = document(json!({ "program": { "environ": ["1"] } }));
5319        let mut other = document(json!({ "program": { "environ": ["2"] } }));
5320        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5321        let expected = document(json!({ "program": { "environ": ["1", "2"] } }));
5322        assert_eq!(some.program, expected.program);
5323    }
5324
5325    #[test]
5326    fn test_merge_from_program_overlapping_runner() {
5327        // It's ok to merge `program.runner = "elf"` with `program.runner = "elf"`.
5328        let mut some =
5329            document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5330        let mut other = document(json!({ "program": { "runner": "elf" } }));
5331        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5332        let expected =
5333            document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5334        assert_eq!(some.program, expected.program);
5335    }
5336
5337    #[test]
5338    fn test_offer_would_duplicate() {
5339        let offer = create_offer(
5340            "fuchsia.logger.LegacyLog",
5341            OneOrMany::One(OfferFromRef::Parent {}),
5342            OneOrMany::One(OfferToRef::Named(Name::from_str("something").unwrap())),
5343        );
5344
5345        let offer_to_all = create_offer(
5346            "fuchsia.logger.LogSink",
5347            OneOrMany::One(OfferFromRef::Parent {}),
5348            OneOrMany::One(OfferToRef::All),
5349        );
5350
5351        // different protocols
5352        assert!(!offer_to_all_would_duplicate(
5353            &offer_to_all,
5354            &offer,
5355            &Name::from_str("something").unwrap()
5356        )
5357        .unwrap());
5358
5359        let offer = create_offer(
5360            "fuchsia.logger.LogSink",
5361            OneOrMany::One(OfferFromRef::Parent {}),
5362            OneOrMany::One(OfferToRef::Named(Name::from_str("not-something").unwrap())),
5363        );
5364
5365        // different targets
5366        assert!(!offer_to_all_would_duplicate(
5367            &offer_to_all,
5368            &offer,
5369            &Name::from_str("something").unwrap()
5370        )
5371        .unwrap());
5372
5373        let mut offer = create_offer(
5374            "fuchsia.logger.LogSink",
5375            OneOrMany::One(OfferFromRef::Parent {}),
5376            OneOrMany::One(OfferToRef::Named(Name::from_str("something").unwrap())),
5377        );
5378
5379        offer.r#as = Some(Name::from_str("FakeLog").unwrap());
5380
5381        // target has alias
5382        assert!(!offer_to_all_would_duplicate(
5383            &offer_to_all,
5384            &offer,
5385            &Name::from_str("something").unwrap()
5386        )
5387        .unwrap());
5388
5389        let offer = create_offer(
5390            "fuchsia.logger.LogSink",
5391            OneOrMany::One(OfferFromRef::Parent {}),
5392            OneOrMany::One(OfferToRef::Named(Name::from_str("something").unwrap())),
5393        );
5394
5395        assert!(offer_to_all_would_duplicate(
5396            &offer_to_all,
5397            &offer,
5398            &Name::from_str("something").unwrap()
5399        )
5400        .unwrap());
5401
5402        let offer = create_offer(
5403            "fuchsia.logger.LogSink",
5404            OneOrMany::One(OfferFromRef::Named(Name::from_str("other").unwrap())),
5405            OneOrMany::One(OfferToRef::Named(Name::from_str("something").unwrap())),
5406        );
5407
5408        assert!(offer_to_all_would_duplicate(
5409            &offer_to_all,
5410            &offer,
5411            &Name::from_str("something").unwrap()
5412        )
5413        .is_err());
5414    }
5415
5416    #[test_case(
5417        document(json!({ "program": { "runner": "elf" } })),
5418        document(json!({ "program": { "runner": "fle" } })),
5419        "runner"
5420        ; "when_runner_conflicts"
5421    )]
5422    #[test_case(
5423        document(json!({ "program": { "binary": "bin/hello_world" } })),
5424        document(json!({ "program": { "binary": "bin/hola_mundo" } })),
5425        "binary"
5426        ; "when_binary_conflicts"
5427    )]
5428    #[test_case(
5429        document(json!({ "program": { "args": ["a".to_owned()] } })),
5430        document(json!({ "program": { "args": ["b".to_owned()] } })),
5431        "args"
5432        ; "when_args_conflicts"
5433    )]
5434    fn test_merge_from_program_error(mut some: Document, mut other: Document, field: &str) {
5435        assert_matches::assert_matches!(
5436            some.merge_from(&mut other, &path::Path::new("some/path")),
5437            Err(Error::Validate {  err, .. })
5438                if err == format!("manifest include had a conflicting `program.{}`: some/path", field)
5439        );
5440    }
5441
5442    #[test_case(
5443        document(json!({ "facets": { "my.key": "my.value" } })),
5444        document(json!({ "facets": { "other.key": "other.value" } })),
5445        document(json!({ "facets": { "my.key": "my.value",  "other.key": "other.value" } }))
5446        ; "two separate keys"
5447    )]
5448    #[test_case(
5449        document(json!({ "facets": { "my.key": "my.value" } })),
5450        document(json!({ "facets": {} })),
5451        document(json!({ "facets": { "my.key": "my.value" } }))
5452        ; "empty other facet"
5453    )]
5454    #[test_case(
5455        document(json!({ "facets": {} })),
5456        document(json!({ "facets": { "other.key": "other.value" } })),
5457        document(json!({ "facets": { "other.key": "other.value" } }))
5458        ; "empty my facet"
5459    )]
5460    #[test_case(
5461        document(json!({ "facets": { "key": { "type": "some_type" } } })),
5462        document(json!({ "facets": { "key": { "runner": "some_runner"} } })),
5463        document(json!({ "facets": { "key": { "type": "some_type", "runner": "some_runner" } } }))
5464        ; "nested facet key"
5465    )]
5466    #[test_case(
5467        document(json!({ "facets": { "key": { "type": "some_type", "nested_key": { "type": "new type" }}}})),
5468        document(json!({ "facets": { "key": { "nested_key": { "runner": "some_runner" }} } })),
5469        document(json!({ "facets": { "key": { "type": "some_type", "nested_key": { "runner": "some_runner", "type": "new type" }}}}))
5470        ; "double nested facet key"
5471    )]
5472    #[test_case(
5473        document(json!({ "facets": { "key": { "array_key": ["value_1", "value_2"] } } })),
5474        document(json!({ "facets": { "key": { "array_key": ["value_3", "value_4"] } } })),
5475        document(json!({ "facets": { "key": { "array_key": ["value_1", "value_2", "value_3", "value_4"] } } }))
5476        ; "merge array values"
5477    )]
5478    fn test_merge_from_facets(mut my: Document, mut other: Document, expected: Document) {
5479        my.merge_from(&mut other, &Path::new("some/path")).unwrap();
5480        assert_eq!(my.facets, expected.facets);
5481    }
5482
5483    #[test_case(
5484        document(json!({ "facets": { "key": "my.value" }})),
5485        document(json!({ "facets": { "key": "other.value" }})),
5486        "facets.key"
5487        ; "conflict first level keys"
5488    )]
5489    #[test_case(
5490        document(json!({ "facets": { "key":  {"type": "cts" }}})),
5491        document(json!({ "facets": { "key":  {"type": "system" }}})),
5492        "facets.key.type"
5493        ; "conflict second level keys"
5494    )]
5495    #[test_case(
5496        document(json!({ "facets": { "key":  {"type": {"key": "value" }}}})),
5497        document(json!({ "facets": { "key":  {"type": "system" }}})),
5498        "facets.key.type"
5499        ; "incompatible self nested type"
5500    )]
5501    #[test_case(
5502        document(json!({ "facets": { "key":  {"type": "system" }}})),
5503        document(json!({ "facets": { "key":  {"type":  {"key": "value" }}}})),
5504        "facets.key.type"
5505        ; "incompatible other nested type"
5506    )]
5507    #[test_case(
5508        document(json!({ "facets": { "key":  {"type": {"key": "my.value" }}}})),
5509        document(json!({ "facets": { "key":  {"type":  {"key": "some.value" }}}})),
5510        "facets.key.type.key"
5511        ; "conflict third level keys"
5512    )]
5513    #[test_case(
5514        document(json!({ "facets": { "key":  {"type": [ "value_1" ]}}})),
5515        document(json!({ "facets": { "key":  {"type":  "value_2" }}})),
5516        "facets.key.type"
5517        ; "incompatible keys"
5518    )]
5519    fn test_merge_from_facet_error(mut my: Document, mut other: Document, field: &str) {
5520        assert_matches::assert_matches!(
5521            my.merge_from(&mut other, &path::Path::new("some/path")),
5522            Err(Error::Validate {  err, .. })
5523                if err == format!("manifest include had a conflicting `{}`: some/path", field)
5524        );
5525    }
5526
5527    #[test_case("protocol")]
5528    #[test_case("service")]
5529    #[test_case("event_stream")]
5530    fn test_merge_from_duplicate_use_array(typename: &str) {
5531        let mut my = document(json!({ "use": [{ typename: "a" }]}));
5532        let mut other = document(json!({ "use": [
5533            { typename: ["a", "b"], "availability": "optional"}
5534        ]}));
5535        let result = document(json!({ "use": [
5536            { typename: "a" },
5537            { typename: "b", "availability": "optional" },
5538        ]}));
5539
5540        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5541        assert_eq!(my, result);
5542    }
5543
5544    #[test_case("directory")]
5545    #[test_case("storage")]
5546    fn test_merge_from_duplicate_use_noarray(typename: &str) {
5547        let mut my = document(json!({ "use": [{ typename: "a", "path": "/a"}]}));
5548        let mut other = document(json!({ "use": [
5549            { typename: "a", "path": "/a", "availability": "optional" },
5550            { typename: "b", "path": "/b", "availability": "optional" },
5551        ]}));
5552        let result = document(json!({ "use": [
5553            { typename: "a", "path": "/a" },
5554            { typename: "b", "path": "/b", "availability": "optional" },
5555        ]}));
5556        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5557        assert_eq!(my, result);
5558    }
5559
5560    #[test_case("protocol")]
5561    #[test_case("service")]
5562    #[test_case("event_stream")]
5563    fn test_merge_from_duplicate_capabilities_array(typename: &str) {
5564        let mut my = document(json!({ "capabilities": [{ typename: "a" }]}));
5565        let mut other = document(json!({ "capabilities": [ { typename: ["a", "b"] } ]}));
5566        let result = document(json!({ "capabilities": [ { typename: "a" }, { typename: "b" } ]}));
5567
5568        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5569        assert_eq!(my, result);
5570    }
5571
5572    #[test_case("directory")]
5573    #[test_case("storage")]
5574    #[test_case("runner")]
5575    #[test_case("resolver")]
5576    fn test_merge_from_duplicate_capabilities_noarray(typename: &str) {
5577        let mut my = document(json!({ "capabilities": [{ typename: "a", "path": "/a"}]}));
5578        let mut other = document(json!({ "capabilities": [
5579            { typename: "a", "path": "/a" },
5580            { typename: "b", "path": "/b" },
5581        ]}));
5582        let result = document(json!({ "capabilities": [
5583            { typename: "a", "path": "/a" },
5584            { typename: "b", "path": "/b" },
5585        ]}));
5586        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5587        assert_eq!(my, result);
5588    }
5589
5590    #[test]
5591    fn test_merge_with_empty_names() {
5592        // This document is an error because there is no capability name.
5593        let mut my = document(json!({ "capabilities": [{ "path": "/a"}]}));
5594
5595        let mut other = document(json!({ "capabilities": [
5596            { "directory": "a", "path": "/a" },
5597            { "directory": "b", "path": "/b" },
5598        ]}));
5599        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap_err();
5600    }
5601
5602    #[test_case("protocol")]
5603    #[test_case("service")]
5604    #[test_case("event_stream")]
5605    #[test_case("directory")]
5606    #[test_case("storage")]
5607    #[test_case("runner")]
5608    #[test_case("resolver")]
5609    fn test_merge_from_duplicate_offers(typename: &str) {
5610        let mut my = document(json!({ "offer": [{ typename: "a", "from": "self", "to": "#c" }]}));
5611        let mut other = document(json!({ "offer": [
5612            { typename: ["a", "b"], "from": "self", "to": "#c", "availability": "optional" }
5613        ]}));
5614        let result = document(json!({ "offer": [
5615            { typename: "a", "from": "self", "to": "#c" },
5616            { typename: "b", "from": "self", "to": "#c", "availability": "optional" },
5617        ]}));
5618
5619        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5620        assert_eq!(my, result);
5621    }
5622
5623    #[test_case("protocol")]
5624    #[test_case("service")]
5625    #[test_case("event_stream")]
5626    #[test_case("directory")]
5627    #[test_case("runner")]
5628    #[test_case("resolver")]
5629    fn test_merge_from_duplicate_exposes(typename: &str) {
5630        let mut my = document(json!({ "expose": [{ typename: "a", "from": "self" }]}));
5631        let mut other = document(json!({ "expose": [
5632            { typename: ["a", "b"], "from": "self" }
5633        ]}));
5634        let result = document(json!({ "expose": [
5635            { typename: "a", "from": "self" },
5636            { typename: "b", "from": "self" },
5637        ]}));
5638
5639        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5640        assert_eq!(my, result);
5641    }
5642
5643    #[test_case(
5644        document(json!({ "use": [
5645            { "protocol": "a", "availability": "required" },
5646            { "protocol": "b", "availability": "optional" },
5647            { "protocol": "c", "availability": "transitional" },
5648            { "protocol": "d", "availability": "same_as_target" },
5649        ]})),
5650        document(json!({ "use": [
5651            { "protocol": ["a"], "availability": "required" },
5652            { "protocol": ["b"], "availability": "optional" },
5653            { "protocol": ["c"], "availability": "transitional" },
5654            { "protocol": ["d"], "availability": "same_as_target" },
5655        ]})),
5656        document(json!({ "use": [
5657            { "protocol": "a", "availability": "required" },
5658            { "protocol": "b", "availability": "optional" },
5659            { "protocol": "c", "availability": "transitional" },
5660            { "protocol": "d", "availability": "same_as_target" },
5661        ]}))
5662        ; "merge both same"
5663    )]
5664    #[test_case(
5665        document(json!({ "use": [
5666            { "protocol": "a", "availability": "optional" },
5667            { "protocol": "b", "availability": "transitional" },
5668            { "protocol": "c", "availability": "transitional" },
5669        ]})),
5670        document(json!({ "use": [
5671            { "protocol": ["a", "x"], "availability": "required" },
5672            { "protocol": ["b", "y"], "availability": "optional" },
5673            { "protocol": ["c", "z"], "availability": "required" },
5674        ]})),
5675        document(json!({ "use": [
5676            { "protocol": ["a", "x"], "availability": "required" },
5677            { "protocol": ["b", "y"], "availability": "optional" },
5678            { "protocol": ["c", "z"], "availability": "required" },
5679        ]}))
5680        ; "merge with upgrade"
5681    )]
5682    #[test_case(
5683        document(json!({ "use": [
5684            { "protocol": "a", "availability": "required" },
5685            { "protocol": "b", "availability": "optional" },
5686            { "protocol": "c", "availability": "required" },
5687        ]})),
5688        document(json!({ "use": [
5689            { "protocol": ["a", "x"], "availability": "optional" },
5690            { "protocol": ["b", "y"], "availability": "transitional" },
5691            { "protocol": ["c", "z"], "availability": "transitional" },
5692        ]})),
5693        document(json!({ "use": [
5694            { "protocol": "a", "availability": "required" },
5695            { "protocol": "b", "availability": "optional" },
5696            { "protocol": "c", "availability": "required" },
5697            { "protocol": "x", "availability": "optional" },
5698            { "protocol": "y", "availability": "transitional" },
5699            { "protocol": "z", "availability": "transitional" },
5700        ]}))
5701        ; "merge with downgrade"
5702    )]
5703    #[test_case(
5704        document(json!({ "use": [
5705            { "protocol": "a", "availability": "optional" },
5706            { "protocol": "b", "availability": "transitional" },
5707            { "protocol": "c", "availability": "transitional" },
5708        ]})),
5709        document(json!({ "use": [
5710            { "protocol": ["a", "x"], "availability": "same_as_target" },
5711            { "protocol": ["b", "y"], "availability": "same_as_target" },
5712            { "protocol": ["c", "z"], "availability": "same_as_target" },
5713        ]})),
5714        document(json!({ "use": [
5715            { "protocol": "a", "availability": "optional" },
5716            { "protocol": "b", "availability": "transitional" },
5717            { "protocol": "c", "availability": "transitional" },
5718            { "protocol": ["a", "x"], "availability": "same_as_target" },
5719            { "protocol": ["b", "y"], "availability": "same_as_target" },
5720            { "protocol": ["c", "z"], "availability": "same_as_target" },
5721        ]}))
5722        ; "merge with no replacement"
5723    )]
5724    #[test_case(
5725        document(json!({ "use": [
5726            { "protocol": ["a", "b", "c"], "availability": "optional" },
5727            { "protocol": "d", "availability": "same_as_target" },
5728            { "protocol": ["e", "f"] },
5729        ]})),
5730        document(json!({ "use": [
5731            { "protocol": ["c", "e", "g"] },
5732            { "protocol": ["d", "h"] },
5733            { "protocol": ["f", "i"], "availability": "transitional" },
5734        ]})),
5735        document(json!({ "use": [
5736            { "protocol": ["a", "b"], "availability": "optional" },
5737            { "protocol": "d", "availability": "same_as_target" },
5738            { "protocol": ["e", "f"] },
5739            { "protocol": ["c", "g"] },
5740            { "protocol": ["d", "h"] },
5741            { "protocol": "i", "availability": "transitional" },
5742        ]}))
5743        ; "merge multiple"
5744    )]
5745
5746    fn test_merge_from_duplicate_capability_availability(
5747        mut my: Document,
5748        mut other: Document,
5749        result: Document,
5750    ) {
5751        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5752        assert_eq!(my, result);
5753    }
5754
5755    #[test_case(
5756        document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
5757        document(json!({ "use": [{ "protocol": ["c", "d"] }]})),
5758        document(json!({ "use": [
5759            { "protocol": ["a", "b"] }, { "protocol": ["c", "d"] }
5760        ]}))
5761        ; "merge capabilities with disjoint sets"
5762    )]
5763    #[test_case(
5764        document(json!({ "use": [
5765            { "protocol": ["a"] },
5766            { "protocol": "b" },
5767        ]})),
5768        document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
5769        document(json!({ "use": [
5770            { "protocol": ["a"] }, { "protocol": "b" },
5771        ]}))
5772        ; "merge capabilities with equal set"
5773    )]
5774    #[test_case(
5775        document(json!({ "use": [
5776            { "protocol": ["a", "b"] },
5777            { "protocol": "c" },
5778        ]})),
5779        document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
5780        document(json!({ "use": [
5781            { "protocol": ["a", "b"] }, { "protocol": "c" },
5782        ]}))
5783        ; "merge capabilities with subset"
5784    )]
5785    #[test_case(
5786        document(json!({ "use": [
5787            { "protocol": ["a", "b"] },
5788        ]})),
5789        document(json!({ "use": [{ "protocol": ["a", "b", "c"] }]})),
5790        document(json!({ "use": [
5791            { "protocol": ["a", "b"] },
5792            { "protocol": "c" },
5793        ]}))
5794        ; "merge capabilities with superset"
5795    )]
5796    #[test_case(
5797        document(json!({ "use": [
5798            { "protocol": ["a", "b"] },
5799        ]})),
5800        document(json!({ "use": [{ "protocol": ["b", "c", "d"] }]})),
5801        document(json!({ "use": [
5802            { "protocol": ["a", "b"] }, { "protocol": ["c", "d"] }
5803        ]}))
5804        ; "merge capabilities with intersection"
5805    )]
5806    #[test_case(
5807        document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
5808        document(json!({ "use": [
5809            { "protocol": ["c", "b", "d"] },
5810            { "protocol": ["e", "d"] },
5811        ]})),
5812        document(json!({ "use": [
5813            {"protocol": ["a", "b"] },
5814            {"protocol": ["c", "d"] },
5815            {"protocol": "e" }]}))
5816        ; "merge capabilities from multiple arrays"
5817    )]
5818    #[test_case(
5819        document(json!({ "use": [{ "protocol": "foo.bar.Baz", "from": "self"}]})),
5820        document(json!({ "use": [{ "service": "foo.bar.Baz", "from": "self"}]})),
5821        document(json!({ "use": [
5822            {"protocol": "foo.bar.Baz", "from": "self"},
5823            {"service": "foo.bar.Baz", "from": "self"}]}))
5824        ; "merge capabilities, types don't match"
5825    )]
5826    #[test_case(
5827        document(json!({ "use": [{ "protocol": "foo.bar.Baz", "from": "self"}]})),
5828        document(json!({ "use": [{ "protocol": "foo.bar.Baz" }]})),
5829        document(json!({ "use": [
5830            {"protocol": "foo.bar.Baz", "from": "self"},
5831            {"protocol": "foo.bar.Baz"}]}))
5832        ; "merge capabilities, fields don't match"
5833    )]
5834
5835    fn test_merge_from_duplicate_capability(
5836        mut my: Document,
5837        mut other: Document,
5838        result: Document,
5839    ) {
5840        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5841        assert_eq!(my, result);
5842    }
5843
5844    #[test_case(&Right::Connect; "connect right")]
5845    #[test_case(&Right::Enumerate; "enumerate right")]
5846    #[test_case(&Right::Execute; "execute right")]
5847    #[test_case(&Right::GetAttributes; "getattr right")]
5848    #[test_case(&Right::ModifyDirectory; "modifydir right")]
5849    #[test_case(&Right::ReadBytes; "readbytes right")]
5850    #[test_case(&Right::Traverse; "traverse right")]
5851    #[test_case(&Right::UpdateAttributes; "updateattrs right")]
5852    #[test_case(&Right::WriteBytes; "writebytes right")]
5853    #[test_case(&Right::ReadAlias; "r right")]
5854    #[test_case(&Right::WriteAlias; "w right")]
5855    #[test_case(&Right::ExecuteAlias; "x right")]
5856    #[test_case(&Right::ReadWriteAlias; "rw right")]
5857    #[test_case(&Right::ReadExecuteAlias; "rx right")]
5858    #[test_case(&OfferFromRef::Self_; "offer from self")]
5859    #[test_case(&OfferFromRef::Parent; "offer from parent")]
5860    #[test_case(&OfferFromRef::Named(Name::new("child".to_string()).unwrap()); "offer from named")]
5861    #[test_case(
5862        &document(json!({}));
5863        "empty document"
5864    )]
5865    #[test_case(
5866        &document(json!({ "use": [{ "protocol": "foo.bar.Baz", "from": "self"}]}));
5867        "use one from self"
5868    )]
5869    #[test_case(
5870        &document(json!({ "use": [{ "protocol": ["foo.bar.Baz", "some.other.Protocol"], "from": "self"}]}));
5871        "use multiple from self"
5872    )]
5873    #[test_case(
5874        &document(json!({
5875            "offer": [{ "protocol": "foo.bar.Baz", "from": "self", "to": "#elements"}],
5876            "collections" :[{"name": "elements", "durability": "transient" }]
5877        }));
5878        "offer from self to collection"
5879    )]
5880    #[test_case(
5881        &document(json!({
5882            "offer": [
5883                { "service": "foo.bar.Baz", "from": "self", "to": "#elements" },
5884                { "service": "some.other.Service", "from": "self", "to": "#elements"},
5885            ],
5886            "collections":[ {"name": "elements", "durability": "transient"} ]}));
5887        "service offers"
5888    )]
5889    #[test_case(
5890        &document(json!({ "expose": [{ "protocol": ["foo.bar.Baz", "some.other.Protocol"], "from": "self"}]}));
5891        "expose protocols from self"
5892    )]
5893    #[test_case(
5894        &document(json!({ "expose": [{ "service": ["foo.bar.Baz", "some.other.Service"], "from": "self"}]}));
5895        "expose service from self"
5896    )]
5897    #[test_case(
5898        &document(json!({ "capabilities": [{ "protocol": "foo.bar.Baz", "from": "self"}]}));
5899        "capabilities from self"
5900    )]
5901    #[test_case(
5902        &document(json!({ "facets": { "my.key": "my.value" } }));
5903        "facets"
5904    )]
5905    #[test_case(
5906        &document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5907        "elf runner program"
5908    )]
5909    fn serialize_roundtrips<T>(val: &T)
5910    where
5911        T: serde::de::DeserializeOwned + Serialize + PartialEq + std::fmt::Debug,
5912    {
5913        let raw = serde_json::to_string(val).expect("serializing `val` should work");
5914        let parsed: T =
5915            serde_json::from_str(&raw).expect("must be able to parse back serialized value");
5916        assert_eq!(val, &parsed, "parsed value must equal original value");
5917    }
5918}