1pub mod error;
12pub mod features;
13pub mod load;
14pub mod one_or_many;
15pub mod types;
16pub(crate) mod validate;
17
18#[allow(unused)] pub 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
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 parse_and_hydrate(file_arc, buffer)
74}
75
76pub 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#[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#[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#[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#[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 let mut to_merge: Vec<(T, Vec<Name>)> = vec![];
145 let mut to_keep: Vec<T> = vec![];
146 self.iter().for_each(|c| {
147 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()]); let r = to_merge.iter().position(|(t, _)| t == ©);
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 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 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 == ©);
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 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 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#[derive(Debug, PartialEq, Eq, Hash, Clone)]
259pub enum AnyRef<'a> {
260 Named(&'a BorrowedName),
262 Parent,
264 Framework,
266 Debug,
268 Self_,
270 Void,
272 Dictionary(&'a DictionaryRef),
274 OwnDictionary(&'a BorrowedName),
277}
278
279impl 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#[derive(Debug, PartialEq, Eq, Hash, Clone)]
297pub struct DictionaryRef {
298 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#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
392#[reference(expected = "\"parent\", \"self\", \"#<child-name>\"")]
393pub enum RootDictionaryRef {
394 Named(Name),
396 Parent,
398 Self_,
400}
401
402#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference, Ord, PartialOrd)]
404#[reference(expected = "\"#<collection-name>\", \"#<child-name>\", or none")]
405pub enum EventScope {
406 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 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 let first_is_letter = s.chars().next().expect("non-empty string").is_ascii_lowercase();
549 let contains_invalid_chars =
551 s.chars().any(|c| !(c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_'));
552 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 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 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 fn are_many_names_allowed(&self) -> bool;
804
805 fn decl_type(&self) -> &'static str;
806 fn supported(&self) -> &[&'static str];
807
808 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, 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 #[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}