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 mod types;
15pub(crate) mod validate;
16
17#[allow(unused)] // A test-only macro is defined outside of a test builds.
18pub mod translate;
19
20use crate::error::Error;
21use cml_macro::{OneOrMany, Reference};
22use json5format::{FormatOptions, PathOption};
23use maplit::{hashmap, hashset};
24use serde::{Deserialize, Serialize, de, ser};
25use serde_json::{Map, Value};
26use std::fmt;
27use std::hash::Hash;
28use std::num::NonZeroU32;
29use std::str::FromStr;
30use std::sync::Arc;
31
32pub use crate::types::capability::{Capability, CapabilityFromRef, ContextCapability};
33pub use crate::types::capability_id::CapabilityId;
34pub use crate::types::child::Child;
35pub use crate::types::collection::Collection;
36use crate::types::common::{ContextCapabilityClause, ContextSpanned, Origin};
37pub use crate::types::document::{
38    Document, DocumentContext, ParsedDocument, convert_parsed_to_document,
39};
40pub use crate::types::environment::{Environment, ResolverRegistration};
41pub use crate::types::expose::{ContextExpose, Expose};
42pub use crate::types::offer::{
43    Offer, OfferFromRef, OfferToAllCapability, OfferToRef, offer_to_all_from_offer,
44};
45pub use crate::types::program::Program;
46pub use crate::types::r#use::{Use, UseFromRef};
47
48pub use cm_types::{
49    AllowedOffers, Availability, BorrowedName, BoundedName, DeliveryType, DependencyType,
50    Durability, HandleType, Name, NamespacePath, OnTerminate, ParseError, Path, RelativePath,
51    StartupMode, StorageId, Url,
52};
53use error::Location;
54
55pub use crate::one_or_many::OneOrMany;
56pub use crate::translate::{CompileOptions, compile};
57pub use crate::validate::{CapabilityRequirements, MustUseRequirement};
58
59/// Parses a string `buffer` into a [Document]. `file` is used for error reporting.
60pub fn parse_one_document(buffer: &String, file: &std::path::Path) -> Result<Document, Error> {
61    serde_json5::from_str(&buffer).map_err(|e| {
62        let serde_json5::Error::Message { location, msg } = e;
63        let location = location.map(|l| Location { line: l.line, column: l.column });
64        Error::parse(msg, location, Some(file))
65    })
66}
67
68pub fn load_cml_with_context(
69    buffer: &String,
70    file: &std::path::Path,
71) -> Result<DocumentContext, Error> {
72    let file_arc = Arc::new(file.to_path_buf());
73    let parsed_doc: ParsedDocument = json_spanned_value::from_str(&buffer).map_err(|e| {
74        let location = Location { line: e.line(), column: e.column() };
75        Error::parse(e, Some(location), Some(file))
76    })?;
77    convert_parsed_to_document(parsed_doc, file_arc, buffer)
78}
79
80/// Parses a string `buffer` into a vector of [Document]. `file` is used for error reporting.
81/// Supports JSON encoded as an array of Document JSON objects.
82pub fn parse_many_documents(
83    buffer: &String,
84    file: &std::path::Path,
85) -> Result<Vec<Document>, Error> {
86    let res: Result<Vec<Document>, _> = serde_json5::from_str(&buffer);
87    match res {
88        Err(_) => {
89            let d = parse_one_document(buffer, file)?;
90            Ok(vec![d])
91        }
92        Ok(docs) => Ok(docs),
93    }
94}
95
96pub fn byte_index_to_location(source: &String, index: usize) -> Location {
97    let mut line = 1usize;
98    let mut column = 1usize;
99
100    for (i, ch) in source.char_indices() {
101        if i == index {
102            break;
103        }
104
105        if ch == '\n' {
106            line += 1;
107            column = 1;
108        } else {
109            column += 1;
110        }
111    }
112
113    return Location { line, column };
114}
115
116/// Generates deserializer for `OneOrMany<Name>`.
117#[derive(OneOrMany, Debug, Clone)]
118#[one_or_many(
119    expected = "a name or nonempty array of names, with unique elements",
120    inner_type = "Name",
121    min_length = 1,
122    unique_items = true
123)]
124pub struct OneOrManyNames;
125
126/// Generates deserializer for `OneOrMany<Path>`.
127#[derive(OneOrMany, Debug, Clone)]
128#[one_or_many(
129    expected = "a path or nonempty array of paths, with unique elements",
130    inner_type = "Path",
131    min_length = 1,
132    unique_items = true
133)]
134pub struct OneOrManyPaths;
135
136/// Generates deserializer for `OneOrMany<EventScope>`.
137#[derive(OneOrMany, Debug, Clone)]
138#[one_or_many(
139    expected = "one or an array of \"#<collection-name>\", or \"#<child-name>\"",
140    inner_type = "EventScope",
141    min_length = 1,
142    unique_items = true
143)]
144pub struct OneOrManyEventScope;
145
146/// A reference in an `offer to` or `exose to`.
147#[derive(Debug, Deserialize, PartialEq, Eq, Hash, Clone, Serialize)]
148#[serde(rename_all = "snake_case")]
149pub enum SourceAvailability {
150    Required,
151    Unknown,
152}
153
154impl Default for SourceAvailability {
155    fn default() -> Self {
156        Self::Required
157    }
158}
159
160impl<T> Canonicalize for Vec<T>
161where
162    T: Canonicalize + CapabilityClause + PathClause,
163{
164    fn canonicalize(&mut self) {
165        // Collapse like-entries into one. Like entries are those that are equal in all fields
166        // but their capability names. Accomplish this by collecting all the names into a vector
167        // keyed by an instance of T with its names removed.
168        let mut to_merge: Vec<(T, Vec<Name>)> = vec![];
169        let mut to_keep: Vec<T> = vec![];
170        self.iter().for_each(|c| {
171            // Any entry with a `path` set cannot be merged with another.
172            if !c.are_many_names_allowed() || c.path().is_some() {
173                to_keep.push(c.clone());
174                return;
175            }
176            let mut names: Vec<Name> = c.names().into_iter().map(Into::into).collect();
177            let mut copy: T = c.clone();
178            copy.set_names(vec![Name::from_str("a").unwrap()]); // The name here is arbitrary.
179            let r = to_merge.iter().position(|(t, _)| t == &copy);
180            match r {
181                Some(i) => to_merge[i].1.append(&mut names),
182                None => to_merge.push((copy, names)),
183            };
184        });
185        let mut merged = to_merge
186            .into_iter()
187            .map(|(mut t, names)| {
188                t.set_names(names);
189                t
190            })
191            .collect::<Vec<_>>();
192        to_keep.append(&mut merged);
193        *self = to_keep;
194
195        self.iter_mut().for_each(|c| c.canonicalize());
196        self.sort_by(|a, b| {
197            // Sort by capability type, then by the name of the first entry for
198            // that type.
199            let a_type = a.capability_type().unwrap();
200            let b_type = b.capability_type().unwrap();
201            a_type.cmp(b_type).then_with(|| {
202                let a_names = a.names();
203                let b_names = b.names();
204                let a_first_name = a_names.first().unwrap();
205                let b_first_name = b_names.first().unwrap();
206                a_first_name.cmp(b_first_name)
207            })
208        });
209    }
210}
211
212/// A relative reference to another object. This is a generic type that can encode any supported
213/// reference subtype. For named references, it holds a reference to the name instead of the name
214/// itself.
215///
216/// Objects of this type are usually derived from conversions of context-specific reference
217/// types that `#[derive(Reference)]`. This type makes it easy to write helper functions that operate on
218/// generic references.
219#[derive(Debug, PartialEq, Eq, Hash, Clone)]
220pub enum AnyRef<'a> {
221    /// A named reference. Parsed as `#name`.
222    Named(&'a BorrowedName),
223    /// A reference to the parent. Parsed as `parent`.
224    Parent,
225    /// A reference to the framework (component manager). Parsed as `framework`.
226    Framework,
227    /// A reference to the debug. Parsed as `debug`.
228    Debug,
229    /// A reference to this component. Parsed as `self`.
230    Self_,
231    /// An intentionally omitted reference.
232    Void,
233    /// A reference to a dictionary. Parsed as a dictionary path.
234    Dictionary(&'a DictionaryRef),
235    /// A reference to a dictionary defined by this component. Parsed as
236    /// `self/<dictionary>`.
237    OwnDictionary(&'a BorrowedName),
238}
239
240/// Format an `AnyRef` as a string.
241impl fmt::Display for AnyRef<'_> {
242    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243        match self {
244            Self::Named(name) => write!(f, "#{}", name),
245            Self::Parent => write!(f, "parent"),
246            Self::Framework => write!(f, "framework"),
247            Self::Debug => write!(f, "debug"),
248            Self::Self_ => write!(f, "self"),
249            Self::Void => write!(f, "void"),
250            Self::Dictionary(d) => write!(f, "{}", d),
251            Self::OwnDictionary(name) => write!(f, "self/{}", name),
252        }
253    }
254}
255
256/// A reference to a (possibly nested) dictionary.
257#[derive(Debug, PartialEq, Eq, Hash, Clone)]
258pub struct DictionaryRef {
259    /// Path to the dictionary relative to `root_dictionary`.
260    pub path: RelativePath,
261    pub root: RootDictionaryRef,
262}
263
264impl<'a> From<&'a DictionaryRef> for AnyRef<'a> {
265    fn from(r: &'a DictionaryRef) -> Self {
266        Self::Dictionary(r)
267    }
268}
269
270impl FromStr for DictionaryRef {
271    type Err = ParseError;
272
273    fn from_str(path: &str) -> Result<Self, ParseError> {
274        match path.find('/') {
275            Some(n) => {
276                let root = path[..n].parse().map_err(|_| ParseError::InvalidValue)?;
277                let path = RelativePath::new(&path[n + 1..])?;
278                Ok(Self { root, path })
279            }
280            None => Err(ParseError::InvalidValue),
281        }
282    }
283}
284
285impl fmt::Display for DictionaryRef {
286    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
287        write!(f, "{}/{}", self.root, self.path)
288    }
289}
290
291impl ser::Serialize for DictionaryRef {
292    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
293    where
294        S: serde::ser::Serializer,
295    {
296        format!("{}", self).serialize(serializer)
297    }
298}
299
300const DICTIONARY_REF_EXPECT_STR: &str = "a path to a dictionary no more \
301    than 4095 characters in length";
302
303impl<'de> de::Deserialize<'de> for DictionaryRef {
304    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
305    where
306        D: de::Deserializer<'de>,
307    {
308        struct Visitor;
309
310        impl<'de> de::Visitor<'de> for Visitor {
311            type Value = DictionaryRef;
312
313            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
314                f.write_str(DICTIONARY_REF_EXPECT_STR)
315            }
316
317            fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
318            where
319                E: de::Error,
320            {
321                s.parse().map_err(|err| match err {
322                    ParseError::InvalidValue => {
323                        E::invalid_value(de::Unexpected::Str(s), &DICTIONARY_REF_EXPECT_STR)
324                    }
325                    ParseError::TooLong | ParseError::Empty => {
326                        E::invalid_length(s.len(), &DICTIONARY_REF_EXPECT_STR)
327                    }
328                    e => {
329                        panic!("unexpected parse error: {:?}", e);
330                    }
331                })
332            }
333        }
334
335        deserializer.deserialize_string(Visitor)
336    }
337}
338
339/// A reference to a root dictionary.
340#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
341#[reference(expected = "\"parent\", \"self\", \"#<child-name>\"")]
342pub enum RootDictionaryRef {
343    /// A reference to a child.
344    Named(Name),
345    /// A reference to the parent.
346    Parent,
347    /// A reference to this component.
348    Self_,
349}
350
351/// The scope of an event.
352#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference, Ord, PartialOrd)]
353#[reference(expected = "\"#<collection-name>\", \"#<child-name>\", or none")]
354pub enum EventScope {
355    /// A reference to a child or a collection.
356    Named(Name),
357}
358
359#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
360#[serde(rename_all = "snake_case")]
361pub enum ConfigType {
362    Bool,
363    Uint8,
364    Uint16,
365    Uint32,
366    Uint64,
367    Int8,
368    Int16,
369    Int32,
370    Int64,
371    String,
372    Vector,
373}
374
375impl From<&cm_rust::ConfigValueType> for ConfigType {
376    fn from(value: &cm_rust::ConfigValueType) -> Self {
377        match value {
378            cm_rust::ConfigValueType::Bool => ConfigType::Bool,
379            cm_rust::ConfigValueType::Uint8 => ConfigType::Uint8,
380            cm_rust::ConfigValueType::Int8 => ConfigType::Int8,
381            cm_rust::ConfigValueType::Uint16 => ConfigType::Uint16,
382            cm_rust::ConfigValueType::Int16 => ConfigType::Int16,
383            cm_rust::ConfigValueType::Uint32 => ConfigType::Uint32,
384            cm_rust::ConfigValueType::Int32 => ConfigType::Int32,
385            cm_rust::ConfigValueType::Uint64 => ConfigType::Uint64,
386            cm_rust::ConfigValueType::Int64 => ConfigType::Int64,
387            cm_rust::ConfigValueType::String { .. } => ConfigType::String,
388            cm_rust::ConfigValueType::Vector { .. } => ConfigType::Vector,
389        }
390    }
391}
392
393#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
394#[serde(tag = "type", deny_unknown_fields, rename_all = "lowercase")]
395pub enum ConfigNestedValueType {
396    Bool {},
397    Uint8 {},
398    Uint16 {},
399    Uint32 {},
400    Uint64 {},
401    Int8 {},
402    Int16 {},
403    Int32 {},
404    Int64 {},
405    String { max_size: NonZeroU32 },
406}
407
408impl ConfigNestedValueType {
409    /// Update the hasher by digesting the ConfigVectorElementType enum value
410    pub fn update_digest(&self, hasher: &mut impl sha2::Digest) {
411        let val = match self {
412            ConfigNestedValueType::Bool {} => 0u8,
413            ConfigNestedValueType::Uint8 {} => 1u8,
414            ConfigNestedValueType::Uint16 {} => 2u8,
415            ConfigNestedValueType::Uint32 {} => 3u8,
416            ConfigNestedValueType::Uint64 {} => 4u8,
417            ConfigNestedValueType::Int8 {} => 5u8,
418            ConfigNestedValueType::Int16 {} => 6u8,
419            ConfigNestedValueType::Int32 {} => 7u8,
420            ConfigNestedValueType::Int64 {} => 8u8,
421            ConfigNestedValueType::String { max_size } => {
422                hasher.update(max_size.get().to_le_bytes());
423                9u8
424            }
425        };
426        hasher.update([val])
427    }
428}
429
430impl From<ConfigNestedValueType> for cm_rust::ConfigNestedValueType {
431    fn from(value: ConfigNestedValueType) -> Self {
432        match value {
433            ConfigNestedValueType::Bool {} => cm_rust::ConfigNestedValueType::Bool,
434            ConfigNestedValueType::Uint8 {} => cm_rust::ConfigNestedValueType::Uint8,
435            ConfigNestedValueType::Uint16 {} => cm_rust::ConfigNestedValueType::Uint16,
436            ConfigNestedValueType::Uint32 {} => cm_rust::ConfigNestedValueType::Uint32,
437            ConfigNestedValueType::Uint64 {} => cm_rust::ConfigNestedValueType::Uint64,
438            ConfigNestedValueType::Int8 {} => cm_rust::ConfigNestedValueType::Int8,
439            ConfigNestedValueType::Int16 {} => cm_rust::ConfigNestedValueType::Int16,
440            ConfigNestedValueType::Int32 {} => cm_rust::ConfigNestedValueType::Int32,
441            ConfigNestedValueType::Int64 {} => cm_rust::ConfigNestedValueType::Int64,
442            ConfigNestedValueType::String { max_size } => {
443                cm_rust::ConfigNestedValueType::String { max_size: max_size.into() }
444            }
445        }
446    }
447}
448
449impl TryFrom<&cm_rust::ConfigNestedValueType> for ConfigNestedValueType {
450    type Error = ();
451    fn try_from(nested: &cm_rust::ConfigNestedValueType) -> Result<Self, ()> {
452        Ok(match nested {
453            cm_rust::ConfigNestedValueType::Bool => ConfigNestedValueType::Bool {},
454            cm_rust::ConfigNestedValueType::Uint8 => ConfigNestedValueType::Uint8 {},
455            cm_rust::ConfigNestedValueType::Int8 => ConfigNestedValueType::Int8 {},
456            cm_rust::ConfigNestedValueType::Uint16 => ConfigNestedValueType::Uint16 {},
457            cm_rust::ConfigNestedValueType::Int16 => ConfigNestedValueType::Int16 {},
458            cm_rust::ConfigNestedValueType::Uint32 => ConfigNestedValueType::Uint32 {},
459            cm_rust::ConfigNestedValueType::Int32 => ConfigNestedValueType::Int32 {},
460            cm_rust::ConfigNestedValueType::Uint64 => ConfigNestedValueType::Uint64 {},
461            cm_rust::ConfigNestedValueType::Int64 => ConfigNestedValueType::Int64 {},
462            cm_rust::ConfigNestedValueType::String { max_size } => {
463                ConfigNestedValueType::String { max_size: NonZeroU32::new(*max_size).ok_or(())? }
464            }
465        })
466    }
467}
468
469#[derive(Clone, Hash, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize)]
470pub struct ConfigKey(String);
471
472impl ConfigKey {
473    pub fn as_str(&self) -> &str {
474        self.0.as_str()
475    }
476}
477
478impl std::fmt::Display for ConfigKey {
479    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
480        write!(f, "{}", self.0)
481    }
482}
483
484impl FromStr for ConfigKey {
485    type Err = ParseError;
486
487    fn from_str(s: &str) -> Result<Self, ParseError> {
488        let length = s.len();
489        if length == 0 {
490            return Err(ParseError::Empty);
491        }
492        if length > 64 {
493            return Err(ParseError::TooLong);
494        }
495
496        // identifiers must start with a letter
497        let first_is_letter = s.chars().next().expect("non-empty string").is_ascii_lowercase();
498        // can contain letters, numbers, and underscores
499        let contains_invalid_chars =
500            s.chars().any(|c| !(c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_'));
501        // cannot end with an underscore
502        let last_is_underscore = s.chars().next_back().expect("non-empty string") == '_';
503
504        if !first_is_letter || contains_invalid_chars || last_is_underscore {
505            return Err(ParseError::InvalidValue);
506        }
507
508        Ok(Self(s.to_string()))
509    }
510}
511
512impl<'de> de::Deserialize<'de> for ConfigKey {
513    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
514    where
515        D: de::Deserializer<'de>,
516    {
517        struct Visitor;
518
519        impl<'de> de::Visitor<'de> for Visitor {
520            type Value = ConfigKey;
521
522            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
523                f.write_str(
524                    "a non-empty string no more than 64 characters in length, which must \
525                    start with a letter, can contain letters, numbers, and underscores, \
526                    but cannot end with an underscore",
527                )
528            }
529
530            fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
531            where
532                E: de::Error,
533            {
534                s.parse().map_err(|err| match err {
535                    ParseError::InvalidValue => E::invalid_value(
536                        de::Unexpected::Str(s),
537                        &"a name which must start with a letter, can contain letters, \
538                        numbers, and underscores, but cannot end with an underscore",
539                    ),
540                    ParseError::TooLong | ParseError::Empty => E::invalid_length(
541                        s.len(),
542                        &"a non-empty name no more than 64 characters in length",
543                    ),
544                    e => {
545                        panic!("unexpected parse error: {:?}", e);
546                    }
547                })
548            }
549        }
550        deserializer.deserialize_string(Visitor)
551    }
552}
553
554#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
555#[serde(deny_unknown_fields, rename_all = "lowercase")]
556pub enum ConfigRuntimeSource {
557    Parent,
558}
559
560#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
561#[serde(tag = "type", deny_unknown_fields, rename_all = "lowercase")]
562pub enum ConfigValueType {
563    Bool {
564        mutability: Option<Vec<ConfigRuntimeSource>>,
565    },
566    Uint8 {
567        mutability: Option<Vec<ConfigRuntimeSource>>,
568    },
569    Uint16 {
570        mutability: Option<Vec<ConfigRuntimeSource>>,
571    },
572    Uint32 {
573        mutability: Option<Vec<ConfigRuntimeSource>>,
574    },
575    Uint64 {
576        mutability: Option<Vec<ConfigRuntimeSource>>,
577    },
578    Int8 {
579        mutability: Option<Vec<ConfigRuntimeSource>>,
580    },
581    Int16 {
582        mutability: Option<Vec<ConfigRuntimeSource>>,
583    },
584    Int32 {
585        mutability: Option<Vec<ConfigRuntimeSource>>,
586    },
587    Int64 {
588        mutability: Option<Vec<ConfigRuntimeSource>>,
589    },
590    String {
591        max_size: NonZeroU32,
592        mutability: Option<Vec<ConfigRuntimeSource>>,
593    },
594    Vector {
595        max_count: NonZeroU32,
596        element: ConfigNestedValueType,
597        mutability: Option<Vec<ConfigRuntimeSource>>,
598    },
599}
600
601impl ConfigValueType {
602    /// Update the hasher by digesting the ConfigValueType enum value
603    pub fn update_digest(&self, hasher: &mut impl sha2::Digest) {
604        let val = match self {
605            ConfigValueType::Bool { .. } => 0u8,
606            ConfigValueType::Uint8 { .. } => 1u8,
607            ConfigValueType::Uint16 { .. } => 2u8,
608            ConfigValueType::Uint32 { .. } => 3u8,
609            ConfigValueType::Uint64 { .. } => 4u8,
610            ConfigValueType::Int8 { .. } => 5u8,
611            ConfigValueType::Int16 { .. } => 6u8,
612            ConfigValueType::Int32 { .. } => 7u8,
613            ConfigValueType::Int64 { .. } => 8u8,
614            ConfigValueType::String { max_size, .. } => {
615                hasher.update(max_size.get().to_le_bytes());
616                9u8
617            }
618            ConfigValueType::Vector { max_count, element, .. } => {
619                hasher.update(max_count.get().to_le_bytes());
620                element.update_digest(hasher);
621                10u8
622            }
623        };
624        hasher.update([val])
625    }
626}
627
628impl From<ConfigValueType> for cm_rust::ConfigValueType {
629    fn from(value: ConfigValueType) -> Self {
630        match value {
631            ConfigValueType::Bool { .. } => cm_rust::ConfigValueType::Bool,
632            ConfigValueType::Uint8 { .. } => cm_rust::ConfigValueType::Uint8,
633            ConfigValueType::Uint16 { .. } => cm_rust::ConfigValueType::Uint16,
634            ConfigValueType::Uint32 { .. } => cm_rust::ConfigValueType::Uint32,
635            ConfigValueType::Uint64 { .. } => cm_rust::ConfigValueType::Uint64,
636            ConfigValueType::Int8 { .. } => cm_rust::ConfigValueType::Int8,
637            ConfigValueType::Int16 { .. } => cm_rust::ConfigValueType::Int16,
638            ConfigValueType::Int32 { .. } => cm_rust::ConfigValueType::Int32,
639            ConfigValueType::Int64 { .. } => cm_rust::ConfigValueType::Int64,
640            ConfigValueType::String { max_size, .. } => {
641                cm_rust::ConfigValueType::String { max_size: max_size.into() }
642            }
643            ConfigValueType::Vector { max_count, element, .. } => {
644                cm_rust::ConfigValueType::Vector {
645                    max_count: max_count.into(),
646                    nested_type: element.into(),
647                }
648            }
649        }
650    }
651}
652
653pub trait FromClause {
654    fn from_(&self) -> OneOrMany<AnyRef<'_>>;
655}
656
657pub trait FromClauseContext {
658    fn from_(&self) -> ContextSpanned<OneOrMany<AnyRef<'_>>>;
659}
660
661pub trait CapabilityClause: Clone + PartialEq + std::fmt::Debug {
662    fn service(&self) -> Option<OneOrMany<&BorrowedName>>;
663    fn protocol(&self) -> Option<OneOrMany<&BorrowedName>>;
664    fn directory(&self) -> Option<OneOrMany<&BorrowedName>>;
665    fn storage(&self) -> Option<OneOrMany<&BorrowedName>>;
666    fn runner(&self) -> Option<OneOrMany<&BorrowedName>>;
667    fn resolver(&self) -> Option<OneOrMany<&BorrowedName>>;
668    fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>>;
669    fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>>;
670    fn config(&self) -> Option<OneOrMany<&BorrowedName>>;
671    fn set_service(&mut self, o: Option<OneOrMany<Name>>);
672    fn set_protocol(&mut self, o: Option<OneOrMany<Name>>);
673    fn set_directory(&mut self, o: Option<OneOrMany<Name>>);
674    fn set_storage(&mut self, o: Option<OneOrMany<Name>>);
675    fn set_runner(&mut self, o: Option<OneOrMany<Name>>);
676    fn set_resolver(&mut self, o: Option<OneOrMany<Name>>);
677    fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>);
678    fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>);
679    fn set_config(&mut self, o: Option<OneOrMany<Name>>);
680
681    fn availability(&self) -> Option<Availability>;
682    fn set_availability(&mut self, a: Option<Availability>);
683
684    /// Returns the name of the capability for display purposes.
685    /// If `service()` returns `Some`, the capability name must be "service", etc.
686    ///
687    /// Returns an error if the capability name is not set, or if there is more than one.
688    fn capability_type(&self) -> Result<&'static str, Error> {
689        let mut types = Vec::new();
690        if self.service().is_some() {
691            types.push("service");
692        }
693        if self.protocol().is_some() {
694            types.push("protocol");
695        }
696        if self.directory().is_some() {
697            types.push("directory");
698        }
699        if self.storage().is_some() {
700            types.push("storage");
701        }
702        if self.event_stream().is_some() {
703            types.push("event_stream");
704        }
705        if self.runner().is_some() {
706            types.push("runner");
707        }
708        if self.config().is_some() {
709            types.push("config");
710        }
711        if self.resolver().is_some() {
712            types.push("resolver");
713        }
714        if self.dictionary().is_some() {
715            types.push("dictionary");
716        }
717        match types.len() {
718            0 => {
719                let supported_keywords = self
720                    .supported()
721                    .into_iter()
722                    .map(|k| format!("\"{}\"", k))
723                    .collect::<Vec<_>>()
724                    .join(", ");
725                Err(Error::validate(format!(
726                    "`{}` declaration is missing a capability keyword, one of: {}",
727                    self.decl_type(),
728                    supported_keywords,
729                )))
730            }
731            1 => Ok(types[0]),
732            _ => Err(Error::validate(format!(
733                "{} declaration has multiple capability types defined: {:?}",
734                self.decl_type(),
735                types
736            ))),
737        }
738    }
739
740    /// Returns true if this capability type allows the ::Many variant of OneOrMany.
741    fn are_many_names_allowed(&self) -> bool;
742
743    fn decl_type(&self) -> &'static str;
744    fn supported(&self) -> &[&'static str];
745
746    /// Returns the names of the capabilities in this clause.
747    /// If `protocol()` returns `Some(OneOrMany::Many(vec!["a", "b"]))`, this returns!["a", "b"].
748    fn names(&self) -> Vec<&BorrowedName> {
749        let res = vec![
750            self.service(),
751            self.protocol(),
752            self.directory(),
753            self.storage(),
754            self.runner(),
755            self.config(),
756            self.resolver(),
757            self.event_stream(),
758            self.dictionary(),
759        ];
760        res.into_iter()
761            .map(|o| o.map(|o| o.into_iter().collect::<Vec<&BorrowedName>>()).unwrap_or(vec![]))
762            .flatten()
763            .collect()
764    }
765
766    fn set_names(&mut self, names: Vec<Name>) {
767        let names = match names.len() {
768            0 => None,
769            1 => Some(OneOrMany::One(names.first().unwrap().clone())),
770            _ => Some(OneOrMany::Many(names)),
771        };
772
773        let cap_type = self.capability_type().unwrap();
774        if cap_type == "protocol" {
775            self.set_protocol(names);
776        } else if cap_type == "service" {
777            self.set_service(names);
778        } else if cap_type == "directory" {
779            self.set_directory(names);
780        } else if cap_type == "storage" {
781            self.set_storage(names);
782        } else if cap_type == "runner" {
783            self.set_runner(names);
784        } else if cap_type == "resolver" {
785            self.set_resolver(names);
786        } else if cap_type == "event_stream" {
787            self.set_event_stream(names);
788        } else if cap_type == "dictionary" {
789            self.set_dictionary(names);
790        } else if cap_type == "config" {
791            self.set_config(names);
792        } else {
793            panic!("Unknown capability type {}", cap_type);
794        }
795    }
796}
797
798trait Canonicalize {
799    fn canonicalize(&mut self);
800}
801
802pub trait AsClause {
803    fn r#as(&self) -> Option<&BorrowedName>;
804}
805
806pub trait AsClauseContext {
807    fn r#as(&self) -> Option<ContextSpanned<&BorrowedName>>;
808}
809
810pub trait PathClause {
811    fn path(&self) -> Option<&Path>;
812}
813
814pub trait FilterClause {
815    fn filter(&self) -> Option<&Map<String, Value>>;
816}
817
818pub fn alias_or_name<'a>(
819    alias: Option<&'a BorrowedName>,
820    name: &'a BorrowedName,
821) -> &'a BorrowedName {
822    alias.unwrap_or(name)
823}
824
825pub fn alias_or_name_context<'a>(
826    alias: Option<ContextSpanned<&'a BorrowedName>>,
827    name: &'a BorrowedName,
828    origin: Origin,
829) -> ContextSpanned<&'a BorrowedName> {
830    alias.unwrap_or(ContextSpanned { value: name, origin })
831}
832
833pub fn alias_or_path<'a>(alias: Option<&'a Path>, path: &'a Path) -> &'a Path {
834    alias.unwrap_or(path)
835}
836
837pub fn format_cml(buffer: &str, file: Option<&std::path::Path>) -> Result<Vec<u8>, Error> {
838    let general_order = PathOption::PropertyNameOrder(vec![
839        "name",
840        "url",
841        "startup",
842        "environment",
843        "config",
844        "dictionary",
845        "durability",
846        "service",
847        "protocol",
848        "directory",
849        "storage",
850        "runner",
851        "resolver",
852        "event",
853        "event_stream",
854        "from",
855        "as",
856        "to",
857        "rights",
858        "path",
859        "subdir",
860        "filter",
861        "dependency",
862        "extends",
863        "runners",
864        "resolvers",
865        "debug",
866    ]);
867    let options = FormatOptions {
868        collapse_containers_of_one: true,
869        sort_array_items: true, // but use options_by_path to turn this off for program args
870        options_by_path: hashmap! {
871            "/*" => hashset! {
872                PathOption::PropertyNameOrder(vec![
873                    "include",
874                    "program",
875                    "children",
876                    "collections",
877                    "capabilities",
878                    "use",
879                    "offer",
880                    "expose",
881                    "environments",
882                    "facets",
883                ])
884            },
885            "/*/program" => hashset! {
886                PathOption::CollapseContainersOfOne(false),
887                PathOption::PropertyNameOrder(vec![
888                    "runner",
889                    "binary",
890                    "args",
891                ]),
892            },
893            "/*/program/*" => hashset! {
894                PathOption::SortArrayItems(false),
895            },
896            "/*/*/*" => hashset! {
897                general_order.clone()
898            },
899            "/*/*/*/*/*" => hashset! {
900                general_order
901            },
902        },
903        ..Default::default()
904    };
905
906    json5format::format(buffer, file.map(|f| f.to_string_lossy().to_string()), Some(options))
907        .map_err(|e| Error::json5(e, file))
908}
909
910#[cfg(test)]
911mod tests {
912    use super::*;
913    use crate::types::document::Document;
914    use crate::types::environment::RunnerRegistration;
915    use crate::types::right::Right;
916    use assert_matches::assert_matches;
917    use fidl_fuchsia_io as fio;
918    use std::path::Path;
919
920    // Exercise reference parsing tests on `OfferFromRef` because it contains every reference
921    // subtype.
922
923    #[test]
924    fn test_parse_named_reference() {
925        assert_matches!("#some-child".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "some-child");
926        assert_matches!("#A".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "A");
927        assert_matches!("#7".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "7");
928        assert_matches!("#_".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "_");
929
930        assert_matches!("#-".parse::<OfferFromRef>(), Err(_));
931        assert_matches!("#.".parse::<OfferFromRef>(), Err(_));
932        assert_matches!("#".parse::<OfferFromRef>(), Err(_));
933        assert_matches!("some-child".parse::<OfferFromRef>(), Err(_));
934    }
935
936    #[test]
937    fn test_parse_reference_test() {
938        assert_matches!("parent".parse::<OfferFromRef>(), Ok(OfferFromRef::Parent));
939        assert_matches!("framework".parse::<OfferFromRef>(), Ok(OfferFromRef::Framework));
940        assert_matches!("self".parse::<OfferFromRef>(), Ok(OfferFromRef::Self_));
941        assert_matches!("#child".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "child");
942
943        assert_matches!("invalid".parse::<OfferFromRef>(), Err(_));
944        assert_matches!("#invalid-child^".parse::<OfferFromRef>(), Err(_));
945    }
946
947    fn json_value_from_str(json: &str, filename: &Path) -> Result<Value, Error> {
948        serde_json::from_str(json).map_err(|e| {
949            Error::parse(
950                format!("Couldn't read input as JSON: {}", e),
951                Some(Location { line: e.line(), column: e.column() }),
952                Some(filename),
953            )
954        })
955    }
956
957    fn parse_as_ref(input: &str) -> Result<OfferFromRef, Error> {
958        serde_json::from_value::<OfferFromRef>(json_value_from_str(input, &Path::new("test.cml"))?)
959            .map_err(|e| Error::parse(format!("{}", e), None, None))
960    }
961
962    #[test]
963    fn test_deserialize_ref() -> Result<(), Error> {
964        assert_matches!(parse_as_ref("\"self\""), Ok(OfferFromRef::Self_));
965        assert_matches!(parse_as_ref("\"parent\""), Ok(OfferFromRef::Parent));
966        assert_matches!(parse_as_ref("\"#child\""), Ok(OfferFromRef::Named(name)) if name == "child");
967
968        assert_matches!(parse_as_ref(r#""invalid""#), Err(_));
969
970        Ok(())
971    }
972
973    macro_rules! test_parse_rights {
974        (
975            $(
976                ($input:expr, $expected:expr),
977            )+
978        ) => {
979            #[test]
980            fn parse_rights() {
981                $(
982                    parse_rights_test($input, $expected);
983                )+
984            }
985        }
986    }
987
988    fn parse_rights_test(input: &str, expected: Right) {
989        let r: Right = serde_json5::from_str(&format!("\"{}\"", input)).expect("invalid json");
990        assert_eq!(r, expected);
991    }
992
993    test_parse_rights! {
994        ("connect", Right::Connect),
995        ("enumerate", Right::Enumerate),
996        ("execute", Right::Execute),
997        ("get_attributes", Right::GetAttributes),
998        ("modify_directory", Right::ModifyDirectory),
999        ("read_bytes", Right::ReadBytes),
1000        ("traverse", Right::Traverse),
1001        ("update_attributes", Right::UpdateAttributes),
1002        ("write_bytes", Right::WriteBytes),
1003        ("r*", Right::ReadAlias),
1004        ("w*", Right::WriteAlias),
1005        ("x*", Right::ExecuteAlias),
1006        ("rw*", Right::ReadWriteAlias),
1007        ("rx*", Right::ReadExecuteAlias),
1008    }
1009
1010    macro_rules! test_expand_rights {
1011        (
1012            $(
1013                ($input:expr, $expected:expr),
1014            )+
1015        ) => {
1016            #[test]
1017            fn expand_rights() {
1018                $(
1019                    expand_rights_test($input, $expected);
1020                )+
1021            }
1022        }
1023    }
1024
1025    fn expand_rights_test(input: Right, expected: Vec<fio::Operations>) {
1026        assert_eq!(input.expand(), expected);
1027    }
1028
1029    test_expand_rights! {
1030        (Right::Connect, vec![fio::Operations::CONNECT]),
1031        (Right::Enumerate, vec![fio::Operations::ENUMERATE]),
1032        (Right::Execute, vec![fio::Operations::EXECUTE]),
1033        (Right::GetAttributes, vec![fio::Operations::GET_ATTRIBUTES]),
1034        (Right::ModifyDirectory, vec![fio::Operations::MODIFY_DIRECTORY]),
1035        (Right::ReadBytes, vec![fio::Operations::READ_BYTES]),
1036        (Right::Traverse, vec![fio::Operations::TRAVERSE]),
1037        (Right::UpdateAttributes, vec![fio::Operations::UPDATE_ATTRIBUTES]),
1038        (Right::WriteBytes, vec![fio::Operations::WRITE_BYTES]),
1039        (Right::ReadAlias, vec![
1040            fio::Operations::CONNECT,
1041            fio::Operations::ENUMERATE,
1042            fio::Operations::TRAVERSE,
1043            fio::Operations::READ_BYTES,
1044            fio::Operations::GET_ATTRIBUTES,
1045        ]),
1046        (Right::WriteAlias, vec![
1047            fio::Operations::CONNECT,
1048            fio::Operations::ENUMERATE,
1049            fio::Operations::TRAVERSE,
1050            fio::Operations::WRITE_BYTES,
1051            fio::Operations::MODIFY_DIRECTORY,
1052            fio::Operations::UPDATE_ATTRIBUTES,
1053        ]),
1054        (Right::ExecuteAlias, vec![
1055            fio::Operations::CONNECT,
1056            fio::Operations::ENUMERATE,
1057            fio::Operations::TRAVERSE,
1058            fio::Operations::EXECUTE,
1059        ]),
1060        (Right::ReadWriteAlias, vec![
1061            fio::Operations::CONNECT,
1062            fio::Operations::ENUMERATE,
1063            fio::Operations::TRAVERSE,
1064            fio::Operations::READ_BYTES,
1065            fio::Operations::WRITE_BYTES,
1066            fio::Operations::MODIFY_DIRECTORY,
1067            fio::Operations::GET_ATTRIBUTES,
1068            fio::Operations::UPDATE_ATTRIBUTES,
1069        ]),
1070        (Right::ReadExecuteAlias, vec![
1071            fio::Operations::CONNECT,
1072            fio::Operations::ENUMERATE,
1073            fio::Operations::TRAVERSE,
1074            fio::Operations::READ_BYTES,
1075            fio::Operations::GET_ATTRIBUTES,
1076            fio::Operations::EXECUTE,
1077        ]),
1078    }
1079
1080    #[test]
1081    fn test_deny_unknown_fields() {
1082        assert_matches!(serde_json5::from_str::<Document>("{ unknown: \"\" }"), Err(_));
1083        assert_matches!(serde_json5::from_str::<Environment>("{ unknown: \"\" }"), Err(_));
1084        assert_matches!(serde_json5::from_str::<RunnerRegistration>("{ unknown: \"\" }"), Err(_));
1085        assert_matches!(serde_json5::from_str::<ResolverRegistration>("{ unknown: \"\" }"), Err(_));
1086        assert_matches!(serde_json5::from_str::<Use>("{ unknown: \"\" }"), Err(_));
1087        assert_matches!(serde_json5::from_str::<Expose>("{ unknown: \"\" }"), Err(_));
1088        assert_matches!(serde_json5::from_str::<Offer>("{ unknown: \"\" }"), Err(_));
1089        assert_matches!(serde_json5::from_str::<Capability>("{ unknown: \"\" }"), Err(_));
1090        assert_matches!(serde_json5::from_str::<Child>("{ unknown: \"\" }"), Err(_));
1091        assert_matches!(serde_json5::from_str::<Collection>("{ unknown: \"\" }"), Err(_));
1092    }
1093}