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, ContextPathClause, 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
212impl<T> CanonicalizeContext for Vec<T>
213where
214    T: CanonicalizeContext + ContextCapabilityClause + ContextPathClause + Clone + PartialEq,
215{
216    fn canonicalize_context(&mut self) {
217        // Collapse like-entries into one. Like entries are those that are equal in all fields
218        // but their capability names. Accomplish this by collecting all the names into a vector
219        // keyed by an instance of T with its names removed.
220        let mut to_merge: Vec<(T, Vec<Name>)> = vec![];
221        let mut to_keep: Vec<T> = vec![];
222        self.iter().for_each(|c| {
223            // Any entry with a `path` set cannot be merged with another.
224            if !c.are_many_names_allowed() || c.path().is_some() {
225                to_keep.push(c.clone());
226                return;
227            }
228            let mut names: Vec<Name> = c.names().into_iter().map(Into::into).collect();
229            let mut copy: T = c.clone();
230            copy.set_names(vec![Name::from_str("a").unwrap()]); // The name here is arbitrary.
231            let r = to_merge.iter().position(|(t, _)| t == &copy);
232            match r {
233                Some(i) => to_merge[i].1.append(&mut names),
234                None => to_merge.push((copy, names)),
235            };
236        });
237        let mut merged = to_merge
238            .into_iter()
239            .map(|(mut t, names)| {
240                t.set_names(names);
241                t
242            })
243            .collect::<Vec<_>>();
244        to_keep.append(&mut merged);
245        *self = to_keep;
246
247        self.iter_mut().for_each(|c| c.canonicalize_context());
248        self.sort_by(|a, b| {
249            // Sort by capability type, then by the name of the first entry for
250            // that type.
251            let a_type = a.capability_type(None).unwrap();
252            let b_type = b.capability_type(None).unwrap();
253            a_type.cmp(b_type).then_with(|| {
254                let a_names = a.names();
255                let b_names = b.names();
256                let a_first_name = a_names.first().unwrap();
257                let b_first_name = b_names.first().unwrap();
258                a_first_name.cmp(b_first_name)
259            })
260        });
261    }
262}
263
264/// A relative reference to another object. This is a generic type that can encode any supported
265/// reference subtype. For named references, it holds a reference to the name instead of the name
266/// itself.
267///
268/// Objects of this type are usually derived from conversions of context-specific reference
269/// types that `#[derive(Reference)]`. This type makes it easy to write helper functions that operate on
270/// generic references.
271#[derive(Debug, PartialEq, Eq, Hash, Clone)]
272pub enum AnyRef<'a> {
273    /// A named reference. Parsed as `#name`.
274    Named(&'a BorrowedName),
275    /// A reference to the parent. Parsed as `parent`.
276    Parent,
277    /// A reference to the framework (component manager). Parsed as `framework`.
278    Framework,
279    /// A reference to the debug. Parsed as `debug`.
280    Debug,
281    /// A reference to this component. Parsed as `self`.
282    Self_,
283    /// An intentionally omitted reference.
284    Void,
285    /// A reference to a dictionary. Parsed as a dictionary path.
286    Dictionary(&'a DictionaryRef),
287    /// A reference to a dictionary defined by this component. Parsed as
288    /// `self/<dictionary>`.
289    OwnDictionary(&'a BorrowedName),
290}
291
292/// Format an `AnyRef` as a string.
293impl fmt::Display for AnyRef<'_> {
294    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295        match self {
296            Self::Named(name) => write!(f, "#{}", name),
297            Self::Parent => write!(f, "parent"),
298            Self::Framework => write!(f, "framework"),
299            Self::Debug => write!(f, "debug"),
300            Self::Self_ => write!(f, "self"),
301            Self::Void => write!(f, "void"),
302            Self::Dictionary(d) => write!(f, "{}", d),
303            Self::OwnDictionary(name) => write!(f, "self/{}", name),
304        }
305    }
306}
307
308/// A reference to a (possibly nested) dictionary.
309#[derive(Debug, PartialEq, Eq, Hash, Clone)]
310pub struct DictionaryRef {
311    /// Path to the dictionary relative to `root_dictionary`.
312    pub path: RelativePath,
313    pub root: RootDictionaryRef,
314}
315
316impl<'a> From<&'a DictionaryRef> for AnyRef<'a> {
317    fn from(r: &'a DictionaryRef) -> Self {
318        Self::Dictionary(r)
319    }
320}
321
322impl<'a> From<&'a Name> for AnyRef<'a> {
323    fn from(name: &'a Name) -> Self {
324        AnyRef::Named(name.as_ref())
325    }
326}
327
328impl<'a> From<&'a BorrowedName> for AnyRef<'a> {
329    fn from(name: &'a BorrowedName) -> Self {
330        AnyRef::Named(name)
331    }
332}
333
334impl FromStr for DictionaryRef {
335    type Err = ParseError;
336
337    fn from_str(path: &str) -> Result<Self, ParseError> {
338        match path.find('/') {
339            Some(n) => {
340                let root = path[..n].parse().map_err(|_| ParseError::InvalidValue)?;
341                let path = RelativePath::new(&path[n + 1..])?;
342                Ok(Self { root, path })
343            }
344            None => Err(ParseError::InvalidValue),
345        }
346    }
347}
348
349impl fmt::Display for DictionaryRef {
350    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351        write!(f, "{}/{}", self.root, self.path)
352    }
353}
354
355impl ser::Serialize for DictionaryRef {
356    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
357    where
358        S: serde::ser::Serializer,
359    {
360        format!("{}", self).serialize(serializer)
361    }
362}
363
364const DICTIONARY_REF_EXPECT_STR: &str = "a path to a dictionary no more \
365    than 4095 characters in length";
366
367impl<'de> de::Deserialize<'de> for DictionaryRef {
368    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
369    where
370        D: de::Deserializer<'de>,
371    {
372        struct Visitor;
373
374        impl<'de> de::Visitor<'de> for Visitor {
375            type Value = DictionaryRef;
376
377            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378                f.write_str(DICTIONARY_REF_EXPECT_STR)
379            }
380
381            fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
382            where
383                E: de::Error,
384            {
385                s.parse().map_err(|err| match err {
386                    ParseError::InvalidValue => {
387                        E::invalid_value(de::Unexpected::Str(s), &DICTIONARY_REF_EXPECT_STR)
388                    }
389                    ParseError::TooLong | ParseError::Empty => {
390                        E::invalid_length(s.len(), &DICTIONARY_REF_EXPECT_STR)
391                    }
392                    e => {
393                        panic!("unexpected parse error: {:?}", e);
394                    }
395                })
396            }
397        }
398
399        deserializer.deserialize_string(Visitor)
400    }
401}
402
403/// A reference to a root dictionary.
404#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
405#[reference(expected = "\"parent\", \"self\", \"#<child-name>\"")]
406pub enum RootDictionaryRef {
407    /// A reference to a child.
408    Named(Name),
409    /// A reference to the parent.
410    Parent,
411    /// A reference to this component.
412    Self_,
413}
414
415/// The scope of an event.
416#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference, Ord, PartialOrd)]
417#[reference(expected = "\"#<collection-name>\", \"#<child-name>\", or none")]
418pub enum EventScope {
419    /// A reference to a child or a collection.
420    Named(Name),
421}
422
423#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
424#[serde(rename_all = "snake_case")]
425pub enum ConfigType {
426    Bool,
427    Uint8,
428    Uint16,
429    Uint32,
430    Uint64,
431    Int8,
432    Int16,
433    Int32,
434    Int64,
435    String,
436    Vector,
437}
438
439impl From<&cm_rust::ConfigValueType> for ConfigType {
440    fn from(value: &cm_rust::ConfigValueType) -> Self {
441        match value {
442            cm_rust::ConfigValueType::Bool => ConfigType::Bool,
443            cm_rust::ConfigValueType::Uint8 => ConfigType::Uint8,
444            cm_rust::ConfigValueType::Int8 => ConfigType::Int8,
445            cm_rust::ConfigValueType::Uint16 => ConfigType::Uint16,
446            cm_rust::ConfigValueType::Int16 => ConfigType::Int16,
447            cm_rust::ConfigValueType::Uint32 => ConfigType::Uint32,
448            cm_rust::ConfigValueType::Int32 => ConfigType::Int32,
449            cm_rust::ConfigValueType::Uint64 => ConfigType::Uint64,
450            cm_rust::ConfigValueType::Int64 => ConfigType::Int64,
451            cm_rust::ConfigValueType::String { .. } => ConfigType::String,
452            cm_rust::ConfigValueType::Vector { .. } => ConfigType::Vector,
453        }
454    }
455}
456
457#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
458#[serde(tag = "type", deny_unknown_fields, rename_all = "lowercase")]
459pub enum ConfigNestedValueType {
460    Bool {},
461    Uint8 {},
462    Uint16 {},
463    Uint32 {},
464    Uint64 {},
465    Int8 {},
466    Int16 {},
467    Int32 {},
468    Int64 {},
469    String { max_size: NonZeroU32 },
470}
471
472impl ConfigNestedValueType {
473    /// Update the hasher by digesting the ConfigVectorElementType enum value
474    pub fn update_digest(&self, hasher: &mut impl sha2::Digest) {
475        let val = match self {
476            ConfigNestedValueType::Bool {} => 0u8,
477            ConfigNestedValueType::Uint8 {} => 1u8,
478            ConfigNestedValueType::Uint16 {} => 2u8,
479            ConfigNestedValueType::Uint32 {} => 3u8,
480            ConfigNestedValueType::Uint64 {} => 4u8,
481            ConfigNestedValueType::Int8 {} => 5u8,
482            ConfigNestedValueType::Int16 {} => 6u8,
483            ConfigNestedValueType::Int32 {} => 7u8,
484            ConfigNestedValueType::Int64 {} => 8u8,
485            ConfigNestedValueType::String { max_size } => {
486                hasher.update(max_size.get().to_le_bytes());
487                9u8
488            }
489        };
490        hasher.update([val])
491    }
492}
493
494impl From<ConfigNestedValueType> for cm_rust::ConfigNestedValueType {
495    fn from(value: ConfigNestedValueType) -> Self {
496        match value {
497            ConfigNestedValueType::Bool {} => cm_rust::ConfigNestedValueType::Bool,
498            ConfigNestedValueType::Uint8 {} => cm_rust::ConfigNestedValueType::Uint8,
499            ConfigNestedValueType::Uint16 {} => cm_rust::ConfigNestedValueType::Uint16,
500            ConfigNestedValueType::Uint32 {} => cm_rust::ConfigNestedValueType::Uint32,
501            ConfigNestedValueType::Uint64 {} => cm_rust::ConfigNestedValueType::Uint64,
502            ConfigNestedValueType::Int8 {} => cm_rust::ConfigNestedValueType::Int8,
503            ConfigNestedValueType::Int16 {} => cm_rust::ConfigNestedValueType::Int16,
504            ConfigNestedValueType::Int32 {} => cm_rust::ConfigNestedValueType::Int32,
505            ConfigNestedValueType::Int64 {} => cm_rust::ConfigNestedValueType::Int64,
506            ConfigNestedValueType::String { max_size } => {
507                cm_rust::ConfigNestedValueType::String { max_size: max_size.into() }
508            }
509        }
510    }
511}
512
513impl TryFrom<&cm_rust::ConfigNestedValueType> for ConfigNestedValueType {
514    type Error = ();
515    fn try_from(nested: &cm_rust::ConfigNestedValueType) -> Result<Self, ()> {
516        Ok(match nested {
517            cm_rust::ConfigNestedValueType::Bool => ConfigNestedValueType::Bool {},
518            cm_rust::ConfigNestedValueType::Uint8 => ConfigNestedValueType::Uint8 {},
519            cm_rust::ConfigNestedValueType::Int8 => ConfigNestedValueType::Int8 {},
520            cm_rust::ConfigNestedValueType::Uint16 => ConfigNestedValueType::Uint16 {},
521            cm_rust::ConfigNestedValueType::Int16 => ConfigNestedValueType::Int16 {},
522            cm_rust::ConfigNestedValueType::Uint32 => ConfigNestedValueType::Uint32 {},
523            cm_rust::ConfigNestedValueType::Int32 => ConfigNestedValueType::Int32 {},
524            cm_rust::ConfigNestedValueType::Uint64 => ConfigNestedValueType::Uint64 {},
525            cm_rust::ConfigNestedValueType::Int64 => ConfigNestedValueType::Int64 {},
526            cm_rust::ConfigNestedValueType::String { max_size } => {
527                ConfigNestedValueType::String { max_size: NonZeroU32::new(*max_size).ok_or(())? }
528            }
529        })
530    }
531}
532
533#[derive(Clone, Hash, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize)]
534pub struct ConfigKey(String);
535
536impl ConfigKey {
537    pub fn as_str(&self) -> &str {
538        self.0.as_str()
539    }
540}
541
542impl std::fmt::Display for ConfigKey {
543    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
544        write!(f, "{}", self.0)
545    }
546}
547
548impl FromStr for ConfigKey {
549    type Err = ParseError;
550
551    fn from_str(s: &str) -> Result<Self, ParseError> {
552        let length = s.len();
553        if length == 0 {
554            return Err(ParseError::Empty);
555        }
556        if length > 64 {
557            return Err(ParseError::TooLong);
558        }
559
560        // identifiers must start with a letter
561        let first_is_letter = s.chars().next().expect("non-empty string").is_ascii_lowercase();
562        // can contain letters, numbers, and underscores
563        let contains_invalid_chars =
564            s.chars().any(|c| !(c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_'));
565        // cannot end with an underscore
566        let last_is_underscore = s.chars().next_back().expect("non-empty string") == '_';
567
568        if !first_is_letter || contains_invalid_chars || last_is_underscore {
569            return Err(ParseError::InvalidValue);
570        }
571
572        Ok(Self(s.to_string()))
573    }
574}
575
576impl<'de> de::Deserialize<'de> for ConfigKey {
577    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
578    where
579        D: de::Deserializer<'de>,
580    {
581        struct Visitor;
582
583        impl<'de> de::Visitor<'de> for Visitor {
584            type Value = ConfigKey;
585
586            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
587                f.write_str(
588                    "a non-empty string no more than 64 characters in length, which must \
589                    start with a letter, can contain letters, numbers, and underscores, \
590                    but cannot end with an underscore",
591                )
592            }
593
594            fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
595            where
596                E: de::Error,
597            {
598                s.parse().map_err(|err| match err {
599                    ParseError::InvalidValue => E::invalid_value(
600                        de::Unexpected::Str(s),
601                        &"a name which must start with a letter, can contain letters, \
602                        numbers, and underscores, but cannot end with an underscore",
603                    ),
604                    ParseError::TooLong | ParseError::Empty => E::invalid_length(
605                        s.len(),
606                        &"a non-empty name no more than 64 characters in length",
607                    ),
608                    e => {
609                        panic!("unexpected parse error: {:?}", e);
610                    }
611                })
612            }
613        }
614        deserializer.deserialize_string(Visitor)
615    }
616}
617
618#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
619#[serde(deny_unknown_fields, rename_all = "lowercase")]
620pub enum ConfigRuntimeSource {
621    Parent,
622}
623
624#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
625#[serde(tag = "type", deny_unknown_fields, rename_all = "lowercase")]
626pub enum ConfigValueType {
627    Bool {
628        mutability: Option<Vec<ConfigRuntimeSource>>,
629    },
630    Uint8 {
631        mutability: Option<Vec<ConfigRuntimeSource>>,
632    },
633    Uint16 {
634        mutability: Option<Vec<ConfigRuntimeSource>>,
635    },
636    Uint32 {
637        mutability: Option<Vec<ConfigRuntimeSource>>,
638    },
639    Uint64 {
640        mutability: Option<Vec<ConfigRuntimeSource>>,
641    },
642    Int8 {
643        mutability: Option<Vec<ConfigRuntimeSource>>,
644    },
645    Int16 {
646        mutability: Option<Vec<ConfigRuntimeSource>>,
647    },
648    Int32 {
649        mutability: Option<Vec<ConfigRuntimeSource>>,
650    },
651    Int64 {
652        mutability: Option<Vec<ConfigRuntimeSource>>,
653    },
654    String {
655        max_size: NonZeroU32,
656        mutability: Option<Vec<ConfigRuntimeSource>>,
657    },
658    Vector {
659        max_count: NonZeroU32,
660        element: ConfigNestedValueType,
661        mutability: Option<Vec<ConfigRuntimeSource>>,
662    },
663}
664
665impl ConfigValueType {
666    /// Update the hasher by digesting the ConfigValueType enum value
667    pub fn update_digest(&self, hasher: &mut impl sha2::Digest) {
668        let val = match self {
669            ConfigValueType::Bool { .. } => 0u8,
670            ConfigValueType::Uint8 { .. } => 1u8,
671            ConfigValueType::Uint16 { .. } => 2u8,
672            ConfigValueType::Uint32 { .. } => 3u8,
673            ConfigValueType::Uint64 { .. } => 4u8,
674            ConfigValueType::Int8 { .. } => 5u8,
675            ConfigValueType::Int16 { .. } => 6u8,
676            ConfigValueType::Int32 { .. } => 7u8,
677            ConfigValueType::Int64 { .. } => 8u8,
678            ConfigValueType::String { max_size, .. } => {
679                hasher.update(max_size.get().to_le_bytes());
680                9u8
681            }
682            ConfigValueType::Vector { max_count, element, .. } => {
683                hasher.update(max_count.get().to_le_bytes());
684                element.update_digest(hasher);
685                10u8
686            }
687        };
688        hasher.update([val])
689    }
690}
691
692impl From<ConfigValueType> for cm_rust::ConfigValueType {
693    fn from(value: ConfigValueType) -> Self {
694        match value {
695            ConfigValueType::Bool { .. } => cm_rust::ConfigValueType::Bool,
696            ConfigValueType::Uint8 { .. } => cm_rust::ConfigValueType::Uint8,
697            ConfigValueType::Uint16 { .. } => cm_rust::ConfigValueType::Uint16,
698            ConfigValueType::Uint32 { .. } => cm_rust::ConfigValueType::Uint32,
699            ConfigValueType::Uint64 { .. } => cm_rust::ConfigValueType::Uint64,
700            ConfigValueType::Int8 { .. } => cm_rust::ConfigValueType::Int8,
701            ConfigValueType::Int16 { .. } => cm_rust::ConfigValueType::Int16,
702            ConfigValueType::Int32 { .. } => cm_rust::ConfigValueType::Int32,
703            ConfigValueType::Int64 { .. } => cm_rust::ConfigValueType::Int64,
704            ConfigValueType::String { max_size, .. } => {
705                cm_rust::ConfigValueType::String { max_size: max_size.into() }
706            }
707            ConfigValueType::Vector { max_count, element, .. } => {
708                cm_rust::ConfigValueType::Vector {
709                    max_count: max_count.into(),
710                    nested_type: element.into(),
711                }
712            }
713        }
714    }
715}
716
717pub trait FromClause {
718    fn from_(&self) -> OneOrMany<AnyRef<'_>>;
719}
720
721pub trait FromClauseContext {
722    fn from_(&self) -> ContextSpanned<OneOrMany<AnyRef<'_>>>;
723}
724
725pub trait CapabilityClause: Clone + PartialEq + std::fmt::Debug {
726    fn service(&self) -> Option<OneOrMany<&BorrowedName>>;
727    fn protocol(&self) -> Option<OneOrMany<&BorrowedName>>;
728    fn directory(&self) -> Option<OneOrMany<&BorrowedName>>;
729    fn storage(&self) -> Option<OneOrMany<&BorrowedName>>;
730    fn runner(&self) -> Option<OneOrMany<&BorrowedName>>;
731    fn resolver(&self) -> Option<OneOrMany<&BorrowedName>>;
732    fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>>;
733    fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>>;
734    fn config(&self) -> Option<OneOrMany<&BorrowedName>>;
735    fn set_service(&mut self, o: Option<OneOrMany<Name>>);
736    fn set_protocol(&mut self, o: Option<OneOrMany<Name>>);
737    fn set_directory(&mut self, o: Option<OneOrMany<Name>>);
738    fn set_storage(&mut self, o: Option<OneOrMany<Name>>);
739    fn set_runner(&mut self, o: Option<OneOrMany<Name>>);
740    fn set_resolver(&mut self, o: Option<OneOrMany<Name>>);
741    fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>);
742    fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>);
743    fn set_config(&mut self, o: Option<OneOrMany<Name>>);
744
745    fn availability(&self) -> Option<Availability>;
746    fn set_availability(&mut self, a: Option<Availability>);
747
748    /// Returns the name of the capability for display purposes.
749    /// If `service()` returns `Some`, the capability name must be "service", etc.
750    ///
751    /// Returns an error if the capability name is not set, or if there is more than one.
752    fn capability_type(&self) -> Result<&'static str, Error> {
753        let mut types = Vec::new();
754        if self.service().is_some() {
755            types.push("service");
756        }
757        if self.protocol().is_some() {
758            types.push("protocol");
759        }
760        if self.directory().is_some() {
761            types.push("directory");
762        }
763        if self.storage().is_some() {
764            types.push("storage");
765        }
766        if self.event_stream().is_some() {
767            types.push("event_stream");
768        }
769        if self.runner().is_some() {
770            types.push("runner");
771        }
772        if self.config().is_some() {
773            types.push("config");
774        }
775        if self.resolver().is_some() {
776            types.push("resolver");
777        }
778        if self.dictionary().is_some() {
779            types.push("dictionary");
780        }
781        match types.len() {
782            0 => {
783                let supported_keywords = self
784                    .supported()
785                    .into_iter()
786                    .map(|k| format!("\"{}\"", k))
787                    .collect::<Vec<_>>()
788                    .join(", ");
789                Err(Error::validate(format!(
790                    "`{}` declaration is missing a capability keyword, one of: {}",
791                    self.decl_type(),
792                    supported_keywords,
793                )))
794            }
795            1 => Ok(types[0]),
796            _ => Err(Error::validate(format!(
797                "{} declaration has multiple capability types defined: {:?}",
798                self.decl_type(),
799                types
800            ))),
801        }
802    }
803
804    /// Returns true if this capability type allows the ::Many variant of OneOrMany.
805    fn are_many_names_allowed(&self) -> bool;
806
807    fn decl_type(&self) -> &'static str;
808    fn supported(&self) -> &[&'static str];
809
810    /// Returns the names of the capabilities in this clause.
811    /// If `protocol()` returns `Some(OneOrMany::Many(vec!["a", "b"]))`, this returns!["a", "b"].
812    fn names(&self) -> Vec<&BorrowedName> {
813        let res = vec![
814            self.service(),
815            self.protocol(),
816            self.directory(),
817            self.storage(),
818            self.runner(),
819            self.config(),
820            self.resolver(),
821            self.event_stream(),
822            self.dictionary(),
823        ];
824        res.into_iter()
825            .map(|o| o.map(|o| o.into_iter().collect::<Vec<&BorrowedName>>()).unwrap_or(vec![]))
826            .flatten()
827            .collect()
828    }
829
830    fn set_names(&mut self, names: Vec<Name>) {
831        let names = match names.len() {
832            0 => None,
833            1 => Some(OneOrMany::One(names.first().unwrap().clone())),
834            _ => Some(OneOrMany::Many(names)),
835        };
836
837        let cap_type = self.capability_type().unwrap();
838        if cap_type == "protocol" {
839            self.set_protocol(names);
840        } else if cap_type == "service" {
841            self.set_service(names);
842        } else if cap_type == "directory" {
843            self.set_directory(names);
844        } else if cap_type == "storage" {
845            self.set_storage(names);
846        } else if cap_type == "runner" {
847            self.set_runner(names);
848        } else if cap_type == "resolver" {
849            self.set_resolver(names);
850        } else if cap_type == "event_stream" {
851            self.set_event_stream(names);
852        } else if cap_type == "dictionary" {
853            self.set_dictionary(names);
854        } else if cap_type == "config" {
855            self.set_config(names);
856        } else {
857            panic!("Unknown capability type {}", cap_type);
858        }
859    }
860}
861
862trait Canonicalize {
863    fn canonicalize(&mut self);
864}
865
866#[allow(dead_code)]
867trait CanonicalizeContext {
868    fn canonicalize_context(&mut self);
869}
870
871pub trait AsClause {
872    fn r#as(&self) -> Option<&BorrowedName>;
873}
874
875pub trait AsClauseContext {
876    fn r#as(&self) -> Option<ContextSpanned<&BorrowedName>>;
877}
878
879pub trait PathClause {
880    fn path(&self) -> Option<&Path>;
881}
882
883pub trait FilterClause {
884    fn filter(&self) -> Option<&Map<String, Value>>;
885}
886
887pub fn alias_or_name<'a>(
888    alias: Option<&'a BorrowedName>,
889    name: &'a BorrowedName,
890) -> &'a BorrowedName {
891    alias.unwrap_or(name)
892}
893
894pub fn alias_or_name_context<'a>(
895    alias: Option<ContextSpanned<&'a BorrowedName>>,
896    name: &'a BorrowedName,
897    origin: Origin,
898) -> ContextSpanned<&'a BorrowedName> {
899    alias.unwrap_or(ContextSpanned { value: name, origin })
900}
901
902pub fn alias_or_path<'a>(alias: Option<&'a Path>, path: &'a Path) -> &'a Path {
903    alias.unwrap_or(path)
904}
905
906pub fn format_cml(buffer: &str, file: Option<&std::path::Path>) -> Result<Vec<u8>, Error> {
907    let general_order = PathOption::PropertyNameOrder(vec![
908        "name",
909        "url",
910        "startup",
911        "environment",
912        "config",
913        "dictionary",
914        "durability",
915        "service",
916        "protocol",
917        "directory",
918        "storage",
919        "runner",
920        "resolver",
921        "event",
922        "event_stream",
923        "from",
924        "as",
925        "to",
926        "rights",
927        "path",
928        "subdir",
929        "filter",
930        "dependency",
931        "extends",
932        "runners",
933        "resolvers",
934        "debug",
935    ]);
936    let options = FormatOptions {
937        collapse_containers_of_one: true,
938        sort_array_items: true, // but use options_by_path to turn this off for program args
939        options_by_path: hashmap! {
940            "/*" => hashset! {
941                PathOption::PropertyNameOrder(vec![
942                    "include",
943                    "program",
944                    "children",
945                    "collections",
946                    "capabilities",
947                    "use",
948                    "offer",
949                    "expose",
950                    "environments",
951                    "facets",
952                ])
953            },
954            "/*/program" => hashset! {
955                PathOption::CollapseContainersOfOne(false),
956                PathOption::PropertyNameOrder(vec![
957                    "runner",
958                    "binary",
959                    "args",
960                ]),
961            },
962            "/*/program/*" => hashset! {
963                PathOption::SortArrayItems(false),
964            },
965            "/*/*/*" => hashset! {
966                general_order.clone()
967            },
968            "/*/*/*/*/*" => hashset! {
969                general_order
970            },
971        },
972        ..Default::default()
973    };
974
975    json5format::format(buffer, file.map(|f| f.to_string_lossy().to_string()), Some(options))
976        .map_err(|e| Error::json5(e, file))
977}
978
979#[cfg(test)]
980mod tests {
981    use super::*;
982    use crate::types::document::Document;
983    use crate::types::environment::RunnerRegistration;
984    use assert_matches::assert_matches;
985    use std::path::Path;
986
987    // Exercise reference parsing tests on `OfferFromRef` because it contains every reference
988    // subtype.
989
990    #[test]
991    fn test_parse_named_reference() {
992        assert_matches!("#some-child".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "some-child");
993        assert_matches!("#A".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "A");
994        assert_matches!("#7".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "7");
995        assert_matches!("#_".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "_");
996
997        assert_matches!("#-".parse::<OfferFromRef>(), Err(_));
998        assert_matches!("#.".parse::<OfferFromRef>(), Err(_));
999        assert_matches!("#".parse::<OfferFromRef>(), Err(_));
1000        assert_matches!("some-child".parse::<OfferFromRef>(), Err(_));
1001    }
1002
1003    #[test]
1004    fn test_parse_reference_test() {
1005        assert_matches!("parent".parse::<OfferFromRef>(), Ok(OfferFromRef::Parent));
1006        assert_matches!("framework".parse::<OfferFromRef>(), Ok(OfferFromRef::Framework));
1007        assert_matches!("self".parse::<OfferFromRef>(), Ok(OfferFromRef::Self_));
1008        assert_matches!("#child".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "child");
1009
1010        assert_matches!("invalid".parse::<OfferFromRef>(), Err(_));
1011        assert_matches!("#invalid-child^".parse::<OfferFromRef>(), Err(_));
1012    }
1013
1014    fn json_value_from_str(json: &str, filename: &Path) -> Result<Value, Error> {
1015        serde_json::from_str(json).map_err(|e| {
1016            Error::parse(
1017                format!("Couldn't read input as JSON: {}", e),
1018                Some(Location { line: e.line(), column: e.column() }),
1019                Some(filename),
1020            )
1021        })
1022    }
1023
1024    fn parse_as_ref(input: &str) -> Result<OfferFromRef, Error> {
1025        serde_json::from_value::<OfferFromRef>(json_value_from_str(input, &Path::new("test.cml"))?)
1026            .map_err(|e| Error::parse(format!("{}", e), None, None))
1027    }
1028
1029    #[test]
1030    fn test_deserialize_ref() -> Result<(), Error> {
1031        assert_matches!(parse_as_ref("\"self\""), Ok(OfferFromRef::Self_));
1032        assert_matches!(parse_as_ref("\"parent\""), Ok(OfferFromRef::Parent));
1033        assert_matches!(parse_as_ref("\"#child\""), Ok(OfferFromRef::Named(name)) if name == "child");
1034
1035        assert_matches!(parse_as_ref(r#""invalid""#), Err(_));
1036
1037        Ok(())
1038    }
1039
1040    #[test]
1041    fn test_deny_unknown_fields() {
1042        assert_matches!(serde_json5::from_str::<Document>("{ unknown: \"\" }"), Err(_));
1043        assert_matches!(serde_json5::from_str::<Environment>("{ unknown: \"\" }"), Err(_));
1044        assert_matches!(serde_json5::from_str::<RunnerRegistration>("{ unknown: \"\" }"), Err(_));
1045        assert_matches!(serde_json5::from_str::<ResolverRegistration>("{ unknown: \"\" }"), Err(_));
1046        assert_matches!(serde_json5::from_str::<Use>("{ unknown: \"\" }"), Err(_));
1047        assert_matches!(serde_json5::from_str::<Expose>("{ unknown: \"\" }"), Err(_));
1048        assert_matches!(serde_json5::from_str::<Offer>("{ unknown: \"\" }"), Err(_));
1049        assert_matches!(serde_json5::from_str::<Capability>("{ unknown: \"\" }"), Err(_));
1050        assert_matches!(serde_json5::from_str::<Child>("{ unknown: \"\" }"), Err(_));
1051        assert_matches!(serde_json5::from_str::<Collection>("{ unknown: \"\" }"), Err(_));
1052    }
1053}