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, BorrowedName, DeliveryType, DependencyType, Durability, Name,
40    NamespacePath, 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 BorrowedName),
90    Protocol(&'a BorrowedName),
91    Directory(&'a BorrowedName),
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 BorrowedName),
104    UsedRunner(&'a BorrowedName),
105    Storage(&'a BorrowedName),
106    Runner(&'a BorrowedName),
107    Resolver(&'a BorrowedName),
108    EventStream(&'a BorrowedName),
109    Dictionary(&'a BorrowedName),
110    Configuration(&'a BorrowedName),
111}
112
113/// Generates a `Vec<&BorrowedName>` -> `Vec<CapabilityId>` conversion function.
114macro_rules! capability_ids_from_names {
115    ($name:ident, $variant:expr) => {
116        fn $name(names: Vec<&'a BorrowedName>) -> 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 BorrowedName>,
408        alias: Option<&'b BorrowedName>,
409        capability_type: &str,
410    ) -> Result<Vec<&'b BorrowedName>, Error> {
411        let names: Vec<&BorrowedName> = 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<&BorrowedName>,
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 BorrowedName),
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 BorrowedName),
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: Vec<Name> = c.names().into_iter().map(Into::into).collect();
1437            let mut copy: T = 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<Name> = ours.names().into_iter().map(Into::into).collect();
1567    let mut their_names: Vec<Name> = theirs.names().into_iter().map(Into::into).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.chunk_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<&BorrowedName> {
1876        if let Some(children) = self.children.as_ref() {
1877            children.iter().map(|c| c.name.as_ref()).collect()
1878        } else {
1879            vec![]
1880        }
1881    }
1882
1883    pub fn all_collection_names(&self) -> Vec<&BorrowedName> {
1884        if let Some(collections) = self.collections.as_ref() {
1885            collections.iter().map(|c| c.name.as_ref()).collect()
1886        } else {
1887            vec![]
1888        }
1889    }
1890
1891    pub fn all_storage_names(&self) -> Vec<&BorrowedName> {
1892        if let Some(capabilities) = self.capabilities.as_ref() {
1893            capabilities.iter().filter_map(|c| c.storage.as_ref().map(|n| n.as_ref())).collect()
1894        } else {
1895            vec![]
1896        }
1897    }
1898
1899    pub fn all_storage_with_sources<'a>(
1900        &'a self,
1901    ) -> HashMap<&'a BorrowedName, &'a CapabilityFromRef> {
1902        if let Some(capabilities) = self.capabilities.as_ref() {
1903            capabilities
1904                .iter()
1905                .filter_map(|c| match (c.storage.as_ref().map(Name::as_ref), c.from.as_ref()) {
1906                    (Some(s), Some(f)) => Some((s, f)),
1907                    _ => None,
1908                })
1909                .collect()
1910        } else {
1911            HashMap::new()
1912        }
1913    }
1914
1915    pub fn all_service_names(&self) -> Vec<&BorrowedName> {
1916        self.capabilities
1917            .as_ref()
1918            .map(|c| {
1919                c.iter()
1920                    .filter_map(|c| c.service.as_ref().map(|o| o.as_ref()))
1921                    .map(|p| p.into_iter())
1922                    .flatten()
1923                    .collect()
1924            })
1925            .unwrap_or_else(|| vec![])
1926    }
1927
1928    pub fn all_protocol_names(&self) -> Vec<&BorrowedName> {
1929        self.capabilities
1930            .as_ref()
1931            .map(|c| {
1932                c.iter()
1933                    .filter_map(|c| c.protocol.as_ref().map(|o| o.as_ref()))
1934                    .map(|p| p.into_iter())
1935                    .flatten()
1936                    .collect()
1937            })
1938            .unwrap_or_else(|| vec![])
1939    }
1940
1941    pub fn all_directory_names(&self) -> Vec<&BorrowedName> {
1942        self.capabilities
1943            .as_ref()
1944            .map(|c| c.iter().filter_map(|c| c.directory.as_ref().map(Name::as_ref)).collect())
1945            .unwrap_or_else(|| vec![])
1946    }
1947
1948    pub fn all_runner_names(&self) -> Vec<&BorrowedName> {
1949        self.capabilities
1950            .as_ref()
1951            .map(|c| c.iter().filter_map(|c| c.runner.as_ref().map(Name::as_ref)).collect())
1952            .unwrap_or_else(|| vec![])
1953    }
1954
1955    pub fn all_resolver_names(&self) -> Vec<&BorrowedName> {
1956        self.capabilities
1957            .as_ref()
1958            .map(|c| c.iter().filter_map(|c| c.resolver.as_ref().map(Name::as_ref)).collect())
1959            .unwrap_or_else(|| vec![])
1960    }
1961
1962    pub fn all_dictionary_names(&self) -> Vec<&BorrowedName> {
1963        if let Some(capabilities) = self.capabilities.as_ref() {
1964            capabilities.iter().filter_map(|c| c.dictionary.as_ref().map(Name::as_ref)).collect()
1965        } else {
1966            vec![]
1967        }
1968    }
1969
1970    pub fn all_dictionaries<'a>(&'a self) -> HashMap<&'a BorrowedName, &'a Capability> {
1971        if let Some(capabilities) = self.capabilities.as_ref() {
1972            capabilities
1973                .iter()
1974                .filter_map(|c| match c.dictionary.as_ref().map(Name::as_ref) {
1975                    Some(s) => Some((s, c)),
1976                    _ => None,
1977                })
1978                .collect()
1979        } else {
1980            HashMap::new()
1981        }
1982    }
1983
1984    pub fn all_config_names(&self) -> Vec<&BorrowedName> {
1985        self.capabilities
1986            .as_ref()
1987            .map(|c| c.iter().filter_map(|c| c.config.as_ref().map(Name::as_ref)).collect())
1988            .unwrap_or_else(|| vec![])
1989    }
1990
1991    pub fn all_environment_names(&self) -> Vec<&BorrowedName> {
1992        self.environments
1993            .as_ref()
1994            .map(|c| c.iter().map(|s| s.name.as_ref()).collect())
1995            .unwrap_or_else(|| vec![])
1996    }
1997
1998    pub fn all_capability_names(&self) -> HashSet<&BorrowedName> {
1999        self.capabilities
2000            .as_ref()
2001            .map(|c| {
2002                c.iter().fold(HashSet::new(), |mut acc, capability| {
2003                    acc.extend(capability.names());
2004                    acc
2005                })
2006            })
2007            .unwrap_or_default()
2008    }
2009}
2010
2011/// Trait that allows us to merge `serde_json::Map`s into `indexmap::IndexMap`s and vice versa.
2012trait ValueMap {
2013    fn get_mut(&mut self, key: &str) -> Option<&mut Value>;
2014    fn insert(&mut self, key: String, val: Value);
2015}
2016
2017impl ValueMap for Map<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
2027impl ValueMap for IndexMap<String, Value> {
2028    fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
2029        self.get_mut(key)
2030    }
2031
2032    fn insert(&mut self, key: String, val: Value) {
2033        self.insert(key, val);
2034    }
2035}
2036
2037#[derive(Deserialize, Debug, PartialEq, Serialize)]
2038#[serde(rename_all = "lowercase")]
2039pub enum EnvironmentExtends {
2040    Realm,
2041    None,
2042}
2043
2044/// Example:
2045///
2046/// ```json5
2047/// environments: [
2048///     {
2049///         name: "test-env",
2050///         extends: "realm",
2051///         runners: [
2052///             {
2053///                 runner: "gtest-runner",
2054///                 from: "#gtest",
2055///             },
2056///         ],
2057///         resolvers: [
2058///             {
2059///                 resolver: "full-resolver",
2060///                 from: "parent",
2061///                 scheme: "fuchsia-pkg",
2062///             },
2063///         ],
2064///     },
2065/// ],
2066/// ```
2067#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
2068#[serde(deny_unknown_fields)]
2069#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
2070pub struct Environment {
2071    /// The name of the environment, which is a string of one or more of the
2072    /// following characters: `a-z`, `0-9`, `_`, `.`, `-`. The name identifies this
2073    /// environment when used in a [reference](#references).
2074    pub name: Name,
2075
2076    /// How the environment should extend this realm's environment.
2077    /// - `realm`: Inherit all properties from this component's environment.
2078    /// - `none`: Start with an empty environment, do not inherit anything.
2079    #[serde(skip_serializing_if = "Option::is_none")]
2080    pub extends: Option<EnvironmentExtends>,
2081
2082    /// The runners registered in the environment. An array of objects
2083    /// with the following properties:
2084    #[reference_doc(recurse)]
2085    #[serde(skip_serializing_if = "Option::is_none")]
2086    pub runners: Option<Vec<RunnerRegistration>>,
2087
2088    /// The resolvers registered in the environment. An array of
2089    /// objects with the following properties:
2090    #[reference_doc(recurse)]
2091    #[serde(skip_serializing_if = "Option::is_none")]
2092    pub resolvers: Option<Vec<ResolverRegistration>>,
2093
2094    /// Debug protocols available to any component in this environment acquired
2095    /// through `use from debug`.
2096    #[reference_doc(recurse)]
2097    #[serde(skip_serializing_if = "Option::is_none")]
2098    pub debug: Option<Vec<DebugRegistration>>,
2099
2100    /// The number of milliseconds to wait, after notifying a component in this environment that it
2101    /// should terminate, before forcibly killing it. This field is required if the environment
2102    /// extends from `none`.
2103    #[serde(rename = "__stop_timeout_ms")]
2104    #[reference_doc(json_type = "number", rename = "__stop_timeout_ms")]
2105    #[serde(skip_serializing_if = "Option::is_none")]
2106    pub stop_timeout_ms: Option<StopTimeoutMs>,
2107}
2108
2109impl Environment {
2110    pub fn merge_from(&mut self, other: &mut Self) -> Result<(), Error> {
2111        if self.extends.is_none() {
2112            self.extends = other.extends.take();
2113        } else if other.extends.is_some() && other.extends != self.extends {
2114            return Err(Error::validate(
2115                "cannot merge `environments` that declare conflicting `extends`",
2116            ));
2117        }
2118
2119        if self.stop_timeout_ms.is_none() {
2120            self.stop_timeout_ms = other.stop_timeout_ms;
2121        } else if other.stop_timeout_ms.is_some() && other.stop_timeout_ms != self.stop_timeout_ms {
2122            return Err(Error::validate(
2123                "cannot merge `environments` that declare conflicting `stop_timeout_ms`",
2124            ));
2125        }
2126
2127        // Perform naive vector concatenation and rely on later validation to ensure
2128        // no conflicting entries.
2129        match &mut self.runners {
2130            Some(r) => {
2131                if let Some(o) = &mut other.runners {
2132                    r.append(o);
2133                }
2134            }
2135            None => self.runners = other.runners.take(),
2136        }
2137
2138        match &mut self.resolvers {
2139            Some(r) => {
2140                if let Some(o) = &mut other.resolvers {
2141                    r.append(o);
2142                }
2143            }
2144            None => self.resolvers = other.resolvers.take(),
2145        }
2146
2147        match &mut self.debug {
2148            Some(r) => {
2149                if let Some(o) = &mut other.debug {
2150                    r.append(o);
2151                }
2152            }
2153            None => self.debug = other.debug.take(),
2154        }
2155        Ok(())
2156    }
2157}
2158
2159#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
2160#[serde(rename_all = "snake_case")]
2161pub enum ConfigType {
2162    Bool,
2163    Uint8,
2164    Uint16,
2165    Uint32,
2166    Uint64,
2167    Int8,
2168    Int16,
2169    Int32,
2170    Int64,
2171    String,
2172    Vector,
2173}
2174
2175impl From<&cm_rust::ConfigValueType> for ConfigType {
2176    fn from(value: &cm_rust::ConfigValueType) -> Self {
2177        match value {
2178            cm_rust::ConfigValueType::Bool => ConfigType::Bool,
2179            cm_rust::ConfigValueType::Uint8 => ConfigType::Uint8,
2180            cm_rust::ConfigValueType::Int8 => ConfigType::Int8,
2181            cm_rust::ConfigValueType::Uint16 => ConfigType::Uint16,
2182            cm_rust::ConfigValueType::Int16 => ConfigType::Int16,
2183            cm_rust::ConfigValueType::Uint32 => ConfigType::Uint32,
2184            cm_rust::ConfigValueType::Int32 => ConfigType::Int32,
2185            cm_rust::ConfigValueType::Uint64 => ConfigType::Uint64,
2186            cm_rust::ConfigValueType::Int64 => ConfigType::Int64,
2187            cm_rust::ConfigValueType::String { .. } => ConfigType::String,
2188            cm_rust::ConfigValueType::Vector { .. } => ConfigType::Vector,
2189        }
2190    }
2191}
2192
2193#[derive(Clone, Hash, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize)]
2194pub struct ConfigKey(String);
2195
2196impl ConfigKey {
2197    pub fn as_str(&self) -> &str {
2198        self.0.as_str()
2199    }
2200}
2201
2202impl std::fmt::Display for ConfigKey {
2203    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2204        write!(f, "{}", self.0)
2205    }
2206}
2207
2208impl FromStr for ConfigKey {
2209    type Err = ParseError;
2210
2211    fn from_str(s: &str) -> Result<Self, ParseError> {
2212        let length = s.len();
2213        if length == 0 {
2214            return Err(ParseError::Empty);
2215        }
2216        if length > 64 {
2217            return Err(ParseError::TooLong);
2218        }
2219
2220        // identifiers must start with a letter
2221        let first_is_letter = s.chars().next().expect("non-empty string").is_ascii_lowercase();
2222        // can contain letters, numbers, and underscores
2223        let contains_invalid_chars =
2224            s.chars().any(|c| !(c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_'));
2225        // cannot end with an underscore
2226        let last_is_underscore = s.chars().next_back().expect("non-empty string") == '_';
2227
2228        if !first_is_letter || contains_invalid_chars || last_is_underscore {
2229            return Err(ParseError::InvalidValue);
2230        }
2231
2232        Ok(Self(s.to_string()))
2233    }
2234}
2235
2236impl<'de> de::Deserialize<'de> for ConfigKey {
2237    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2238    where
2239        D: de::Deserializer<'de>,
2240    {
2241        struct Visitor;
2242
2243        impl<'de> de::Visitor<'de> for Visitor {
2244            type Value = ConfigKey;
2245
2246            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2247                f.write_str(
2248                    "a non-empty string no more than 64 characters in length, which must \
2249                    start with a letter, can contain letters, numbers, and underscores, \
2250                    but cannot end with an underscore",
2251                )
2252            }
2253
2254            fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
2255            where
2256                E: de::Error,
2257            {
2258                s.parse().map_err(|err| match err {
2259                    ParseError::InvalidValue => E::invalid_value(
2260                        de::Unexpected::Str(s),
2261                        &"a name which must start with a letter, can contain letters, \
2262                        numbers, and underscores, but cannot end with an underscore",
2263                    ),
2264                    ParseError::TooLong | ParseError::Empty => E::invalid_length(
2265                        s.len(),
2266                        &"a non-empty name no more than 64 characters in length",
2267                    ),
2268                    e => {
2269                        panic!("unexpected parse error: {:?}", e);
2270                    }
2271                })
2272            }
2273        }
2274        deserializer.deserialize_string(Visitor)
2275    }
2276}
2277
2278#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
2279#[serde(deny_unknown_fields, rename_all = "lowercase")]
2280pub enum ConfigRuntimeSource {
2281    Parent,
2282}
2283
2284#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
2285#[serde(tag = "type", deny_unknown_fields, rename_all = "lowercase")]
2286pub enum ConfigValueType {
2287    Bool {
2288        mutability: Option<Vec<ConfigRuntimeSource>>,
2289    },
2290    Uint8 {
2291        mutability: Option<Vec<ConfigRuntimeSource>>,
2292    },
2293    Uint16 {
2294        mutability: Option<Vec<ConfigRuntimeSource>>,
2295    },
2296    Uint32 {
2297        mutability: Option<Vec<ConfigRuntimeSource>>,
2298    },
2299    Uint64 {
2300        mutability: Option<Vec<ConfigRuntimeSource>>,
2301    },
2302    Int8 {
2303        mutability: Option<Vec<ConfigRuntimeSource>>,
2304    },
2305    Int16 {
2306        mutability: Option<Vec<ConfigRuntimeSource>>,
2307    },
2308    Int32 {
2309        mutability: Option<Vec<ConfigRuntimeSource>>,
2310    },
2311    Int64 {
2312        mutability: Option<Vec<ConfigRuntimeSource>>,
2313    },
2314    String {
2315        max_size: NonZeroU32,
2316        mutability: Option<Vec<ConfigRuntimeSource>>,
2317    },
2318    Vector {
2319        max_count: NonZeroU32,
2320        element: ConfigNestedValueType,
2321        mutability: Option<Vec<ConfigRuntimeSource>>,
2322    },
2323}
2324
2325impl ConfigValueType {
2326    /// Update the hasher by digesting the ConfigValueType enum value
2327    pub fn update_digest(&self, hasher: &mut impl sha2::Digest) {
2328        let val = match self {
2329            ConfigValueType::Bool { .. } => 0u8,
2330            ConfigValueType::Uint8 { .. } => 1u8,
2331            ConfigValueType::Uint16 { .. } => 2u8,
2332            ConfigValueType::Uint32 { .. } => 3u8,
2333            ConfigValueType::Uint64 { .. } => 4u8,
2334            ConfigValueType::Int8 { .. } => 5u8,
2335            ConfigValueType::Int16 { .. } => 6u8,
2336            ConfigValueType::Int32 { .. } => 7u8,
2337            ConfigValueType::Int64 { .. } => 8u8,
2338            ConfigValueType::String { max_size, .. } => {
2339                hasher.update(max_size.get().to_le_bytes());
2340                9u8
2341            }
2342            ConfigValueType::Vector { max_count, element, .. } => {
2343                hasher.update(max_count.get().to_le_bytes());
2344                element.update_digest(hasher);
2345                10u8
2346            }
2347        };
2348        hasher.update([val])
2349    }
2350}
2351
2352impl From<ConfigValueType> for cm_rust::ConfigValueType {
2353    fn from(value: ConfigValueType) -> Self {
2354        match value {
2355            ConfigValueType::Bool { .. } => cm_rust::ConfigValueType::Bool,
2356            ConfigValueType::Uint8 { .. } => cm_rust::ConfigValueType::Uint8,
2357            ConfigValueType::Uint16 { .. } => cm_rust::ConfigValueType::Uint16,
2358            ConfigValueType::Uint32 { .. } => cm_rust::ConfigValueType::Uint32,
2359            ConfigValueType::Uint64 { .. } => cm_rust::ConfigValueType::Uint64,
2360            ConfigValueType::Int8 { .. } => cm_rust::ConfigValueType::Int8,
2361            ConfigValueType::Int16 { .. } => cm_rust::ConfigValueType::Int16,
2362            ConfigValueType::Int32 { .. } => cm_rust::ConfigValueType::Int32,
2363            ConfigValueType::Int64 { .. } => cm_rust::ConfigValueType::Int64,
2364            ConfigValueType::String { max_size, .. } => {
2365                cm_rust::ConfigValueType::String { max_size: max_size.into() }
2366            }
2367            ConfigValueType::Vector { max_count, element, .. } => {
2368                cm_rust::ConfigValueType::Vector {
2369                    max_count: max_count.into(),
2370                    nested_type: element.into(),
2371                }
2372            }
2373        }
2374    }
2375}
2376
2377#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
2378#[serde(tag = "type", deny_unknown_fields, rename_all = "lowercase")]
2379pub enum ConfigNestedValueType {
2380    Bool {},
2381    Uint8 {},
2382    Uint16 {},
2383    Uint32 {},
2384    Uint64 {},
2385    Int8 {},
2386    Int16 {},
2387    Int32 {},
2388    Int64 {},
2389    String { max_size: NonZeroU32 },
2390}
2391
2392impl ConfigNestedValueType {
2393    /// Update the hasher by digesting the ConfigVectorElementType enum value
2394    pub fn update_digest(&self, hasher: &mut impl sha2::Digest) {
2395        let val = match self {
2396            ConfigNestedValueType::Bool {} => 0u8,
2397            ConfigNestedValueType::Uint8 {} => 1u8,
2398            ConfigNestedValueType::Uint16 {} => 2u8,
2399            ConfigNestedValueType::Uint32 {} => 3u8,
2400            ConfigNestedValueType::Uint64 {} => 4u8,
2401            ConfigNestedValueType::Int8 {} => 5u8,
2402            ConfigNestedValueType::Int16 {} => 6u8,
2403            ConfigNestedValueType::Int32 {} => 7u8,
2404            ConfigNestedValueType::Int64 {} => 8u8,
2405            ConfigNestedValueType::String { max_size } => {
2406                hasher.update(max_size.get().to_le_bytes());
2407                9u8
2408            }
2409        };
2410        hasher.update([val])
2411    }
2412}
2413
2414impl From<ConfigNestedValueType> for cm_rust::ConfigNestedValueType {
2415    fn from(value: ConfigNestedValueType) -> Self {
2416        match value {
2417            ConfigNestedValueType::Bool {} => cm_rust::ConfigNestedValueType::Bool,
2418            ConfigNestedValueType::Uint8 {} => cm_rust::ConfigNestedValueType::Uint8,
2419            ConfigNestedValueType::Uint16 {} => cm_rust::ConfigNestedValueType::Uint16,
2420            ConfigNestedValueType::Uint32 {} => cm_rust::ConfigNestedValueType::Uint32,
2421            ConfigNestedValueType::Uint64 {} => cm_rust::ConfigNestedValueType::Uint64,
2422            ConfigNestedValueType::Int8 {} => cm_rust::ConfigNestedValueType::Int8,
2423            ConfigNestedValueType::Int16 {} => cm_rust::ConfigNestedValueType::Int16,
2424            ConfigNestedValueType::Int32 {} => cm_rust::ConfigNestedValueType::Int32,
2425            ConfigNestedValueType::Int64 {} => cm_rust::ConfigNestedValueType::Int64,
2426            ConfigNestedValueType::String { max_size } => {
2427                cm_rust::ConfigNestedValueType::String { max_size: max_size.into() }
2428            }
2429        }
2430    }
2431}
2432
2433impl TryFrom<&cm_rust::ConfigNestedValueType> for ConfigNestedValueType {
2434    type Error = ();
2435    fn try_from(nested: &cm_rust::ConfigNestedValueType) -> Result<Self, ()> {
2436        Ok(match nested {
2437            cm_rust::ConfigNestedValueType::Bool => ConfigNestedValueType::Bool {},
2438            cm_rust::ConfigNestedValueType::Uint8 => ConfigNestedValueType::Uint8 {},
2439            cm_rust::ConfigNestedValueType::Int8 => ConfigNestedValueType::Int8 {},
2440            cm_rust::ConfigNestedValueType::Uint16 => ConfigNestedValueType::Uint16 {},
2441            cm_rust::ConfigNestedValueType::Int16 => ConfigNestedValueType::Int16 {},
2442            cm_rust::ConfigNestedValueType::Uint32 => ConfigNestedValueType::Uint32 {},
2443            cm_rust::ConfigNestedValueType::Int32 => ConfigNestedValueType::Int32 {},
2444            cm_rust::ConfigNestedValueType::Uint64 => ConfigNestedValueType::Uint64 {},
2445            cm_rust::ConfigNestedValueType::Int64 => ConfigNestedValueType::Int64 {},
2446            cm_rust::ConfigNestedValueType::String { max_size } => {
2447                ConfigNestedValueType::String { max_size: NonZeroU32::new(*max_size).ok_or(())? }
2448            }
2449        })
2450    }
2451}
2452
2453#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
2454#[serde(deny_unknown_fields)]
2455#[reference_doc(fields_as = "list")]
2456pub struct RunnerRegistration {
2457    /// The [name](#name) of a runner capability, whose source is specified in `from`.
2458    pub runner: Name,
2459
2460    /// The source of the runner capability, one of:
2461    /// - `parent`: The component's parent.
2462    /// - `self`: This component.
2463    /// - `#<child-name>`: A [reference](#references) to a child component
2464    ///     instance.
2465    pub from: RegistrationRef,
2466
2467    /// An explicit name for the runner as it will be known in
2468    /// this environment. If omitted, defaults to `runner`.
2469    #[serde(skip_serializing_if = "Option::is_none")]
2470    pub r#as: Option<Name>,
2471}
2472
2473#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
2474#[serde(deny_unknown_fields)]
2475#[reference_doc(fields_as = "list")]
2476pub struct ResolverRegistration {
2477    /// The [name](#name) of a resolver capability,
2478    /// whose source is specified in `from`.
2479    pub resolver: Name,
2480
2481    /// The source of the resolver capability, one of:
2482    /// - `parent`: The component's parent.
2483    /// - `self`: This component.
2484    /// - `#<child-name>`: A [reference](#references) to a child component
2485    ///     instance.
2486    pub from: RegistrationRef,
2487
2488    /// The URL scheme for which the resolver should handle
2489    /// resolution.
2490    pub scheme: cm_types::UrlScheme,
2491}
2492
2493#[derive(Deserialize, Debug, PartialEq, Clone, ReferenceDoc, Serialize, Default)]
2494#[serde(deny_unknown_fields)]
2495#[reference_doc(fields_as = "list")]
2496pub struct Capability {
2497    /// The [name](#name) for this service capability. Specifying `path` is valid
2498    /// only when this value is a string.
2499    #[serde(skip_serializing_if = "Option::is_none")]
2500    #[reference_doc(skip = true)]
2501    pub service: Option<OneOrMany<Name>>,
2502
2503    /// The [name](#name) for this protocol capability. Specifying `path` is valid
2504    /// only when this value is a string.
2505    #[serde(skip_serializing_if = "Option::is_none")]
2506    #[reference_doc(skip = true)]
2507    pub protocol: Option<OneOrMany<Name>>,
2508
2509    /// The [name](#name) for this directory capability.
2510    #[serde(skip_serializing_if = "Option::is_none")]
2511    #[reference_doc(skip = true)]
2512    pub directory: Option<Name>,
2513
2514    /// The [name](#name) for this storage capability.
2515    #[serde(skip_serializing_if = "Option::is_none")]
2516    #[reference_doc(skip = true)]
2517    pub storage: Option<Name>,
2518
2519    /// The [name](#name) for this runner capability.
2520    #[serde(skip_serializing_if = "Option::is_none")]
2521    #[reference_doc(skip = true)]
2522    pub runner: Option<Name>,
2523
2524    /// The [name](#name) for this resolver capability.
2525    #[serde(skip_serializing_if = "Option::is_none")]
2526    #[reference_doc(skip = true)]
2527    pub resolver: Option<Name>,
2528
2529    /// The [name](#name) for this event_stream capability.
2530    #[serde(skip_serializing_if = "Option::is_none")]
2531    #[reference_doc(skip = true)]
2532    pub event_stream: Option<OneOrMany<Name>>,
2533
2534    /// The [name](#name) for this dictionary capability.
2535    #[serde(skip_serializing_if = "Option::is_none")]
2536    #[reference_doc(skip = true)]
2537    pub dictionary: Option<Name>,
2538
2539    /// The [name](#name) for this configuration capability.
2540    #[serde(skip_serializing_if = "Option::is_none")]
2541    #[reference_doc(skip = true)]
2542    pub config: Option<Name>,
2543
2544    /// The path within the [outgoing directory][glossary.outgoing directory] of the component's
2545    /// program to source the capability.
2546    ///
2547    /// For `protocol` and `service`, defaults to `/svc/${protocol}`, otherwise required.
2548    ///
2549    /// For `protocol`, the target of the path MUST be a channel, which tends to speak
2550    /// the protocol matching the name of this capability.
2551    ///
2552    /// For `service`, `directory`, the target of the path MUST be a directory.
2553    ///
2554    /// For `runner`, the target of the path MUST be a channel and MUST speak
2555    /// the protocol `fuchsia.component.runner.ComponentRunner`.
2556    ///
2557    /// For `resolver`, the target of the path MUST be a channel and MUST speak
2558    /// the protocol `fuchsia.component.resolution.Resolver`.
2559    ///
2560    /// For `dictionary`, this is optional. If provided, it is a path to a
2561    /// `fuchsia.component.sandbox/DictionaryRouter` served by the program which should return a
2562    /// `fuchsia.component.sandbox/DictionaryRef`, by which the program may dynamically provide
2563    /// a dictionary from itself. If this is set for `dictionary`, `offer` to this dictionary
2564    /// is not allowed.
2565    #[serde(skip_serializing_if = "Option::is_none")]
2566    pub path: Option<Path>,
2567
2568    /// (`directory` only) The maximum [directory rights][doc-directory-rights] that may be set
2569    /// when using this directory.
2570    #[serde(skip_serializing_if = "Option::is_none")]
2571    #[reference_doc(json_type = "array of string")]
2572    pub rights: Option<Rights>,
2573
2574    /// (`storage` only) The source component of an existing directory capability backing this
2575    /// storage capability, one of:
2576    /// - `parent`: The component's parent.
2577    /// - `self`: This component.
2578    /// - `#<child-name>`: A [reference](#references) to a child component
2579    ///     instance.
2580    #[serde(skip_serializing_if = "Option::is_none")]
2581    pub from: Option<CapabilityFromRef>,
2582
2583    /// (`storage` only) The [name](#name) of the directory capability backing the storage. The
2584    /// capability must be available from the component referenced in `from`.
2585    #[serde(skip_serializing_if = "Option::is_none")]
2586    pub backing_dir: Option<Name>,
2587
2588    /// (`storage` only) A subdirectory within `backing_dir` where per-component isolated storage
2589    /// directories are created
2590    #[serde(skip_serializing_if = "Option::is_none")]
2591    pub subdir: Option<RelativePath>,
2592
2593    /// (`storage` only) The identifier used to isolated storage for a component, one of:
2594    /// - `static_instance_id`: The instance ID in the component ID index is used
2595    ///     as the key for a component's storage. Components which are not listed in
2596    ///     the component ID index will not be able to use this storage capability.
2597    /// - `static_instance_id_or_moniker`: If the component is listed in the
2598    ///     component ID index, the instance ID is used as the key for a component's
2599    ///     storage. Otherwise, the component's moniker from the storage
2600    ///     capability is used.
2601    #[serde(skip_serializing_if = "Option::is_none")]
2602    pub storage_id: Option<StorageId>,
2603
2604    /// (`configuration` only) The type of configuration, one of:
2605    /// - `bool`: Boolean type.
2606    /// - `uint8`: Unsigned 8 bit type.
2607    /// - `uint16`: Unsigned 16 bit type.
2608    /// - `uint32`: Unsigned 32 bit type.
2609    /// - `uint64`: Unsigned 64 bit type.
2610    /// - `int8`: Signed 8 bit type.
2611    /// - `int16`: Signed 16 bit type.
2612    /// - `int32`: Signed 32 bit type.
2613    /// - `int64`: Signed 64 bit type.
2614    /// - `string`: ASCII string type.
2615    /// - `vector`: Vector type. See `element` for the type of the element within the vector.
2616    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
2617    #[reference_doc(rename = "type")]
2618    pub config_type: Option<ConfigType>,
2619
2620    /// (`configuration` only) Only supported if this configuration `type` is 'string'.
2621    /// This is the max size of the string.
2622    #[serde(rename = "max_size", skip_serializing_if = "Option::is_none")]
2623    #[reference_doc(rename = "max_size")]
2624    pub config_max_size: Option<NonZeroU32>,
2625
2626    /// (`configuration` only) Only supported if this configuration `type` is 'vector'.
2627    /// This is the max number of elements in the vector.
2628    #[serde(rename = "max_count", skip_serializing_if = "Option::is_none")]
2629    #[reference_doc(rename = "max_count")]
2630    pub config_max_count: Option<NonZeroU32>,
2631
2632    /// (`configuration` only) Only supported if this configuration `type` is 'vector'.
2633    /// This is the type of the elements in the configuration vector.
2634    ///
2635    /// Example (simple type):
2636    ///
2637    /// ```json5
2638    /// { type: "uint8" }
2639    /// ```
2640    ///
2641    /// Example (string type):
2642    ///
2643    /// ```json5
2644    /// {
2645    ///   type: "string",
2646    ///   max_size: 100,
2647    /// }
2648    /// ```
2649    #[serde(rename = "element", skip_serializing_if = "Option::is_none")]
2650    #[reference_doc(rename = "element", json_type = "object")]
2651    pub config_element_type: Option<ConfigNestedValueType>,
2652
2653    /// (`configuration` only) The value of the configuration.
2654    #[serde(skip_serializing_if = "Option::is_none")]
2655    pub value: Option<serde_json::Value>,
2656
2657    /// (`protocol` only) Specifies when the framework will open the protocol
2658    /// from this component's outgoing directory when someone requests the
2659    /// capability. Allowed values are:
2660    ///
2661    /// - `eager`: (default) the framework will open the capability as soon as
2662    ///   some consumer component requests it.
2663    /// - `on_readable`: the framework will open the capability when the server
2664    ///   endpoint pipelined in a connection request becomes readable.
2665    ///
2666    #[serde(skip_serializing_if = "Option::is_none")]
2667    pub delivery: Option<DeliveryType>,
2668}
2669
2670#[derive(Deserialize, Debug, Clone, PartialEq, ReferenceDoc, Serialize)]
2671#[serde(deny_unknown_fields)]
2672#[reference_doc(fields_as = "list")]
2673pub struct DebugRegistration {
2674    /// The name(s) of the protocol(s) to make available.
2675    pub protocol: Option<OneOrMany<Name>>,
2676
2677    /// The source of the capability(s), one of:
2678    /// - `parent`: The component's parent.
2679    /// - `self`: This component.
2680    /// - `#<child-name>`: A [reference](#references) to a child component
2681    ///     instance.
2682    pub from: OfferFromRef,
2683
2684    /// If specified, the name that the capability in `protocol` should be made
2685    /// available as to clients. Disallowed if `protocol` is an array.
2686    #[serde(skip_serializing_if = "Option::is_none")]
2687    pub r#as: Option<Name>,
2688}
2689
2690#[derive(Debug, PartialEq, Default, Serialize)]
2691pub struct Program {
2692    #[serde(skip_serializing_if = "Option::is_none")]
2693    pub runner: Option<Name>,
2694    #[serde(flatten)]
2695    pub info: IndexMap<String, Value>,
2696}
2697
2698impl<'de> de::Deserialize<'de> for Program {
2699    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2700    where
2701        D: de::Deserializer<'de>,
2702    {
2703        struct Visitor;
2704
2705        const EXPECTED_PROGRAM: &'static str =
2706            "a JSON object that includes a `runner` string property";
2707        const EXPECTED_RUNNER: &'static str =
2708            "a non-empty `runner` string property no more than 255 characters in length \
2709            that consists of [A-Za-z0-9_.-] and starts with [A-Za-z0-9_]";
2710
2711        impl<'de> de::Visitor<'de> for Visitor {
2712            type Value = Program;
2713
2714            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2715                f.write_str(EXPECTED_PROGRAM)
2716            }
2717
2718            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
2719            where
2720                A: de::MapAccess<'de>,
2721            {
2722                let mut info = IndexMap::new();
2723                let mut runner = None;
2724                while let Some(e) = map.next_entry::<String, Value>()? {
2725                    let (k, v) = e;
2726                    if &k == "runner" {
2727                        if let Value::String(s) = v {
2728                            runner = Some(s);
2729                        } else {
2730                            return Err(de::Error::invalid_value(
2731                                de::Unexpected::Map,
2732                                &EXPECTED_RUNNER,
2733                            ));
2734                        }
2735                    } else {
2736                        info.insert(k, v);
2737                    }
2738                }
2739                let runner = runner
2740                    .map(|r| {
2741                        Name::new(r.clone()).map_err(|e| match e {
2742                            ParseError::InvalidValue => de::Error::invalid_value(
2743                                serde::de::Unexpected::Str(&r),
2744                                &EXPECTED_RUNNER,
2745                            ),
2746                            ParseError::TooLong | ParseError::Empty => {
2747                                de::Error::invalid_length(r.len(), &EXPECTED_RUNNER)
2748                            }
2749                            _ => {
2750                                panic!("unexpected parse error: {:?}", e);
2751                            }
2752                        })
2753                    })
2754                    .transpose()?;
2755                Ok(Program { runner, info })
2756            }
2757        }
2758
2759        deserializer.deserialize_map(Visitor)
2760    }
2761}
2762
2763/// Example:
2764///
2765/// ```json5
2766/// use: [
2767///     {
2768///         protocol: [
2769///             "fuchsia.ui.scenic.Scenic",
2770///             "fuchsia.accessibility.Manager",
2771///         ]
2772///     },
2773///     {
2774///         directory: "themes",
2775///         path: "/data/themes",
2776///         rights: [ "r*" ],
2777///     },
2778///     {
2779///         storage: "persistent",
2780///         path: "/data",
2781///     },
2782///     {
2783///         event_stream: [
2784///             "started",
2785///             "stopped",
2786///         ],
2787///         from: "framework",
2788///     },
2789///     {
2790///         runner: "own_test_runner".
2791///         from: "#test_runner",
2792///     },
2793/// ],
2794/// ```
2795#[derive(Deserialize, Debug, Default, PartialEq, Clone, ReferenceDoc, Serialize)]
2796#[serde(deny_unknown_fields)]
2797#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
2798pub struct Use {
2799    /// When using a service capability, the [name](#name) of a [service capability][doc-service].
2800    #[serde(skip_serializing_if = "Option::is_none")]
2801    #[reference_doc(skip = true)]
2802    pub service: Option<OneOrMany<Name>>,
2803
2804    /// When using a protocol capability, the [name](#name) of a [protocol capability][doc-protocol].
2805    #[serde(skip_serializing_if = "Option::is_none")]
2806    #[reference_doc(skip = true)]
2807    pub protocol: Option<OneOrMany<Name>>,
2808
2809    /// When using a directory capability, the [name](#name) of a [directory capability][doc-directory].
2810    #[serde(skip_serializing_if = "Option::is_none")]
2811    #[reference_doc(skip = true)]
2812    pub directory: Option<Name>,
2813
2814    /// When using a storage capability, the [name](#name) of a [storage capability][doc-storage].
2815    #[serde(skip_serializing_if = "Option::is_none")]
2816    #[reference_doc(skip = true)]
2817    pub storage: Option<Name>,
2818
2819    /// When using an event stream capability, the [name](#name) of an [event stream capability][doc-event].
2820    #[serde(skip_serializing_if = "Option::is_none")]
2821    #[reference_doc(skip = true)]
2822    pub event_stream: Option<OneOrMany<Name>>,
2823
2824    /// When using a runner capability, the [name](#name) of a [runner capability][doc-runners].
2825    #[serde(skip_serializing_if = "Option::is_none")]
2826    #[reference_doc(skip = true)]
2827    pub runner: Option<Name>,
2828
2829    /// When using a configuration capability, the [name](#name) of a [configuration capability][doc-configuration].
2830    #[serde(skip_serializing_if = "Option::is_none")]
2831    #[reference_doc(skip = true)]
2832    pub config: Option<Name>,
2833
2834    /// The source of the capability. Defaults to `parent`.  One of:
2835    /// - `parent`: The component's parent.
2836    /// - `debug`: One of [`debug_capabilities`][fidl-environment-decl] in the
2837    ///     environment assigned to this component.
2838    /// - `framework`: The Component Framework runtime.
2839    /// - `self`: This component.
2840    /// - `#<capability-name>`: The name of another capability from which the
2841    ///     requested capability is derived.
2842    /// - `#<child-name>`: A [reference](#references) to a child component
2843    ///     instance.
2844    ///
2845    /// [fidl-environment-decl]: /reference/fidl/fuchsia.component.decl#Environment
2846    #[serde(skip_serializing_if = "Option::is_none")]
2847    pub from: Option<UseFromRef>,
2848
2849    /// The path at which to install the capability in the component's namespace. For protocols,
2850    /// defaults to `/svc/${protocol}`.  Required for `directory` and `storage`. This property is
2851    /// disallowed for declarations with arrays of capability names and for runner capabilities.
2852    #[serde(skip_serializing_if = "Option::is_none")]
2853    pub path: Option<Path>,
2854
2855    /// (`directory` only) the maximum [directory rights][doc-directory-rights] to apply to
2856    /// the directory in the component's namespace.
2857    #[serde(skip_serializing_if = "Option::is_none")]
2858    #[reference_doc(json_type = "array of string")]
2859    pub rights: Option<Rights>,
2860
2861    /// (`directory` only) A subdirectory within the directory capability to provide in the
2862    /// component's namespace.
2863    #[serde(skip_serializing_if = "Option::is_none")]
2864    pub subdir: Option<RelativePath>,
2865
2866    /// (`event_stream` only) When defined the event stream will contain events about only the
2867    /// components defined in the scope.
2868    #[serde(skip_serializing_if = "Option::is_none")]
2869    pub scope: Option<OneOrMany<EventScope>>,
2870
2871    /// (`event_stream` only) Capability requested event streams require specifying a filter
2872    /// referring to the protocol to which the events in the event stream apply. The content of the
2873    /// filter will be an object mapping from "name" to the "protocol name".
2874    #[serde(skip_serializing_if = "Option::is_none")]
2875    pub filter: Option<Map<String, Value>>,
2876
2877    /// The type of dependency between the source and
2878    /// this component, one of:
2879    /// - `strong`: a strong dependency, which is used to determine shutdown
2880    ///     ordering. Component manager is guaranteed to stop the target before the
2881    ///     source. This is the default.
2882    /// - `weak`: a weak dependency, which is ignored during shutdown. When component manager
2883    ///     stops the parent realm, the source may stop before the clients. Clients of weak
2884    ///     dependencies must be able to handle these dependencies becoming unavailable.
2885    /// This property is disallowed for runner capabilities, which are always a `strong` dependency.
2886    #[serde(skip_serializing_if = "Option::is_none")]
2887    pub dependency: Option<DependencyType>,
2888
2889    /// The expectations around this capability's availability. One
2890    /// of:
2891    /// - `required` (default): a required dependency, the component is unable to perform its
2892    ///     work without this capability.
2893    /// - `optional`: an optional dependency, the component will be able to function without this
2894    ///     capability (although if the capability is unavailable some functionality may be
2895    ///     disabled).
2896    /// - `transitional`: the source may omit the route completely without even having to route
2897    ///     from `void`. Used for soft transitions that introduce new capabilities.
2898    /// This property is disallowed for runner capabilities, which are always `required`.
2899    ///
2900    /// For more information, see the
2901    /// [availability](/docs/concepts/components/v2/capabilities/availability.md) documentation.
2902    #[serde(skip_serializing_if = "Option::is_none")]
2903    pub availability: Option<Availability>,
2904
2905    /// (`config` only) The configuration key in the component's `config` block that this capability
2906    /// will set.
2907    #[serde(skip_serializing_if = "Option::is_none")]
2908    pub key: Option<Name>,
2909
2910    /// (`config` only) The type of configuration, one of:
2911    /// - `bool`: Boolean type.
2912    /// - `uint8`: Unsigned 8 bit type.
2913    /// - `uint16`: Unsigned 16 bit type.
2914    /// - `uint32`: Unsigned 32 bit type.
2915    /// - `uint64`: Unsigned 64 bit type.
2916    /// - `int8`: Signed 8 bit type.
2917    /// - `int16`: Signed 16 bit type.
2918    /// - `int32`: Signed 32 bit type.
2919    /// - `int64`: Signed 64 bit type.
2920    /// - `string`: ASCII string type.
2921    /// - `vector`: Vector type. See `element` for the type of the element within the vector
2922    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
2923    #[reference_doc(rename = "type")]
2924    pub config_type: Option<ConfigType>,
2925
2926    /// (`configuration` only) Only supported if this configuration `type` is 'string'.
2927    /// This is the max size of the string.
2928    #[serde(rename = "max_size", skip_serializing_if = "Option::is_none")]
2929    #[reference_doc(rename = "max_size")]
2930    pub config_max_size: Option<NonZeroU32>,
2931
2932    /// (`configuration` only) Only supported if this configuration `type` is 'vector'.
2933    /// This is the max number of elements in the vector.
2934    #[serde(rename = "max_count", skip_serializing_if = "Option::is_none")]
2935    #[reference_doc(rename = "max_count")]
2936    pub config_max_count: Option<NonZeroU32>,
2937
2938    /// (`configuration` only) Only supported if this configuration `type` is 'vector'.
2939    /// This is the type of the elements in the configuration vector.
2940    ///
2941    /// Example (simple type):
2942    ///
2943    /// ```json5
2944    /// { type: "uint8" }
2945    /// ```
2946    ///
2947    /// Example (string type):
2948    ///
2949    /// ```json5
2950    /// {
2951    ///   type: "string",
2952    ///   max_size: 100,
2953    /// }
2954    /// ```
2955    #[serde(rename = "element", skip_serializing_if = "Option::is_none")]
2956    #[reference_doc(rename = "element", json_type = "object")]
2957    pub config_element_type: Option<ConfigNestedValueType>,
2958
2959    /// (`configuration` only) The default value of this configuration.
2960    /// Default values are used if the capability is optional and routed from `void`.
2961    /// This is only supported if `availability` is not `required``.
2962    #[serde(rename = "default", skip_serializing_if = "Option::is_none")]
2963    #[reference_doc(rename = "default")]
2964    pub config_default: Option<serde_json::Value>,
2965}
2966
2967/// Example:
2968///
2969/// ```json5
2970/// expose: [
2971///     {
2972///         directory: "themes",
2973///         from: "self",
2974///     },
2975///     {
2976///         protocol: "pkg.Cache",
2977///         from: "#pkg_cache",
2978///         as: "fuchsia.pkg.PackageCache",
2979///     },
2980///     {
2981///         protocol: [
2982///             "fuchsia.ui.app.ViewProvider",
2983///             "fuchsia.fonts.Provider",
2984///         ],
2985///         from: "self",
2986///     },
2987///     {
2988///         runner: "web-chromium",
2989///         from: "#web_runner",
2990///         as: "web",
2991///     },
2992///     {
2993///         resolver: "full-resolver",
2994///         from: "#full-resolver",
2995///     },
2996/// ],
2997/// ```
2998#[derive(Deserialize, Debug, PartialEq, Clone, ReferenceDoc, Serialize)]
2999#[serde(deny_unknown_fields)]
3000#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
3001pub struct Expose {
3002    /// When routing a service, the [name](#name) of a [service capability][doc-service].
3003    #[serde(skip_serializing_if = "Option::is_none")]
3004    #[reference_doc(skip = true)]
3005    pub service: Option<OneOrMany<Name>>,
3006
3007    /// When routing a protocol, the [name](#name) of a [protocol capability][doc-protocol].
3008    #[serde(skip_serializing_if = "Option::is_none")]
3009    #[reference_doc(skip = true)]
3010    pub protocol: Option<OneOrMany<Name>>,
3011
3012    /// When routing a directory, the [name](#name) of a [directory capability][doc-directory].
3013    #[serde(skip_serializing_if = "Option::is_none")]
3014    #[reference_doc(skip = true)]
3015    pub directory: Option<OneOrMany<Name>>,
3016
3017    /// When routing a runner, the [name](#name) of a [runner capability][doc-runners].
3018    #[serde(skip_serializing_if = "Option::is_none")]
3019    #[reference_doc(skip = true)]
3020    pub runner: Option<OneOrMany<Name>>,
3021
3022    /// When routing a resolver, the [name](#name) of a [resolver capability][doc-resolvers].
3023    #[serde(skip_serializing_if = "Option::is_none")]
3024    #[reference_doc(skip = true)]
3025    pub resolver: Option<OneOrMany<Name>>,
3026
3027    /// When routing a dictionary, the [name](#name) of a [dictionary capability][doc-dictionaries].
3028    #[serde(skip_serializing_if = "Option::is_none")]
3029    #[reference_doc(skip = true)]
3030    pub dictionary: Option<OneOrMany<Name>>,
3031
3032    /// When routing a config, the [name](#name) of a configuration capability.
3033    #[serde(skip_serializing_if = "Option::is_none")]
3034    #[reference_doc(skip = true)]
3035    pub config: Option<OneOrMany<Name>>,
3036
3037    /// `from`: The source of the capability, one of:
3038    /// - `self`: This component. Requires a corresponding
3039    ///     [`capability`](#capabilities) declaration.
3040    /// - `framework`: The Component Framework runtime.
3041    /// - `#<child-name>`: A [reference](#references) to a child component
3042    ///     instance.
3043    pub from: OneOrMany<ExposeFromRef>,
3044
3045    /// The [name](#name) for the capability as it will be known by the target. If omitted,
3046    /// defaults to the original name. `as` cannot be used when an array of multiple capability
3047    /// names is provided.
3048    #[serde(skip_serializing_if = "Option::is_none")]
3049    pub r#as: Option<Name>,
3050
3051    /// The capability target. Either `parent` or `framework`. Defaults to `parent`.
3052    #[serde(skip_serializing_if = "Option::is_none")]
3053    pub to: Option<ExposeToRef>,
3054
3055    /// (`directory` only) the maximum [directory rights][doc-directory-rights] to apply to
3056    /// the exposed directory capability.
3057    #[serde(skip_serializing_if = "Option::is_none")]
3058    #[reference_doc(json_type = "array of string")]
3059    pub rights: Option<Rights>,
3060
3061    /// (`directory` only) the relative path of a subdirectory within the source directory
3062    /// capability to route.
3063    #[serde(skip_serializing_if = "Option::is_none")]
3064    pub subdir: Option<RelativePath>,
3065
3066    /// (`event_stream` only) the name(s) of the event streams being exposed.
3067    #[serde(skip_serializing_if = "Option::is_none")]
3068    pub event_stream: Option<OneOrMany<Name>>,
3069
3070    /// (`event_stream` only) the scope(s) of the event streams being exposed. This is used to
3071    /// downscope the range of components to which an event stream refers and make it refer only to
3072    /// the components defined in the scope.
3073    #[serde(skip_serializing_if = "Option::is_none")]
3074    pub scope: Option<OneOrMany<EventScope>>,
3075
3076    /// `availability` _(optional)_: The expectations around this capability's availability. Affects
3077    /// build-time and runtime route validation. One of:
3078    /// - `required` (default): a required dependency, the source must exist and provide it. Use
3079    ///     this when the target of this expose requires this capability to function properly.
3080    /// - `optional`: an optional dependency. Use this when the target of the expose can function
3081    ///     with or without this capability. The target must not have a `required` dependency on the
3082    ///     capability. The ultimate source of this expose must be `void` or an actual component.
3083    /// - `same_as_target`: the availability expectations of this capability will match the
3084    ///     target's. If the target requires the capability, then this field is set to `required`.
3085    ///     If the target has an optional dependency on the capability, then the field is set to
3086    ///     `optional`.
3087    /// - `transitional`: like `optional`, but will tolerate a missing source. Use this
3088    ///     only to avoid validation errors during transitional periods of multi-step code changes.
3089    ///
3090    /// For more information, see the
3091    /// [availability](/docs/concepts/components/v2/capabilities/availability.md) documentation.
3092    #[serde(skip_serializing_if = "Option::is_none")]
3093    pub availability: Option<Availability>,
3094
3095    /// Whether or not the source of this offer must exist. One of:
3096    /// - `required` (default): the source (`from`) must be defined in this manifest.
3097    /// - `unknown`: the source of this offer will be rewritten to `void` if its source (`from`)
3098    ///     is not defined in this manifest after includes are processed.
3099    #[serde(skip_serializing_if = "Option::is_none")]
3100    pub source_availability: Option<SourceAvailability>,
3101}
3102
3103impl Expose {
3104    pub fn new_from(from: OneOrMany<ExposeFromRef>) -> Self {
3105        Self {
3106            from,
3107            service: None,
3108            protocol: None,
3109            directory: None,
3110            config: None,
3111            runner: None,
3112            resolver: None,
3113            dictionary: None,
3114            r#as: None,
3115            to: None,
3116            rights: None,
3117            subdir: None,
3118            event_stream: None,
3119            scope: None,
3120            availability: None,
3121            source_availability: None,
3122        }
3123    }
3124}
3125
3126/// Example:
3127///
3128/// ```json5
3129/// offer: [
3130///     {
3131///         protocol: "fuchsia.logger.LogSink",
3132///         from: "#logger",
3133///         to: [ "#fshost", "#pkg_cache" ],
3134///         dependency: "weak",
3135///     },
3136///     {
3137///         protocol: [
3138///             "fuchsia.ui.app.ViewProvider",
3139///             "fuchsia.fonts.Provider",
3140///         ],
3141///         from: "#session",
3142///         to: [ "#ui_shell" ],
3143///         dependency: "strong",
3144///     },
3145///     {
3146///         directory: "blobfs",
3147///         from: "self",
3148///         to: [ "#pkg_cache" ],
3149///     },
3150///     {
3151///         directory: "fshost-config",
3152///         from: "parent",
3153///         to: [ "#fshost" ],
3154///         as: "config",
3155///     },
3156///     {
3157///         storage: "cache",
3158///         from: "parent",
3159///         to: [ "#logger" ],
3160///     },
3161///     {
3162///         runner: "web",
3163///         from: "parent",
3164///         to: [ "#user-shell" ],
3165///     },
3166///     {
3167///         resolver: "full-resolver",
3168///         from: "parent",
3169///         to: [ "#user-shell" ],
3170///     },
3171///     {
3172///         event_stream: "stopped",
3173///         from: "framework",
3174///         to: [ "#logger" ],
3175///     },
3176/// ],
3177/// ```
3178#[derive(Deserialize, Debug, PartialEq, Clone, ReferenceDoc, Serialize)]
3179#[serde(deny_unknown_fields)]
3180#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
3181pub struct Offer {
3182    /// When routing a service, the [name](#name) of a [service capability][doc-service].
3183    #[serde(skip_serializing_if = "Option::is_none")]
3184    pub service: Option<OneOrMany<Name>>,
3185
3186    /// When routing a protocol, the [name](#name) of a [protocol capability][doc-protocol].
3187    #[serde(skip_serializing_if = "Option::is_none")]
3188    pub protocol: Option<OneOrMany<Name>>,
3189
3190    /// When routing a directory, the [name](#name) of a [directory capability][doc-directory].
3191    #[serde(skip_serializing_if = "Option::is_none")]
3192    pub directory: Option<OneOrMany<Name>>,
3193
3194    /// When routing a runner, the [name](#name) of a [runner capability][doc-runners].
3195    #[serde(skip_serializing_if = "Option::is_none")]
3196    pub runner: Option<OneOrMany<Name>>,
3197
3198    /// When routing a resolver, the [name](#name) of a [resolver capability][doc-resolvers].
3199    #[serde(skip_serializing_if = "Option::is_none")]
3200    pub resolver: Option<OneOrMany<Name>>,
3201
3202    /// When routing a storage capability, the [name](#name) of a [storage capability][doc-storage].
3203    #[serde(skip_serializing_if = "Option::is_none")]
3204    pub storage: Option<OneOrMany<Name>>,
3205
3206    /// When routing a dictionary, the [name](#name) of a [dictionary capability][doc-dictionaries].
3207    #[serde(skip_serializing_if = "Option::is_none")]
3208    pub dictionary: Option<OneOrMany<Name>>,
3209
3210    /// When routing a config, the [name](#name) of a configuration capability.
3211    #[serde(skip_serializing_if = "Option::is_none")]
3212    pub config: Option<OneOrMany<Name>>,
3213
3214    /// `from`: The source of the capability, one of:
3215    /// - `parent`: The component's parent. This source can be used for all
3216    ///     capability types.
3217    /// - `self`: This component. Requires a corresponding
3218    ///     [`capability`](#capabilities) declaration.
3219    /// - `framework`: The Component Framework runtime.
3220    /// - `#<child-name>`: A [reference](#references) to a child component
3221    ///     instance. This source can only be used when offering protocol,
3222    ///     directory, or runner capabilities.
3223    /// - `void`: The source is intentionally omitted. Only valid when `availability` is
3224    ///     `optional` or `transitional`.
3225    pub from: OneOrMany<OfferFromRef>,
3226
3227    /// Capability target(s). One of:
3228    /// - `#<target-name>` or \[`#name1`, ...\]: A [reference](#references) to a child or collection,
3229    ///   or an array of references.
3230    /// - `all`: Short-hand for an `offer` clause containing all child [references](#references).
3231    pub to: OneOrMany<OfferToRef>,
3232
3233    /// An explicit [name](#name) for the capability as it will be known by the target. If omitted,
3234    /// defaults to the original name. `as` cannot be used when an array of multiple names is
3235    /// provided.
3236    #[serde(skip_serializing_if = "Option::is_none")]
3237    pub r#as: Option<Name>,
3238
3239    /// The type of dependency between the source and
3240    /// targets, one of:
3241    /// - `strong`: a strong dependency, which is used to determine shutdown
3242    ///     ordering. Component manager is guaranteed to stop the target before the
3243    ///     source. This is the default.
3244    /// - `weak`: a weak dependency, which is ignored during
3245    ///     shutdown. When component manager stops the parent realm, the source may
3246    ///     stop before the clients. Clients of weak dependencies must be able to
3247    ///     handle these dependencies becoming unavailable.
3248    #[serde(skip_serializing_if = "Option::is_none")]
3249    pub dependency: Option<DependencyType>,
3250
3251    /// (`directory` only) the maximum [directory rights][doc-directory-rights] to apply to
3252    /// the offered directory capability.
3253    #[serde(skip_serializing_if = "Option::is_none")]
3254    #[reference_doc(json_type = "array of string")]
3255    pub rights: Option<Rights>,
3256
3257    /// (`directory` only) the relative path of a subdirectory within the source directory
3258    /// capability to route.
3259    #[serde(skip_serializing_if = "Option::is_none")]
3260    pub subdir: Option<RelativePath>,
3261
3262    /// (`event_stream` only) the name(s) of the event streams being offered.
3263    #[serde(skip_serializing_if = "Option::is_none")]
3264    pub event_stream: Option<OneOrMany<Name>>,
3265
3266    /// (`event_stream` only) When defined the event stream will contain events about only the
3267    /// components defined in the scope.
3268    #[serde(skip_serializing_if = "Option::is_none")]
3269    pub scope: Option<OneOrMany<EventScope>>,
3270
3271    /// `availability` _(optional)_: The expectations around this capability's availability. Affects
3272    /// build-time and runtime route validation. One of:
3273    /// - `required` (default): a required dependency, the source must exist and provide it. Use
3274    ///     this when the target of this offer requires this capability to function properly.
3275    /// - `optional`: an optional dependency. Use this when the target of the offer can function
3276    ///     with or without this capability. The target must not have a `required` dependency on the
3277    ///     capability. The ultimate source of this offer must be `void` or an actual component.
3278    /// - `same_as_target`: the availability expectations of this capability will match the
3279    ///     target's. If the target requires the capability, then this field is set to `required`.
3280    ///     If the target has an optional dependency on the capability, then the field is set to
3281    ///     `optional`.
3282    /// - `transitional`: like `optional`, but will tolerate a missing source. Use this
3283    ///     only to avoid validation errors during transitional periods of multi-step code changes.
3284    ///
3285    /// For more information, see the
3286    /// [availability](/docs/concepts/components/v2/capabilities/availability.md) documentation.
3287    #[serde(skip_serializing_if = "Option::is_none")]
3288    pub availability: Option<Availability>,
3289
3290    /// Whether or not the source of this offer must exist. One of:
3291    /// - `required` (default): the source (`from`) must be defined in this manifest.
3292    /// - `unknown`: the source of this offer will be rewritten to `void` if its source (`from`)
3293    ///     is not defined in this manifest after includes are processed.
3294    #[serde(skip_serializing_if = "Option::is_none")]
3295    pub source_availability: Option<SourceAvailability>,
3296}
3297
3298/// Example:
3299///
3300/// ```json5
3301/// children: [
3302///     {
3303///         name: "logger",
3304///         url: "fuchsia-pkg://fuchsia.com/logger#logger.cm",
3305///     },
3306///     {
3307///         name: "pkg_cache",
3308///         url: "fuchsia-pkg://fuchsia.com/pkg_cache#meta/pkg_cache.cm",
3309///         startup: "eager",
3310///     },
3311///     {
3312///         name: "child",
3313///         url: "#meta/child.cm",
3314///     }
3315/// ],
3316/// ```
3317///
3318/// [component-url]: /docs/reference/components/url.md
3319/// [doc-eager]: /docs/development/components/connect.md#eager
3320/// [doc-reboot-on-terminate]: /docs/development/components/connect.md#reboot-on-terminate
3321#[derive(ReferenceDoc, Deserialize, Debug, PartialEq, Serialize)]
3322#[serde(deny_unknown_fields)]
3323#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
3324pub struct Child {
3325    /// The name of the child component instance, which is a string of one
3326    /// or more of the following characters: `a-z`, `0-9`, `_`, `.`, `-`. The name
3327    /// identifies this component when used in a [reference](#references).
3328    pub name: Name,
3329
3330    /// The [component URL][component-url] for the child component instance.
3331    pub url: Url,
3332
3333    /// The component instance's startup mode. One of:
3334    /// - `lazy` _(default)_: Start the component instance only if another
3335    ///     component instance binds to it.
3336    /// - [`eager`][doc-eager]: Start the component instance as soon as its parent
3337    ///     starts.
3338    #[serde(default)]
3339    #[serde(skip_serializing_if = "StartupMode::is_lazy")]
3340    pub startup: StartupMode,
3341
3342    /// Determines the fault recovery policy to apply if this component terminates.
3343    /// - `none` _(default)_: Do nothing.
3344    /// - `reboot`: Gracefully reboot the system if the component terminates for
3345    ///     any reason other than graceful exit. This is a special feature for use only by a narrow
3346    ///     set of components; see [Termination policies][doc-reboot-on-terminate] for more
3347    ///     information.
3348    #[serde(skip_serializing_if = "Option::is_none")]
3349    pub on_terminate: Option<OnTerminate>,
3350
3351    /// If present, the name of the environment to be assigned to the child component instance, one
3352    /// of [`environments`](#environments). If omitted, the child will inherit the same environment
3353    /// assigned to this component.
3354    #[serde(skip_serializing_if = "Option::is_none")]
3355    pub environment: Option<EnvironmentRef>,
3356}
3357
3358#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
3359#[serde(deny_unknown_fields)]
3360#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
3361/// Example:
3362///
3363/// ```json5
3364/// collections: [
3365///     {
3366///         name: "tests",
3367///         durability: "transient",
3368///     },
3369/// ],
3370/// ```
3371pub struct Collection {
3372    /// The name of the component collection, which is a string of one or
3373    /// more of the following characters: `a-z`, `0-9`, `_`, `.`, `-`. The name
3374    /// identifies this collection when used in a [reference](#references).
3375    pub name: Name,
3376
3377    /// The duration of child component instances in the collection.
3378    /// - `transient`: The instance exists until its parent is stopped or it is
3379    ///     explicitly destroyed.
3380    /// - `single_run`: The instance is started when it is created, and destroyed
3381    ///     when it is stopped.
3382    pub durability: Durability,
3383
3384    /// If present, the environment that will be
3385    /// assigned to instances in this collection, one of
3386    /// [`environments`](#environments). If omitted, instances in this collection
3387    /// will inherit the same environment assigned to this component.
3388    pub environment: Option<EnvironmentRef>,
3389
3390    /// Constraints on the dynamic offers that target the components in this collection.
3391    /// Dynamic offers are specified when calling `fuchsia.component.Realm/CreateChild`.
3392    /// - `static_only`: Only those specified in this `.cml` file. No dynamic offers.
3393    ///     This is the default.
3394    /// - `static_and_dynamic`: Both static offers and those specified at runtime
3395    ///     with `CreateChild` are allowed.
3396    pub allowed_offers: Option<AllowedOffers>,
3397
3398    /// Allow child names up to 1024 characters long instead of the usual 255 character limit.
3399    /// Default is false.
3400    pub allow_long_names: Option<bool>,
3401
3402    /// If set to `true`, the data in isolated storage used by dynamic child instances and
3403    /// their descendants will persist after the instances are destroyed. A new child instance
3404    /// created with the same name will share the same storage path as the previous instance.
3405    pub persistent_storage: Option<bool>,
3406}
3407
3408pub trait FromClause {
3409    fn from_(&self) -> OneOrMany<AnyRef<'_>>;
3410}
3411
3412pub trait CapabilityClause: Clone + PartialEq + std::fmt::Debug {
3413    fn service(&self) -> Option<OneOrMany<&BorrowedName>>;
3414    fn protocol(&self) -> Option<OneOrMany<&BorrowedName>>;
3415    fn directory(&self) -> Option<OneOrMany<&BorrowedName>>;
3416    fn storage(&self) -> Option<OneOrMany<&BorrowedName>>;
3417    fn runner(&self) -> Option<OneOrMany<&BorrowedName>>;
3418    fn resolver(&self) -> Option<OneOrMany<&BorrowedName>>;
3419    fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>>;
3420    fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>>;
3421    fn config(&self) -> Option<OneOrMany<&BorrowedName>>;
3422    fn set_service(&mut self, o: Option<OneOrMany<Name>>);
3423    fn set_protocol(&mut self, o: Option<OneOrMany<Name>>);
3424    fn set_directory(&mut self, o: Option<OneOrMany<Name>>);
3425    fn set_storage(&mut self, o: Option<OneOrMany<Name>>);
3426    fn set_runner(&mut self, o: Option<OneOrMany<Name>>);
3427    fn set_resolver(&mut self, o: Option<OneOrMany<Name>>);
3428    fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>);
3429    fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>);
3430    fn set_config(&mut self, o: Option<OneOrMany<Name>>);
3431
3432    fn availability(&self) -> Option<Availability>;
3433    fn set_availability(&mut self, a: Option<Availability>);
3434
3435    /// Returns the name of the capability for display purposes.
3436    /// If `service()` returns `Some`, the capability name must be "service", etc.
3437    ///
3438    /// Returns an error if the capability name is not set, or if there is more than one.
3439    fn capability_type(&self) -> Result<&'static str, Error> {
3440        let mut types = Vec::new();
3441        if self.service().is_some() {
3442            types.push("service");
3443        }
3444        if self.protocol().is_some() {
3445            types.push("protocol");
3446        }
3447        if self.directory().is_some() {
3448            types.push("directory");
3449        }
3450        if self.storage().is_some() {
3451            types.push("storage");
3452        }
3453        if self.event_stream().is_some() {
3454            types.push("event_stream");
3455        }
3456        if self.runner().is_some() {
3457            types.push("runner");
3458        }
3459        if self.config().is_some() {
3460            types.push("config");
3461        }
3462        if self.resolver().is_some() {
3463            types.push("resolver");
3464        }
3465        if self.dictionary().is_some() {
3466            types.push("dictionary");
3467        }
3468        match types.len() {
3469            0 => {
3470                let supported_keywords = self
3471                    .supported()
3472                    .into_iter()
3473                    .map(|k| format!("\"{}\"", k))
3474                    .collect::<Vec<_>>()
3475                    .join(", ");
3476                Err(Error::validate(format!(
3477                    "`{}` declaration is missing a capability keyword, one of: {}",
3478                    self.decl_type(),
3479                    supported_keywords,
3480                )))
3481            }
3482            1 => Ok(types[0]),
3483            _ => Err(Error::validate(format!(
3484                "{} declaration has multiple capability types defined: {:?}",
3485                self.decl_type(),
3486                types
3487            ))),
3488        }
3489    }
3490
3491    /// Returns true if this capability type allows the ::Many variant of OneOrMany.
3492    fn are_many_names_allowed(&self) -> bool;
3493
3494    fn decl_type(&self) -> &'static str;
3495    fn supported(&self) -> &[&'static str];
3496
3497    /// Returns the names of the capabilities in this clause.
3498    /// If `protocol()` returns `Some(OneOrMany::Many(vec!["a", "b"]))`, this returns!["a", "b"].
3499    fn names(&self) -> Vec<&BorrowedName> {
3500        let res = vec![
3501            self.service(),
3502            self.protocol(),
3503            self.directory(),
3504            self.storage(),
3505            self.runner(),
3506            self.config(),
3507            self.resolver(),
3508            self.event_stream(),
3509            self.dictionary(),
3510        ];
3511        res.into_iter()
3512            .map(|o| o.map(|o| o.into_iter().collect::<Vec<&BorrowedName>>()).unwrap_or(vec![]))
3513            .flatten()
3514            .collect()
3515    }
3516
3517    fn set_names(&mut self, names: Vec<Name>) {
3518        let names = match names.len() {
3519            0 => None,
3520            1 => Some(OneOrMany::One(names.first().unwrap().clone())),
3521            _ => Some(OneOrMany::Many(names)),
3522        };
3523
3524        let cap_type = self.capability_type().unwrap();
3525        if cap_type == "protocol" {
3526            self.set_protocol(names);
3527        } else if cap_type == "service" {
3528            self.set_service(names);
3529        } else if cap_type == "directory" {
3530            self.set_directory(names);
3531        } else if cap_type == "storage" {
3532            self.set_storage(names);
3533        } else if cap_type == "runner" {
3534            self.set_runner(names);
3535        } else if cap_type == "resolver" {
3536            self.set_resolver(names);
3537        } else if cap_type == "event_stream" {
3538            self.set_event_stream(names);
3539        } else if cap_type == "dictionary" {
3540            self.set_dictionary(names);
3541        } else if cap_type == "config" {
3542            self.set_config(names);
3543        } else {
3544            panic!("Unknown capability type {}", cap_type);
3545        }
3546    }
3547}
3548
3549trait Canonicalize {
3550    fn canonicalize(&mut self);
3551}
3552
3553pub trait AsClause {
3554    fn r#as(&self) -> Option<&BorrowedName>;
3555}
3556
3557pub trait PathClause {
3558    fn path(&self) -> Option<&Path>;
3559}
3560
3561pub trait FilterClause {
3562    fn filter(&self) -> Option<&Map<String, Value>>;
3563}
3564
3565pub trait RightsClause {
3566    fn rights(&self) -> Option<&Rights>;
3567}
3568
3569fn always_one<T>(o: Option<OneOrMany<T>>) -> Option<T> {
3570    o.map(|o| match o {
3571        OneOrMany::One(o) => o,
3572        OneOrMany::Many(_) => panic!("many is impossible"),
3573    })
3574}
3575
3576impl Canonicalize for Capability {
3577    fn canonicalize(&mut self) {
3578        // Sort the names of the capabilities. Only capabilities with OneOrMany values are included here.
3579        if let Some(service) = &mut self.service {
3580            service.canonicalize()
3581        } else if let Some(protocol) = &mut self.protocol {
3582            protocol.canonicalize()
3583        } else if let Some(event_stream) = &mut self.event_stream {
3584            event_stream.canonicalize()
3585        }
3586    }
3587}
3588
3589fn option_one_or_many_as_ref<T, S: ?Sized>(o: &Option<OneOrMany<T>>) -> Option<OneOrMany<&S>>
3590where
3591    T: AsRef<S>,
3592{
3593    o.as_ref().map(|o| o.as_ref())
3594}
3595
3596impl CapabilityClause for Capability {
3597    fn service(&self) -> Option<OneOrMany<&BorrowedName>> {
3598        option_one_or_many_as_ref(&self.service)
3599    }
3600    fn protocol(&self) -> Option<OneOrMany<&BorrowedName>> {
3601        option_one_or_many_as_ref(&self.protocol)
3602    }
3603    fn directory(&self) -> Option<OneOrMany<&BorrowedName>> {
3604        self.directory.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3605    }
3606    fn storage(&self) -> Option<OneOrMany<&BorrowedName>> {
3607        self.storage.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3608    }
3609    fn runner(&self) -> Option<OneOrMany<&BorrowedName>> {
3610        self.runner.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3611    }
3612    fn resolver(&self) -> Option<OneOrMany<&BorrowedName>> {
3613        self.resolver.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3614    }
3615    fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>> {
3616        option_one_or_many_as_ref(&self.event_stream)
3617    }
3618    fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>> {
3619        self.dictionary.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3620    }
3621    fn config(&self) -> Option<OneOrMany<&BorrowedName>> {
3622        self.config.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3623    }
3624
3625    fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
3626        self.service = o;
3627    }
3628    fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
3629        self.protocol = o;
3630    }
3631    fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
3632        self.directory = always_one(o);
3633    }
3634    fn set_storage(&mut self, o: Option<OneOrMany<Name>>) {
3635        self.storage = always_one(o);
3636    }
3637    fn set_runner(&mut self, o: Option<OneOrMany<Name>>) {
3638        self.runner = always_one(o);
3639    }
3640    fn set_resolver(&mut self, o: Option<OneOrMany<Name>>) {
3641        self.resolver = always_one(o);
3642    }
3643    fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
3644        self.event_stream = o;
3645    }
3646    fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>) {
3647        self.dictionary = always_one(o);
3648    }
3649
3650    fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
3651        self.config = always_one(o);
3652    }
3653
3654    fn availability(&self) -> Option<Availability> {
3655        None
3656    }
3657    fn set_availability(&mut self, _a: Option<Availability>) {}
3658
3659    fn decl_type(&self) -> &'static str {
3660        "capability"
3661    }
3662    fn supported(&self) -> &[&'static str] {
3663        &[
3664            "service",
3665            "protocol",
3666            "directory",
3667            "storage",
3668            "runner",
3669            "resolver",
3670            "event_stream",
3671            "dictionary",
3672            "config",
3673        ]
3674    }
3675    fn are_many_names_allowed(&self) -> bool {
3676        ["service", "protocol", "event_stream"].contains(&self.capability_type().unwrap())
3677    }
3678}
3679
3680impl AsClause for Capability {
3681    fn r#as(&self) -> Option<&BorrowedName> {
3682        None
3683    }
3684}
3685
3686impl PathClause for Capability {
3687    fn path(&self) -> Option<&Path> {
3688        self.path.as_ref()
3689    }
3690}
3691
3692impl FilterClause for Capability {
3693    fn filter(&self) -> Option<&Map<String, Value>> {
3694        None
3695    }
3696}
3697
3698impl RightsClause for Capability {
3699    fn rights(&self) -> Option<&Rights> {
3700        self.rights.as_ref()
3701    }
3702}
3703
3704impl CapabilityClause for DebugRegistration {
3705    fn service(&self) -> Option<OneOrMany<&BorrowedName>> {
3706        None
3707    }
3708    fn protocol(&self) -> Option<OneOrMany<&BorrowedName>> {
3709        option_one_or_many_as_ref(&self.protocol)
3710    }
3711    fn directory(&self) -> Option<OneOrMany<&BorrowedName>> {
3712        None
3713    }
3714    fn storage(&self) -> Option<OneOrMany<&BorrowedName>> {
3715        None
3716    }
3717    fn runner(&self) -> Option<OneOrMany<&BorrowedName>> {
3718        None
3719    }
3720    fn resolver(&self) -> Option<OneOrMany<&BorrowedName>> {
3721        None
3722    }
3723    fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>> {
3724        None
3725    }
3726    fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>> {
3727        None
3728    }
3729    fn config(&self) -> Option<OneOrMany<&BorrowedName>> {
3730        None
3731    }
3732
3733    fn set_service(&mut self, _o: Option<OneOrMany<Name>>) {}
3734    fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
3735        self.protocol = o;
3736    }
3737    fn set_directory(&mut self, _o: Option<OneOrMany<Name>>) {}
3738    fn set_storage(&mut self, _o: Option<OneOrMany<Name>>) {}
3739    fn set_runner(&mut self, _o: Option<OneOrMany<Name>>) {}
3740    fn set_resolver(&mut self, _o: Option<OneOrMany<Name>>) {}
3741    fn set_event_stream(&mut self, _o: Option<OneOrMany<Name>>) {}
3742    fn set_dictionary(&mut self, _o: Option<OneOrMany<Name>>) {}
3743    fn set_config(&mut self, _o: Option<OneOrMany<Name>>) {}
3744
3745    fn availability(&self) -> Option<Availability> {
3746        None
3747    }
3748    fn set_availability(&mut self, _a: Option<Availability>) {}
3749
3750    fn decl_type(&self) -> &'static str {
3751        "debug"
3752    }
3753    fn supported(&self) -> &[&'static str] {
3754        &["service", "protocol"]
3755    }
3756    fn are_many_names_allowed(&self) -> bool {
3757        ["protocol"].contains(&self.capability_type().unwrap())
3758    }
3759}
3760
3761impl AsClause for DebugRegistration {
3762    fn r#as(&self) -> Option<&BorrowedName> {
3763        self.r#as.as_ref().map(Name::as_ref)
3764    }
3765}
3766
3767impl PathClause for DebugRegistration {
3768    fn path(&self) -> Option<&Path> {
3769        None
3770    }
3771}
3772
3773impl FromClause for DebugRegistration {
3774    fn from_(&self) -> OneOrMany<AnyRef<'_>> {
3775        OneOrMany::One(AnyRef::from(&self.from))
3776    }
3777}
3778
3779impl Canonicalize for Use {
3780    fn canonicalize(&mut self) {
3781        // Sort the names of the capabilities. Only capabilities with OneOrMany values are included here.
3782        if let Some(service) = &mut self.service {
3783            service.canonicalize();
3784        } else if let Some(protocol) = &mut self.protocol {
3785            protocol.canonicalize();
3786        } else if let Some(event_stream) = &mut self.event_stream {
3787            event_stream.canonicalize();
3788            if let Some(scope) = &mut self.scope {
3789                scope.canonicalize();
3790            }
3791        }
3792    }
3793}
3794
3795impl CapabilityClause for Use {
3796    fn service(&self) -> Option<OneOrMany<&BorrowedName>> {
3797        option_one_or_many_as_ref(&self.service)
3798    }
3799    fn protocol(&self) -> Option<OneOrMany<&BorrowedName>> {
3800        option_one_or_many_as_ref(&self.protocol)
3801    }
3802    fn directory(&self) -> Option<OneOrMany<&BorrowedName>> {
3803        self.directory.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3804    }
3805    fn storage(&self) -> Option<OneOrMany<&BorrowedName>> {
3806        self.storage.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3807    }
3808    fn runner(&self) -> Option<OneOrMany<&BorrowedName>> {
3809        self.runner.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3810    }
3811    fn resolver(&self) -> Option<OneOrMany<&BorrowedName>> {
3812        None
3813    }
3814    fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>> {
3815        option_one_or_many_as_ref(&self.event_stream)
3816    }
3817    fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>> {
3818        None
3819    }
3820    fn config(&self) -> Option<OneOrMany<&BorrowedName>> {
3821        self.config.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3822    }
3823
3824    fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
3825        self.service = o;
3826    }
3827    fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
3828        self.protocol = o;
3829    }
3830    fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
3831        self.directory = always_one(o);
3832    }
3833    fn set_storage(&mut self, o: Option<OneOrMany<Name>>) {
3834        self.storage = always_one(o);
3835    }
3836    fn set_runner(&mut self, _o: Option<OneOrMany<Name>>) {}
3837    fn set_resolver(&mut self, _o: Option<OneOrMany<Name>>) {}
3838    fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
3839        self.event_stream = o;
3840    }
3841    fn set_dictionary(&mut self, _o: Option<OneOrMany<Name>>) {}
3842    fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
3843        self.config = always_one(o);
3844    }
3845
3846    fn availability(&self) -> Option<Availability> {
3847        self.availability
3848    }
3849    fn set_availability(&mut self, a: Option<Availability>) {
3850        self.availability = a;
3851    }
3852
3853    fn decl_type(&self) -> &'static str {
3854        "use"
3855    }
3856    fn supported(&self) -> &[&'static str] {
3857        &["service", "protocol", "directory", "storage", "event_stream", "runner", "config"]
3858    }
3859    fn are_many_names_allowed(&self) -> bool {
3860        ["service", "protocol", "event_stream"].contains(&self.capability_type().unwrap())
3861    }
3862}
3863
3864impl FilterClause for Use {
3865    fn filter(&self) -> Option<&Map<String, Value>> {
3866        self.filter.as_ref()
3867    }
3868}
3869
3870impl PathClause for Use {
3871    fn path(&self) -> Option<&Path> {
3872        self.path.as_ref()
3873    }
3874}
3875
3876impl FromClause for Use {
3877    fn from_(&self) -> OneOrMany<AnyRef<'_>> {
3878        let one = match &self.from {
3879            Some(from) => AnyRef::from(from),
3880            // Default for `use`.
3881            None => AnyRef::Parent,
3882        };
3883        OneOrMany::One(one)
3884    }
3885}
3886
3887impl FromClause for Expose {
3888    fn from_(&self) -> OneOrMany<AnyRef<'_>> {
3889        one_or_many_from_impl(&self.from)
3890    }
3891}
3892
3893impl RightsClause for Use {
3894    fn rights(&self) -> Option<&Rights> {
3895        self.rights.as_ref()
3896    }
3897}
3898
3899impl Canonicalize for Expose {
3900    fn canonicalize(&mut self) {
3901        // Sort the names of the capabilities. Only capabilities with OneOrMany values are included here.
3902        if let Some(service) = &mut self.service {
3903            service.canonicalize();
3904        } else if let Some(protocol) = &mut self.protocol {
3905            protocol.canonicalize();
3906        } else if let Some(directory) = &mut self.directory {
3907            directory.canonicalize();
3908        } else if let Some(runner) = &mut self.runner {
3909            runner.canonicalize();
3910        } else if let Some(resolver) = &mut self.resolver {
3911            resolver.canonicalize();
3912        } else if let Some(event_stream) = &mut self.event_stream {
3913            event_stream.canonicalize();
3914            if let Some(scope) = &mut self.scope {
3915                scope.canonicalize();
3916            }
3917        }
3918        // TODO(https://fxbug.dev/300500098): canonicalize dictionaries
3919    }
3920}
3921
3922impl CapabilityClause for Expose {
3923    fn service(&self) -> Option<OneOrMany<&BorrowedName>> {
3924        option_one_or_many_as_ref(&self.service)
3925    }
3926    fn protocol(&self) -> Option<OneOrMany<&BorrowedName>> {
3927        option_one_or_many_as_ref(&self.protocol)
3928    }
3929    fn directory(&self) -> Option<OneOrMany<&BorrowedName>> {
3930        option_one_or_many_as_ref(&self.directory)
3931    }
3932    fn storage(&self) -> Option<OneOrMany<&BorrowedName>> {
3933        None
3934    }
3935    fn runner(&self) -> Option<OneOrMany<&BorrowedName>> {
3936        option_one_or_many_as_ref(&self.runner)
3937    }
3938    fn resolver(&self) -> Option<OneOrMany<&BorrowedName>> {
3939        option_one_or_many_as_ref(&self.resolver)
3940    }
3941    fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>> {
3942        option_one_or_many_as_ref(&self.event_stream)
3943    }
3944    fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>> {
3945        option_one_or_many_as_ref(&self.dictionary)
3946    }
3947    fn config(&self) -> Option<OneOrMany<&BorrowedName>> {
3948        option_one_or_many_as_ref(&self.config)
3949    }
3950
3951    fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
3952        self.service = o;
3953    }
3954    fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
3955        self.protocol = o;
3956    }
3957    fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
3958        self.directory = o;
3959    }
3960    fn set_storage(&mut self, _o: Option<OneOrMany<Name>>) {}
3961    fn set_runner(&mut self, o: Option<OneOrMany<Name>>) {
3962        self.runner = o;
3963    }
3964    fn set_resolver(&mut self, o: Option<OneOrMany<Name>>) {
3965        self.resolver = o;
3966    }
3967    fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
3968        self.event_stream = o;
3969    }
3970    fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>) {
3971        self.dictionary = o;
3972    }
3973    fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
3974        self.config = o;
3975    }
3976
3977    fn availability(&self) -> Option<Availability> {
3978        None
3979    }
3980    fn set_availability(&mut self, _a: Option<Availability>) {}
3981
3982    fn decl_type(&self) -> &'static str {
3983        "expose"
3984    }
3985    fn supported(&self) -> &[&'static str] {
3986        &[
3987            "service",
3988            "protocol",
3989            "directory",
3990            "runner",
3991            "resolver",
3992            "event_stream",
3993            "dictionary",
3994            "config",
3995        ]
3996    }
3997    fn are_many_names_allowed(&self) -> bool {
3998        [
3999            "service",
4000            "protocol",
4001            "directory",
4002            "runner",
4003            "resolver",
4004            "event_stream",
4005            "dictionary",
4006            "config",
4007        ]
4008        .contains(&self.capability_type().unwrap())
4009    }
4010}
4011
4012impl AsClause for Expose {
4013    fn r#as(&self) -> Option<&BorrowedName> {
4014        self.r#as.as_ref().map(Name::as_ref)
4015    }
4016}
4017
4018impl PathClause for Expose {
4019    fn path(&self) -> Option<&Path> {
4020        None
4021    }
4022}
4023
4024impl FilterClause for Expose {
4025    fn filter(&self) -> Option<&Map<String, Value>> {
4026        None
4027    }
4028}
4029
4030impl RightsClause for Expose {
4031    fn rights(&self) -> Option<&Rights> {
4032        self.rights.as_ref()
4033    }
4034}
4035
4036impl FromClause for Offer {
4037    fn from_(&self) -> OneOrMany<AnyRef<'_>> {
4038        one_or_many_from_impl(&self.from)
4039    }
4040}
4041
4042impl Canonicalize for Offer {
4043    fn canonicalize(&mut self) {
4044        // Sort the names of the capabilities. Only capabilities with OneOrMany values are included here.
4045        if let Some(service) = &mut self.service {
4046            service.canonicalize();
4047        } else if let Some(protocol) = &mut self.protocol {
4048            protocol.canonicalize();
4049        } else if let Some(directory) = &mut self.directory {
4050            directory.canonicalize();
4051        } else if let Some(runner) = &mut self.runner {
4052            runner.canonicalize();
4053        } else if let Some(resolver) = &mut self.resolver {
4054            resolver.canonicalize();
4055        } else if let Some(storage) = &mut self.storage {
4056            storage.canonicalize();
4057        } else if let Some(event_stream) = &mut self.event_stream {
4058            event_stream.canonicalize();
4059            if let Some(scope) = &mut self.scope {
4060                scope.canonicalize();
4061            }
4062        }
4063    }
4064}
4065
4066impl CapabilityClause for Offer {
4067    fn service(&self) -> Option<OneOrMany<&BorrowedName>> {
4068        option_one_or_many_as_ref(&self.service)
4069    }
4070    fn protocol(&self) -> Option<OneOrMany<&BorrowedName>> {
4071        option_one_or_many_as_ref(&self.protocol)
4072    }
4073    fn directory(&self) -> Option<OneOrMany<&BorrowedName>> {
4074        option_one_or_many_as_ref(&self.directory)
4075    }
4076    fn storage(&self) -> Option<OneOrMany<&BorrowedName>> {
4077        option_one_or_many_as_ref(&self.storage)
4078    }
4079    fn runner(&self) -> Option<OneOrMany<&BorrowedName>> {
4080        option_one_or_many_as_ref(&self.runner)
4081    }
4082    fn resolver(&self) -> Option<OneOrMany<&BorrowedName>> {
4083        option_one_or_many_as_ref(&self.resolver)
4084    }
4085    fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>> {
4086        option_one_or_many_as_ref(&self.event_stream)
4087    }
4088    fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>> {
4089        option_one_or_many_as_ref(&self.dictionary)
4090    }
4091    fn config(&self) -> Option<OneOrMany<&BorrowedName>> {
4092        option_one_or_many_as_ref(&self.config)
4093    }
4094
4095    fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
4096        self.service = o;
4097    }
4098    fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
4099        self.protocol = o;
4100    }
4101    fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
4102        self.directory = o;
4103    }
4104    fn set_storage(&mut self, o: Option<OneOrMany<Name>>) {
4105        self.storage = o;
4106    }
4107    fn set_runner(&mut self, o: Option<OneOrMany<Name>>) {
4108        self.runner = o;
4109    }
4110    fn set_resolver(&mut self, o: Option<OneOrMany<Name>>) {
4111        self.resolver = o;
4112    }
4113    fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
4114        self.event_stream = o;
4115    }
4116    fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>) {
4117        self.dictionary = o;
4118    }
4119    fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
4120        self.config = o
4121    }
4122
4123    fn availability(&self) -> Option<Availability> {
4124        self.availability
4125    }
4126    fn set_availability(&mut self, a: Option<Availability>) {
4127        self.availability = a;
4128    }
4129
4130    fn decl_type(&self) -> &'static str {
4131        "offer"
4132    }
4133    fn supported(&self) -> &[&'static str] {
4134        &[
4135            "service",
4136            "protocol",
4137            "directory",
4138            "storage",
4139            "runner",
4140            "resolver",
4141            "event_stream",
4142            "config",
4143        ]
4144    }
4145    fn are_many_names_allowed(&self) -> bool {
4146        [
4147            "service",
4148            "protocol",
4149            "directory",
4150            "storage",
4151            "runner",
4152            "resolver",
4153            "event_stream",
4154            "config",
4155        ]
4156        .contains(&self.capability_type().unwrap())
4157    }
4158}
4159
4160impl AsClause for Offer {
4161    fn r#as(&self) -> Option<&BorrowedName> {
4162        self.r#as.as_ref().map(Name::as_ref)
4163    }
4164}
4165
4166impl PathClause for Offer {
4167    fn path(&self) -> Option<&Path> {
4168        None
4169    }
4170}
4171
4172impl RightsClause for Offer {
4173    fn rights(&self) -> Option<&Rights> {
4174        self.rights.as_ref()
4175    }
4176}
4177
4178impl FromClause for RunnerRegistration {
4179    fn from_(&self) -> OneOrMany<AnyRef<'_>> {
4180        OneOrMany::One(AnyRef::from(&self.from))
4181    }
4182}
4183
4184impl FromClause for ResolverRegistration {
4185    fn from_(&self) -> OneOrMany<AnyRef<'_>> {
4186        OneOrMany::One(AnyRef::from(&self.from))
4187    }
4188}
4189
4190fn one_or_many_from_impl<'a, T>(from: &'a OneOrMany<T>) -> OneOrMany<AnyRef<'a>>
4191where
4192    AnyRef<'a>: From<&'a T>,
4193    T: 'a,
4194{
4195    let r = match from {
4196        OneOrMany::One(r) => OneOrMany::One(r.into()),
4197        OneOrMany::Many(v) => OneOrMany::Many(v.into_iter().map(|r| r.into()).collect()),
4198    };
4199    r.into()
4200}
4201
4202pub fn alias_or_name<'a>(
4203    alias: Option<&'a BorrowedName>,
4204    name: &'a BorrowedName,
4205) -> &'a BorrowedName {
4206    alias.unwrap_or(name)
4207}
4208
4209pub fn alias_or_path<'a>(alias: Option<&'a Path>, path: &'a Path) -> &'a Path {
4210    alias.unwrap_or(path)
4211}
4212
4213pub fn format_cml(buffer: &str, file: Option<&std::path::Path>) -> Result<Vec<u8>, Error> {
4214    let general_order = PathOption::PropertyNameOrder(vec![
4215        "name",
4216        "url",
4217        "startup",
4218        "environment",
4219        "config",
4220        "dictionary",
4221        "durability",
4222        "service",
4223        "protocol",
4224        "directory",
4225        "storage",
4226        "runner",
4227        "resolver",
4228        "event",
4229        "event_stream",
4230        "from",
4231        "as",
4232        "to",
4233        "rights",
4234        "path",
4235        "subdir",
4236        "filter",
4237        "dependency",
4238        "extends",
4239        "runners",
4240        "resolvers",
4241        "debug",
4242    ]);
4243    let options = FormatOptions {
4244        collapse_containers_of_one: true,
4245        sort_array_items: true, // but use options_by_path to turn this off for program args
4246        options_by_path: hashmap! {
4247            "/*" => hashset! {
4248                PathOption::PropertyNameOrder(vec![
4249                    "include",
4250                    "program",
4251                    "children",
4252                    "collections",
4253                    "capabilities",
4254                    "use",
4255                    "offer",
4256                    "expose",
4257                    "environments",
4258                    "facets",
4259                ])
4260            },
4261            "/*/program" => hashset! {
4262                PathOption::CollapseContainersOfOne(false),
4263                PathOption::PropertyNameOrder(vec![
4264                    "runner",
4265                    "binary",
4266                    "args",
4267                ]),
4268            },
4269            "/*/program/*" => hashset! {
4270                PathOption::SortArrayItems(false),
4271            },
4272            "/*/*/*" => hashset! {
4273                general_order.clone()
4274            },
4275            "/*/*/*/*/*" => hashset! {
4276                general_order
4277            },
4278        },
4279        ..Default::default()
4280    };
4281
4282    json5format::format(buffer, file.map(|f| f.to_string_lossy().to_string()), Some(options))
4283        .map_err(|e| Error::json5(e, file))
4284}
4285
4286pub fn offer_to_all_and_component_diff_sources_message<'a>(
4287    capability: impl Iterator<Item = OfferToAllCapability<'a>>,
4288    component: &str,
4289) -> String {
4290    let mut output = String::new();
4291    let mut capability = capability.peekable();
4292    write!(&mut output, "{} ", capability.peek().unwrap().offer_type()).unwrap();
4293    for (i, capability) in capability.enumerate() {
4294        if i > 0 {
4295            write!(&mut output, ", ").unwrap();
4296        }
4297        write!(&mut output, "{}", capability.name()).unwrap();
4298    }
4299    write!(
4300        &mut output,
4301        r#" is offered to both "all" and child component "{}" with different sources"#,
4302        component
4303    )
4304    .unwrap();
4305    output
4306}
4307
4308pub fn offer_to_all_and_component_diff_capabilities_message<'a>(
4309    capability: impl Iterator<Item = OfferToAllCapability<'a>>,
4310    component: &str,
4311) -> String {
4312    let mut output = String::new();
4313    let mut capability_peek = capability.peekable();
4314
4315    // Clone is needed so the iterator can be moved forward.
4316    // This doesn't actually allocate memory or copy a string, as only the reference
4317    // held by the OfferToAllCapability<'a> is copied.
4318    let first_offer_to_all = capability_peek.peek().unwrap().clone();
4319    write!(&mut output, "{} ", first_offer_to_all.offer_type()).unwrap();
4320    for (i, capability) in capability_peek.enumerate() {
4321        if i > 0 {
4322            write!(&mut output, ", ").unwrap();
4323        }
4324        write!(&mut output, "{}", capability.name()).unwrap();
4325    }
4326    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();
4327    output
4328}
4329
4330/// Returns `Ok(true)` if desugaring the `offer_to_all` using `name` duplicates
4331/// `specific_offer`. Returns `Ok(false)` if not a duplicate.
4332///
4333/// Returns Err if there is a validation error.
4334pub fn offer_to_all_would_duplicate(
4335    offer_to_all: &Offer,
4336    specific_offer: &Offer,
4337    target: &cm_types::BorrowedName,
4338) -> Result<bool, Error> {
4339    // Only protocols and dictionaries may be offered to all
4340    assert!(offer_to_all.protocol.is_some() || offer_to_all.dictionary.is_some());
4341
4342    // If none of the pairs of the cross products of the two offer's protocols
4343    // match, then the offer is certainly not a duplicate
4344    if CapabilityId::from_offer_expose(specific_offer).iter().flatten().all(
4345        |specific_offer_cap_id| {
4346            CapabilityId::from_offer_expose(offer_to_all)
4347                .iter()
4348                .flatten()
4349                .all(|offer_to_all_cap_id| offer_to_all_cap_id != specific_offer_cap_id)
4350        },
4351    ) {
4352        return Ok(false);
4353    }
4354
4355    let to_field_matches = specific_offer.to.iter().any(
4356        |specific_offer_to| matches!(specific_offer_to, OfferToRef::Named(c) if **c == *target),
4357    );
4358
4359    if !to_field_matches {
4360        return Ok(false);
4361    }
4362
4363    if offer_to_all.from != specific_offer.from {
4364        return Err(Error::validate(offer_to_all_and_component_diff_sources_message(
4365            offer_to_all_from_offer(offer_to_all),
4366            target.as_str(),
4367        )));
4368    }
4369
4370    // Since the capability ID's match, the underlying protocol must also match
4371    if offer_to_all_from_offer(offer_to_all).all(|to_all_protocol| {
4372        offer_to_all_from_offer(specific_offer)
4373            .all(|to_specific_protocol| to_all_protocol != to_specific_protocol)
4374    }) {
4375        return Err(Error::validate(offer_to_all_and_component_diff_capabilities_message(
4376            offer_to_all_from_offer(offer_to_all),
4377            target.as_str(),
4378        )));
4379    }
4380
4381    Ok(true)
4382}
4383
4384impl Offer {
4385    /// Creates a new empty offer. This offer just has the `from` and `to` fields set, so to make
4386    /// it useful it needs at least the capability name set in the necesssary attribute.
4387    pub fn empty(from: OneOrMany<OfferFromRef>, to: OneOrMany<OfferToRef>) -> Offer {
4388        Self {
4389            protocol: None,
4390            from,
4391            to,
4392            r#as: None,
4393            service: None,
4394            directory: None,
4395            config: None,
4396            runner: None,
4397            resolver: None,
4398            storage: None,
4399            dictionary: None,
4400            dependency: None,
4401            rights: None,
4402            subdir: None,
4403            event_stream: None,
4404            scope: None,
4405            availability: None,
4406            source_availability: None,
4407        }
4408    }
4409}
4410
4411#[cfg(test)]
4412pub fn create_offer(
4413    protocol_name: &str,
4414    from: OneOrMany<OfferFromRef>,
4415    to: OneOrMany<OfferToRef>,
4416) -> Offer {
4417    Offer {
4418        protocol: Some(OneOrMany::One(Name::from_str(protocol_name).unwrap())),
4419        ..Offer::empty(from, to)
4420    }
4421}
4422
4423#[cfg(test)]
4424mod tests {
4425    use super::*;
4426    use assert_matches::assert_matches;
4427    use difference::Changeset;
4428    use serde_json::{json, to_string_pretty, to_value};
4429    use std::path::Path;
4430    use test_case::test_case;
4431
4432    macro_rules! assert_json_eq {
4433        ($a:expr, $e:expr) => {{
4434            if $a != $e {
4435                let expected = to_string_pretty(&$e).unwrap();
4436                let actual = to_string_pretty(&$a).unwrap();
4437                assert_eq!(
4438                    $a,
4439                    $e,
4440                    "JSON actual != expected. Diffs:\n\n{}",
4441                    Changeset::new(&actual, &expected, "\n")
4442                );
4443            }
4444        }};
4445    }
4446
4447    // Exercise reference parsing tests on `OfferFromRef` because it contains every reference
4448    // subtype.
4449
4450    #[test]
4451    fn test_parse_named_reference() {
4452        assert_matches!("#some-child".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "some-child");
4453        assert_matches!("#A".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "A");
4454        assert_matches!("#7".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "7");
4455        assert_matches!("#_".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "_");
4456
4457        assert_matches!("#-".parse::<OfferFromRef>(), Err(_));
4458        assert_matches!("#.".parse::<OfferFromRef>(), Err(_));
4459        assert_matches!("#".parse::<OfferFromRef>(), Err(_));
4460        assert_matches!("some-child".parse::<OfferFromRef>(), Err(_));
4461    }
4462
4463    #[test]
4464    fn test_parse_reference_test() {
4465        assert_matches!("parent".parse::<OfferFromRef>(), Ok(OfferFromRef::Parent));
4466        assert_matches!("framework".parse::<OfferFromRef>(), Ok(OfferFromRef::Framework));
4467        assert_matches!("self".parse::<OfferFromRef>(), Ok(OfferFromRef::Self_));
4468        assert_matches!("#child".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "child");
4469
4470        assert_matches!("invalid".parse::<OfferFromRef>(), Err(_));
4471        assert_matches!("#invalid-child^".parse::<OfferFromRef>(), Err(_));
4472    }
4473
4474    fn json_value_from_str(json: &str, filename: &Path) -> Result<Value, Error> {
4475        serde_json::from_str(json).map_err(|e| {
4476            Error::parse(
4477                format!("Couldn't read input as JSON: {}", e),
4478                Some(Location { line: e.line(), column: e.column() }),
4479                Some(filename),
4480            )
4481        })
4482    }
4483
4484    fn parse_as_ref(input: &str) -> Result<OfferFromRef, Error> {
4485        serde_json::from_value::<OfferFromRef>(json_value_from_str(input, &Path::new("test.cml"))?)
4486            .map_err(|e| Error::parse(format!("{}", e), None, None))
4487    }
4488
4489    #[test]
4490    fn test_deserialize_ref() -> Result<(), Error> {
4491        assert_matches!(parse_as_ref("\"self\""), Ok(OfferFromRef::Self_));
4492        assert_matches!(parse_as_ref("\"parent\""), Ok(OfferFromRef::Parent));
4493        assert_matches!(parse_as_ref("\"#child\""), Ok(OfferFromRef::Named(name)) if name == "child");
4494
4495        assert_matches!(parse_as_ref(r#""invalid""#), Err(_));
4496
4497        Ok(())
4498    }
4499
4500    macro_rules! test_parse_rights {
4501        (
4502            $(
4503                ($input:expr, $expected:expr),
4504            )+
4505        ) => {
4506            #[test]
4507            fn parse_rights() {
4508                $(
4509                    parse_rights_test($input, $expected);
4510                )+
4511            }
4512        }
4513    }
4514
4515    fn parse_rights_test(input: &str, expected: Right) {
4516        let r: Right = serde_json5::from_str(&format!("\"{}\"", input)).expect("invalid json");
4517        assert_eq!(r, expected);
4518    }
4519
4520    test_parse_rights! {
4521        ("connect", Right::Connect),
4522        ("enumerate", Right::Enumerate),
4523        ("execute", Right::Execute),
4524        ("get_attributes", Right::GetAttributes),
4525        ("modify_directory", Right::ModifyDirectory),
4526        ("read_bytes", Right::ReadBytes),
4527        ("traverse", Right::Traverse),
4528        ("update_attributes", Right::UpdateAttributes),
4529        ("write_bytes", Right::WriteBytes),
4530        ("r*", Right::ReadAlias),
4531        ("w*", Right::WriteAlias),
4532        ("x*", Right::ExecuteAlias),
4533        ("rw*", Right::ReadWriteAlias),
4534        ("rx*", Right::ReadExecuteAlias),
4535    }
4536
4537    macro_rules! test_expand_rights {
4538        (
4539            $(
4540                ($input:expr, $expected:expr),
4541            )+
4542        ) => {
4543            #[test]
4544            fn expand_rights() {
4545                $(
4546                    expand_rights_test($input, $expected);
4547                )+
4548            }
4549        }
4550    }
4551
4552    fn expand_rights_test(input: Right, expected: Vec<fio::Operations>) {
4553        assert_eq!(input.expand(), expected);
4554    }
4555
4556    test_expand_rights! {
4557        (Right::Connect, vec![fio::Operations::CONNECT]),
4558        (Right::Enumerate, vec![fio::Operations::ENUMERATE]),
4559        (Right::Execute, vec![fio::Operations::EXECUTE]),
4560        (Right::GetAttributes, vec![fio::Operations::GET_ATTRIBUTES]),
4561        (Right::ModifyDirectory, vec![fio::Operations::MODIFY_DIRECTORY]),
4562        (Right::ReadBytes, vec![fio::Operations::READ_BYTES]),
4563        (Right::Traverse, vec![fio::Operations::TRAVERSE]),
4564        (Right::UpdateAttributes, vec![fio::Operations::UPDATE_ATTRIBUTES]),
4565        (Right::WriteBytes, vec![fio::Operations::WRITE_BYTES]),
4566        (Right::ReadAlias, vec![
4567            fio::Operations::CONNECT,
4568            fio::Operations::ENUMERATE,
4569            fio::Operations::TRAVERSE,
4570            fio::Operations::READ_BYTES,
4571            fio::Operations::GET_ATTRIBUTES,
4572        ]),
4573        (Right::WriteAlias, vec![
4574            fio::Operations::CONNECT,
4575            fio::Operations::ENUMERATE,
4576            fio::Operations::TRAVERSE,
4577            fio::Operations::WRITE_BYTES,
4578            fio::Operations::MODIFY_DIRECTORY,
4579            fio::Operations::UPDATE_ATTRIBUTES,
4580        ]),
4581        (Right::ExecuteAlias, vec![
4582            fio::Operations::CONNECT,
4583            fio::Operations::ENUMERATE,
4584            fio::Operations::TRAVERSE,
4585            fio::Operations::EXECUTE,
4586        ]),
4587        (Right::ReadWriteAlias, vec![
4588            fio::Operations::CONNECT,
4589            fio::Operations::ENUMERATE,
4590            fio::Operations::TRAVERSE,
4591            fio::Operations::READ_BYTES,
4592            fio::Operations::WRITE_BYTES,
4593            fio::Operations::MODIFY_DIRECTORY,
4594            fio::Operations::GET_ATTRIBUTES,
4595            fio::Operations::UPDATE_ATTRIBUTES,
4596        ]),
4597        (Right::ReadExecuteAlias, vec![
4598            fio::Operations::CONNECT,
4599            fio::Operations::ENUMERATE,
4600            fio::Operations::TRAVERSE,
4601            fio::Operations::READ_BYTES,
4602            fio::Operations::GET_ATTRIBUTES,
4603            fio::Operations::EXECUTE,
4604        ]),
4605    }
4606
4607    #[test]
4608    fn test_deny_unknown_fields() {
4609        assert_matches!(serde_json5::from_str::<Document>("{ unknown: \"\" }"), Err(_));
4610        assert_matches!(serde_json5::from_str::<Environment>("{ unknown: \"\" }"), Err(_));
4611        assert_matches!(serde_json5::from_str::<RunnerRegistration>("{ unknown: \"\" }"), Err(_));
4612        assert_matches!(serde_json5::from_str::<ResolverRegistration>("{ unknown: \"\" }"), Err(_));
4613        assert_matches!(serde_json5::from_str::<Use>("{ unknown: \"\" }"), Err(_));
4614        assert_matches!(serde_json5::from_str::<Expose>("{ unknown: \"\" }"), Err(_));
4615        assert_matches!(serde_json5::from_str::<Offer>("{ unknown: \"\" }"), Err(_));
4616        assert_matches!(serde_json5::from_str::<Capability>("{ unknown: \"\" }"), Err(_));
4617        assert_matches!(serde_json5::from_str::<Child>("{ unknown: \"\" }"), Err(_));
4618        assert_matches!(serde_json5::from_str::<Collection>("{ unknown: \"\" }"), Err(_));
4619    }
4620
4621    // TODO: Use Default::default() instead
4622
4623    fn empty_offer() -> Offer {
4624        Offer {
4625            service: None,
4626            protocol: None,
4627            directory: None,
4628            storage: None,
4629            runner: None,
4630            resolver: None,
4631            dictionary: None,
4632            config: None,
4633            from: OneOrMany::One(OfferFromRef::Self_),
4634            to: OneOrMany::Many(vec![]),
4635            r#as: None,
4636            rights: None,
4637            subdir: None,
4638            dependency: None,
4639            event_stream: None,
4640            scope: None,
4641            availability: None,
4642            source_availability: None,
4643        }
4644    }
4645
4646    fn empty_use() -> Use {
4647        Use {
4648            service: None,
4649            protocol: None,
4650            scope: None,
4651            directory: None,
4652            storage: None,
4653            config: None,
4654            key: None,
4655            from: None,
4656            path: None,
4657            rights: None,
4658            subdir: None,
4659            event_stream: None,
4660            runner: None,
4661            filter: None,
4662            dependency: None,
4663            availability: None,
4664            config_element_type: None,
4665            config_max_count: None,
4666            config_max_size: None,
4667            config_type: None,
4668            config_default: None,
4669        }
4670    }
4671
4672    #[test]
4673    fn test_capability_id() -> Result<(), Error> {
4674        // service
4675        let a: Name = "a".parse().unwrap();
4676        let b: Name = "b".parse().unwrap();
4677        assert_eq!(
4678            CapabilityId::from_offer_expose(&Offer {
4679                service: Some(OneOrMany::One(a.clone())),
4680                ..empty_offer()
4681            },)?,
4682            vec![CapabilityId::Service(&a)]
4683        );
4684        assert_eq!(
4685            CapabilityId::from_offer_expose(&Offer {
4686                service: Some(OneOrMany::Many(vec![a.clone(), b.clone()],)),
4687                ..empty_offer()
4688            },)?,
4689            vec![CapabilityId::Service(&a), CapabilityId::Service(&b)]
4690        );
4691        assert_eq!(
4692            CapabilityId::from_use(&Use {
4693                service: Some(OneOrMany::One(a.clone())),
4694                ..empty_use()
4695            },)?,
4696            vec![CapabilityId::UsedService("/svc/a".parse().unwrap())]
4697        );
4698        assert_eq!(
4699            CapabilityId::from_use(&Use {
4700                service: Some(OneOrMany::Many(vec![a.clone(), b.clone(),],)),
4701                ..empty_use()
4702            },)?,
4703            vec![
4704                CapabilityId::UsedService("/svc/a".parse().unwrap()),
4705                CapabilityId::UsedService("/svc/b".parse().unwrap())
4706            ]
4707        );
4708        assert_eq!(
4709            CapabilityId::from_use(&Use {
4710                event_stream: Some(OneOrMany::One(Name::new("test".to_string()).unwrap())),
4711                path: Some(cm_types::Path::new("/svc/myevent".to_string()).unwrap()),
4712                ..empty_use()
4713            },)?,
4714            vec![CapabilityId::UsedEventStream("/svc/myevent".parse().unwrap()),]
4715        );
4716        assert_eq!(
4717            CapabilityId::from_use(&Use {
4718                event_stream: Some(OneOrMany::One(Name::new("test".to_string()).unwrap())),
4719                ..empty_use()
4720            },)?,
4721            vec![CapabilityId::UsedEventStream(
4722                "/svc/fuchsia.component.EventStream".parse().unwrap()
4723            ),]
4724        );
4725        assert_eq!(
4726            CapabilityId::from_use(&Use {
4727                service: Some(OneOrMany::One(a.clone())),
4728                path: Some("/b".parse().unwrap()),
4729                ..empty_use()
4730            },)?,
4731            vec![CapabilityId::UsedService("/b".parse().unwrap())]
4732        );
4733
4734        // protocol
4735        assert_eq!(
4736            CapabilityId::from_offer_expose(&Offer {
4737                protocol: Some(OneOrMany::One(a.clone())),
4738                ..empty_offer()
4739            },)?,
4740            vec![CapabilityId::Protocol(&a)]
4741        );
4742        assert_eq!(
4743            CapabilityId::from_offer_expose(&Offer {
4744                protocol: Some(OneOrMany::Many(vec![a.clone(), b.clone()],)),
4745                ..empty_offer()
4746            },)?,
4747            vec![CapabilityId::Protocol(&a), CapabilityId::Protocol(&b)]
4748        );
4749        assert_eq!(
4750            CapabilityId::from_use(&Use {
4751                protocol: Some(OneOrMany::One(a.clone())),
4752                ..empty_use()
4753            },)?,
4754            vec![CapabilityId::UsedProtocol("/svc/a".parse().unwrap())]
4755        );
4756        assert_eq!(
4757            CapabilityId::from_use(&Use {
4758                protocol: Some(OneOrMany::Many(vec![a.clone(), b.clone(),],)),
4759                ..empty_use()
4760            },)?,
4761            vec![
4762                CapabilityId::UsedProtocol("/svc/a".parse().unwrap()),
4763                CapabilityId::UsedProtocol("/svc/b".parse().unwrap())
4764            ]
4765        );
4766        assert_eq!(
4767            CapabilityId::from_use(&Use {
4768                protocol: Some(OneOrMany::One(a.clone())),
4769                path: Some("/b".parse().unwrap()),
4770                ..empty_use()
4771            },)?,
4772            vec![CapabilityId::UsedProtocol("/b".parse().unwrap())]
4773        );
4774
4775        // directory
4776        assert_eq!(
4777            CapabilityId::from_offer_expose(&Offer {
4778                directory: Some(OneOrMany::One(a.clone())),
4779                ..empty_offer()
4780            },)?,
4781            vec![CapabilityId::Directory(&a)]
4782        );
4783        assert_eq!(
4784            CapabilityId::from_offer_expose(&Offer {
4785                directory: Some(OneOrMany::Many(vec![a.clone(), b.clone()])),
4786                ..empty_offer()
4787            },)?,
4788            vec![CapabilityId::Directory(&a), CapabilityId::Directory(&b),]
4789        );
4790        assert_eq!(
4791            CapabilityId::from_use(&Use {
4792                directory: Some(a.clone()),
4793                path: Some("/b".parse().unwrap()),
4794                ..empty_use()
4795            },)?,
4796            vec![CapabilityId::UsedDirectory("/b".parse().unwrap())]
4797        );
4798
4799        // storage
4800        assert_eq!(
4801            CapabilityId::from_offer_expose(&Offer {
4802                storage: Some(OneOrMany::One(a.clone())),
4803                ..empty_offer()
4804            },)?,
4805            vec![CapabilityId::Storage(&a)]
4806        );
4807        assert_eq!(
4808            CapabilityId::from_offer_expose(&Offer {
4809                storage: Some(OneOrMany::Many(vec![a.clone(), b.clone()])),
4810                ..empty_offer()
4811            },)?,
4812            vec![CapabilityId::Storage(&a), CapabilityId::Storage(&b),]
4813        );
4814        assert_eq!(
4815            CapabilityId::from_use(&Use {
4816                storage: Some(a.clone()),
4817                path: Some("/b".parse().unwrap()),
4818                ..empty_use()
4819            },)?,
4820            vec![CapabilityId::UsedStorage("/b".parse().unwrap())]
4821        );
4822
4823        // runner
4824        assert_eq!(
4825            CapabilityId::from_use(&Use { runner: Some("elf".parse().unwrap()), ..empty_use() })?,
4826            vec![CapabilityId::UsedRunner(BorrowedName::new("elf").unwrap())]
4827        );
4828
4829        // "as" aliasing.
4830        assert_eq!(
4831            CapabilityId::from_offer_expose(&Offer {
4832                service: Some(OneOrMany::One(a.clone())),
4833                r#as: Some(b.clone()),
4834                ..empty_offer()
4835            },)?,
4836            vec![CapabilityId::Service(&b)]
4837        );
4838
4839        // Error case.
4840        assert_matches!(CapabilityId::from_offer_expose(&empty_offer()), Err(_));
4841
4842        Ok(())
4843    }
4844
4845    fn document(contents: serde_json::Value) -> Document {
4846        serde_json5::from_str::<Document>(&contents.to_string()).unwrap()
4847    }
4848
4849    #[test]
4850    fn test_includes() {
4851        assert_eq!(document(json!({})).includes(), Vec::<String>::new());
4852        assert_eq!(document(json!({ "include": []})).includes(), Vec::<String>::new());
4853        assert_eq!(
4854            document(json!({ "include": [ "foo.cml", "bar.cml" ]})).includes(),
4855            vec!["foo.cml", "bar.cml"]
4856        );
4857    }
4858
4859    #[test]
4860    fn test_merge_same_section() {
4861        let mut some = document(json!({ "use": [{ "protocol": "foo" }] }));
4862        let mut other = document(json!({ "use": [{ "protocol": "bar" }] }));
4863        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
4864        let uses = some.r#use.as_ref().unwrap();
4865        assert_eq!(uses.len(), 2);
4866        assert_eq!(
4867            uses[0].protocol.as_ref().unwrap(),
4868            &OneOrMany::One("foo".parse::<Name>().unwrap())
4869        );
4870        assert_eq!(
4871            uses[1].protocol.as_ref().unwrap(),
4872            &OneOrMany::One("bar".parse::<Name>().unwrap())
4873        );
4874    }
4875
4876    #[test]
4877    fn test_merge_upgraded_availability() {
4878        let mut some =
4879            document(json!({ "use": [{ "protocol": "foo", "availability": "optional" }] }));
4880        let mut other1 = document(json!({ "use": [{ "protocol": "foo" }] }));
4881        let mut other2 =
4882            document(json!({ "use": [{ "protocol": "foo", "availability": "transitional" }] }));
4883        let mut other3 =
4884            document(json!({ "use": [{ "protocol": "foo", "availability": "same_as_target" }] }));
4885        some.merge_from(&mut other1, &Path::new("some/path")).unwrap();
4886        some.merge_from(&mut other2, &Path::new("some/path")).unwrap();
4887        some.merge_from(&mut other3, &Path::new("some/path")).unwrap();
4888        let uses = some.r#use.as_ref().unwrap();
4889        assert_eq!(uses.len(), 2);
4890        assert_eq!(
4891            uses[0].protocol.as_ref().unwrap(),
4892            &OneOrMany::One("foo".parse::<Name>().unwrap())
4893        );
4894        assert!(uses[0].availability.is_none());
4895        assert_eq!(
4896            uses[1].protocol.as_ref().unwrap(),
4897            &OneOrMany::One("foo".parse::<Name>().unwrap())
4898        );
4899        assert_eq!(uses[1].availability.as_ref().unwrap(), &Availability::SameAsTarget,);
4900    }
4901
4902    #[test]
4903    fn test_merge_different_sections() {
4904        let mut some = document(json!({ "use": [{ "protocol": "foo" }] }));
4905        let mut other = document(json!({ "expose": [{ "protocol": "bar", "from": "self" }] }));
4906        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
4907        let uses = some.r#use.as_ref().unwrap();
4908        let exposes = some.expose.as_ref().unwrap();
4909        assert_eq!(uses.len(), 1);
4910        assert_eq!(exposes.len(), 1);
4911        assert_eq!(
4912            uses[0].protocol.as_ref().unwrap(),
4913            &OneOrMany::One("foo".parse::<Name>().unwrap())
4914        );
4915        assert_eq!(
4916            exposes[0].protocol.as_ref().unwrap(),
4917            &OneOrMany::One("bar".parse::<Name>().unwrap())
4918        );
4919    }
4920
4921    #[test]
4922    fn test_merge_environments() {
4923        let mut some = document(json!({ "environments": [
4924            {
4925                "name": "one",
4926                "extends": "realm",
4927            },
4928            {
4929                "name": "two",
4930                "extends": "none",
4931                "runners": [
4932                    {
4933                        "runner": "r1",
4934                        "from": "#c1",
4935                    },
4936                    {
4937                        "runner": "r2",
4938                        "from": "#c2",
4939                    },
4940                ],
4941                "resolvers": [
4942                    {
4943                        "resolver": "res1",
4944                        "from": "#c1",
4945                        "scheme": "foo",
4946                    },
4947                ],
4948                "debug": [
4949                    {
4950                        "protocol": "baz",
4951                        "from": "#c2"
4952                    }
4953                ]
4954            },
4955        ]}));
4956        let mut other = document(json!({ "environments": [
4957            {
4958                "name": "two",
4959                "__stop_timeout_ms": 100,
4960                "runners": [
4961                    {
4962                        "runner": "r3",
4963                        "from": "#c3",
4964                    },
4965                ],
4966                "resolvers": [
4967                    {
4968                        "resolver": "res2",
4969                        "from": "#c1",
4970                        "scheme": "bar",
4971                    },
4972                ],
4973                "debug": [
4974                    {
4975                        "protocol": "faz",
4976                        "from": "#c2"
4977                    }
4978                ]
4979            },
4980            {
4981                "name": "three",
4982                "__stop_timeout_ms": 1000,
4983            },
4984        ]}));
4985        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
4986        assert_eq!(
4987            to_value(some).unwrap(),
4988            json!({"environments": [
4989                {
4990                    "name": "one",
4991                    "extends": "realm",
4992                },
4993                {
4994                    "name": "three",
4995                    "__stop_timeout_ms": 1000,
4996                },
4997                {
4998                    "name": "two",
4999                    "extends": "none",
5000                    "__stop_timeout_ms": 100,
5001                    "runners": [
5002                        {
5003                            "runner": "r1",
5004                            "from": "#c1",
5005                        },
5006                        {
5007                            "runner": "r2",
5008                            "from": "#c2",
5009                        },
5010                        {
5011                            "runner": "r3",
5012                            "from": "#c3",
5013                        },
5014                    ],
5015                    "resolvers": [
5016                        {
5017                            "resolver": "res1",
5018                            "from": "#c1",
5019                            "scheme": "foo",
5020                        },
5021                        {
5022                            "resolver": "res2",
5023                            "from": "#c1",
5024                            "scheme": "bar",
5025                        },
5026                    ],
5027                    "debug": [
5028                        {
5029                            "protocol": "baz",
5030                            "from": "#c2"
5031                        },
5032                        {
5033                            "protocol": "faz",
5034                            "from": "#c2"
5035                        }
5036                    ]
5037                },
5038            ]})
5039        );
5040    }
5041
5042    #[test]
5043    fn test_merge_environments_errors() {
5044        {
5045            let mut some = document(json!({"environments": [{"name": "one", "extends": "realm"}]}));
5046            let mut other = document(json!({"environments": [{"name": "one", "extends": "none"}]}));
5047            assert!(some.merge_from(&mut other, &Path::new("some/path")).is_err());
5048        }
5049        {
5050            let mut some =
5051                document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]}));
5052            let mut other =
5053                document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 20}]}));
5054            assert!(some.merge_from(&mut other, &Path::new("some/path")).is_err());
5055        }
5056
5057        // It's ok if the values match.
5058        {
5059            let mut some = document(json!({"environments": [{"name": "one", "extends": "realm"}]}));
5060            let mut other =
5061                document(json!({"environments": [{"name": "one", "extends": "realm"}]}));
5062            some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5063            assert_eq!(
5064                to_value(some).unwrap(),
5065                json!({"environments": [{"name": "one", "extends": "realm"}]})
5066            );
5067        }
5068        {
5069            let mut some =
5070                document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]}));
5071            let mut other =
5072                document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]}));
5073            some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5074            assert_eq!(
5075                to_value(some).unwrap(),
5076                json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]})
5077            );
5078        }
5079    }
5080
5081    #[test]
5082    fn test_merge_from_other_config() {
5083        let mut some = document(json!({}));
5084        let mut other = document(json!({ "config": { "bar": { "type": "bool" } } }));
5085
5086        some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5087        let expected = document(json!({ "config": { "bar": { "type": "bool" } } }));
5088        assert_eq!(some.config, expected.config);
5089    }
5090
5091    #[test]
5092    fn test_merge_from_some_config() {
5093        let mut some = document(json!({ "config": { "bar": { "type": "bool" } } }));
5094        let mut other = document(json!({}));
5095
5096        some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5097        let expected = document(json!({ "config": { "bar": { "type": "bool" } } }));
5098        assert_eq!(some.config, expected.config);
5099    }
5100
5101    #[test]
5102    fn test_merge_from_config() {
5103        let mut some = document(json!({ "config": { "foo": { "type": "bool" } } }));
5104        let mut other = document(json!({ "config": { "bar": { "type": "bool" } } }));
5105        some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5106
5107        assert_eq!(
5108            some,
5109            document(json!({
5110                "config": {
5111                    "foo": { "type": "bool" },
5112                    "bar": { "type": "bool" },
5113                }
5114            })),
5115        );
5116    }
5117
5118    #[test]
5119    fn test_merge_from_config_dedupe_identical_fields() {
5120        let mut some = document(json!({ "config": { "foo": { "type": "bool" } } }));
5121        let mut other = document(json!({ "config": { "foo": { "type": "bool" } } }));
5122        some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5123
5124        assert_eq!(some, document(json!({ "config": { "foo": { "type": "bool" } } })));
5125    }
5126
5127    #[test]
5128    fn test_merge_from_config_conflicting_keys() {
5129        let mut some = document(json!({ "config": { "foo": { "type": "bool" } } }));
5130        let mut other = document(json!({ "config": { "foo": { "type": "uint8" } } }));
5131
5132        assert_matches::assert_matches!(
5133            some.merge_from(&mut other, &path::Path::new("some/path")),
5134            Err(Error::Validate { err, .. })
5135                if err == "Found conflicting entry for config key `foo` in `some/path`."
5136        );
5137    }
5138
5139    #[test]
5140    fn test_canonicalize() {
5141        let mut some = document(json!({
5142            "children": [
5143                // Will be sorted by name
5144                { "name": "b_child", "url": "http://foo/b" },
5145                { "name": "a_child", "url": "http://foo/a" },
5146            ],
5147            "environments": [
5148                // Will be sorted by name
5149                { "name": "b_env" },
5150                { "name": "a_env" },
5151            ],
5152            "collections": [
5153                // Will be sorted by name
5154                { "name": "b_coll", "durability": "transient" },
5155                { "name": "a_coll", "durability": "transient" },
5156            ],
5157            // Will have entries sorted by capability type, then
5158            // by capability name (using the first entry in Many cases).
5159            "capabilities": [
5160                // Will be merged with "bar"
5161                { "protocol": ["foo"] },
5162                { "protocol": "bar" },
5163                // Will not be merged, but will be sorted before "bar"
5164                { "protocol": "arg", "path": "/arg" },
5165                // Will have list of names sorted
5166                { "service": ["b", "a"] },
5167                // Will have list of names sorted
5168                { "event_stream": ["b", "a"] },
5169                { "runner": "myrunner" },
5170                // The following two will *not* be merged, because they have a `path`.
5171                { "runner": "mypathrunner1", "path": "/foo" },
5172                { "runner": "mypathrunner2", "path": "/foo" },
5173            ],
5174            // Same rules as for "capabilities".
5175            "offer": [
5176                // Will be sorted after "bar"
5177                { "protocol": "baz", "from": "#a_child", "to": "#c_child"  },
5178                // The following two entries will be merged
5179                { "protocol": ["foo"], "from": "#a_child", "to": "#b_child"  },
5180                { "protocol": "bar", "from": "#a_child", "to": "#b_child"  },
5181                // Will have list of names sorted
5182                { "service": ["b", "a"], "from": "#a_child", "to": "#b_child"  },
5183                // Will have list of names sorted
5184                {
5185                    "event_stream": ["b", "a"],
5186                    "from": "#a_child",
5187                    "to": "#b_child",
5188                    "scope": ["#b", "#c", "#a"]  // Also gets sorted
5189                },
5190                { "runner": [ "myrunner", "a" ], "from": "#a_child", "to": "#b_child"  },
5191                { "runner": [ "b" ], "from": "#a_child", "to": "#b_child"  },
5192                { "directory": [ "b" ], "from": "#a_child", "to": "#b_child"  },
5193            ],
5194            "expose": [
5195                { "protocol": ["foo"], "from": "#a_child" },
5196                { "protocol": "bar", "from": "#a_child" },  // Will appear before protocol: foo
5197                // Will have list of names sorted
5198                { "service": ["b", "a"], "from": "#a_child" },
5199                // Will have list of names sorted
5200                {
5201                    "event_stream": ["b", "a"],
5202                    "from": "#a_child",
5203                    "scope": ["#b", "#c", "#a"]  // Also gets sorted
5204                },
5205                { "runner": [ "myrunner", "a" ], "from": "#a_child" },
5206                { "runner": [ "b" ], "from": "#a_child" },
5207                { "directory": [ "b" ], "from": "#a_child" },
5208            ],
5209            "use": [
5210                // Will be sorted after "baz"
5211                { "protocol": ["zazzle"], "path": "/zazbaz" },
5212                // These will be merged
5213                { "protocol": ["foo"] },
5214                { "protocol": "bar" },
5215                // Will have list of names sorted
5216                { "service": ["b", "a"] },
5217                // Will have list of names sorted
5218                { "event_stream": ["b", "a"], "scope": ["#b", "#a"] },
5219            ],
5220        }));
5221        some.canonicalize();
5222
5223        assert_json_eq!(
5224            some,
5225            document(json!({
5226                "children": [
5227                    { "name": "a_child", "url": "http://foo/a" },
5228                    { "name": "b_child", "url": "http://foo/b" },
5229                ],
5230                "collections": [
5231                    { "name": "a_coll", "durability": "transient" },
5232                    { "name": "b_coll", "durability": "transient" },
5233                ],
5234                "environments": [
5235                    { "name": "a_env" },
5236                    { "name": "b_env" },
5237                ],
5238                "capabilities": [
5239                    { "event_stream": ["a", "b"] },
5240                    { "protocol": "arg", "path": "/arg" },
5241                    { "protocol": ["bar", "foo"] },
5242                    { "runner": "mypathrunner1", "path": "/foo" },
5243                    { "runner": "mypathrunner2", "path": "/foo" },
5244                    { "runner": "myrunner" },
5245                    { "service": ["a", "b"] },
5246                ],
5247                "use": [
5248                    { "event_stream": ["a", "b"], "scope": ["#a", "#b"] },
5249                    { "protocol": ["bar", "foo"] },
5250                    { "protocol": "zazzle", "path": "/zazbaz" },
5251                    { "service": ["a", "b"] },
5252                ],
5253                "offer": [
5254                    { "directory": "b", "from": "#a_child", "to": "#b_child" },
5255                    {
5256                        "event_stream": ["a", "b"],
5257                        "from": "#a_child",
5258                        "to": "#b_child",
5259                        "scope": ["#a", "#b", "#c"],
5260                    },
5261                    { "protocol": ["bar", "foo"], "from": "#a_child", "to": "#b_child" },
5262                    { "protocol": "baz", "from": "#a_child", "to": "#c_child"  },
5263                    { "runner": [ "a", "b", "myrunner" ], "from": "#a_child", "to": "#b_child" },
5264                    { "service": ["a", "b"], "from": "#a_child", "to": "#b_child" },
5265                ],
5266                "expose": [
5267                    { "directory": "b", "from": "#a_child" },
5268                    {
5269                        "event_stream": ["a", "b"],
5270                        "from": "#a_child",
5271                        "scope": ["#a", "#b", "#c"],
5272                    },
5273                    { "protocol": ["bar", "foo"], "from": "#a_child" },
5274                    { "runner": [ "a", "b", "myrunner" ], "from": "#a_child" },
5275                    { "service": ["a", "b"], "from": "#a_child" },
5276                ],
5277            }))
5278        )
5279    }
5280
5281    #[test]
5282    fn deny_unknown_config_type_fields() {
5283        let input = json!({ "config": { "foo": { "type": "bool", "unknown": "should error" } } });
5284        serde_json5::from_str::<Document>(&input.to_string())
5285            .expect_err("must reject unknown config field attributes");
5286    }
5287
5288    #[test]
5289    fn deny_unknown_config_nested_type_fields() {
5290        let input = json!({
5291            "config": {
5292                "foo": {
5293                    "type": "vector",
5294                    "max_count": 10,
5295                    "element": {
5296                        "type": "bool",
5297                        "unknown": "should error"
5298                    },
5299
5300                }
5301            }
5302        });
5303        serde_json5::from_str::<Document>(&input.to_string())
5304            .expect_err("must reject unknown config field attributes");
5305    }
5306
5307    #[test]
5308    fn test_merge_from_program() {
5309        let mut some = document(json!({ "program": { "binary": "bin/hello_world" } }));
5310        let mut other = document(json!({ "program": { "runner": "elf" } }));
5311        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5312        let expected =
5313            document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5314        assert_eq!(some.program, expected.program);
5315    }
5316
5317    #[test]
5318    fn test_merge_from_program_without_runner() {
5319        let mut some =
5320            document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5321        // https://fxbug.dev/42160240: merging with a document that doesn't have a runner doesn't override the
5322        // runner that we already have assigned.
5323        let mut other = document(json!({ "program": {} }));
5324        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5325        let expected =
5326            document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5327        assert_eq!(some.program, expected.program);
5328    }
5329
5330    #[test]
5331    fn test_merge_from_program_overlapping_environ() {
5332        // It's ok to merge `program.environ` by concatenating the arrays together.
5333        let mut some = document(json!({ "program": { "environ": ["1"] } }));
5334        let mut other = document(json!({ "program": { "environ": ["2"] } }));
5335        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5336        let expected = document(json!({ "program": { "environ": ["1", "2"] } }));
5337        assert_eq!(some.program, expected.program);
5338    }
5339
5340    #[test]
5341    fn test_merge_from_program_overlapping_runner() {
5342        // It's ok to merge `program.runner = "elf"` with `program.runner = "elf"`.
5343        let mut some =
5344            document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5345        let mut other = document(json!({ "program": { "runner": "elf" } }));
5346        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5347        let expected =
5348            document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5349        assert_eq!(some.program, expected.program);
5350    }
5351
5352    #[test]
5353    fn test_offer_would_duplicate() {
5354        let offer = create_offer(
5355            "fuchsia.logger.LegacyLog",
5356            OneOrMany::One(OfferFromRef::Parent {}),
5357            OneOrMany::One(OfferToRef::Named(Name::from_str("something").unwrap())),
5358        );
5359
5360        let offer_to_all = create_offer(
5361            "fuchsia.logger.LogSink",
5362            OneOrMany::One(OfferFromRef::Parent {}),
5363            OneOrMany::One(OfferToRef::All),
5364        );
5365
5366        // different protocols
5367        assert!(!offer_to_all_would_duplicate(
5368            &offer_to_all,
5369            &offer,
5370            &Name::from_str("something").unwrap()
5371        )
5372        .unwrap());
5373
5374        let offer = create_offer(
5375            "fuchsia.logger.LogSink",
5376            OneOrMany::One(OfferFromRef::Parent {}),
5377            OneOrMany::One(OfferToRef::Named(Name::from_str("not-something").unwrap())),
5378        );
5379
5380        // different targets
5381        assert!(!offer_to_all_would_duplicate(
5382            &offer_to_all,
5383            &offer,
5384            &Name::from_str("something").unwrap()
5385        )
5386        .unwrap());
5387
5388        let mut offer = create_offer(
5389            "fuchsia.logger.LogSink",
5390            OneOrMany::One(OfferFromRef::Parent {}),
5391            OneOrMany::One(OfferToRef::Named(Name::from_str("something").unwrap())),
5392        );
5393
5394        offer.r#as = Some(Name::from_str("FakeLog").unwrap());
5395
5396        // target has alias
5397        assert!(!offer_to_all_would_duplicate(
5398            &offer_to_all,
5399            &offer,
5400            &Name::from_str("something").unwrap()
5401        )
5402        .unwrap());
5403
5404        let offer = create_offer(
5405            "fuchsia.logger.LogSink",
5406            OneOrMany::One(OfferFromRef::Parent {}),
5407            OneOrMany::One(OfferToRef::Named(Name::from_str("something").unwrap())),
5408        );
5409
5410        assert!(offer_to_all_would_duplicate(
5411            &offer_to_all,
5412            &offer,
5413            &Name::from_str("something").unwrap()
5414        )
5415        .unwrap());
5416
5417        let offer = create_offer(
5418            "fuchsia.logger.LogSink",
5419            OneOrMany::One(OfferFromRef::Named(Name::from_str("other").unwrap())),
5420            OneOrMany::One(OfferToRef::Named(Name::from_str("something").unwrap())),
5421        );
5422
5423        assert!(offer_to_all_would_duplicate(
5424            &offer_to_all,
5425            &offer,
5426            &Name::from_str("something").unwrap()
5427        )
5428        .is_err());
5429    }
5430
5431    #[test_case(
5432        document(json!({ "program": { "runner": "elf" } })),
5433        document(json!({ "program": { "runner": "fle" } })),
5434        "runner"
5435        ; "when_runner_conflicts"
5436    )]
5437    #[test_case(
5438        document(json!({ "program": { "binary": "bin/hello_world" } })),
5439        document(json!({ "program": { "binary": "bin/hola_mundo" } })),
5440        "binary"
5441        ; "when_binary_conflicts"
5442    )]
5443    #[test_case(
5444        document(json!({ "program": { "args": ["a".to_owned()] } })),
5445        document(json!({ "program": { "args": ["b".to_owned()] } })),
5446        "args"
5447        ; "when_args_conflicts"
5448    )]
5449    fn test_merge_from_program_error(mut some: Document, mut other: Document, field: &str) {
5450        assert_matches::assert_matches!(
5451            some.merge_from(&mut other, &path::Path::new("some/path")),
5452            Err(Error::Validate {  err, .. })
5453                if err == format!("manifest include had a conflicting `program.{}`: some/path", field)
5454        );
5455    }
5456
5457    #[test_case(
5458        document(json!({ "facets": { "my.key": "my.value" } })),
5459        document(json!({ "facets": { "other.key": "other.value" } })),
5460        document(json!({ "facets": { "my.key": "my.value",  "other.key": "other.value" } }))
5461        ; "two separate keys"
5462    )]
5463    #[test_case(
5464        document(json!({ "facets": { "my.key": "my.value" } })),
5465        document(json!({ "facets": {} })),
5466        document(json!({ "facets": { "my.key": "my.value" } }))
5467        ; "empty other facet"
5468    )]
5469    #[test_case(
5470        document(json!({ "facets": {} })),
5471        document(json!({ "facets": { "other.key": "other.value" } })),
5472        document(json!({ "facets": { "other.key": "other.value" } }))
5473        ; "empty my facet"
5474    )]
5475    #[test_case(
5476        document(json!({ "facets": { "key": { "type": "some_type" } } })),
5477        document(json!({ "facets": { "key": { "runner": "some_runner"} } })),
5478        document(json!({ "facets": { "key": { "type": "some_type", "runner": "some_runner" } } }))
5479        ; "nested facet key"
5480    )]
5481    #[test_case(
5482        document(json!({ "facets": { "key": { "type": "some_type", "nested_key": { "type": "new type" }}}})),
5483        document(json!({ "facets": { "key": { "nested_key": { "runner": "some_runner" }} } })),
5484        document(json!({ "facets": { "key": { "type": "some_type", "nested_key": { "runner": "some_runner", "type": "new type" }}}}))
5485        ; "double nested facet key"
5486    )]
5487    #[test_case(
5488        document(json!({ "facets": { "key": { "array_key": ["value_1", "value_2"] } } })),
5489        document(json!({ "facets": { "key": { "array_key": ["value_3", "value_4"] } } })),
5490        document(json!({ "facets": { "key": { "array_key": ["value_1", "value_2", "value_3", "value_4"] } } }))
5491        ; "merge array values"
5492    )]
5493    fn test_merge_from_facets(mut my: Document, mut other: Document, expected: Document) {
5494        my.merge_from(&mut other, &Path::new("some/path")).unwrap();
5495        assert_eq!(my.facets, expected.facets);
5496    }
5497
5498    #[test_case(
5499        document(json!({ "facets": { "key": "my.value" }})),
5500        document(json!({ "facets": { "key": "other.value" }})),
5501        "facets.key"
5502        ; "conflict first level keys"
5503    )]
5504    #[test_case(
5505        document(json!({ "facets": { "key":  {"type": "cts" }}})),
5506        document(json!({ "facets": { "key":  {"type": "system" }}})),
5507        "facets.key.type"
5508        ; "conflict second level keys"
5509    )]
5510    #[test_case(
5511        document(json!({ "facets": { "key":  {"type": {"key": "value" }}}})),
5512        document(json!({ "facets": { "key":  {"type": "system" }}})),
5513        "facets.key.type"
5514        ; "incompatible self nested type"
5515    )]
5516    #[test_case(
5517        document(json!({ "facets": { "key":  {"type": "system" }}})),
5518        document(json!({ "facets": { "key":  {"type":  {"key": "value" }}}})),
5519        "facets.key.type"
5520        ; "incompatible other nested type"
5521    )]
5522    #[test_case(
5523        document(json!({ "facets": { "key":  {"type": {"key": "my.value" }}}})),
5524        document(json!({ "facets": { "key":  {"type":  {"key": "some.value" }}}})),
5525        "facets.key.type.key"
5526        ; "conflict third level keys"
5527    )]
5528    #[test_case(
5529        document(json!({ "facets": { "key":  {"type": [ "value_1" ]}}})),
5530        document(json!({ "facets": { "key":  {"type":  "value_2" }}})),
5531        "facets.key.type"
5532        ; "incompatible keys"
5533    )]
5534    fn test_merge_from_facet_error(mut my: Document, mut other: Document, field: &str) {
5535        assert_matches::assert_matches!(
5536            my.merge_from(&mut other, &path::Path::new("some/path")),
5537            Err(Error::Validate {  err, .. })
5538                if err == format!("manifest include had a conflicting `{}`: some/path", field)
5539        );
5540    }
5541
5542    #[test_case("protocol")]
5543    #[test_case("service")]
5544    #[test_case("event_stream")]
5545    fn test_merge_from_duplicate_use_array(typename: &str) {
5546        let mut my = document(json!({ "use": [{ typename: "a" }]}));
5547        let mut other = document(json!({ "use": [
5548            { typename: ["a", "b"], "availability": "optional"}
5549        ]}));
5550        let result = document(json!({ "use": [
5551            { typename: "a" },
5552            { typename: "b", "availability": "optional" },
5553        ]}));
5554
5555        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5556        assert_eq!(my, result);
5557    }
5558
5559    #[test_case("directory")]
5560    #[test_case("storage")]
5561    fn test_merge_from_duplicate_use_noarray(typename: &str) {
5562        let mut my = document(json!({ "use": [{ typename: "a", "path": "/a"}]}));
5563        let mut other = document(json!({ "use": [
5564            { typename: "a", "path": "/a", "availability": "optional" },
5565            { typename: "b", "path": "/b", "availability": "optional" },
5566        ]}));
5567        let result = document(json!({ "use": [
5568            { typename: "a", "path": "/a" },
5569            { typename: "b", "path": "/b", "availability": "optional" },
5570        ]}));
5571        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5572        assert_eq!(my, result);
5573    }
5574
5575    #[test_case("protocol")]
5576    #[test_case("service")]
5577    #[test_case("event_stream")]
5578    fn test_merge_from_duplicate_capabilities_array(typename: &str) {
5579        let mut my = document(json!({ "capabilities": [{ typename: "a" }]}));
5580        let mut other = document(json!({ "capabilities": [ { typename: ["a", "b"] } ]}));
5581        let result = document(json!({ "capabilities": [ { typename: "a" }, { typename: "b" } ]}));
5582
5583        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5584        assert_eq!(my, result);
5585    }
5586
5587    #[test_case("directory")]
5588    #[test_case("storage")]
5589    #[test_case("runner")]
5590    #[test_case("resolver")]
5591    fn test_merge_from_duplicate_capabilities_noarray(typename: &str) {
5592        let mut my = document(json!({ "capabilities": [{ typename: "a", "path": "/a"}]}));
5593        let mut other = document(json!({ "capabilities": [
5594            { typename: "a", "path": "/a" },
5595            { typename: "b", "path": "/b" },
5596        ]}));
5597        let result = document(json!({ "capabilities": [
5598            { typename: "a", "path": "/a" },
5599            { typename: "b", "path": "/b" },
5600        ]}));
5601        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5602        assert_eq!(my, result);
5603    }
5604
5605    #[test]
5606    fn test_merge_with_empty_names() {
5607        // This document is an error because there is no capability name.
5608        let mut my = document(json!({ "capabilities": [{ "path": "/a"}]}));
5609
5610        let mut other = document(json!({ "capabilities": [
5611            { "directory": "a", "path": "/a" },
5612            { "directory": "b", "path": "/b" },
5613        ]}));
5614        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap_err();
5615    }
5616
5617    #[test_case("protocol")]
5618    #[test_case("service")]
5619    #[test_case("event_stream")]
5620    #[test_case("directory")]
5621    #[test_case("storage")]
5622    #[test_case("runner")]
5623    #[test_case("resolver")]
5624    fn test_merge_from_duplicate_offers(typename: &str) {
5625        let mut my = document(json!({ "offer": [{ typename: "a", "from": "self", "to": "#c" }]}));
5626        let mut other = document(json!({ "offer": [
5627            { typename: ["a", "b"], "from": "self", "to": "#c", "availability": "optional" }
5628        ]}));
5629        let result = document(json!({ "offer": [
5630            { typename: "a", "from": "self", "to": "#c" },
5631            { typename: "b", "from": "self", "to": "#c", "availability": "optional" },
5632        ]}));
5633
5634        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5635        assert_eq!(my, result);
5636    }
5637
5638    #[test_case("protocol")]
5639    #[test_case("service")]
5640    #[test_case("event_stream")]
5641    #[test_case("directory")]
5642    #[test_case("runner")]
5643    #[test_case("resolver")]
5644    fn test_merge_from_duplicate_exposes(typename: &str) {
5645        let mut my = document(json!({ "expose": [{ typename: "a", "from": "self" }]}));
5646        let mut other = document(json!({ "expose": [
5647            { typename: ["a", "b"], "from": "self" }
5648        ]}));
5649        let result = document(json!({ "expose": [
5650            { typename: "a", "from": "self" },
5651            { typename: "b", "from": "self" },
5652        ]}));
5653
5654        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5655        assert_eq!(my, result);
5656    }
5657
5658    #[test_case(
5659        document(json!({ "use": [
5660            { "protocol": "a", "availability": "required" },
5661            { "protocol": "b", "availability": "optional" },
5662            { "protocol": "c", "availability": "transitional" },
5663            { "protocol": "d", "availability": "same_as_target" },
5664        ]})),
5665        document(json!({ "use": [
5666            { "protocol": ["a"], "availability": "required" },
5667            { "protocol": ["b"], "availability": "optional" },
5668            { "protocol": ["c"], "availability": "transitional" },
5669            { "protocol": ["d"], "availability": "same_as_target" },
5670        ]})),
5671        document(json!({ "use": [
5672            { "protocol": "a", "availability": "required" },
5673            { "protocol": "b", "availability": "optional" },
5674            { "protocol": "c", "availability": "transitional" },
5675            { "protocol": "d", "availability": "same_as_target" },
5676        ]}))
5677        ; "merge both same"
5678    )]
5679    #[test_case(
5680        document(json!({ "use": [
5681            { "protocol": "a", "availability": "optional" },
5682            { "protocol": "b", "availability": "transitional" },
5683            { "protocol": "c", "availability": "transitional" },
5684        ]})),
5685        document(json!({ "use": [
5686            { "protocol": ["a", "x"], "availability": "required" },
5687            { "protocol": ["b", "y"], "availability": "optional" },
5688            { "protocol": ["c", "z"], "availability": "required" },
5689        ]})),
5690        document(json!({ "use": [
5691            { "protocol": ["a", "x"], "availability": "required" },
5692            { "protocol": ["b", "y"], "availability": "optional" },
5693            { "protocol": ["c", "z"], "availability": "required" },
5694        ]}))
5695        ; "merge with upgrade"
5696    )]
5697    #[test_case(
5698        document(json!({ "use": [
5699            { "protocol": "a", "availability": "required" },
5700            { "protocol": "b", "availability": "optional" },
5701            { "protocol": "c", "availability": "required" },
5702        ]})),
5703        document(json!({ "use": [
5704            { "protocol": ["a", "x"], "availability": "optional" },
5705            { "protocol": ["b", "y"], "availability": "transitional" },
5706            { "protocol": ["c", "z"], "availability": "transitional" },
5707        ]})),
5708        document(json!({ "use": [
5709            { "protocol": "a", "availability": "required" },
5710            { "protocol": "b", "availability": "optional" },
5711            { "protocol": "c", "availability": "required" },
5712            { "protocol": "x", "availability": "optional" },
5713            { "protocol": "y", "availability": "transitional" },
5714            { "protocol": "z", "availability": "transitional" },
5715        ]}))
5716        ; "merge with downgrade"
5717    )]
5718    #[test_case(
5719        document(json!({ "use": [
5720            { "protocol": "a", "availability": "optional" },
5721            { "protocol": "b", "availability": "transitional" },
5722            { "protocol": "c", "availability": "transitional" },
5723        ]})),
5724        document(json!({ "use": [
5725            { "protocol": ["a", "x"], "availability": "same_as_target" },
5726            { "protocol": ["b", "y"], "availability": "same_as_target" },
5727            { "protocol": ["c", "z"], "availability": "same_as_target" },
5728        ]})),
5729        document(json!({ "use": [
5730            { "protocol": "a", "availability": "optional" },
5731            { "protocol": "b", "availability": "transitional" },
5732            { "protocol": "c", "availability": "transitional" },
5733            { "protocol": ["a", "x"], "availability": "same_as_target" },
5734            { "protocol": ["b", "y"], "availability": "same_as_target" },
5735            { "protocol": ["c", "z"], "availability": "same_as_target" },
5736        ]}))
5737        ; "merge with no replacement"
5738    )]
5739    #[test_case(
5740        document(json!({ "use": [
5741            { "protocol": ["a", "b", "c"], "availability": "optional" },
5742            { "protocol": "d", "availability": "same_as_target" },
5743            { "protocol": ["e", "f"] },
5744        ]})),
5745        document(json!({ "use": [
5746            { "protocol": ["c", "e", "g"] },
5747            { "protocol": ["d", "h"] },
5748            { "protocol": ["f", "i"], "availability": "transitional" },
5749        ]})),
5750        document(json!({ "use": [
5751            { "protocol": ["a", "b"], "availability": "optional" },
5752            { "protocol": "d", "availability": "same_as_target" },
5753            { "protocol": ["e", "f"] },
5754            { "protocol": ["c", "g"] },
5755            { "protocol": ["d", "h"] },
5756            { "protocol": "i", "availability": "transitional" },
5757        ]}))
5758        ; "merge multiple"
5759    )]
5760
5761    fn test_merge_from_duplicate_capability_availability(
5762        mut my: Document,
5763        mut other: Document,
5764        result: Document,
5765    ) {
5766        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5767        assert_eq!(my, result);
5768    }
5769
5770    #[test_case(
5771        document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
5772        document(json!({ "use": [{ "protocol": ["c", "d"] }]})),
5773        document(json!({ "use": [
5774            { "protocol": ["a", "b"] }, { "protocol": ["c", "d"] }
5775        ]}))
5776        ; "merge capabilities with disjoint sets"
5777    )]
5778    #[test_case(
5779        document(json!({ "use": [
5780            { "protocol": ["a"] },
5781            { "protocol": "b" },
5782        ]})),
5783        document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
5784        document(json!({ "use": [
5785            { "protocol": ["a"] }, { "protocol": "b" },
5786        ]}))
5787        ; "merge capabilities with equal set"
5788    )]
5789    #[test_case(
5790        document(json!({ "use": [
5791            { "protocol": ["a", "b"] },
5792            { "protocol": "c" },
5793        ]})),
5794        document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
5795        document(json!({ "use": [
5796            { "protocol": ["a", "b"] }, { "protocol": "c" },
5797        ]}))
5798        ; "merge capabilities with subset"
5799    )]
5800    #[test_case(
5801        document(json!({ "use": [
5802            { "protocol": ["a", "b"] },
5803        ]})),
5804        document(json!({ "use": [{ "protocol": ["a", "b", "c"] }]})),
5805        document(json!({ "use": [
5806            { "protocol": ["a", "b"] },
5807            { "protocol": "c" },
5808        ]}))
5809        ; "merge capabilities with superset"
5810    )]
5811    #[test_case(
5812        document(json!({ "use": [
5813            { "protocol": ["a", "b"] },
5814        ]})),
5815        document(json!({ "use": [{ "protocol": ["b", "c", "d"] }]})),
5816        document(json!({ "use": [
5817            { "protocol": ["a", "b"] }, { "protocol": ["c", "d"] }
5818        ]}))
5819        ; "merge capabilities with intersection"
5820    )]
5821    #[test_case(
5822        document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
5823        document(json!({ "use": [
5824            { "protocol": ["c", "b", "d"] },
5825            { "protocol": ["e", "d"] },
5826        ]})),
5827        document(json!({ "use": [
5828            {"protocol": ["a", "b"] },
5829            {"protocol": ["c", "d"] },
5830            {"protocol": "e" }]}))
5831        ; "merge capabilities from multiple arrays"
5832    )]
5833    #[test_case(
5834        document(json!({ "use": [{ "protocol": "foo.bar.Baz", "from": "self"}]})),
5835        document(json!({ "use": [{ "service": "foo.bar.Baz", "from": "self"}]})),
5836        document(json!({ "use": [
5837            {"protocol": "foo.bar.Baz", "from": "self"},
5838            {"service": "foo.bar.Baz", "from": "self"}]}))
5839        ; "merge capabilities, types don't match"
5840    )]
5841    #[test_case(
5842        document(json!({ "use": [{ "protocol": "foo.bar.Baz", "from": "self"}]})),
5843        document(json!({ "use": [{ "protocol": "foo.bar.Baz" }]})),
5844        document(json!({ "use": [
5845            {"protocol": "foo.bar.Baz", "from": "self"},
5846            {"protocol": "foo.bar.Baz"}]}))
5847        ; "merge capabilities, fields don't match"
5848    )]
5849
5850    fn test_merge_from_duplicate_capability(
5851        mut my: Document,
5852        mut other: Document,
5853        result: Document,
5854    ) {
5855        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5856        assert_eq!(my, result);
5857    }
5858
5859    #[test_case(&Right::Connect; "connect right")]
5860    #[test_case(&Right::Enumerate; "enumerate right")]
5861    #[test_case(&Right::Execute; "execute right")]
5862    #[test_case(&Right::GetAttributes; "getattr right")]
5863    #[test_case(&Right::ModifyDirectory; "modifydir right")]
5864    #[test_case(&Right::ReadBytes; "readbytes right")]
5865    #[test_case(&Right::Traverse; "traverse right")]
5866    #[test_case(&Right::UpdateAttributes; "updateattrs right")]
5867    #[test_case(&Right::WriteBytes; "writebytes right")]
5868    #[test_case(&Right::ReadAlias; "r right")]
5869    #[test_case(&Right::WriteAlias; "w right")]
5870    #[test_case(&Right::ExecuteAlias; "x right")]
5871    #[test_case(&Right::ReadWriteAlias; "rw right")]
5872    #[test_case(&Right::ReadExecuteAlias; "rx right")]
5873    #[test_case(&OfferFromRef::Self_; "offer from self")]
5874    #[test_case(&OfferFromRef::Parent; "offer from parent")]
5875    #[test_case(&OfferFromRef::Named(Name::new("child".to_string()).unwrap()); "offer from named")]
5876    #[test_case(
5877        &document(json!({}));
5878        "empty document"
5879    )]
5880    #[test_case(
5881        &document(json!({ "use": [{ "protocol": "foo.bar.Baz", "from": "self"}]}));
5882        "use one from self"
5883    )]
5884    #[test_case(
5885        &document(json!({ "use": [{ "protocol": ["foo.bar.Baz", "some.other.Protocol"], "from": "self"}]}));
5886        "use multiple from self"
5887    )]
5888    #[test_case(
5889        &document(json!({
5890            "offer": [{ "protocol": "foo.bar.Baz", "from": "self", "to": "#elements"}],
5891            "collections" :[{"name": "elements", "durability": "transient" }]
5892        }));
5893        "offer from self to collection"
5894    )]
5895    #[test_case(
5896        &document(json!({
5897            "offer": [
5898                { "service": "foo.bar.Baz", "from": "self", "to": "#elements" },
5899                { "service": "some.other.Service", "from": "self", "to": "#elements"},
5900            ],
5901            "collections":[ {"name": "elements", "durability": "transient"} ]}));
5902        "service offers"
5903    )]
5904    #[test_case(
5905        &document(json!({ "expose": [{ "protocol": ["foo.bar.Baz", "some.other.Protocol"], "from": "self"}]}));
5906        "expose protocols from self"
5907    )]
5908    #[test_case(
5909        &document(json!({ "expose": [{ "service": ["foo.bar.Baz", "some.other.Service"], "from": "self"}]}));
5910        "expose service from self"
5911    )]
5912    #[test_case(
5913        &document(json!({ "capabilities": [{ "protocol": "foo.bar.Baz", "from": "self"}]}));
5914        "capabilities from self"
5915    )]
5916    #[test_case(
5917        &document(json!({ "facets": { "my.key": "my.value" } }));
5918        "facets"
5919    )]
5920    #[test_case(
5921        &document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5922        "elf runner program"
5923    )]
5924    fn serialize_roundtrips<T>(val: &T)
5925    where
5926        T: serde::de::DeserializeOwned + Serialize + PartialEq + std::fmt::Debug,
5927    {
5928        let raw = serde_json::to_string(val).expect("serializing `val` should work");
5929        let parsed: T =
5930            serde_json::from_str(&raw).expect("must be able to parse back serialized value");
5931        assert_eq!(val, &parsed, "parsed value must equal original value");
5932    }
5933}