Skip to main content

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