1pub mod error;
12pub mod features;
13pub mod one_or_many;
14pub mod types;
15pub(crate) mod validate;
16
17#[allow(unused)] pub 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
59pub 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
80pub 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#[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#[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#[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#[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 let mut to_merge: Vec<(T, Vec<Name>)> = vec![];
169 let mut to_keep: Vec<T> = vec![];
170 self.iter().for_each(|c| {
171 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()]); let r = to_merge.iter().position(|(t, _)| t == ©);
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 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#[derive(Debug, PartialEq, Eq, Hash, Clone)]
220pub enum AnyRef<'a> {
221 Named(&'a BorrowedName),
223 Parent,
225 Framework,
227 Debug,
229 Self_,
231 Void,
233 Dictionary(&'a DictionaryRef),
235 OwnDictionary(&'a BorrowedName),
238}
239
240impl 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#[derive(Debug, PartialEq, Eq, Hash, Clone)]
258pub struct DictionaryRef {
259 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#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
341#[reference(expected = "\"parent\", \"self\", \"#<child-name>\"")]
342pub enum RootDictionaryRef {
343 Named(Name),
345 Parent,
347 Self_,
349}
350
351#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference, Ord, PartialOrd)]
353#[reference(expected = "\"#<collection-name>\", \"#<child-name>\", or none")]
354pub enum EventScope {
355 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 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 let first_is_letter = s.chars().next().expect("non-empty string").is_ascii_lowercase();
498 let contains_invalid_chars =
500 s.chars().any(|c| !(c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_'));
501 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 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 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 fn are_many_names_allowed(&self) -> bool;
742
743 fn decl_type(&self) -> &'static str;
744 fn supported(&self) -> &[&'static str];
745
746 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, 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 #[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}