1pub mod error;
12pub mod features;
13pub mod one_or_many;
14pub(crate) mod validate;
15
16#[allow(unused)] pub mod translate;
18
19use crate::error::Error;
20use cml_macro::{CheckedVec, OneOrMany, Reference};
21use fidl_fuchsia_io as fio;
22use indexmap::IndexMap;
23use itertools::Itertools;
24use json5format::{FormatOptions, PathOption};
25use lazy_static::lazy_static;
26use maplit::{hashmap, hashset};
27use reference_doc::ReferenceDoc;
28use serde::{de, ser, Deserialize, Serialize};
29use serde_json::{Map, Value};
30use std::collections::{BTreeMap, HashMap, HashSet};
31use std::fmt::Write;
32use std::hash::Hash;
33use std::num::NonZeroU32;
34use std::str::FromStr;
35use std::{cmp, fmt, path};
36use validate::offer_to_all_from_offer;
37
38pub use cm_types::{
39 AllowedOffers, Availability, BorrowedName, DeliveryType, DependencyType, Durability, Name,
40 NamespacePath, OnTerminate, ParseError, Path, RelativePath, StartupMode, StorageId, Url,
41};
42use error::Location;
43
44pub use crate::one_or_many::OneOrMany;
45pub use crate::translate::{compile, CompileOptions};
46pub use crate::validate::{CapabilityRequirements, MustUseRequirement, OfferToAllCapability};
47
48lazy_static! {
49 static ref DEFAULT_EVENT_STREAM_NAME: Name = "EventStream".parse().unwrap();
50}
51
52pub fn parse_one_document(buffer: &String, file: &std::path::Path) -> Result<Document, Error> {
54 serde_json5::from_str(&buffer).map_err(|e| {
55 let serde_json5::Error::Message { location, msg } = e;
56 let location = location.map(|l| Location { line: l.line, column: l.column });
57 Error::parse(msg, location, Some(file))
58 })
59}
60
61pub fn parse_many_documents(
64 buffer: &String,
65 file: &std::path::Path,
66) -> Result<Vec<Document>, Error> {
67 let res: Result<Vec<Document>, _> = serde_json5::from_str(&buffer);
68 match res {
69 Err(_) => {
70 let d = parse_one_document(buffer, file)?;
71 Ok(vec![d])
72 }
73 Ok(docs) => Ok(docs),
74 }
75}
76
77#[derive(Debug, PartialEq, Eq, Hash, Clone)]
88pub enum CapabilityId<'a> {
89 Service(&'a BorrowedName),
90 Protocol(&'a BorrowedName),
91 Directory(&'a BorrowedName),
92 UsedService(Path),
94 UsedProtocol(Path),
96 UsedDirectory(Path),
98 UsedStorage(Path),
100 UsedEventStream(Path),
102 UsedConfiguration(&'a BorrowedName),
104 UsedRunner(&'a BorrowedName),
105 Storage(&'a BorrowedName),
106 Runner(&'a BorrowedName),
107 Resolver(&'a BorrowedName),
108 EventStream(&'a BorrowedName),
109 Dictionary(&'a BorrowedName),
110 Configuration(&'a BorrowedName),
111}
112
113macro_rules! capability_ids_from_names {
115 ($name:ident, $variant:expr) => {
116 fn $name(names: Vec<&'a BorrowedName>) -> Vec<Self> {
117 names.into_iter().map(|n| $variant(n)).collect()
118 }
119 };
120}
121
122macro_rules! capability_ids_from_paths {
124 ($name:ident, $variant:expr) => {
125 fn $name(paths: Vec<Path>) -> Vec<Self> {
126 paths.into_iter().map(|p| $variant(p)).collect()
127 }
128 };
129}
130
131impl<'a> CapabilityId<'a> {
132 pub fn type_str(&self) -> &'static str {
134 match self {
135 CapabilityId::Service(_) => "service",
136 CapabilityId::Protocol(_) => "protocol",
137 CapabilityId::Directory(_) => "directory",
138 CapabilityId::UsedService(_) => "service",
139 CapabilityId::UsedProtocol(_) => "protocol",
140 CapabilityId::UsedDirectory(_) => "directory",
141 CapabilityId::UsedStorage(_) => "storage",
142 CapabilityId::UsedEventStream(_) => "event_stream",
143 CapabilityId::UsedRunner(_) => "runner",
144 CapabilityId::UsedConfiguration(_) => "config",
145 CapabilityId::Storage(_) => "storage",
146 CapabilityId::Runner(_) => "runner",
147 CapabilityId::Resolver(_) => "resolver",
148 CapabilityId::EventStream(_) => "event_stream",
149 CapabilityId::Dictionary(_) => "dictionary",
150 CapabilityId::Configuration(_) => "config",
151 }
152 }
153
154 pub fn get_dir_path(&self) -> Option<NamespacePath> {
156 match self {
157 CapabilityId::UsedService(p)
158 | CapabilityId::UsedProtocol(p)
159 | CapabilityId::UsedEventStream(p) => Some(p.parent()),
160 CapabilityId::UsedDirectory(p) | CapabilityId::UsedStorage(p) => Some(p.clone().into()),
161 _ => None,
162 }
163 }
164
165 pub fn from_use(use_: &'a Use) -> Result<Vec<Self>, Error> {
174 let alias = use_.path.as_ref();
176 if let Some(n) = use_.service() {
177 return Ok(Self::used_services_from(Self::get_one_or_many_svc_paths(
178 n,
179 alias,
180 use_.capability_type().unwrap(),
181 )?));
182 } else if let Some(n) = use_.protocol() {
183 return Ok(Self::used_protocols_from(Self::get_one_or_many_svc_paths(
184 n,
185 alias,
186 use_.capability_type().unwrap(),
187 )?));
188 } else if let Some(_) = use_.directory.as_ref() {
189 if use_.path.is_none() {
190 return Err(Error::validate("\"path\" should be present for `use directory`."));
191 }
192 return Ok(vec![CapabilityId::UsedDirectory(use_.path.as_ref().unwrap().clone())]);
193 } else if let Some(_) = use_.storage.as_ref() {
194 if use_.path.is_none() {
195 return Err(Error::validate("\"path\" should be present for `use storage`."));
196 }
197 return Ok(vec![CapabilityId::UsedStorage(use_.path.as_ref().unwrap().clone())]);
198 } else if let Some(_) = use_.event_stream() {
199 if let Some(path) = use_.path() {
200 return Ok(vec![CapabilityId::UsedEventStream(path.clone())]);
201 }
202 return Ok(vec![CapabilityId::UsedEventStream(Path::new(
203 "/svc/fuchsia.component.EventStream",
204 )?)]);
205 } else if let Some(n) = use_.runner() {
206 match n {
207 OneOrMany::One(name) => {
208 return Ok(vec![CapabilityId::UsedRunner(name)]);
209 }
210 OneOrMany::Many(_) => {
211 return Err(Error::validate("`use runner` should occur at most once."));
212 }
213 }
214 } else if let Some(_) = use_.config() {
215 return match &use_.key {
216 None => Err(Error::validate("\"key\" should be present for `use config`.")),
217 Some(name) => Ok(vec![CapabilityId::UsedConfiguration(name)]),
218 };
219 }
220 let supported_keywords = use_
222 .supported()
223 .into_iter()
224 .map(|k| format!("\"{}\"", k))
225 .collect::<Vec<_>>()
226 .join(", ");
227 Err(Error::validate(format!(
228 "`{}` declaration is missing a capability keyword, one of: {}",
229 use_.decl_type(),
230 supported_keywords,
231 )))
232 }
233
234 pub fn from_capability(capability: &'a Capability) -> Result<Vec<Self>, Error> {
235 if let Some(n) = capability.service() {
237 if n.is_many() && capability.path.is_some() {
238 return Err(Error::validate(
239 "\"path\" can only be specified when one `service` is supplied.",
240 ));
241 }
242 return Ok(Self::services_from(Self::get_one_or_many_names(
243 n,
244 None,
245 capability.capability_type().unwrap(),
246 )?));
247 } else if let Some(n) = capability.protocol() {
248 if n.is_many() && capability.path.is_some() {
249 return Err(Error::validate(
250 "\"path\" can only be specified when one `protocol` is supplied.",
251 ));
252 }
253 return Ok(Self::protocols_from(Self::get_one_or_many_names(
254 n,
255 None,
256 capability.capability_type().unwrap(),
257 )?));
258 } else if let Some(n) = capability.directory() {
259 return Ok(Self::directories_from(Self::get_one_or_many_names(
260 n,
261 None,
262 capability.capability_type().unwrap(),
263 )?));
264 } else if let Some(n) = capability.storage() {
265 if capability.storage_id.is_none() {
266 return Err(Error::validate(
267 "Storage declaration is missing \"storage_id\", but is required.",
268 ));
269 }
270 return Ok(Self::storages_from(Self::get_one_or_many_names(
271 n,
272 None,
273 capability.capability_type().unwrap(),
274 )?));
275 } else if let Some(n) = capability.runner() {
276 return Ok(Self::runners_from(Self::get_one_or_many_names(
277 n,
278 None,
279 capability.capability_type().unwrap(),
280 )?));
281 } else if let Some(n) = capability.resolver() {
282 return Ok(Self::resolvers_from(Self::get_one_or_many_names(
283 n,
284 None,
285 capability.capability_type().unwrap(),
286 )?));
287 } else if let Some(n) = capability.event_stream() {
288 return Ok(Self::event_streams_from(Self::get_one_or_many_names(
289 n,
290 None,
291 capability.capability_type().unwrap(),
292 )?));
293 } else if let Some(n) = capability.dictionary() {
294 return Ok(Self::dictionaries_from(Self::get_one_or_many_names(
295 n,
296 None,
297 capability.capability_type().unwrap(),
298 )?));
299 } else if let Some(n) = capability.config() {
300 return Ok(Self::configurations_from(Self::get_one_or_many_names(
301 n,
302 None,
303 capability.capability_type().unwrap(),
304 )?));
305 }
306
307 let supported_keywords = capability
309 .supported()
310 .into_iter()
311 .map(|k| format!("\"{}\"", k))
312 .collect::<Vec<_>>()
313 .join(", ");
314 Err(Error::validate(format!(
315 "`{}` declaration is missing a capability keyword, one of: {}",
316 capability.decl_type(),
317 supported_keywords,
318 )))
319 }
320
321 pub fn from_offer_expose<T>(clause: &'a T) -> Result<Vec<Self>, Error>
330 where
331 T: CapabilityClause + AsClause + fmt::Debug,
332 {
333 let alias = clause.r#as();
335 if let Some(n) = clause.service() {
336 return Ok(Self::services_from(Self::get_one_or_many_names(
337 n,
338 alias,
339 clause.capability_type().unwrap(),
340 )?));
341 } else if let Some(n) = clause.protocol() {
342 return Ok(Self::protocols_from(Self::get_one_or_many_names(
343 n,
344 alias,
345 clause.capability_type().unwrap(),
346 )?));
347 } else if let Some(n) = clause.directory() {
348 return Ok(Self::directories_from(Self::get_one_or_many_names(
349 n,
350 alias,
351 clause.capability_type().unwrap(),
352 )?));
353 } else if let Some(n) = clause.storage() {
354 return Ok(Self::storages_from(Self::get_one_or_many_names(
355 n,
356 alias,
357 clause.capability_type().unwrap(),
358 )?));
359 } else if let Some(n) = clause.runner() {
360 return Ok(Self::runners_from(Self::get_one_or_many_names(
361 n,
362 alias,
363 clause.capability_type().unwrap(),
364 )?));
365 } else if let Some(n) = clause.resolver() {
366 return Ok(Self::resolvers_from(Self::get_one_or_many_names(
367 n,
368 alias,
369 clause.capability_type().unwrap(),
370 )?));
371 } else if let Some(event_stream) = clause.event_stream() {
372 return Ok(Self::event_streams_from(Self::get_one_or_many_names(
373 event_stream,
374 alias,
375 clause.capability_type().unwrap(),
376 )?));
377 } else if let Some(n) = clause.dictionary() {
378 return Ok(Self::dictionaries_from(Self::get_one_or_many_names(
379 n,
380 alias,
381 clause.capability_type().unwrap(),
382 )?));
383 } else if let Some(n) = clause.config() {
384 return Ok(Self::configurations_from(Self::get_one_or_many_names(
385 n,
386 alias,
387 clause.capability_type().unwrap(),
388 )?));
389 }
390
391 let supported_keywords = clause
393 .supported()
394 .into_iter()
395 .map(|k| format!("\"{}\"", k))
396 .collect::<Vec<_>>()
397 .join(", ");
398 Err(Error::validate(format!(
399 "`{}` declaration is missing a capability keyword, one of: {}",
400 clause.decl_type(),
401 supported_keywords,
402 )))
403 }
404
405 fn get_one_or_many_names<'b>(
407 names: OneOrMany<&'b BorrowedName>,
408 alias: Option<&'b BorrowedName>,
409 capability_type: &str,
410 ) -> Result<Vec<&'b BorrowedName>, Error> {
411 let names: Vec<&BorrowedName> = names.into_iter().collect();
412 if names.len() == 1 {
413 Ok(vec![alias_or_name(alias, &names[0])])
414 } else {
415 if alias.is_some() {
416 return Err(Error::validate(format!(
417 "\"as\" can only be specified when one `{}` is supplied.",
418 capability_type,
419 )));
420 }
421 Ok(names)
422 }
423 }
424
425 fn get_one_or_many_svc_paths(
427 names: OneOrMany<&BorrowedName>,
428 alias: Option<&Path>,
429 capability_type: &str,
430 ) -> Result<Vec<Path>, Error> {
431 let names: Vec<_> = names.into_iter().collect();
432 match (names.len(), alias) {
433 (_, None) => {
434 Ok(names.into_iter().map(|n| format!("/svc/{}", n).parse().unwrap()).collect())
435 }
436 (1, Some(alias)) => Ok(vec![alias.clone()]),
437 (_, Some(_)) => {
438 return Err(Error::validate(format!(
439 "\"path\" can only be specified when one `{}` is supplied.",
440 capability_type,
441 )));
442 }
443 }
444 }
445
446 capability_ids_from_names!(services_from, CapabilityId::Service);
447 capability_ids_from_names!(protocols_from, CapabilityId::Protocol);
448 capability_ids_from_names!(directories_from, CapabilityId::Directory);
449 capability_ids_from_names!(storages_from, CapabilityId::Storage);
450 capability_ids_from_names!(runners_from, CapabilityId::Runner);
451 capability_ids_from_names!(resolvers_from, CapabilityId::Resolver);
452 capability_ids_from_names!(event_streams_from, CapabilityId::EventStream);
453 capability_ids_from_names!(dictionaries_from, CapabilityId::Dictionary);
454 capability_ids_from_names!(configurations_from, CapabilityId::Configuration);
455 capability_ids_from_paths!(used_services_from, CapabilityId::UsedService);
456 capability_ids_from_paths!(used_protocols_from, CapabilityId::UsedProtocol);
457}
458
459impl fmt::Display for CapabilityId<'_> {
460 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
462 match self {
463 CapabilityId::Service(n)
464 | CapabilityId::Storage(n)
465 | CapabilityId::Runner(n)
466 | CapabilityId::UsedRunner(n)
467 | CapabilityId::Resolver(n)
468 | CapabilityId::EventStream(n)
469 | CapabilityId::Configuration(n)
470 | CapabilityId::UsedConfiguration(n)
471 | CapabilityId::Dictionary(n) => write!(f, "{}", n),
472 CapabilityId::UsedService(p)
473 | CapabilityId::UsedProtocol(p)
474 | CapabilityId::UsedDirectory(p)
475 | CapabilityId::UsedStorage(p)
476 | CapabilityId::UsedEventStream(p) => write!(f, "{}", p),
477 CapabilityId::Protocol(p) | CapabilityId::Directory(p) => write!(f, "{}", p),
478 }
479 }
480}
481
482#[derive(CheckedVec, Debug, PartialEq, Clone)]
484#[checked_vec(
485 expected = "a nonempty array of rights, with unique elements",
486 min_length = 1,
487 unique_items = true
488)]
489pub struct Rights(pub Vec<Right>);
490
491#[derive(OneOrMany, Debug, Clone)]
493#[one_or_many(
494 expected = "a name or nonempty array of names, with unique elements",
495 inner_type = "Name",
496 min_length = 1,
497 unique_items = true
498)]
499pub struct OneOrManyNames;
500
501#[derive(OneOrMany, Debug, Clone)]
503#[one_or_many(
504 expected = "a path or nonempty array of paths, with unique elements",
505 inner_type = "Path",
506 min_length = 1,
507 unique_items = true
508)]
509pub struct OneOrManyPaths;
510
511#[derive(OneOrMany, Debug, Clone)]
513#[one_or_many(
514 expected = "one or an array of \"framework\", \"self\", \"#<child-name>\", or a dictionary path",
515 inner_type = "ExposeFromRef",
516 min_length = 1,
517 unique_items = true
518)]
519pub struct OneOrManyExposeFromRefs;
520
521#[derive(OneOrMany, Debug, Clone)]
523#[one_or_many(
524 expected = "one or an array of \"#<child-name>\", \"#<collection-name>\", or \"self/<dictionary>\", with unique elements",
525 inner_type = "OfferToRef",
526 min_length = 1,
527 unique_items = true
528)]
529pub struct OneOrManyOfferToRefs;
530
531#[derive(OneOrMany, Debug, Clone)]
533#[one_or_many(
534 expected = "one or an array of \"parent\", \"framework\", \"self\", \"#<child-name>\", \"#<collection-name>\", or a dictionary path",
535 inner_type = "OfferFromRef",
536 min_length = 1,
537 unique_items = true
538)]
539pub struct OneOrManyOfferFromRefs;
540
541#[derive(OneOrMany, Debug, Clone)]
543#[one_or_many(
544 expected = "one or an array of \"#<collection-name>\", or \"#<child-name>\"",
545 inner_type = "EventScope",
546 min_length = 1,
547 unique_items = true
548)]
549pub struct OneOrManyEventScope;
550
551#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
553pub struct StopTimeoutMs(pub u32);
554
555impl<'de> de::Deserialize<'de> for StopTimeoutMs {
556 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
557 where
558 D: de::Deserializer<'de>,
559 {
560 struct Visitor;
561
562 impl<'de> de::Visitor<'de> for Visitor {
563 type Value = StopTimeoutMs;
564
565 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
566 f.write_str("an unsigned 32-bit integer")
567 }
568
569 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
570 where
571 E: de::Error,
572 {
573 if v < 0 || v > i64::from(u32::max_value()) {
574 return Err(E::invalid_value(
575 de::Unexpected::Signed(v),
576 &"an unsigned 32-bit integer",
577 ));
578 }
579 Ok(StopTimeoutMs(v as u32))
580 }
581
582 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
583 where
584 E: de::Error,
585 {
586 self.visit_i64(value as i64)
587 }
588 }
589
590 deserializer.deserialize_i64(Visitor)
591 }
592}
593
594#[derive(Debug, PartialEq, Eq, Hash, Clone)]
602pub enum AnyRef<'a> {
603 Named(&'a BorrowedName),
605 Parent,
607 Framework,
609 Debug,
611 Self_,
613 Void,
615 Dictionary(&'a DictionaryRef),
617 OwnDictionary(&'a BorrowedName),
620}
621
622impl fmt::Display for AnyRef<'_> {
624 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
625 match self {
626 Self::Named(name) => write!(f, "#{}", name),
627 Self::Parent => write!(f, "parent"),
628 Self::Framework => write!(f, "framework"),
629 Self::Debug => write!(f, "debug"),
630 Self::Self_ => write!(f, "self"),
631 Self::Void => write!(f, "void"),
632 Self::Dictionary(d) => write!(f, "{}", d),
633 Self::OwnDictionary(name) => write!(f, "self/{}", name),
634 }
635 }
636}
637
638#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
640#[reference(
641 expected = "\"parent\", \"framework\", \"debug\", \"self\", \"#<capability-name>\", \"#<child-name>\", \"#<collection-name>\", dictionary path, or none"
642)]
643pub enum UseFromRef {
644 Parent,
646 Framework,
648 Debug,
650 Named(Name),
662 Self_,
664 Dictionary(DictionaryRef),
666}
667
668#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference, Ord, PartialOrd)]
670#[reference(expected = "\"#<collection-name>\", \"#<child-name>\", or none")]
671pub enum EventScope {
672 Named(Name),
674}
675
676#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
678#[reference(expected = "\"framework\", \"self\", \"void\", or \"#<child-name>\"")]
679pub enum ExposeFromRef {
680 Named(Name),
682 Framework,
684 Self_,
686 Void,
688 Dictionary(DictionaryRef),
690}
691
692#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
694#[reference(expected = "\"parent\", \"framework\", or none")]
695pub enum ExposeToRef {
696 Parent,
698 Framework,
700}
701
702#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
704#[reference(
705 expected = "\"parent\", \"framework\", \"self\", \"void\", \"#<child-name>\", or a dictionary path"
706)]
707pub enum OfferFromRef {
708 Named(Name),
710 Parent,
712 Framework,
714 Self_,
716 Void,
718 Dictionary(DictionaryRef),
720}
721
722impl OfferFromRef {
723 pub fn is_named(&self) -> bool {
724 match self {
725 OfferFromRef::Named(_) => true,
726 _ => false,
727 }
728 }
729}
730
731#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
733#[reference(expected = "\"#<child-name>\", \"#<collection-name>\", or \"self/<dictionary>\"")]
734pub enum OfferToRef {
735 Named(Name),
737
738 All,
740
741 OwnDictionary(Name),
743}
744
745#[derive(Debug, Deserialize, PartialEq, Eq, Hash, Clone, Serialize)]
747#[serde(rename_all = "snake_case")]
748pub enum SourceAvailability {
749 Required,
750 Unknown,
751}
752
753impl Default for SourceAvailability {
754 fn default() -> Self {
755 Self::Required
756 }
757}
758
759#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
761#[reference(expected = "\"#<environment-name>\"")]
762pub enum EnvironmentRef {
763 Named(Name),
765}
766
767#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
769#[reference(expected = "\"parent\", \"self\", or \"#<child-name>\"")]
770pub enum CapabilityFromRef {
771 Named(Name),
773 Parent,
775 Self_,
777}
778
779#[derive(Debug, PartialEq, Eq, Hash, Clone)]
781pub struct DictionaryRef {
782 pub path: RelativePath,
784 pub root: RootDictionaryRef,
785}
786
787impl<'a> From<&'a DictionaryRef> for AnyRef<'a> {
788 fn from(r: &'a DictionaryRef) -> Self {
789 Self::Dictionary(r)
790 }
791}
792
793impl FromStr for DictionaryRef {
794 type Err = ParseError;
795
796 fn from_str(path: &str) -> Result<Self, ParseError> {
797 match path.find('/') {
798 Some(n) => {
799 let root = path[..n].parse().map_err(|_| ParseError::InvalidValue)?;
800 let path = RelativePath::new(&path[n + 1..])?;
801 Ok(Self { root, path })
802 }
803 None => Err(ParseError::InvalidValue),
804 }
805 }
806}
807
808impl fmt::Display for DictionaryRef {
809 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
810 write!(f, "{}/{}", self.root, self.path)
811 }
812}
813
814impl ser::Serialize for DictionaryRef {
815 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
816 where
817 S: serde::ser::Serializer,
818 {
819 format!("{}", self).serialize(serializer)
820 }
821}
822
823const DICTIONARY_REF_EXPECT_STR: &str = "a path to a dictionary no more \
824 than 4095 characters in length";
825
826impl<'de> de::Deserialize<'de> for DictionaryRef {
827 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
828 where
829 D: de::Deserializer<'de>,
830 {
831 struct Visitor;
832
833 impl<'de> de::Visitor<'de> for Visitor {
834 type Value = DictionaryRef;
835
836 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
837 f.write_str(DICTIONARY_REF_EXPECT_STR)
838 }
839
840 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
841 where
842 E: de::Error,
843 {
844 s.parse().map_err(|err| match err {
845 ParseError::InvalidValue => {
846 E::invalid_value(de::Unexpected::Str(s), &DICTIONARY_REF_EXPECT_STR)
847 }
848 ParseError::TooLong | ParseError::Empty => {
849 E::invalid_length(s.len(), &DICTIONARY_REF_EXPECT_STR)
850 }
851 e => {
852 panic!("unexpected parse error: {:?}", e);
853 }
854 })
855 }
856 }
857
858 deserializer.deserialize_string(Visitor)
859 }
860}
861
862#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
864#[reference(expected = "\"parent\", \"self\", \"#<child-name>\"")]
865pub enum RootDictionaryRef {
866 Named(Name),
868 Parent,
870 Self_,
872}
873
874#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
876#[reference(expected = "\"parent\", \"self\", or \"#<child-name>\"")]
877pub enum RegistrationRef {
878 Named(Name),
880 Parent,
882 Self_,
884}
885
886#[derive(Deserialize, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
888#[serde(rename_all = "snake_case")]
889pub enum Right {
890 Connect,
892 Enumerate,
893 Execute,
894 GetAttributes,
895 ModifyDirectory,
896 ReadBytes,
897 Traverse,
898 UpdateAttributes,
899 WriteBytes,
900
901 #[serde(rename = "r*")]
903 ReadAlias,
904 #[serde(rename = "w*")]
905 WriteAlias,
906 #[serde(rename = "x*")]
907 ExecuteAlias,
908 #[serde(rename = "rw*")]
909 ReadWriteAlias,
910 #[serde(rename = "rx*")]
911 ReadExecuteAlias,
912}
913
914impl fmt::Display for Right {
915 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
916 let s = match self {
917 Self::Connect => "connect",
918 Self::Enumerate => "enumerate",
919 Self::Execute => "execute",
920 Self::GetAttributes => "get_attributes",
921 Self::ModifyDirectory => "modify_directory",
922 Self::ReadBytes => "read_bytes",
923 Self::Traverse => "traverse",
924 Self::UpdateAttributes => "update_attributes",
925 Self::WriteBytes => "write_bytes",
926 Self::ReadAlias => "r*",
927 Self::WriteAlias => "w*",
928 Self::ExecuteAlias => "x*",
929 Self::ReadWriteAlias => "rw*",
930 Self::ReadExecuteAlias => "rx*",
931 };
932 write!(f, "{}", s)
933 }
934}
935
936impl Right {
937 pub fn expand(&self) -> Vec<fio::Operations> {
939 match self {
940 Self::Connect => vec![fio::Operations::CONNECT],
941 Self::Enumerate => vec![fio::Operations::ENUMERATE],
942 Self::Execute => vec![fio::Operations::EXECUTE],
943 Self::GetAttributes => vec![fio::Operations::GET_ATTRIBUTES],
944 Self::ModifyDirectory => vec![fio::Operations::MODIFY_DIRECTORY],
945 Self::ReadBytes => vec![fio::Operations::READ_BYTES],
946 Self::Traverse => vec![fio::Operations::TRAVERSE],
947 Self::UpdateAttributes => vec![fio::Operations::UPDATE_ATTRIBUTES],
948 Self::WriteBytes => vec![fio::Operations::WRITE_BYTES],
949 Self::ReadAlias => vec![
950 fio::Operations::CONNECT,
951 fio::Operations::ENUMERATE,
952 fio::Operations::TRAVERSE,
953 fio::Operations::READ_BYTES,
954 fio::Operations::GET_ATTRIBUTES,
955 ],
956 Self::WriteAlias => vec![
957 fio::Operations::CONNECT,
958 fio::Operations::ENUMERATE,
959 fio::Operations::TRAVERSE,
960 fio::Operations::WRITE_BYTES,
961 fio::Operations::MODIFY_DIRECTORY,
962 fio::Operations::UPDATE_ATTRIBUTES,
963 ],
964 Self::ExecuteAlias => vec![
965 fio::Operations::CONNECT,
966 fio::Operations::ENUMERATE,
967 fio::Operations::TRAVERSE,
968 fio::Operations::EXECUTE,
969 ],
970 Self::ReadWriteAlias => vec![
971 fio::Operations::CONNECT,
972 fio::Operations::ENUMERATE,
973 fio::Operations::TRAVERSE,
974 fio::Operations::READ_BYTES,
975 fio::Operations::WRITE_BYTES,
976 fio::Operations::MODIFY_DIRECTORY,
977 fio::Operations::GET_ATTRIBUTES,
978 fio::Operations::UPDATE_ATTRIBUTES,
979 ],
980 Self::ReadExecuteAlias => vec![
981 fio::Operations::CONNECT,
982 fio::Operations::ENUMERATE,
983 fio::Operations::TRAVERSE,
984 fio::Operations::READ_BYTES,
985 fio::Operations::GET_ATTRIBUTES,
986 fio::Operations::EXECUTE,
987 ],
988 }
989 }
990}
991
992#[derive(ReferenceDoc, Deserialize, Debug, Default, PartialEq, Serialize)]
1040#[serde(deny_unknown_fields)]
1041pub struct Document {
1042 #[serde(skip_serializing_if = "Option::is_none")]
1178 pub include: Option<Vec<String>>,
1179
1180 #[reference_doc(json_type = "object")]
1215 #[serde(skip_serializing_if = "Option::is_none")]
1216 pub program: Option<Program>,
1217
1218 #[reference_doc(recurse)]
1223 #[serde(skip_serializing_if = "Option::is_none")]
1224 pub children: Option<Vec<Child>>,
1225
1226 #[reference_doc(recurse)]
1229 #[serde(skip_serializing_if = "Option::is_none")]
1230 pub collections: Option<Vec<Collection>>,
1231
1232 #[reference_doc(recurse)]
1237 #[serde(skip_serializing_if = "Option::is_none")]
1238 pub environments: Option<Vec<Environment>>,
1239
1240 #[reference_doc(recurse)]
1263 #[serde(skip_serializing_if = "Option::is_none")]
1264 pub capabilities: Option<Vec<Capability>>,
1265
1266 #[reference_doc(recurse)]
1290 #[serde(skip_serializing_if = "Option::is_none")]
1291 pub r#use: Option<Vec<Use>>,
1292
1293 #[reference_doc(recurse)]
1312 #[serde(skip_serializing_if = "Option::is_none")]
1313 pub expose: Option<Vec<Expose>>,
1314
1315 #[reference_doc(recurse)]
1336 #[serde(skip_serializing_if = "Option::is_none")]
1337 pub offer: Option<Vec<Offer>>,
1338
1339 #[serde(skip_serializing_if = "Option::is_none")]
1343 pub facets: Option<IndexMap<String, Value>>,
1344
1345 #[reference_doc(json_type = "object")]
1412 #[serde(skip_serializing_if = "Option::is_none")]
1413 pub config: Option<BTreeMap<ConfigKey, ConfigValueType>>,
1418}
1419
1420impl<T> Canonicalize for Vec<T>
1421where
1422 T: Canonicalize + CapabilityClause + PathClause,
1423{
1424 fn canonicalize(&mut self) {
1425 let mut to_merge: Vec<(T, Vec<Name>)> = vec![];
1429 let mut to_keep: Vec<T> = vec![];
1430 self.iter().for_each(|c| {
1431 if !c.are_many_names_allowed() || c.path().is_some() {
1433 to_keep.push(c.clone());
1434 return;
1435 }
1436 let mut names: Vec<Name> = c.names().into_iter().map(Into::into).collect();
1437 let mut copy: T = c.clone();
1438 copy.set_names(vec![Name::from_str("a").unwrap()]); let r = to_merge.iter().position(|(t, _)| t == ©);
1440 match r {
1441 Some(i) => to_merge[i].1.append(&mut names),
1442 None => to_merge.push((copy, names)),
1443 };
1444 });
1445 let mut merged = to_merge
1446 .into_iter()
1447 .map(|(mut t, names)| {
1448 t.set_names(names);
1449 t
1450 })
1451 .collect::<Vec<_>>();
1452 to_keep.append(&mut merged);
1453 *self = to_keep;
1454
1455 self.iter_mut().for_each(|c| c.canonicalize());
1456 self.sort_by(|a, b| {
1457 let a_type = a.capability_type().unwrap();
1460 let b_type = b.capability_type().unwrap();
1461 a_type.cmp(b_type).then_with(|| {
1462 let a_names = a.names();
1463 let b_names = b.names();
1464 let a_first_name = a_names.first().unwrap();
1465 let b_first_name = b_names.first().unwrap();
1466 a_first_name.cmp(b_first_name)
1467 })
1468 });
1469 }
1470}
1471
1472fn merge_from_capability_field<T: CapabilityClause>(
1475 us: &mut Option<Vec<T>>,
1476 other: &mut Option<Vec<T>>,
1477) -> Result<(), Error> {
1478 for entry in us.iter().flatten().chain(other.iter().flatten()) {
1481 if entry.names().is_empty() {
1482 return Err(Error::Validate {
1483 err: format!("{}: Missing type name: {:#?}", entry.decl_type(), entry),
1484 filename: None,
1485 });
1486 }
1487 }
1488
1489 if let Some(all_ours) = us.as_mut() {
1490 if let Some(all_theirs) = other.take() {
1491 for mut theirs in all_theirs {
1492 for ours in &mut *all_ours {
1493 compute_diff(ours, &mut theirs);
1494 }
1495 all_ours.push(theirs);
1496 }
1497 }
1498 all_ours.retain(|ours| !ours.names().is_empty())
1500 } else if let Some(theirs) = other.take() {
1501 us.replace(theirs);
1502 }
1503 Ok(())
1504}
1505
1506fn merge_from_other_field<T: std::cmp::PartialEq>(
1509 us: &mut Option<Vec<T>>,
1510 other: &mut Option<Vec<T>>,
1511) {
1512 if let Some(ref mut ours) = us {
1513 if let Some(theirs) = other.take() {
1514 for t in theirs {
1516 if !ours.contains(&t) {
1517 ours.push(t);
1518 }
1519 }
1520 }
1521 } else if let Some(theirs) = other.take() {
1522 us.replace(theirs);
1523 }
1524}
1525
1526fn compute_diff<T: CapabilityClause>(ours: &mut T, theirs: &mut T) {
1533 if ours.names().is_empty() || theirs.names().is_empty() {
1535 return;
1536 }
1537
1538 if ours.capability_type().unwrap() != theirs.capability_type().unwrap() {
1540 return;
1541 }
1542
1543 let mut ours_partial = ours.clone();
1545 let mut theirs_partial = theirs.clone();
1546 for e in [&mut ours_partial, &mut theirs_partial] {
1547 e.set_names(Vec::new());
1548 e.set_availability(None);
1550 }
1551 if ours_partial != theirs_partial {
1552 return;
1554 }
1555
1556 let Some(avail_cmp) = ours
1558 .availability()
1559 .unwrap_or_default()
1560 .partial_cmp(&theirs.availability().unwrap_or_default())
1561 else {
1562 return;
1564 };
1565
1566 let mut our_names: Vec<Name> = ours.names().into_iter().map(Into::into).collect();
1567 let mut their_names: Vec<Name> = theirs.names().into_iter().map(Into::into).collect();
1568
1569 let mut our_entries_to_remove = HashSet::new();
1570 let mut their_entries_to_remove = HashSet::new();
1571 for e in &their_names {
1572 if !our_names.contains(e) {
1573 continue;
1575 }
1576 match avail_cmp {
1577 cmp::Ordering::Less => {
1578 our_entries_to_remove.insert(e.clone());
1581 }
1582 cmp::Ordering::Greater => {
1583 their_entries_to_remove.insert(e.clone());
1586 }
1587 cmp::Ordering::Equal => {
1588 their_entries_to_remove.insert(e.clone());
1590 }
1591 }
1592 }
1593 our_names.retain(|e| !our_entries_to_remove.contains(e));
1594 their_names.retain(|e| !their_entries_to_remove.contains(e));
1595
1596 ours.set_names(our_names);
1597 theirs.set_names(their_names);
1598}
1599
1600impl Document {
1601 pub fn merge_from(
1602 &mut self,
1603 other: &mut Document,
1604 include_path: &path::Path,
1605 ) -> Result<(), Error> {
1606 merge_from_capability_field(&mut self.r#use, &mut other.r#use)?;
1609 merge_from_capability_field(&mut self.expose, &mut other.expose)?;
1610 merge_from_capability_field(&mut self.offer, &mut other.offer)?;
1611 merge_from_capability_field(&mut self.capabilities, &mut other.capabilities)?;
1612 merge_from_other_field(&mut self.include, &mut other.include);
1613 merge_from_other_field(&mut self.children, &mut other.children);
1614 merge_from_other_field(&mut self.collections, &mut other.collections);
1615 self.merge_environment(other, include_path)?;
1616 self.merge_program(other, include_path)?;
1617 self.merge_facets(other, include_path)?;
1618 self.merge_config(other, include_path)?;
1619
1620 Ok(())
1621 }
1622
1623 pub fn canonicalize(&mut self) {
1624 if let Some(children) = &mut self.children {
1626 children.sort_by(|a, b| a.name.cmp(&b.name));
1627 }
1628 if let Some(collections) = &mut self.collections {
1629 collections.sort_by(|a, b| a.name.cmp(&b.name));
1630 }
1631 if let Some(environments) = &mut self.environments {
1632 environments.sort_by(|a, b| a.name.cmp(&b.name));
1633 }
1634 if let Some(capabilities) = &mut self.capabilities {
1635 capabilities.canonicalize();
1636 }
1637 if let Some(offers) = &mut self.offer {
1638 offers.canonicalize();
1639 }
1640 if let Some(expose) = &mut self.expose {
1641 expose.canonicalize();
1642 }
1643 if let Some(r#use) = &mut self.r#use {
1644 r#use.canonicalize();
1645 }
1646 }
1647
1648 fn merge_program(
1649 &mut self,
1650 other: &mut Document,
1651 include_path: &path::Path,
1652 ) -> Result<(), Error> {
1653 if let None = other.program {
1654 return Ok(());
1655 }
1656 if let None = self.program {
1657 self.program = Some(Program::default());
1658 }
1659 let my_program = self.program.as_mut().unwrap();
1660 let other_program = other.program.as_mut().unwrap();
1661 if let Some(other_runner) = other_program.runner.take() {
1662 my_program.runner = match &my_program.runner {
1663 Some(runner) if *runner != other_runner => {
1664 return Err(Error::validate(format!(
1665 "manifest include had a conflicting `program.runner`: {}",
1666 include_path.display()
1667 )))
1668 }
1669 _ => Some(other_runner),
1670 }
1671 }
1672
1673 Self::merge_maps_with_options(
1674 &mut my_program.info,
1675 &other_program.info,
1676 "program",
1677 include_path,
1678 Some(vec!["environ", "features"]),
1679 )
1680 }
1681
1682 fn merge_environment(
1683 &mut self,
1684 other: &mut Document,
1685 _include_path: &path::Path,
1686 ) -> Result<(), Error> {
1687 if let None = other.environments {
1688 return Ok(());
1689 }
1690 if let None = self.environments {
1691 self.environments = Some(vec![]);
1692 }
1693
1694 let my_environments = self.environments.as_mut().unwrap();
1695 let other_environments = other.environments.as_mut().unwrap();
1696 my_environments.sort_by(|x, y| x.name.cmp(&y.name));
1697 other_environments.sort_by(|x, y| x.name.cmp(&y.name));
1698
1699 let all_environments =
1700 my_environments.into_iter().merge_by(other_environments, |x, y| x.name <= y.name);
1701 let groups = all_environments.chunk_by(|e| e.name.clone());
1702
1703 let mut merged_environments = vec![];
1704 for (name, group) in groups.into_iter() {
1705 let mut merged_environment = Environment {
1706 name: name.clone(),
1707 extends: None,
1708 runners: None,
1709 resolvers: None,
1710 debug: None,
1711 stop_timeout_ms: None,
1712 };
1713 for e in group {
1714 merged_environment.merge_from(e)?;
1715 }
1716 merged_environments.push(merged_environment);
1717 }
1718
1719 self.environments = Some(merged_environments);
1720 Ok(())
1721 }
1722
1723 fn merge_maps<'s, Source, Dest>(
1724 self_map: &mut Dest,
1725 include_map: Source,
1726 outer_key: &str,
1727 include_path: &path::Path,
1728 ) -> Result<(), Error>
1729 where
1730 Source: IntoIterator<Item = (&'s String, &'s Value)>,
1731 Dest: ValueMap,
1732 {
1733 Self::merge_maps_with_options(self_map, include_map, outer_key, include_path, None)
1734 }
1735
1736 fn merge_maps_with_options<'s, Source, Dest>(
1741 self_map: &mut Dest,
1742 include_map: Source,
1743 outer_key: &str,
1744 include_path: &path::Path,
1745 allow_array_concatenation_keys: Option<Vec<&str>>,
1746 ) -> Result<(), Error>
1747 where
1748 Source: IntoIterator<Item = (&'s String, &'s Value)>,
1749 Dest: ValueMap,
1750 {
1751 for (key, value) in include_map {
1752 match self_map.get_mut(key) {
1753 None => {
1754 self_map.insert(key.clone(), value.clone());
1756 }
1757 Some(Value::Object(self_nested_map)) => match value {
1759 Value::Object(include_nested_map) => {
1761 let combined_key = format!("{}.{}", outer_key, key);
1762
1763 Self::merge_maps(
1765 self_nested_map,
1766 include_nested_map,
1767 &combined_key,
1768 include_path,
1769 )?;
1770 }
1771 _ => {
1772 return Err(Error::validate(format!(
1774 "manifest include had a conflicting `{}.{}`: {}",
1775 outer_key,
1776 key,
1777 include_path.display()
1778 )));
1779 }
1780 },
1781 Some(Value::Array(self_nested_vec)) => match value {
1782 Value::Array(include_nested_vec) => {
1785 if let Some(allowed_keys) = &allow_array_concatenation_keys {
1786 if !allowed_keys.contains(&key.as_str()) {
1787 return Err(Error::validate(format!(
1790 "manifest include had a conflicting `{}.{}`: {}",
1791 outer_key,
1792 key,
1793 include_path.display()
1794 )));
1795 }
1796 }
1797 let mut new_values = include_nested_vec.clone();
1798 self_nested_vec.append(&mut new_values);
1799 }
1800 _ => {
1801 return Err(Error::validate(format!(
1803 "manifest include had a conflicting `{}.{}`: {}",
1804 outer_key,
1805 key,
1806 include_path.display()
1807 )));
1808 }
1809 },
1810 _ => {
1811 return Err(Error::validate(format!(
1813 "manifest include had a conflicting `{}.{}`: {}",
1814 outer_key,
1815 key,
1816 include_path.display()
1817 )));
1818 }
1819 }
1820 }
1821 Ok(())
1822 }
1823
1824 fn merge_facets(
1825 &mut self,
1826 other: &mut Document,
1827 include_path: &path::Path,
1828 ) -> Result<(), Error> {
1829 if let None = other.facets {
1830 return Ok(());
1831 }
1832 if let None = self.facets {
1833 self.facets = Some(Default::default());
1834 }
1835 let my_facets = self.facets.as_mut().unwrap();
1836 let other_facets = other.facets.as_ref().unwrap();
1837
1838 Self::merge_maps(my_facets, other_facets, "facets", include_path)
1839 }
1840
1841 fn merge_config(
1842 &mut self,
1843 other: &mut Document,
1844 include_path: &path::Path,
1845 ) -> Result<(), Error> {
1846 if let Some(other_config) = other.config.as_mut() {
1847 if let Some(self_config) = self.config.as_mut() {
1848 for (key, field) in other_config {
1849 match self_config.entry(key.clone()) {
1850 std::collections::btree_map::Entry::Vacant(v) => {
1851 v.insert(field.clone());
1852 }
1853 std::collections::btree_map::Entry::Occupied(o) => {
1854 if o.get() != field {
1855 let msg = format!(
1856 "Found conflicting entry for config key `{key}` in `{}`.",
1857 include_path.display()
1858 );
1859 return Err(Error::validate(&msg));
1860 }
1861 }
1862 }
1863 }
1864 } else {
1865 self.config.replace(std::mem::take(other_config));
1866 }
1867 }
1868 Ok(())
1869 }
1870
1871 pub fn includes(&self) -> Vec<String> {
1872 self.include.clone().unwrap_or_default()
1873 }
1874
1875 pub fn all_children_names(&self) -> Vec<&BorrowedName> {
1876 if let Some(children) = self.children.as_ref() {
1877 children.iter().map(|c| c.name.as_ref()).collect()
1878 } else {
1879 vec![]
1880 }
1881 }
1882
1883 pub fn all_collection_names(&self) -> Vec<&BorrowedName> {
1884 if let Some(collections) = self.collections.as_ref() {
1885 collections.iter().map(|c| c.name.as_ref()).collect()
1886 } else {
1887 vec![]
1888 }
1889 }
1890
1891 pub fn all_storage_names(&self) -> Vec<&BorrowedName> {
1892 if let Some(capabilities) = self.capabilities.as_ref() {
1893 capabilities.iter().filter_map(|c| c.storage.as_ref().map(|n| n.as_ref())).collect()
1894 } else {
1895 vec![]
1896 }
1897 }
1898
1899 pub fn all_storage_with_sources<'a>(
1900 &'a self,
1901 ) -> HashMap<&'a BorrowedName, &'a CapabilityFromRef> {
1902 if let Some(capabilities) = self.capabilities.as_ref() {
1903 capabilities
1904 .iter()
1905 .filter_map(|c| match (c.storage.as_ref().map(Name::as_ref), c.from.as_ref()) {
1906 (Some(s), Some(f)) => Some((s, f)),
1907 _ => None,
1908 })
1909 .collect()
1910 } else {
1911 HashMap::new()
1912 }
1913 }
1914
1915 pub fn all_service_names(&self) -> Vec<&BorrowedName> {
1916 self.capabilities
1917 .as_ref()
1918 .map(|c| {
1919 c.iter()
1920 .filter_map(|c| c.service.as_ref().map(|o| o.as_ref()))
1921 .map(|p| p.into_iter())
1922 .flatten()
1923 .collect()
1924 })
1925 .unwrap_or_else(|| vec![])
1926 }
1927
1928 pub fn all_protocol_names(&self) -> Vec<&BorrowedName> {
1929 self.capabilities
1930 .as_ref()
1931 .map(|c| {
1932 c.iter()
1933 .filter_map(|c| c.protocol.as_ref().map(|o| o.as_ref()))
1934 .map(|p| p.into_iter())
1935 .flatten()
1936 .collect()
1937 })
1938 .unwrap_or_else(|| vec![])
1939 }
1940
1941 pub fn all_directory_names(&self) -> Vec<&BorrowedName> {
1942 self.capabilities
1943 .as_ref()
1944 .map(|c| c.iter().filter_map(|c| c.directory.as_ref().map(Name::as_ref)).collect())
1945 .unwrap_or_else(|| vec![])
1946 }
1947
1948 pub fn all_runner_names(&self) -> Vec<&BorrowedName> {
1949 self.capabilities
1950 .as_ref()
1951 .map(|c| c.iter().filter_map(|c| c.runner.as_ref().map(Name::as_ref)).collect())
1952 .unwrap_or_else(|| vec![])
1953 }
1954
1955 pub fn all_resolver_names(&self) -> Vec<&BorrowedName> {
1956 self.capabilities
1957 .as_ref()
1958 .map(|c| c.iter().filter_map(|c| c.resolver.as_ref().map(Name::as_ref)).collect())
1959 .unwrap_or_else(|| vec![])
1960 }
1961
1962 pub fn all_dictionary_names(&self) -> Vec<&BorrowedName> {
1963 if let Some(capabilities) = self.capabilities.as_ref() {
1964 capabilities.iter().filter_map(|c| c.dictionary.as_ref().map(Name::as_ref)).collect()
1965 } else {
1966 vec![]
1967 }
1968 }
1969
1970 pub fn all_dictionaries<'a>(&'a self) -> HashMap<&'a BorrowedName, &'a Capability> {
1971 if let Some(capabilities) = self.capabilities.as_ref() {
1972 capabilities
1973 .iter()
1974 .filter_map(|c| match c.dictionary.as_ref().map(Name::as_ref) {
1975 Some(s) => Some((s, c)),
1976 _ => None,
1977 })
1978 .collect()
1979 } else {
1980 HashMap::new()
1981 }
1982 }
1983
1984 pub fn all_config_names(&self) -> Vec<&BorrowedName> {
1985 self.capabilities
1986 .as_ref()
1987 .map(|c| c.iter().filter_map(|c| c.config.as_ref().map(Name::as_ref)).collect())
1988 .unwrap_or_else(|| vec![])
1989 }
1990
1991 pub fn all_environment_names(&self) -> Vec<&BorrowedName> {
1992 self.environments
1993 .as_ref()
1994 .map(|c| c.iter().map(|s| s.name.as_ref()).collect())
1995 .unwrap_or_else(|| vec![])
1996 }
1997
1998 pub fn all_capability_names(&self) -> HashSet<&BorrowedName> {
1999 self.capabilities
2000 .as_ref()
2001 .map(|c| {
2002 c.iter().fold(HashSet::new(), |mut acc, capability| {
2003 acc.extend(capability.names());
2004 acc
2005 })
2006 })
2007 .unwrap_or_default()
2008 }
2009}
2010
2011trait ValueMap {
2013 fn get_mut(&mut self, key: &str) -> Option<&mut Value>;
2014 fn insert(&mut self, key: String, val: Value);
2015}
2016
2017impl ValueMap for Map<String, Value> {
2018 fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
2019 self.get_mut(key)
2020 }
2021
2022 fn insert(&mut self, key: String, val: Value) {
2023 self.insert(key, val);
2024 }
2025}
2026
2027impl ValueMap for IndexMap<String, Value> {
2028 fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
2029 self.get_mut(key)
2030 }
2031
2032 fn insert(&mut self, key: String, val: Value) {
2033 self.insert(key, val);
2034 }
2035}
2036
2037#[derive(Deserialize, Debug, PartialEq, Serialize)]
2038#[serde(rename_all = "lowercase")]
2039pub enum EnvironmentExtends {
2040 Realm,
2041 None,
2042}
2043
2044#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
2068#[serde(deny_unknown_fields)]
2069#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
2070pub struct Environment {
2071 pub name: Name,
2075
2076 #[serde(skip_serializing_if = "Option::is_none")]
2080 pub extends: Option<EnvironmentExtends>,
2081
2082 #[reference_doc(recurse)]
2085 #[serde(skip_serializing_if = "Option::is_none")]
2086 pub runners: Option<Vec<RunnerRegistration>>,
2087
2088 #[reference_doc(recurse)]
2091 #[serde(skip_serializing_if = "Option::is_none")]
2092 pub resolvers: Option<Vec<ResolverRegistration>>,
2093
2094 #[reference_doc(recurse)]
2097 #[serde(skip_serializing_if = "Option::is_none")]
2098 pub debug: Option<Vec<DebugRegistration>>,
2099
2100 #[serde(rename = "__stop_timeout_ms")]
2104 #[reference_doc(json_type = "number", rename = "__stop_timeout_ms")]
2105 #[serde(skip_serializing_if = "Option::is_none")]
2106 pub stop_timeout_ms: Option<StopTimeoutMs>,
2107}
2108
2109impl Environment {
2110 pub fn merge_from(&mut self, other: &mut Self) -> Result<(), Error> {
2111 if self.extends.is_none() {
2112 self.extends = other.extends.take();
2113 } else if other.extends.is_some() && other.extends != self.extends {
2114 return Err(Error::validate(
2115 "cannot merge `environments` that declare conflicting `extends`",
2116 ));
2117 }
2118
2119 if self.stop_timeout_ms.is_none() {
2120 self.stop_timeout_ms = other.stop_timeout_ms;
2121 } else if other.stop_timeout_ms.is_some() && other.stop_timeout_ms != self.stop_timeout_ms {
2122 return Err(Error::validate(
2123 "cannot merge `environments` that declare conflicting `stop_timeout_ms`",
2124 ));
2125 }
2126
2127 match &mut self.runners {
2130 Some(r) => {
2131 if let Some(o) = &mut other.runners {
2132 r.append(o);
2133 }
2134 }
2135 None => self.runners = other.runners.take(),
2136 }
2137
2138 match &mut self.resolvers {
2139 Some(r) => {
2140 if let Some(o) = &mut other.resolvers {
2141 r.append(o);
2142 }
2143 }
2144 None => self.resolvers = other.resolvers.take(),
2145 }
2146
2147 match &mut self.debug {
2148 Some(r) => {
2149 if let Some(o) = &mut other.debug {
2150 r.append(o);
2151 }
2152 }
2153 None => self.debug = other.debug.take(),
2154 }
2155 Ok(())
2156 }
2157}
2158
2159#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
2160#[serde(rename_all = "snake_case")]
2161pub enum ConfigType {
2162 Bool,
2163 Uint8,
2164 Uint16,
2165 Uint32,
2166 Uint64,
2167 Int8,
2168 Int16,
2169 Int32,
2170 Int64,
2171 String,
2172 Vector,
2173}
2174
2175impl From<&cm_rust::ConfigValueType> for ConfigType {
2176 fn from(value: &cm_rust::ConfigValueType) -> Self {
2177 match value {
2178 cm_rust::ConfigValueType::Bool => ConfigType::Bool,
2179 cm_rust::ConfigValueType::Uint8 => ConfigType::Uint8,
2180 cm_rust::ConfigValueType::Int8 => ConfigType::Int8,
2181 cm_rust::ConfigValueType::Uint16 => ConfigType::Uint16,
2182 cm_rust::ConfigValueType::Int16 => ConfigType::Int16,
2183 cm_rust::ConfigValueType::Uint32 => ConfigType::Uint32,
2184 cm_rust::ConfigValueType::Int32 => ConfigType::Int32,
2185 cm_rust::ConfigValueType::Uint64 => ConfigType::Uint64,
2186 cm_rust::ConfigValueType::Int64 => ConfigType::Int64,
2187 cm_rust::ConfigValueType::String { .. } => ConfigType::String,
2188 cm_rust::ConfigValueType::Vector { .. } => ConfigType::Vector,
2189 }
2190 }
2191}
2192
2193#[derive(Clone, Hash, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize)]
2194pub struct ConfigKey(String);
2195
2196impl ConfigKey {
2197 pub fn as_str(&self) -> &str {
2198 self.0.as_str()
2199 }
2200}
2201
2202impl std::fmt::Display for ConfigKey {
2203 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2204 write!(f, "{}", self.0)
2205 }
2206}
2207
2208impl FromStr for ConfigKey {
2209 type Err = ParseError;
2210
2211 fn from_str(s: &str) -> Result<Self, ParseError> {
2212 let length = s.len();
2213 if length == 0 {
2214 return Err(ParseError::Empty);
2215 }
2216 if length > 64 {
2217 return Err(ParseError::TooLong);
2218 }
2219
2220 let first_is_letter = s.chars().next().expect("non-empty string").is_ascii_lowercase();
2222 let contains_invalid_chars =
2224 s.chars().any(|c| !(c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_'));
2225 let last_is_underscore = s.chars().next_back().expect("non-empty string") == '_';
2227
2228 if !first_is_letter || contains_invalid_chars || last_is_underscore {
2229 return Err(ParseError::InvalidValue);
2230 }
2231
2232 Ok(Self(s.to_string()))
2233 }
2234}
2235
2236impl<'de> de::Deserialize<'de> for ConfigKey {
2237 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2238 where
2239 D: de::Deserializer<'de>,
2240 {
2241 struct Visitor;
2242
2243 impl<'de> de::Visitor<'de> for Visitor {
2244 type Value = ConfigKey;
2245
2246 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2247 f.write_str(
2248 "a non-empty string no more than 64 characters in length, which must \
2249 start with a letter, can contain letters, numbers, and underscores, \
2250 but cannot end with an underscore",
2251 )
2252 }
2253
2254 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
2255 where
2256 E: de::Error,
2257 {
2258 s.parse().map_err(|err| match err {
2259 ParseError::InvalidValue => E::invalid_value(
2260 de::Unexpected::Str(s),
2261 &"a name which must start with a letter, can contain letters, \
2262 numbers, and underscores, but cannot end with an underscore",
2263 ),
2264 ParseError::TooLong | ParseError::Empty => E::invalid_length(
2265 s.len(),
2266 &"a non-empty name no more than 64 characters in length",
2267 ),
2268 e => {
2269 panic!("unexpected parse error: {:?}", e);
2270 }
2271 })
2272 }
2273 }
2274 deserializer.deserialize_string(Visitor)
2275 }
2276}
2277
2278#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
2279#[serde(deny_unknown_fields, rename_all = "lowercase")]
2280pub enum ConfigRuntimeSource {
2281 Parent,
2282}
2283
2284#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
2285#[serde(tag = "type", deny_unknown_fields, rename_all = "lowercase")]
2286pub enum ConfigValueType {
2287 Bool {
2288 mutability: Option<Vec<ConfigRuntimeSource>>,
2289 },
2290 Uint8 {
2291 mutability: Option<Vec<ConfigRuntimeSource>>,
2292 },
2293 Uint16 {
2294 mutability: Option<Vec<ConfigRuntimeSource>>,
2295 },
2296 Uint32 {
2297 mutability: Option<Vec<ConfigRuntimeSource>>,
2298 },
2299 Uint64 {
2300 mutability: Option<Vec<ConfigRuntimeSource>>,
2301 },
2302 Int8 {
2303 mutability: Option<Vec<ConfigRuntimeSource>>,
2304 },
2305 Int16 {
2306 mutability: Option<Vec<ConfigRuntimeSource>>,
2307 },
2308 Int32 {
2309 mutability: Option<Vec<ConfigRuntimeSource>>,
2310 },
2311 Int64 {
2312 mutability: Option<Vec<ConfigRuntimeSource>>,
2313 },
2314 String {
2315 max_size: NonZeroU32,
2316 mutability: Option<Vec<ConfigRuntimeSource>>,
2317 },
2318 Vector {
2319 max_count: NonZeroU32,
2320 element: ConfigNestedValueType,
2321 mutability: Option<Vec<ConfigRuntimeSource>>,
2322 },
2323}
2324
2325impl ConfigValueType {
2326 pub fn update_digest(&self, hasher: &mut impl sha2::Digest) {
2328 let val = match self {
2329 ConfigValueType::Bool { .. } => 0u8,
2330 ConfigValueType::Uint8 { .. } => 1u8,
2331 ConfigValueType::Uint16 { .. } => 2u8,
2332 ConfigValueType::Uint32 { .. } => 3u8,
2333 ConfigValueType::Uint64 { .. } => 4u8,
2334 ConfigValueType::Int8 { .. } => 5u8,
2335 ConfigValueType::Int16 { .. } => 6u8,
2336 ConfigValueType::Int32 { .. } => 7u8,
2337 ConfigValueType::Int64 { .. } => 8u8,
2338 ConfigValueType::String { max_size, .. } => {
2339 hasher.update(max_size.get().to_le_bytes());
2340 9u8
2341 }
2342 ConfigValueType::Vector { max_count, element, .. } => {
2343 hasher.update(max_count.get().to_le_bytes());
2344 element.update_digest(hasher);
2345 10u8
2346 }
2347 };
2348 hasher.update([val])
2349 }
2350}
2351
2352impl From<ConfigValueType> for cm_rust::ConfigValueType {
2353 fn from(value: ConfigValueType) -> Self {
2354 match value {
2355 ConfigValueType::Bool { .. } => cm_rust::ConfigValueType::Bool,
2356 ConfigValueType::Uint8 { .. } => cm_rust::ConfigValueType::Uint8,
2357 ConfigValueType::Uint16 { .. } => cm_rust::ConfigValueType::Uint16,
2358 ConfigValueType::Uint32 { .. } => cm_rust::ConfigValueType::Uint32,
2359 ConfigValueType::Uint64 { .. } => cm_rust::ConfigValueType::Uint64,
2360 ConfigValueType::Int8 { .. } => cm_rust::ConfigValueType::Int8,
2361 ConfigValueType::Int16 { .. } => cm_rust::ConfigValueType::Int16,
2362 ConfigValueType::Int32 { .. } => cm_rust::ConfigValueType::Int32,
2363 ConfigValueType::Int64 { .. } => cm_rust::ConfigValueType::Int64,
2364 ConfigValueType::String { max_size, .. } => {
2365 cm_rust::ConfigValueType::String { max_size: max_size.into() }
2366 }
2367 ConfigValueType::Vector { max_count, element, .. } => {
2368 cm_rust::ConfigValueType::Vector {
2369 max_count: max_count.into(),
2370 nested_type: element.into(),
2371 }
2372 }
2373 }
2374 }
2375}
2376
2377#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
2378#[serde(tag = "type", deny_unknown_fields, rename_all = "lowercase")]
2379pub enum ConfigNestedValueType {
2380 Bool {},
2381 Uint8 {},
2382 Uint16 {},
2383 Uint32 {},
2384 Uint64 {},
2385 Int8 {},
2386 Int16 {},
2387 Int32 {},
2388 Int64 {},
2389 String { max_size: NonZeroU32 },
2390}
2391
2392impl ConfigNestedValueType {
2393 pub fn update_digest(&self, hasher: &mut impl sha2::Digest) {
2395 let val = match self {
2396 ConfigNestedValueType::Bool {} => 0u8,
2397 ConfigNestedValueType::Uint8 {} => 1u8,
2398 ConfigNestedValueType::Uint16 {} => 2u8,
2399 ConfigNestedValueType::Uint32 {} => 3u8,
2400 ConfigNestedValueType::Uint64 {} => 4u8,
2401 ConfigNestedValueType::Int8 {} => 5u8,
2402 ConfigNestedValueType::Int16 {} => 6u8,
2403 ConfigNestedValueType::Int32 {} => 7u8,
2404 ConfigNestedValueType::Int64 {} => 8u8,
2405 ConfigNestedValueType::String { max_size } => {
2406 hasher.update(max_size.get().to_le_bytes());
2407 9u8
2408 }
2409 };
2410 hasher.update([val])
2411 }
2412}
2413
2414impl From<ConfigNestedValueType> for cm_rust::ConfigNestedValueType {
2415 fn from(value: ConfigNestedValueType) -> Self {
2416 match value {
2417 ConfigNestedValueType::Bool {} => cm_rust::ConfigNestedValueType::Bool,
2418 ConfigNestedValueType::Uint8 {} => cm_rust::ConfigNestedValueType::Uint8,
2419 ConfigNestedValueType::Uint16 {} => cm_rust::ConfigNestedValueType::Uint16,
2420 ConfigNestedValueType::Uint32 {} => cm_rust::ConfigNestedValueType::Uint32,
2421 ConfigNestedValueType::Uint64 {} => cm_rust::ConfigNestedValueType::Uint64,
2422 ConfigNestedValueType::Int8 {} => cm_rust::ConfigNestedValueType::Int8,
2423 ConfigNestedValueType::Int16 {} => cm_rust::ConfigNestedValueType::Int16,
2424 ConfigNestedValueType::Int32 {} => cm_rust::ConfigNestedValueType::Int32,
2425 ConfigNestedValueType::Int64 {} => cm_rust::ConfigNestedValueType::Int64,
2426 ConfigNestedValueType::String { max_size } => {
2427 cm_rust::ConfigNestedValueType::String { max_size: max_size.into() }
2428 }
2429 }
2430 }
2431}
2432
2433impl TryFrom<&cm_rust::ConfigNestedValueType> for ConfigNestedValueType {
2434 type Error = ();
2435 fn try_from(nested: &cm_rust::ConfigNestedValueType) -> Result<Self, ()> {
2436 Ok(match nested {
2437 cm_rust::ConfigNestedValueType::Bool => ConfigNestedValueType::Bool {},
2438 cm_rust::ConfigNestedValueType::Uint8 => ConfigNestedValueType::Uint8 {},
2439 cm_rust::ConfigNestedValueType::Int8 => ConfigNestedValueType::Int8 {},
2440 cm_rust::ConfigNestedValueType::Uint16 => ConfigNestedValueType::Uint16 {},
2441 cm_rust::ConfigNestedValueType::Int16 => ConfigNestedValueType::Int16 {},
2442 cm_rust::ConfigNestedValueType::Uint32 => ConfigNestedValueType::Uint32 {},
2443 cm_rust::ConfigNestedValueType::Int32 => ConfigNestedValueType::Int32 {},
2444 cm_rust::ConfigNestedValueType::Uint64 => ConfigNestedValueType::Uint64 {},
2445 cm_rust::ConfigNestedValueType::Int64 => ConfigNestedValueType::Int64 {},
2446 cm_rust::ConfigNestedValueType::String { max_size } => {
2447 ConfigNestedValueType::String { max_size: NonZeroU32::new(*max_size).ok_or(())? }
2448 }
2449 })
2450 }
2451}
2452
2453#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
2454#[serde(deny_unknown_fields)]
2455#[reference_doc(fields_as = "list")]
2456pub struct RunnerRegistration {
2457 pub runner: Name,
2459
2460 pub from: RegistrationRef,
2466
2467 #[serde(skip_serializing_if = "Option::is_none")]
2470 pub r#as: Option<Name>,
2471}
2472
2473#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
2474#[serde(deny_unknown_fields)]
2475#[reference_doc(fields_as = "list")]
2476pub struct ResolverRegistration {
2477 pub resolver: Name,
2480
2481 pub from: RegistrationRef,
2487
2488 pub scheme: cm_types::UrlScheme,
2491}
2492
2493#[derive(Deserialize, Debug, PartialEq, Clone, ReferenceDoc, Serialize, Default)]
2494#[serde(deny_unknown_fields)]
2495#[reference_doc(fields_as = "list")]
2496pub struct Capability {
2497 #[serde(skip_serializing_if = "Option::is_none")]
2500 #[reference_doc(skip = true)]
2501 pub service: Option<OneOrMany<Name>>,
2502
2503 #[serde(skip_serializing_if = "Option::is_none")]
2506 #[reference_doc(skip = true)]
2507 pub protocol: Option<OneOrMany<Name>>,
2508
2509 #[serde(skip_serializing_if = "Option::is_none")]
2511 #[reference_doc(skip = true)]
2512 pub directory: Option<Name>,
2513
2514 #[serde(skip_serializing_if = "Option::is_none")]
2516 #[reference_doc(skip = true)]
2517 pub storage: Option<Name>,
2518
2519 #[serde(skip_serializing_if = "Option::is_none")]
2521 #[reference_doc(skip = true)]
2522 pub runner: Option<Name>,
2523
2524 #[serde(skip_serializing_if = "Option::is_none")]
2526 #[reference_doc(skip = true)]
2527 pub resolver: Option<Name>,
2528
2529 #[serde(skip_serializing_if = "Option::is_none")]
2531 #[reference_doc(skip = true)]
2532 pub event_stream: Option<OneOrMany<Name>>,
2533
2534 #[serde(skip_serializing_if = "Option::is_none")]
2536 #[reference_doc(skip = true)]
2537 pub dictionary: Option<Name>,
2538
2539 #[serde(skip_serializing_if = "Option::is_none")]
2541 #[reference_doc(skip = true)]
2542 pub config: Option<Name>,
2543
2544 #[serde(skip_serializing_if = "Option::is_none")]
2566 pub path: Option<Path>,
2567
2568 #[serde(skip_serializing_if = "Option::is_none")]
2571 #[reference_doc(json_type = "array of string")]
2572 pub rights: Option<Rights>,
2573
2574 #[serde(skip_serializing_if = "Option::is_none")]
2581 pub from: Option<CapabilityFromRef>,
2582
2583 #[serde(skip_serializing_if = "Option::is_none")]
2586 pub backing_dir: Option<Name>,
2587
2588 #[serde(skip_serializing_if = "Option::is_none")]
2591 pub subdir: Option<RelativePath>,
2592
2593 #[serde(skip_serializing_if = "Option::is_none")]
2602 pub storage_id: Option<StorageId>,
2603
2604 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
2617 #[reference_doc(rename = "type")]
2618 pub config_type: Option<ConfigType>,
2619
2620 #[serde(rename = "max_size", skip_serializing_if = "Option::is_none")]
2623 #[reference_doc(rename = "max_size")]
2624 pub config_max_size: Option<NonZeroU32>,
2625
2626 #[serde(rename = "max_count", skip_serializing_if = "Option::is_none")]
2629 #[reference_doc(rename = "max_count")]
2630 pub config_max_count: Option<NonZeroU32>,
2631
2632 #[serde(rename = "element", skip_serializing_if = "Option::is_none")]
2650 #[reference_doc(rename = "element", json_type = "object")]
2651 pub config_element_type: Option<ConfigNestedValueType>,
2652
2653 #[serde(skip_serializing_if = "Option::is_none")]
2655 pub value: Option<serde_json::Value>,
2656
2657 #[serde(skip_serializing_if = "Option::is_none")]
2667 pub delivery: Option<DeliveryType>,
2668}
2669
2670#[derive(Deserialize, Debug, Clone, PartialEq, ReferenceDoc, Serialize)]
2671#[serde(deny_unknown_fields)]
2672#[reference_doc(fields_as = "list")]
2673pub struct DebugRegistration {
2674 pub protocol: Option<OneOrMany<Name>>,
2676
2677 pub from: OfferFromRef,
2683
2684 #[serde(skip_serializing_if = "Option::is_none")]
2687 pub r#as: Option<Name>,
2688}
2689
2690#[derive(Debug, PartialEq, Default, Serialize)]
2691pub struct Program {
2692 #[serde(skip_serializing_if = "Option::is_none")]
2693 pub runner: Option<Name>,
2694 #[serde(flatten)]
2695 pub info: IndexMap<String, Value>,
2696}
2697
2698impl<'de> de::Deserialize<'de> for Program {
2699 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2700 where
2701 D: de::Deserializer<'de>,
2702 {
2703 struct Visitor;
2704
2705 const EXPECTED_PROGRAM: &'static str =
2706 "a JSON object that includes a `runner` string property";
2707 const EXPECTED_RUNNER: &'static str =
2708 "a non-empty `runner` string property no more than 255 characters in length \
2709 that consists of [A-Za-z0-9_.-] and starts with [A-Za-z0-9_]";
2710
2711 impl<'de> de::Visitor<'de> for Visitor {
2712 type Value = Program;
2713
2714 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2715 f.write_str(EXPECTED_PROGRAM)
2716 }
2717
2718 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
2719 where
2720 A: de::MapAccess<'de>,
2721 {
2722 let mut info = IndexMap::new();
2723 let mut runner = None;
2724 while let Some(e) = map.next_entry::<String, Value>()? {
2725 let (k, v) = e;
2726 if &k == "runner" {
2727 if let Value::String(s) = v {
2728 runner = Some(s);
2729 } else {
2730 return Err(de::Error::invalid_value(
2731 de::Unexpected::Map,
2732 &EXPECTED_RUNNER,
2733 ));
2734 }
2735 } else {
2736 info.insert(k, v);
2737 }
2738 }
2739 let runner = runner
2740 .map(|r| {
2741 Name::new(r.clone()).map_err(|e| match e {
2742 ParseError::InvalidValue => de::Error::invalid_value(
2743 serde::de::Unexpected::Str(&r),
2744 &EXPECTED_RUNNER,
2745 ),
2746 ParseError::TooLong | ParseError::Empty => {
2747 de::Error::invalid_length(r.len(), &EXPECTED_RUNNER)
2748 }
2749 _ => {
2750 panic!("unexpected parse error: {:?}", e);
2751 }
2752 })
2753 })
2754 .transpose()?;
2755 Ok(Program { runner, info })
2756 }
2757 }
2758
2759 deserializer.deserialize_map(Visitor)
2760 }
2761}
2762
2763#[derive(Deserialize, Debug, Default, PartialEq, Clone, ReferenceDoc, Serialize)]
2796#[serde(deny_unknown_fields)]
2797#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
2798pub struct Use {
2799 #[serde(skip_serializing_if = "Option::is_none")]
2801 #[reference_doc(skip = true)]
2802 pub service: Option<OneOrMany<Name>>,
2803
2804 #[serde(skip_serializing_if = "Option::is_none")]
2806 #[reference_doc(skip = true)]
2807 pub protocol: Option<OneOrMany<Name>>,
2808
2809 #[serde(skip_serializing_if = "Option::is_none")]
2811 #[reference_doc(skip = true)]
2812 pub directory: Option<Name>,
2813
2814 #[serde(skip_serializing_if = "Option::is_none")]
2816 #[reference_doc(skip = true)]
2817 pub storage: Option<Name>,
2818
2819 #[serde(skip_serializing_if = "Option::is_none")]
2821 #[reference_doc(skip = true)]
2822 pub event_stream: Option<OneOrMany<Name>>,
2823
2824 #[serde(skip_serializing_if = "Option::is_none")]
2826 #[reference_doc(skip = true)]
2827 pub runner: Option<Name>,
2828
2829 #[serde(skip_serializing_if = "Option::is_none")]
2831 #[reference_doc(skip = true)]
2832 pub config: Option<Name>,
2833
2834 #[serde(skip_serializing_if = "Option::is_none")]
2847 pub from: Option<UseFromRef>,
2848
2849 #[serde(skip_serializing_if = "Option::is_none")]
2853 pub path: Option<Path>,
2854
2855 #[serde(skip_serializing_if = "Option::is_none")]
2858 #[reference_doc(json_type = "array of string")]
2859 pub rights: Option<Rights>,
2860
2861 #[serde(skip_serializing_if = "Option::is_none")]
2864 pub subdir: Option<RelativePath>,
2865
2866 #[serde(skip_serializing_if = "Option::is_none")]
2869 pub scope: Option<OneOrMany<EventScope>>,
2870
2871 #[serde(skip_serializing_if = "Option::is_none")]
2875 pub filter: Option<Map<String, Value>>,
2876
2877 #[serde(skip_serializing_if = "Option::is_none")]
2887 pub dependency: Option<DependencyType>,
2888
2889 #[serde(skip_serializing_if = "Option::is_none")]
2903 pub availability: Option<Availability>,
2904
2905 #[serde(skip_serializing_if = "Option::is_none")]
2908 pub key: Option<Name>,
2909
2910 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
2923 #[reference_doc(rename = "type")]
2924 pub config_type: Option<ConfigType>,
2925
2926 #[serde(rename = "max_size", skip_serializing_if = "Option::is_none")]
2929 #[reference_doc(rename = "max_size")]
2930 pub config_max_size: Option<NonZeroU32>,
2931
2932 #[serde(rename = "max_count", skip_serializing_if = "Option::is_none")]
2935 #[reference_doc(rename = "max_count")]
2936 pub config_max_count: Option<NonZeroU32>,
2937
2938 #[serde(rename = "element", skip_serializing_if = "Option::is_none")]
2956 #[reference_doc(rename = "element", json_type = "object")]
2957 pub config_element_type: Option<ConfigNestedValueType>,
2958
2959 #[serde(rename = "default", skip_serializing_if = "Option::is_none")]
2963 #[reference_doc(rename = "default")]
2964 pub config_default: Option<serde_json::Value>,
2965}
2966
2967#[derive(Deserialize, Debug, PartialEq, Clone, ReferenceDoc, Serialize)]
2999#[serde(deny_unknown_fields)]
3000#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
3001pub struct Expose {
3002 #[serde(skip_serializing_if = "Option::is_none")]
3004 #[reference_doc(skip = true)]
3005 pub service: Option<OneOrMany<Name>>,
3006
3007 #[serde(skip_serializing_if = "Option::is_none")]
3009 #[reference_doc(skip = true)]
3010 pub protocol: Option<OneOrMany<Name>>,
3011
3012 #[serde(skip_serializing_if = "Option::is_none")]
3014 #[reference_doc(skip = true)]
3015 pub directory: Option<OneOrMany<Name>>,
3016
3017 #[serde(skip_serializing_if = "Option::is_none")]
3019 #[reference_doc(skip = true)]
3020 pub runner: Option<OneOrMany<Name>>,
3021
3022 #[serde(skip_serializing_if = "Option::is_none")]
3024 #[reference_doc(skip = true)]
3025 pub resolver: Option<OneOrMany<Name>>,
3026
3027 #[serde(skip_serializing_if = "Option::is_none")]
3029 #[reference_doc(skip = true)]
3030 pub dictionary: Option<OneOrMany<Name>>,
3031
3032 #[serde(skip_serializing_if = "Option::is_none")]
3034 #[reference_doc(skip = true)]
3035 pub config: Option<OneOrMany<Name>>,
3036
3037 pub from: OneOrMany<ExposeFromRef>,
3044
3045 #[serde(skip_serializing_if = "Option::is_none")]
3049 pub r#as: Option<Name>,
3050
3051 #[serde(skip_serializing_if = "Option::is_none")]
3053 pub to: Option<ExposeToRef>,
3054
3055 #[serde(skip_serializing_if = "Option::is_none")]
3058 #[reference_doc(json_type = "array of string")]
3059 pub rights: Option<Rights>,
3060
3061 #[serde(skip_serializing_if = "Option::is_none")]
3064 pub subdir: Option<RelativePath>,
3065
3066 #[serde(skip_serializing_if = "Option::is_none")]
3068 pub event_stream: Option<OneOrMany<Name>>,
3069
3070 #[serde(skip_serializing_if = "Option::is_none")]
3074 pub scope: Option<OneOrMany<EventScope>>,
3075
3076 #[serde(skip_serializing_if = "Option::is_none")]
3093 pub availability: Option<Availability>,
3094
3095 #[serde(skip_serializing_if = "Option::is_none")]
3100 pub source_availability: Option<SourceAvailability>,
3101}
3102
3103impl Expose {
3104 pub fn new_from(from: OneOrMany<ExposeFromRef>) -> Self {
3105 Self {
3106 from,
3107 service: None,
3108 protocol: None,
3109 directory: None,
3110 config: None,
3111 runner: None,
3112 resolver: None,
3113 dictionary: None,
3114 r#as: None,
3115 to: None,
3116 rights: None,
3117 subdir: None,
3118 event_stream: None,
3119 scope: None,
3120 availability: None,
3121 source_availability: None,
3122 }
3123 }
3124}
3125
3126#[derive(Deserialize, Debug, PartialEq, Clone, ReferenceDoc, Serialize)]
3179#[serde(deny_unknown_fields)]
3180#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
3181pub struct Offer {
3182 #[serde(skip_serializing_if = "Option::is_none")]
3184 pub service: Option<OneOrMany<Name>>,
3185
3186 #[serde(skip_serializing_if = "Option::is_none")]
3188 pub protocol: Option<OneOrMany<Name>>,
3189
3190 #[serde(skip_serializing_if = "Option::is_none")]
3192 pub directory: Option<OneOrMany<Name>>,
3193
3194 #[serde(skip_serializing_if = "Option::is_none")]
3196 pub runner: Option<OneOrMany<Name>>,
3197
3198 #[serde(skip_serializing_if = "Option::is_none")]
3200 pub resolver: Option<OneOrMany<Name>>,
3201
3202 #[serde(skip_serializing_if = "Option::is_none")]
3204 pub storage: Option<OneOrMany<Name>>,
3205
3206 #[serde(skip_serializing_if = "Option::is_none")]
3208 pub dictionary: Option<OneOrMany<Name>>,
3209
3210 #[serde(skip_serializing_if = "Option::is_none")]
3212 pub config: Option<OneOrMany<Name>>,
3213
3214 pub from: OneOrMany<OfferFromRef>,
3226
3227 pub to: OneOrMany<OfferToRef>,
3232
3233 #[serde(skip_serializing_if = "Option::is_none")]
3237 pub r#as: Option<Name>,
3238
3239 #[serde(skip_serializing_if = "Option::is_none")]
3249 pub dependency: Option<DependencyType>,
3250
3251 #[serde(skip_serializing_if = "Option::is_none")]
3254 #[reference_doc(json_type = "array of string")]
3255 pub rights: Option<Rights>,
3256
3257 #[serde(skip_serializing_if = "Option::is_none")]
3260 pub subdir: Option<RelativePath>,
3261
3262 #[serde(skip_serializing_if = "Option::is_none")]
3264 pub event_stream: Option<OneOrMany<Name>>,
3265
3266 #[serde(skip_serializing_if = "Option::is_none")]
3269 pub scope: Option<OneOrMany<EventScope>>,
3270
3271 #[serde(skip_serializing_if = "Option::is_none")]
3288 pub availability: Option<Availability>,
3289
3290 #[serde(skip_serializing_if = "Option::is_none")]
3295 pub source_availability: Option<SourceAvailability>,
3296}
3297
3298#[derive(ReferenceDoc, Deserialize, Debug, PartialEq, Serialize)]
3322#[serde(deny_unknown_fields)]
3323#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
3324pub struct Child {
3325 pub name: Name,
3329
3330 pub url: Url,
3332
3333 #[serde(default)]
3339 #[serde(skip_serializing_if = "StartupMode::is_lazy")]
3340 pub startup: StartupMode,
3341
3342 #[serde(skip_serializing_if = "Option::is_none")]
3349 pub on_terminate: Option<OnTerminate>,
3350
3351 #[serde(skip_serializing_if = "Option::is_none")]
3355 pub environment: Option<EnvironmentRef>,
3356}
3357
3358#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
3359#[serde(deny_unknown_fields)]
3360#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
3361pub struct Collection {
3372 pub name: Name,
3376
3377 pub durability: Durability,
3383
3384 pub environment: Option<EnvironmentRef>,
3389
3390 pub allowed_offers: Option<AllowedOffers>,
3397
3398 pub allow_long_names: Option<bool>,
3401
3402 pub persistent_storage: Option<bool>,
3406}
3407
3408pub trait FromClause {
3409 fn from_(&self) -> OneOrMany<AnyRef<'_>>;
3410}
3411
3412pub trait CapabilityClause: Clone + PartialEq + std::fmt::Debug {
3413 fn service(&self) -> Option<OneOrMany<&BorrowedName>>;
3414 fn protocol(&self) -> Option<OneOrMany<&BorrowedName>>;
3415 fn directory(&self) -> Option<OneOrMany<&BorrowedName>>;
3416 fn storage(&self) -> Option<OneOrMany<&BorrowedName>>;
3417 fn runner(&self) -> Option<OneOrMany<&BorrowedName>>;
3418 fn resolver(&self) -> Option<OneOrMany<&BorrowedName>>;
3419 fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>>;
3420 fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>>;
3421 fn config(&self) -> Option<OneOrMany<&BorrowedName>>;
3422 fn set_service(&mut self, o: Option<OneOrMany<Name>>);
3423 fn set_protocol(&mut self, o: Option<OneOrMany<Name>>);
3424 fn set_directory(&mut self, o: Option<OneOrMany<Name>>);
3425 fn set_storage(&mut self, o: Option<OneOrMany<Name>>);
3426 fn set_runner(&mut self, o: Option<OneOrMany<Name>>);
3427 fn set_resolver(&mut self, o: Option<OneOrMany<Name>>);
3428 fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>);
3429 fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>);
3430 fn set_config(&mut self, o: Option<OneOrMany<Name>>);
3431
3432 fn availability(&self) -> Option<Availability>;
3433 fn set_availability(&mut self, a: Option<Availability>);
3434
3435 fn capability_type(&self) -> Result<&'static str, Error> {
3440 let mut types = Vec::new();
3441 if self.service().is_some() {
3442 types.push("service");
3443 }
3444 if self.protocol().is_some() {
3445 types.push("protocol");
3446 }
3447 if self.directory().is_some() {
3448 types.push("directory");
3449 }
3450 if self.storage().is_some() {
3451 types.push("storage");
3452 }
3453 if self.event_stream().is_some() {
3454 types.push("event_stream");
3455 }
3456 if self.runner().is_some() {
3457 types.push("runner");
3458 }
3459 if self.config().is_some() {
3460 types.push("config");
3461 }
3462 if self.resolver().is_some() {
3463 types.push("resolver");
3464 }
3465 if self.dictionary().is_some() {
3466 types.push("dictionary");
3467 }
3468 match types.len() {
3469 0 => {
3470 let supported_keywords = self
3471 .supported()
3472 .into_iter()
3473 .map(|k| format!("\"{}\"", k))
3474 .collect::<Vec<_>>()
3475 .join(", ");
3476 Err(Error::validate(format!(
3477 "`{}` declaration is missing a capability keyword, one of: {}",
3478 self.decl_type(),
3479 supported_keywords,
3480 )))
3481 }
3482 1 => Ok(types[0]),
3483 _ => Err(Error::validate(format!(
3484 "{} declaration has multiple capability types defined: {:?}",
3485 self.decl_type(),
3486 types
3487 ))),
3488 }
3489 }
3490
3491 fn are_many_names_allowed(&self) -> bool;
3493
3494 fn decl_type(&self) -> &'static str;
3495 fn supported(&self) -> &[&'static str];
3496
3497 fn names(&self) -> Vec<&BorrowedName> {
3500 let res = vec![
3501 self.service(),
3502 self.protocol(),
3503 self.directory(),
3504 self.storage(),
3505 self.runner(),
3506 self.config(),
3507 self.resolver(),
3508 self.event_stream(),
3509 self.dictionary(),
3510 ];
3511 res.into_iter()
3512 .map(|o| o.map(|o| o.into_iter().collect::<Vec<&BorrowedName>>()).unwrap_or(vec![]))
3513 .flatten()
3514 .collect()
3515 }
3516
3517 fn set_names(&mut self, names: Vec<Name>) {
3518 let names = match names.len() {
3519 0 => None,
3520 1 => Some(OneOrMany::One(names.first().unwrap().clone())),
3521 _ => Some(OneOrMany::Many(names)),
3522 };
3523
3524 let cap_type = self.capability_type().unwrap();
3525 if cap_type == "protocol" {
3526 self.set_protocol(names);
3527 } else if cap_type == "service" {
3528 self.set_service(names);
3529 } else if cap_type == "directory" {
3530 self.set_directory(names);
3531 } else if cap_type == "storage" {
3532 self.set_storage(names);
3533 } else if cap_type == "runner" {
3534 self.set_runner(names);
3535 } else if cap_type == "resolver" {
3536 self.set_resolver(names);
3537 } else if cap_type == "event_stream" {
3538 self.set_event_stream(names);
3539 } else if cap_type == "dictionary" {
3540 self.set_dictionary(names);
3541 } else if cap_type == "config" {
3542 self.set_config(names);
3543 } else {
3544 panic!("Unknown capability type {}", cap_type);
3545 }
3546 }
3547}
3548
3549trait Canonicalize {
3550 fn canonicalize(&mut self);
3551}
3552
3553pub trait AsClause {
3554 fn r#as(&self) -> Option<&BorrowedName>;
3555}
3556
3557pub trait PathClause {
3558 fn path(&self) -> Option<&Path>;
3559}
3560
3561pub trait FilterClause {
3562 fn filter(&self) -> Option<&Map<String, Value>>;
3563}
3564
3565pub trait RightsClause {
3566 fn rights(&self) -> Option<&Rights>;
3567}
3568
3569fn always_one<T>(o: Option<OneOrMany<T>>) -> Option<T> {
3570 o.map(|o| match o {
3571 OneOrMany::One(o) => o,
3572 OneOrMany::Many(_) => panic!("many is impossible"),
3573 })
3574}
3575
3576impl Canonicalize for Capability {
3577 fn canonicalize(&mut self) {
3578 if let Some(service) = &mut self.service {
3580 service.canonicalize()
3581 } else if let Some(protocol) = &mut self.protocol {
3582 protocol.canonicalize()
3583 } else if let Some(event_stream) = &mut self.event_stream {
3584 event_stream.canonicalize()
3585 }
3586 }
3587}
3588
3589fn option_one_or_many_as_ref<T, S: ?Sized>(o: &Option<OneOrMany<T>>) -> Option<OneOrMany<&S>>
3590where
3591 T: AsRef<S>,
3592{
3593 o.as_ref().map(|o| o.as_ref())
3594}
3595
3596impl CapabilityClause for Capability {
3597 fn service(&self) -> Option<OneOrMany<&BorrowedName>> {
3598 option_one_or_many_as_ref(&self.service)
3599 }
3600 fn protocol(&self) -> Option<OneOrMany<&BorrowedName>> {
3601 option_one_or_many_as_ref(&self.protocol)
3602 }
3603 fn directory(&self) -> Option<OneOrMany<&BorrowedName>> {
3604 self.directory.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3605 }
3606 fn storage(&self) -> Option<OneOrMany<&BorrowedName>> {
3607 self.storage.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3608 }
3609 fn runner(&self) -> Option<OneOrMany<&BorrowedName>> {
3610 self.runner.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3611 }
3612 fn resolver(&self) -> Option<OneOrMany<&BorrowedName>> {
3613 self.resolver.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3614 }
3615 fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>> {
3616 option_one_or_many_as_ref(&self.event_stream)
3617 }
3618 fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>> {
3619 self.dictionary.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3620 }
3621 fn config(&self) -> Option<OneOrMany<&BorrowedName>> {
3622 self.config.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3623 }
3624
3625 fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
3626 self.service = o;
3627 }
3628 fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
3629 self.protocol = o;
3630 }
3631 fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
3632 self.directory = always_one(o);
3633 }
3634 fn set_storage(&mut self, o: Option<OneOrMany<Name>>) {
3635 self.storage = always_one(o);
3636 }
3637 fn set_runner(&mut self, o: Option<OneOrMany<Name>>) {
3638 self.runner = always_one(o);
3639 }
3640 fn set_resolver(&mut self, o: Option<OneOrMany<Name>>) {
3641 self.resolver = always_one(o);
3642 }
3643 fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
3644 self.event_stream = o;
3645 }
3646 fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>) {
3647 self.dictionary = always_one(o);
3648 }
3649
3650 fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
3651 self.config = always_one(o);
3652 }
3653
3654 fn availability(&self) -> Option<Availability> {
3655 None
3656 }
3657 fn set_availability(&mut self, _a: Option<Availability>) {}
3658
3659 fn decl_type(&self) -> &'static str {
3660 "capability"
3661 }
3662 fn supported(&self) -> &[&'static str] {
3663 &[
3664 "service",
3665 "protocol",
3666 "directory",
3667 "storage",
3668 "runner",
3669 "resolver",
3670 "event_stream",
3671 "dictionary",
3672 "config",
3673 ]
3674 }
3675 fn are_many_names_allowed(&self) -> bool {
3676 ["service", "protocol", "event_stream"].contains(&self.capability_type().unwrap())
3677 }
3678}
3679
3680impl AsClause for Capability {
3681 fn r#as(&self) -> Option<&BorrowedName> {
3682 None
3683 }
3684}
3685
3686impl PathClause for Capability {
3687 fn path(&self) -> Option<&Path> {
3688 self.path.as_ref()
3689 }
3690}
3691
3692impl FilterClause for Capability {
3693 fn filter(&self) -> Option<&Map<String, Value>> {
3694 None
3695 }
3696}
3697
3698impl RightsClause for Capability {
3699 fn rights(&self) -> Option<&Rights> {
3700 self.rights.as_ref()
3701 }
3702}
3703
3704impl CapabilityClause for DebugRegistration {
3705 fn service(&self) -> Option<OneOrMany<&BorrowedName>> {
3706 None
3707 }
3708 fn protocol(&self) -> Option<OneOrMany<&BorrowedName>> {
3709 option_one_or_many_as_ref(&self.protocol)
3710 }
3711 fn directory(&self) -> Option<OneOrMany<&BorrowedName>> {
3712 None
3713 }
3714 fn storage(&self) -> Option<OneOrMany<&BorrowedName>> {
3715 None
3716 }
3717 fn runner(&self) -> Option<OneOrMany<&BorrowedName>> {
3718 None
3719 }
3720 fn resolver(&self) -> Option<OneOrMany<&BorrowedName>> {
3721 None
3722 }
3723 fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>> {
3724 None
3725 }
3726 fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>> {
3727 None
3728 }
3729 fn config(&self) -> Option<OneOrMany<&BorrowedName>> {
3730 None
3731 }
3732
3733 fn set_service(&mut self, _o: Option<OneOrMany<Name>>) {}
3734 fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
3735 self.protocol = o;
3736 }
3737 fn set_directory(&mut self, _o: Option<OneOrMany<Name>>) {}
3738 fn set_storage(&mut self, _o: Option<OneOrMany<Name>>) {}
3739 fn set_runner(&mut self, _o: Option<OneOrMany<Name>>) {}
3740 fn set_resolver(&mut self, _o: Option<OneOrMany<Name>>) {}
3741 fn set_event_stream(&mut self, _o: Option<OneOrMany<Name>>) {}
3742 fn set_dictionary(&mut self, _o: Option<OneOrMany<Name>>) {}
3743 fn set_config(&mut self, _o: Option<OneOrMany<Name>>) {}
3744
3745 fn availability(&self) -> Option<Availability> {
3746 None
3747 }
3748 fn set_availability(&mut self, _a: Option<Availability>) {}
3749
3750 fn decl_type(&self) -> &'static str {
3751 "debug"
3752 }
3753 fn supported(&self) -> &[&'static str] {
3754 &["service", "protocol"]
3755 }
3756 fn are_many_names_allowed(&self) -> bool {
3757 ["protocol"].contains(&self.capability_type().unwrap())
3758 }
3759}
3760
3761impl AsClause for DebugRegistration {
3762 fn r#as(&self) -> Option<&BorrowedName> {
3763 self.r#as.as_ref().map(Name::as_ref)
3764 }
3765}
3766
3767impl PathClause for DebugRegistration {
3768 fn path(&self) -> Option<&Path> {
3769 None
3770 }
3771}
3772
3773impl FromClause for DebugRegistration {
3774 fn from_(&self) -> OneOrMany<AnyRef<'_>> {
3775 OneOrMany::One(AnyRef::from(&self.from))
3776 }
3777}
3778
3779impl Canonicalize for Use {
3780 fn canonicalize(&mut self) {
3781 if let Some(service) = &mut self.service {
3783 service.canonicalize();
3784 } else if let Some(protocol) = &mut self.protocol {
3785 protocol.canonicalize();
3786 } else if let Some(event_stream) = &mut self.event_stream {
3787 event_stream.canonicalize();
3788 if let Some(scope) = &mut self.scope {
3789 scope.canonicalize();
3790 }
3791 }
3792 }
3793}
3794
3795impl CapabilityClause for Use {
3796 fn service(&self) -> Option<OneOrMany<&BorrowedName>> {
3797 option_one_or_many_as_ref(&self.service)
3798 }
3799 fn protocol(&self) -> Option<OneOrMany<&BorrowedName>> {
3800 option_one_or_many_as_ref(&self.protocol)
3801 }
3802 fn directory(&self) -> Option<OneOrMany<&BorrowedName>> {
3803 self.directory.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3804 }
3805 fn storage(&self) -> Option<OneOrMany<&BorrowedName>> {
3806 self.storage.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3807 }
3808 fn runner(&self) -> Option<OneOrMany<&BorrowedName>> {
3809 self.runner.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3810 }
3811 fn resolver(&self) -> Option<OneOrMany<&BorrowedName>> {
3812 None
3813 }
3814 fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>> {
3815 option_one_or_many_as_ref(&self.event_stream)
3816 }
3817 fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>> {
3818 None
3819 }
3820 fn config(&self) -> Option<OneOrMany<&BorrowedName>> {
3821 self.config.as_ref().map(|n| OneOrMany::One(n.as_ref()))
3822 }
3823
3824 fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
3825 self.service = o;
3826 }
3827 fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
3828 self.protocol = o;
3829 }
3830 fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
3831 self.directory = always_one(o);
3832 }
3833 fn set_storage(&mut self, o: Option<OneOrMany<Name>>) {
3834 self.storage = always_one(o);
3835 }
3836 fn set_runner(&mut self, _o: Option<OneOrMany<Name>>) {}
3837 fn set_resolver(&mut self, _o: Option<OneOrMany<Name>>) {}
3838 fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
3839 self.event_stream = o;
3840 }
3841 fn set_dictionary(&mut self, _o: Option<OneOrMany<Name>>) {}
3842 fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
3843 self.config = always_one(o);
3844 }
3845
3846 fn availability(&self) -> Option<Availability> {
3847 self.availability
3848 }
3849 fn set_availability(&mut self, a: Option<Availability>) {
3850 self.availability = a;
3851 }
3852
3853 fn decl_type(&self) -> &'static str {
3854 "use"
3855 }
3856 fn supported(&self) -> &[&'static str] {
3857 &["service", "protocol", "directory", "storage", "event_stream", "runner", "config"]
3858 }
3859 fn are_many_names_allowed(&self) -> bool {
3860 ["service", "protocol", "event_stream"].contains(&self.capability_type().unwrap())
3861 }
3862}
3863
3864impl FilterClause for Use {
3865 fn filter(&self) -> Option<&Map<String, Value>> {
3866 self.filter.as_ref()
3867 }
3868}
3869
3870impl PathClause for Use {
3871 fn path(&self) -> Option<&Path> {
3872 self.path.as_ref()
3873 }
3874}
3875
3876impl FromClause for Use {
3877 fn from_(&self) -> OneOrMany<AnyRef<'_>> {
3878 let one = match &self.from {
3879 Some(from) => AnyRef::from(from),
3880 None => AnyRef::Parent,
3882 };
3883 OneOrMany::One(one)
3884 }
3885}
3886
3887impl FromClause for Expose {
3888 fn from_(&self) -> OneOrMany<AnyRef<'_>> {
3889 one_or_many_from_impl(&self.from)
3890 }
3891}
3892
3893impl RightsClause for Use {
3894 fn rights(&self) -> Option<&Rights> {
3895 self.rights.as_ref()
3896 }
3897}
3898
3899impl Canonicalize for Expose {
3900 fn canonicalize(&mut self) {
3901 if let Some(service) = &mut self.service {
3903 service.canonicalize();
3904 } else if let Some(protocol) = &mut self.protocol {
3905 protocol.canonicalize();
3906 } else if let Some(directory) = &mut self.directory {
3907 directory.canonicalize();
3908 } else if let Some(runner) = &mut self.runner {
3909 runner.canonicalize();
3910 } else if let Some(resolver) = &mut self.resolver {
3911 resolver.canonicalize();
3912 } else if let Some(event_stream) = &mut self.event_stream {
3913 event_stream.canonicalize();
3914 if let Some(scope) = &mut self.scope {
3915 scope.canonicalize();
3916 }
3917 }
3918 }
3920}
3921
3922impl CapabilityClause for Expose {
3923 fn service(&self) -> Option<OneOrMany<&BorrowedName>> {
3924 option_one_or_many_as_ref(&self.service)
3925 }
3926 fn protocol(&self) -> Option<OneOrMany<&BorrowedName>> {
3927 option_one_or_many_as_ref(&self.protocol)
3928 }
3929 fn directory(&self) -> Option<OneOrMany<&BorrowedName>> {
3930 option_one_or_many_as_ref(&self.directory)
3931 }
3932 fn storage(&self) -> Option<OneOrMany<&BorrowedName>> {
3933 None
3934 }
3935 fn runner(&self) -> Option<OneOrMany<&BorrowedName>> {
3936 option_one_or_many_as_ref(&self.runner)
3937 }
3938 fn resolver(&self) -> Option<OneOrMany<&BorrowedName>> {
3939 option_one_or_many_as_ref(&self.resolver)
3940 }
3941 fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>> {
3942 option_one_or_many_as_ref(&self.event_stream)
3943 }
3944 fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>> {
3945 option_one_or_many_as_ref(&self.dictionary)
3946 }
3947 fn config(&self) -> Option<OneOrMany<&BorrowedName>> {
3948 option_one_or_many_as_ref(&self.config)
3949 }
3950
3951 fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
3952 self.service = o;
3953 }
3954 fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
3955 self.protocol = o;
3956 }
3957 fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
3958 self.directory = o;
3959 }
3960 fn set_storage(&mut self, _o: Option<OneOrMany<Name>>) {}
3961 fn set_runner(&mut self, o: Option<OneOrMany<Name>>) {
3962 self.runner = o;
3963 }
3964 fn set_resolver(&mut self, o: Option<OneOrMany<Name>>) {
3965 self.resolver = o;
3966 }
3967 fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
3968 self.event_stream = o;
3969 }
3970 fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>) {
3971 self.dictionary = o;
3972 }
3973 fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
3974 self.config = o;
3975 }
3976
3977 fn availability(&self) -> Option<Availability> {
3978 None
3979 }
3980 fn set_availability(&mut self, _a: Option<Availability>) {}
3981
3982 fn decl_type(&self) -> &'static str {
3983 "expose"
3984 }
3985 fn supported(&self) -> &[&'static str] {
3986 &[
3987 "service",
3988 "protocol",
3989 "directory",
3990 "runner",
3991 "resolver",
3992 "event_stream",
3993 "dictionary",
3994 "config",
3995 ]
3996 }
3997 fn are_many_names_allowed(&self) -> bool {
3998 [
3999 "service",
4000 "protocol",
4001 "directory",
4002 "runner",
4003 "resolver",
4004 "event_stream",
4005 "dictionary",
4006 "config",
4007 ]
4008 .contains(&self.capability_type().unwrap())
4009 }
4010}
4011
4012impl AsClause for Expose {
4013 fn r#as(&self) -> Option<&BorrowedName> {
4014 self.r#as.as_ref().map(Name::as_ref)
4015 }
4016}
4017
4018impl PathClause for Expose {
4019 fn path(&self) -> Option<&Path> {
4020 None
4021 }
4022}
4023
4024impl FilterClause for Expose {
4025 fn filter(&self) -> Option<&Map<String, Value>> {
4026 None
4027 }
4028}
4029
4030impl RightsClause for Expose {
4031 fn rights(&self) -> Option<&Rights> {
4032 self.rights.as_ref()
4033 }
4034}
4035
4036impl FromClause for Offer {
4037 fn from_(&self) -> OneOrMany<AnyRef<'_>> {
4038 one_or_many_from_impl(&self.from)
4039 }
4040}
4041
4042impl Canonicalize for Offer {
4043 fn canonicalize(&mut self) {
4044 if let Some(service) = &mut self.service {
4046 service.canonicalize();
4047 } else if let Some(protocol) = &mut self.protocol {
4048 protocol.canonicalize();
4049 } else if let Some(directory) = &mut self.directory {
4050 directory.canonicalize();
4051 } else if let Some(runner) = &mut self.runner {
4052 runner.canonicalize();
4053 } else if let Some(resolver) = &mut self.resolver {
4054 resolver.canonicalize();
4055 } else if let Some(storage) = &mut self.storage {
4056 storage.canonicalize();
4057 } else if let Some(event_stream) = &mut self.event_stream {
4058 event_stream.canonicalize();
4059 if let Some(scope) = &mut self.scope {
4060 scope.canonicalize();
4061 }
4062 }
4063 }
4064}
4065
4066impl CapabilityClause for Offer {
4067 fn service(&self) -> Option<OneOrMany<&BorrowedName>> {
4068 option_one_or_many_as_ref(&self.service)
4069 }
4070 fn protocol(&self) -> Option<OneOrMany<&BorrowedName>> {
4071 option_one_or_many_as_ref(&self.protocol)
4072 }
4073 fn directory(&self) -> Option<OneOrMany<&BorrowedName>> {
4074 option_one_or_many_as_ref(&self.directory)
4075 }
4076 fn storage(&self) -> Option<OneOrMany<&BorrowedName>> {
4077 option_one_or_many_as_ref(&self.storage)
4078 }
4079 fn runner(&self) -> Option<OneOrMany<&BorrowedName>> {
4080 option_one_or_many_as_ref(&self.runner)
4081 }
4082 fn resolver(&self) -> Option<OneOrMany<&BorrowedName>> {
4083 option_one_or_many_as_ref(&self.resolver)
4084 }
4085 fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>> {
4086 option_one_or_many_as_ref(&self.event_stream)
4087 }
4088 fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>> {
4089 option_one_or_many_as_ref(&self.dictionary)
4090 }
4091 fn config(&self) -> Option<OneOrMany<&BorrowedName>> {
4092 option_one_or_many_as_ref(&self.config)
4093 }
4094
4095 fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
4096 self.service = o;
4097 }
4098 fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
4099 self.protocol = o;
4100 }
4101 fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
4102 self.directory = o;
4103 }
4104 fn set_storage(&mut self, o: Option<OneOrMany<Name>>) {
4105 self.storage = o;
4106 }
4107 fn set_runner(&mut self, o: Option<OneOrMany<Name>>) {
4108 self.runner = o;
4109 }
4110 fn set_resolver(&mut self, o: Option<OneOrMany<Name>>) {
4111 self.resolver = o;
4112 }
4113 fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
4114 self.event_stream = o;
4115 }
4116 fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>) {
4117 self.dictionary = o;
4118 }
4119 fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
4120 self.config = o
4121 }
4122
4123 fn availability(&self) -> Option<Availability> {
4124 self.availability
4125 }
4126 fn set_availability(&mut self, a: Option<Availability>) {
4127 self.availability = a;
4128 }
4129
4130 fn decl_type(&self) -> &'static str {
4131 "offer"
4132 }
4133 fn supported(&self) -> &[&'static str] {
4134 &[
4135 "service",
4136 "protocol",
4137 "directory",
4138 "storage",
4139 "runner",
4140 "resolver",
4141 "event_stream",
4142 "config",
4143 ]
4144 }
4145 fn are_many_names_allowed(&self) -> bool {
4146 [
4147 "service",
4148 "protocol",
4149 "directory",
4150 "storage",
4151 "runner",
4152 "resolver",
4153 "event_stream",
4154 "config",
4155 ]
4156 .contains(&self.capability_type().unwrap())
4157 }
4158}
4159
4160impl AsClause for Offer {
4161 fn r#as(&self) -> Option<&BorrowedName> {
4162 self.r#as.as_ref().map(Name::as_ref)
4163 }
4164}
4165
4166impl PathClause for Offer {
4167 fn path(&self) -> Option<&Path> {
4168 None
4169 }
4170}
4171
4172impl RightsClause for Offer {
4173 fn rights(&self) -> Option<&Rights> {
4174 self.rights.as_ref()
4175 }
4176}
4177
4178impl FromClause for RunnerRegistration {
4179 fn from_(&self) -> OneOrMany<AnyRef<'_>> {
4180 OneOrMany::One(AnyRef::from(&self.from))
4181 }
4182}
4183
4184impl FromClause for ResolverRegistration {
4185 fn from_(&self) -> OneOrMany<AnyRef<'_>> {
4186 OneOrMany::One(AnyRef::from(&self.from))
4187 }
4188}
4189
4190fn one_or_many_from_impl<'a, T>(from: &'a OneOrMany<T>) -> OneOrMany<AnyRef<'a>>
4191where
4192 AnyRef<'a>: From<&'a T>,
4193 T: 'a,
4194{
4195 let r = match from {
4196 OneOrMany::One(r) => OneOrMany::One(r.into()),
4197 OneOrMany::Many(v) => OneOrMany::Many(v.into_iter().map(|r| r.into()).collect()),
4198 };
4199 r.into()
4200}
4201
4202pub fn alias_or_name<'a>(
4203 alias: Option<&'a BorrowedName>,
4204 name: &'a BorrowedName,
4205) -> &'a BorrowedName {
4206 alias.unwrap_or(name)
4207}
4208
4209pub fn alias_or_path<'a>(alias: Option<&'a Path>, path: &'a Path) -> &'a Path {
4210 alias.unwrap_or(path)
4211}
4212
4213pub fn format_cml(buffer: &str, file: Option<&std::path::Path>) -> Result<Vec<u8>, Error> {
4214 let general_order = PathOption::PropertyNameOrder(vec![
4215 "name",
4216 "url",
4217 "startup",
4218 "environment",
4219 "config",
4220 "dictionary",
4221 "durability",
4222 "service",
4223 "protocol",
4224 "directory",
4225 "storage",
4226 "runner",
4227 "resolver",
4228 "event",
4229 "event_stream",
4230 "from",
4231 "as",
4232 "to",
4233 "rights",
4234 "path",
4235 "subdir",
4236 "filter",
4237 "dependency",
4238 "extends",
4239 "runners",
4240 "resolvers",
4241 "debug",
4242 ]);
4243 let options = FormatOptions {
4244 collapse_containers_of_one: true,
4245 sort_array_items: true, options_by_path: hashmap! {
4247 "/*" => hashset! {
4248 PathOption::PropertyNameOrder(vec![
4249 "include",
4250 "program",
4251 "children",
4252 "collections",
4253 "capabilities",
4254 "use",
4255 "offer",
4256 "expose",
4257 "environments",
4258 "facets",
4259 ])
4260 },
4261 "/*/program" => hashset! {
4262 PathOption::CollapseContainersOfOne(false),
4263 PathOption::PropertyNameOrder(vec![
4264 "runner",
4265 "binary",
4266 "args",
4267 ]),
4268 },
4269 "/*/program/*" => hashset! {
4270 PathOption::SortArrayItems(false),
4271 },
4272 "/*/*/*" => hashset! {
4273 general_order.clone()
4274 },
4275 "/*/*/*/*/*" => hashset! {
4276 general_order
4277 },
4278 },
4279 ..Default::default()
4280 };
4281
4282 json5format::format(buffer, file.map(|f| f.to_string_lossy().to_string()), Some(options))
4283 .map_err(|e| Error::json5(e, file))
4284}
4285
4286pub fn offer_to_all_and_component_diff_sources_message<'a>(
4287 capability: impl Iterator<Item = OfferToAllCapability<'a>>,
4288 component: &str,
4289) -> String {
4290 let mut output = String::new();
4291 let mut capability = capability.peekable();
4292 write!(&mut output, "{} ", capability.peek().unwrap().offer_type()).unwrap();
4293 for (i, capability) in capability.enumerate() {
4294 if i > 0 {
4295 write!(&mut output, ", ").unwrap();
4296 }
4297 write!(&mut output, "{}", capability.name()).unwrap();
4298 }
4299 write!(
4300 &mut output,
4301 r#" is offered to both "all" and child component "{}" with different sources"#,
4302 component
4303 )
4304 .unwrap();
4305 output
4306}
4307
4308pub fn offer_to_all_and_component_diff_capabilities_message<'a>(
4309 capability: impl Iterator<Item = OfferToAllCapability<'a>>,
4310 component: &str,
4311) -> String {
4312 let mut output = String::new();
4313 let mut capability_peek = capability.peekable();
4314
4315 let first_offer_to_all = capability_peek.peek().unwrap().clone();
4319 write!(&mut output, "{} ", first_offer_to_all.offer_type()).unwrap();
4320 for (i, capability) in capability_peek.enumerate() {
4321 if i > 0 {
4322 write!(&mut output, ", ").unwrap();
4323 }
4324 write!(&mut output, "{}", capability.name()).unwrap();
4325 }
4326 write!(&mut output, r#" is aliased to "{}" with the same name as an offer to "all", but from different source {}"#, component, first_offer_to_all.offer_type_plural()).unwrap();
4327 output
4328}
4329
4330pub fn offer_to_all_would_duplicate(
4335 offer_to_all: &Offer,
4336 specific_offer: &Offer,
4337 target: &cm_types::BorrowedName,
4338) -> Result<bool, Error> {
4339 assert!(offer_to_all.protocol.is_some() || offer_to_all.dictionary.is_some());
4341
4342 if CapabilityId::from_offer_expose(specific_offer).iter().flatten().all(
4345 |specific_offer_cap_id| {
4346 CapabilityId::from_offer_expose(offer_to_all)
4347 .iter()
4348 .flatten()
4349 .all(|offer_to_all_cap_id| offer_to_all_cap_id != specific_offer_cap_id)
4350 },
4351 ) {
4352 return Ok(false);
4353 }
4354
4355 let to_field_matches = specific_offer.to.iter().any(
4356 |specific_offer_to| matches!(specific_offer_to, OfferToRef::Named(c) if **c == *target),
4357 );
4358
4359 if !to_field_matches {
4360 return Ok(false);
4361 }
4362
4363 if offer_to_all.from != specific_offer.from {
4364 return Err(Error::validate(offer_to_all_and_component_diff_sources_message(
4365 offer_to_all_from_offer(offer_to_all),
4366 target.as_str(),
4367 )));
4368 }
4369
4370 if offer_to_all_from_offer(offer_to_all).all(|to_all_protocol| {
4372 offer_to_all_from_offer(specific_offer)
4373 .all(|to_specific_protocol| to_all_protocol != to_specific_protocol)
4374 }) {
4375 return Err(Error::validate(offer_to_all_and_component_diff_capabilities_message(
4376 offer_to_all_from_offer(offer_to_all),
4377 target.as_str(),
4378 )));
4379 }
4380
4381 Ok(true)
4382}
4383
4384impl Offer {
4385 pub fn empty(from: OneOrMany<OfferFromRef>, to: OneOrMany<OfferToRef>) -> Offer {
4388 Self {
4389 protocol: None,
4390 from,
4391 to,
4392 r#as: None,
4393 service: None,
4394 directory: None,
4395 config: None,
4396 runner: None,
4397 resolver: None,
4398 storage: None,
4399 dictionary: None,
4400 dependency: None,
4401 rights: None,
4402 subdir: None,
4403 event_stream: None,
4404 scope: None,
4405 availability: None,
4406 source_availability: None,
4407 }
4408 }
4409}
4410
4411#[cfg(test)]
4412pub fn create_offer(
4413 protocol_name: &str,
4414 from: OneOrMany<OfferFromRef>,
4415 to: OneOrMany<OfferToRef>,
4416) -> Offer {
4417 Offer {
4418 protocol: Some(OneOrMany::One(Name::from_str(protocol_name).unwrap())),
4419 ..Offer::empty(from, to)
4420 }
4421}
4422
4423#[cfg(test)]
4424mod tests {
4425 use super::*;
4426 use assert_matches::assert_matches;
4427 use difference::Changeset;
4428 use serde_json::{json, to_string_pretty, to_value};
4429 use std::path::Path;
4430 use test_case::test_case;
4431
4432 macro_rules! assert_json_eq {
4433 ($a:expr, $e:expr) => {{
4434 if $a != $e {
4435 let expected = to_string_pretty(&$e).unwrap();
4436 let actual = to_string_pretty(&$a).unwrap();
4437 assert_eq!(
4438 $a,
4439 $e,
4440 "JSON actual != expected. Diffs:\n\n{}",
4441 Changeset::new(&actual, &expected, "\n")
4442 );
4443 }
4444 }};
4445 }
4446
4447 #[test]
4451 fn test_parse_named_reference() {
4452 assert_matches!("#some-child".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "some-child");
4453 assert_matches!("#A".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "A");
4454 assert_matches!("#7".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "7");
4455 assert_matches!("#_".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "_");
4456
4457 assert_matches!("#-".parse::<OfferFromRef>(), Err(_));
4458 assert_matches!("#.".parse::<OfferFromRef>(), Err(_));
4459 assert_matches!("#".parse::<OfferFromRef>(), Err(_));
4460 assert_matches!("some-child".parse::<OfferFromRef>(), Err(_));
4461 }
4462
4463 #[test]
4464 fn test_parse_reference_test() {
4465 assert_matches!("parent".parse::<OfferFromRef>(), Ok(OfferFromRef::Parent));
4466 assert_matches!("framework".parse::<OfferFromRef>(), Ok(OfferFromRef::Framework));
4467 assert_matches!("self".parse::<OfferFromRef>(), Ok(OfferFromRef::Self_));
4468 assert_matches!("#child".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "child");
4469
4470 assert_matches!("invalid".parse::<OfferFromRef>(), Err(_));
4471 assert_matches!("#invalid-child^".parse::<OfferFromRef>(), Err(_));
4472 }
4473
4474 fn json_value_from_str(json: &str, filename: &Path) -> Result<Value, Error> {
4475 serde_json::from_str(json).map_err(|e| {
4476 Error::parse(
4477 format!("Couldn't read input as JSON: {}", e),
4478 Some(Location { line: e.line(), column: e.column() }),
4479 Some(filename),
4480 )
4481 })
4482 }
4483
4484 fn parse_as_ref(input: &str) -> Result<OfferFromRef, Error> {
4485 serde_json::from_value::<OfferFromRef>(json_value_from_str(input, &Path::new("test.cml"))?)
4486 .map_err(|e| Error::parse(format!("{}", e), None, None))
4487 }
4488
4489 #[test]
4490 fn test_deserialize_ref() -> Result<(), Error> {
4491 assert_matches!(parse_as_ref("\"self\""), Ok(OfferFromRef::Self_));
4492 assert_matches!(parse_as_ref("\"parent\""), Ok(OfferFromRef::Parent));
4493 assert_matches!(parse_as_ref("\"#child\""), Ok(OfferFromRef::Named(name)) if name == "child");
4494
4495 assert_matches!(parse_as_ref(r#""invalid""#), Err(_));
4496
4497 Ok(())
4498 }
4499
4500 macro_rules! test_parse_rights {
4501 (
4502 $(
4503 ($input:expr, $expected:expr),
4504 )+
4505 ) => {
4506 #[test]
4507 fn parse_rights() {
4508 $(
4509 parse_rights_test($input, $expected);
4510 )+
4511 }
4512 }
4513 }
4514
4515 fn parse_rights_test(input: &str, expected: Right) {
4516 let r: Right = serde_json5::from_str(&format!("\"{}\"", input)).expect("invalid json");
4517 assert_eq!(r, expected);
4518 }
4519
4520 test_parse_rights! {
4521 ("connect", Right::Connect),
4522 ("enumerate", Right::Enumerate),
4523 ("execute", Right::Execute),
4524 ("get_attributes", Right::GetAttributes),
4525 ("modify_directory", Right::ModifyDirectory),
4526 ("read_bytes", Right::ReadBytes),
4527 ("traverse", Right::Traverse),
4528 ("update_attributes", Right::UpdateAttributes),
4529 ("write_bytes", Right::WriteBytes),
4530 ("r*", Right::ReadAlias),
4531 ("w*", Right::WriteAlias),
4532 ("x*", Right::ExecuteAlias),
4533 ("rw*", Right::ReadWriteAlias),
4534 ("rx*", Right::ReadExecuteAlias),
4535 }
4536
4537 macro_rules! test_expand_rights {
4538 (
4539 $(
4540 ($input:expr, $expected:expr),
4541 )+
4542 ) => {
4543 #[test]
4544 fn expand_rights() {
4545 $(
4546 expand_rights_test($input, $expected);
4547 )+
4548 }
4549 }
4550 }
4551
4552 fn expand_rights_test(input: Right, expected: Vec<fio::Operations>) {
4553 assert_eq!(input.expand(), expected);
4554 }
4555
4556 test_expand_rights! {
4557 (Right::Connect, vec![fio::Operations::CONNECT]),
4558 (Right::Enumerate, vec![fio::Operations::ENUMERATE]),
4559 (Right::Execute, vec![fio::Operations::EXECUTE]),
4560 (Right::GetAttributes, vec![fio::Operations::GET_ATTRIBUTES]),
4561 (Right::ModifyDirectory, vec![fio::Operations::MODIFY_DIRECTORY]),
4562 (Right::ReadBytes, vec![fio::Operations::READ_BYTES]),
4563 (Right::Traverse, vec![fio::Operations::TRAVERSE]),
4564 (Right::UpdateAttributes, vec![fio::Operations::UPDATE_ATTRIBUTES]),
4565 (Right::WriteBytes, vec![fio::Operations::WRITE_BYTES]),
4566 (Right::ReadAlias, vec![
4567 fio::Operations::CONNECT,
4568 fio::Operations::ENUMERATE,
4569 fio::Operations::TRAVERSE,
4570 fio::Operations::READ_BYTES,
4571 fio::Operations::GET_ATTRIBUTES,
4572 ]),
4573 (Right::WriteAlias, vec![
4574 fio::Operations::CONNECT,
4575 fio::Operations::ENUMERATE,
4576 fio::Operations::TRAVERSE,
4577 fio::Operations::WRITE_BYTES,
4578 fio::Operations::MODIFY_DIRECTORY,
4579 fio::Operations::UPDATE_ATTRIBUTES,
4580 ]),
4581 (Right::ExecuteAlias, vec![
4582 fio::Operations::CONNECT,
4583 fio::Operations::ENUMERATE,
4584 fio::Operations::TRAVERSE,
4585 fio::Operations::EXECUTE,
4586 ]),
4587 (Right::ReadWriteAlias, vec![
4588 fio::Operations::CONNECT,
4589 fio::Operations::ENUMERATE,
4590 fio::Operations::TRAVERSE,
4591 fio::Operations::READ_BYTES,
4592 fio::Operations::WRITE_BYTES,
4593 fio::Operations::MODIFY_DIRECTORY,
4594 fio::Operations::GET_ATTRIBUTES,
4595 fio::Operations::UPDATE_ATTRIBUTES,
4596 ]),
4597 (Right::ReadExecuteAlias, vec![
4598 fio::Operations::CONNECT,
4599 fio::Operations::ENUMERATE,
4600 fio::Operations::TRAVERSE,
4601 fio::Operations::READ_BYTES,
4602 fio::Operations::GET_ATTRIBUTES,
4603 fio::Operations::EXECUTE,
4604 ]),
4605 }
4606
4607 #[test]
4608 fn test_deny_unknown_fields() {
4609 assert_matches!(serde_json5::from_str::<Document>("{ unknown: \"\" }"), Err(_));
4610 assert_matches!(serde_json5::from_str::<Environment>("{ unknown: \"\" }"), Err(_));
4611 assert_matches!(serde_json5::from_str::<RunnerRegistration>("{ unknown: \"\" }"), Err(_));
4612 assert_matches!(serde_json5::from_str::<ResolverRegistration>("{ unknown: \"\" }"), Err(_));
4613 assert_matches!(serde_json5::from_str::<Use>("{ unknown: \"\" }"), Err(_));
4614 assert_matches!(serde_json5::from_str::<Expose>("{ unknown: \"\" }"), Err(_));
4615 assert_matches!(serde_json5::from_str::<Offer>("{ unknown: \"\" }"), Err(_));
4616 assert_matches!(serde_json5::from_str::<Capability>("{ unknown: \"\" }"), Err(_));
4617 assert_matches!(serde_json5::from_str::<Child>("{ unknown: \"\" }"), Err(_));
4618 assert_matches!(serde_json5::from_str::<Collection>("{ unknown: \"\" }"), Err(_));
4619 }
4620
4621 fn empty_offer() -> Offer {
4624 Offer {
4625 service: None,
4626 protocol: None,
4627 directory: None,
4628 storage: None,
4629 runner: None,
4630 resolver: None,
4631 dictionary: None,
4632 config: None,
4633 from: OneOrMany::One(OfferFromRef::Self_),
4634 to: OneOrMany::Many(vec![]),
4635 r#as: None,
4636 rights: None,
4637 subdir: None,
4638 dependency: None,
4639 event_stream: None,
4640 scope: None,
4641 availability: None,
4642 source_availability: None,
4643 }
4644 }
4645
4646 fn empty_use() -> Use {
4647 Use {
4648 service: None,
4649 protocol: None,
4650 scope: None,
4651 directory: None,
4652 storage: None,
4653 config: None,
4654 key: None,
4655 from: None,
4656 path: None,
4657 rights: None,
4658 subdir: None,
4659 event_stream: None,
4660 runner: None,
4661 filter: None,
4662 dependency: None,
4663 availability: None,
4664 config_element_type: None,
4665 config_max_count: None,
4666 config_max_size: None,
4667 config_type: None,
4668 config_default: None,
4669 }
4670 }
4671
4672 #[test]
4673 fn test_capability_id() -> Result<(), Error> {
4674 let a: Name = "a".parse().unwrap();
4676 let b: Name = "b".parse().unwrap();
4677 assert_eq!(
4678 CapabilityId::from_offer_expose(&Offer {
4679 service: Some(OneOrMany::One(a.clone())),
4680 ..empty_offer()
4681 },)?,
4682 vec![CapabilityId::Service(&a)]
4683 );
4684 assert_eq!(
4685 CapabilityId::from_offer_expose(&Offer {
4686 service: Some(OneOrMany::Many(vec![a.clone(), b.clone()],)),
4687 ..empty_offer()
4688 },)?,
4689 vec![CapabilityId::Service(&a), CapabilityId::Service(&b)]
4690 );
4691 assert_eq!(
4692 CapabilityId::from_use(&Use {
4693 service: Some(OneOrMany::One(a.clone())),
4694 ..empty_use()
4695 },)?,
4696 vec![CapabilityId::UsedService("/svc/a".parse().unwrap())]
4697 );
4698 assert_eq!(
4699 CapabilityId::from_use(&Use {
4700 service: Some(OneOrMany::Many(vec![a.clone(), b.clone(),],)),
4701 ..empty_use()
4702 },)?,
4703 vec![
4704 CapabilityId::UsedService("/svc/a".parse().unwrap()),
4705 CapabilityId::UsedService("/svc/b".parse().unwrap())
4706 ]
4707 );
4708 assert_eq!(
4709 CapabilityId::from_use(&Use {
4710 event_stream: Some(OneOrMany::One(Name::new("test".to_string()).unwrap())),
4711 path: Some(cm_types::Path::new("/svc/myevent".to_string()).unwrap()),
4712 ..empty_use()
4713 },)?,
4714 vec![CapabilityId::UsedEventStream("/svc/myevent".parse().unwrap()),]
4715 );
4716 assert_eq!(
4717 CapabilityId::from_use(&Use {
4718 event_stream: Some(OneOrMany::One(Name::new("test".to_string()).unwrap())),
4719 ..empty_use()
4720 },)?,
4721 vec![CapabilityId::UsedEventStream(
4722 "/svc/fuchsia.component.EventStream".parse().unwrap()
4723 ),]
4724 );
4725 assert_eq!(
4726 CapabilityId::from_use(&Use {
4727 service: Some(OneOrMany::One(a.clone())),
4728 path: Some("/b".parse().unwrap()),
4729 ..empty_use()
4730 },)?,
4731 vec![CapabilityId::UsedService("/b".parse().unwrap())]
4732 );
4733
4734 assert_eq!(
4736 CapabilityId::from_offer_expose(&Offer {
4737 protocol: Some(OneOrMany::One(a.clone())),
4738 ..empty_offer()
4739 },)?,
4740 vec![CapabilityId::Protocol(&a)]
4741 );
4742 assert_eq!(
4743 CapabilityId::from_offer_expose(&Offer {
4744 protocol: Some(OneOrMany::Many(vec![a.clone(), b.clone()],)),
4745 ..empty_offer()
4746 },)?,
4747 vec![CapabilityId::Protocol(&a), CapabilityId::Protocol(&b)]
4748 );
4749 assert_eq!(
4750 CapabilityId::from_use(&Use {
4751 protocol: Some(OneOrMany::One(a.clone())),
4752 ..empty_use()
4753 },)?,
4754 vec![CapabilityId::UsedProtocol("/svc/a".parse().unwrap())]
4755 );
4756 assert_eq!(
4757 CapabilityId::from_use(&Use {
4758 protocol: Some(OneOrMany::Many(vec![a.clone(), b.clone(),],)),
4759 ..empty_use()
4760 },)?,
4761 vec![
4762 CapabilityId::UsedProtocol("/svc/a".parse().unwrap()),
4763 CapabilityId::UsedProtocol("/svc/b".parse().unwrap())
4764 ]
4765 );
4766 assert_eq!(
4767 CapabilityId::from_use(&Use {
4768 protocol: Some(OneOrMany::One(a.clone())),
4769 path: Some("/b".parse().unwrap()),
4770 ..empty_use()
4771 },)?,
4772 vec![CapabilityId::UsedProtocol("/b".parse().unwrap())]
4773 );
4774
4775 assert_eq!(
4777 CapabilityId::from_offer_expose(&Offer {
4778 directory: Some(OneOrMany::One(a.clone())),
4779 ..empty_offer()
4780 },)?,
4781 vec![CapabilityId::Directory(&a)]
4782 );
4783 assert_eq!(
4784 CapabilityId::from_offer_expose(&Offer {
4785 directory: Some(OneOrMany::Many(vec![a.clone(), b.clone()])),
4786 ..empty_offer()
4787 },)?,
4788 vec![CapabilityId::Directory(&a), CapabilityId::Directory(&b),]
4789 );
4790 assert_eq!(
4791 CapabilityId::from_use(&Use {
4792 directory: Some(a.clone()),
4793 path: Some("/b".parse().unwrap()),
4794 ..empty_use()
4795 },)?,
4796 vec![CapabilityId::UsedDirectory("/b".parse().unwrap())]
4797 );
4798
4799 assert_eq!(
4801 CapabilityId::from_offer_expose(&Offer {
4802 storage: Some(OneOrMany::One(a.clone())),
4803 ..empty_offer()
4804 },)?,
4805 vec![CapabilityId::Storage(&a)]
4806 );
4807 assert_eq!(
4808 CapabilityId::from_offer_expose(&Offer {
4809 storage: Some(OneOrMany::Many(vec![a.clone(), b.clone()])),
4810 ..empty_offer()
4811 },)?,
4812 vec![CapabilityId::Storage(&a), CapabilityId::Storage(&b),]
4813 );
4814 assert_eq!(
4815 CapabilityId::from_use(&Use {
4816 storage: Some(a.clone()),
4817 path: Some("/b".parse().unwrap()),
4818 ..empty_use()
4819 },)?,
4820 vec![CapabilityId::UsedStorage("/b".parse().unwrap())]
4821 );
4822
4823 assert_eq!(
4825 CapabilityId::from_use(&Use { runner: Some("elf".parse().unwrap()), ..empty_use() })?,
4826 vec![CapabilityId::UsedRunner(BorrowedName::new("elf").unwrap())]
4827 );
4828
4829 assert_eq!(
4831 CapabilityId::from_offer_expose(&Offer {
4832 service: Some(OneOrMany::One(a.clone())),
4833 r#as: Some(b.clone()),
4834 ..empty_offer()
4835 },)?,
4836 vec![CapabilityId::Service(&b)]
4837 );
4838
4839 assert_matches!(CapabilityId::from_offer_expose(&empty_offer()), Err(_));
4841
4842 Ok(())
4843 }
4844
4845 fn document(contents: serde_json::Value) -> Document {
4846 serde_json5::from_str::<Document>(&contents.to_string()).unwrap()
4847 }
4848
4849 #[test]
4850 fn test_includes() {
4851 assert_eq!(document(json!({})).includes(), Vec::<String>::new());
4852 assert_eq!(document(json!({ "include": []})).includes(), Vec::<String>::new());
4853 assert_eq!(
4854 document(json!({ "include": [ "foo.cml", "bar.cml" ]})).includes(),
4855 vec!["foo.cml", "bar.cml"]
4856 );
4857 }
4858
4859 #[test]
4860 fn test_merge_same_section() {
4861 let mut some = document(json!({ "use": [{ "protocol": "foo" }] }));
4862 let mut other = document(json!({ "use": [{ "protocol": "bar" }] }));
4863 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
4864 let uses = some.r#use.as_ref().unwrap();
4865 assert_eq!(uses.len(), 2);
4866 assert_eq!(
4867 uses[0].protocol.as_ref().unwrap(),
4868 &OneOrMany::One("foo".parse::<Name>().unwrap())
4869 );
4870 assert_eq!(
4871 uses[1].protocol.as_ref().unwrap(),
4872 &OneOrMany::One("bar".parse::<Name>().unwrap())
4873 );
4874 }
4875
4876 #[test]
4877 fn test_merge_upgraded_availability() {
4878 let mut some =
4879 document(json!({ "use": [{ "protocol": "foo", "availability": "optional" }] }));
4880 let mut other1 = document(json!({ "use": [{ "protocol": "foo" }] }));
4881 let mut other2 =
4882 document(json!({ "use": [{ "protocol": "foo", "availability": "transitional" }] }));
4883 let mut other3 =
4884 document(json!({ "use": [{ "protocol": "foo", "availability": "same_as_target" }] }));
4885 some.merge_from(&mut other1, &Path::new("some/path")).unwrap();
4886 some.merge_from(&mut other2, &Path::new("some/path")).unwrap();
4887 some.merge_from(&mut other3, &Path::new("some/path")).unwrap();
4888 let uses = some.r#use.as_ref().unwrap();
4889 assert_eq!(uses.len(), 2);
4890 assert_eq!(
4891 uses[0].protocol.as_ref().unwrap(),
4892 &OneOrMany::One("foo".parse::<Name>().unwrap())
4893 );
4894 assert!(uses[0].availability.is_none());
4895 assert_eq!(
4896 uses[1].protocol.as_ref().unwrap(),
4897 &OneOrMany::One("foo".parse::<Name>().unwrap())
4898 );
4899 assert_eq!(uses[1].availability.as_ref().unwrap(), &Availability::SameAsTarget,);
4900 }
4901
4902 #[test]
4903 fn test_merge_different_sections() {
4904 let mut some = document(json!({ "use": [{ "protocol": "foo" }] }));
4905 let mut other = document(json!({ "expose": [{ "protocol": "bar", "from": "self" }] }));
4906 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
4907 let uses = some.r#use.as_ref().unwrap();
4908 let exposes = some.expose.as_ref().unwrap();
4909 assert_eq!(uses.len(), 1);
4910 assert_eq!(exposes.len(), 1);
4911 assert_eq!(
4912 uses[0].protocol.as_ref().unwrap(),
4913 &OneOrMany::One("foo".parse::<Name>().unwrap())
4914 );
4915 assert_eq!(
4916 exposes[0].protocol.as_ref().unwrap(),
4917 &OneOrMany::One("bar".parse::<Name>().unwrap())
4918 );
4919 }
4920
4921 #[test]
4922 fn test_merge_environments() {
4923 let mut some = document(json!({ "environments": [
4924 {
4925 "name": "one",
4926 "extends": "realm",
4927 },
4928 {
4929 "name": "two",
4930 "extends": "none",
4931 "runners": [
4932 {
4933 "runner": "r1",
4934 "from": "#c1",
4935 },
4936 {
4937 "runner": "r2",
4938 "from": "#c2",
4939 },
4940 ],
4941 "resolvers": [
4942 {
4943 "resolver": "res1",
4944 "from": "#c1",
4945 "scheme": "foo",
4946 },
4947 ],
4948 "debug": [
4949 {
4950 "protocol": "baz",
4951 "from": "#c2"
4952 }
4953 ]
4954 },
4955 ]}));
4956 let mut other = document(json!({ "environments": [
4957 {
4958 "name": "two",
4959 "__stop_timeout_ms": 100,
4960 "runners": [
4961 {
4962 "runner": "r3",
4963 "from": "#c3",
4964 },
4965 ],
4966 "resolvers": [
4967 {
4968 "resolver": "res2",
4969 "from": "#c1",
4970 "scheme": "bar",
4971 },
4972 ],
4973 "debug": [
4974 {
4975 "protocol": "faz",
4976 "from": "#c2"
4977 }
4978 ]
4979 },
4980 {
4981 "name": "three",
4982 "__stop_timeout_ms": 1000,
4983 },
4984 ]}));
4985 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
4986 assert_eq!(
4987 to_value(some).unwrap(),
4988 json!({"environments": [
4989 {
4990 "name": "one",
4991 "extends": "realm",
4992 },
4993 {
4994 "name": "three",
4995 "__stop_timeout_ms": 1000,
4996 },
4997 {
4998 "name": "two",
4999 "extends": "none",
5000 "__stop_timeout_ms": 100,
5001 "runners": [
5002 {
5003 "runner": "r1",
5004 "from": "#c1",
5005 },
5006 {
5007 "runner": "r2",
5008 "from": "#c2",
5009 },
5010 {
5011 "runner": "r3",
5012 "from": "#c3",
5013 },
5014 ],
5015 "resolvers": [
5016 {
5017 "resolver": "res1",
5018 "from": "#c1",
5019 "scheme": "foo",
5020 },
5021 {
5022 "resolver": "res2",
5023 "from": "#c1",
5024 "scheme": "bar",
5025 },
5026 ],
5027 "debug": [
5028 {
5029 "protocol": "baz",
5030 "from": "#c2"
5031 },
5032 {
5033 "protocol": "faz",
5034 "from": "#c2"
5035 }
5036 ]
5037 },
5038 ]})
5039 );
5040 }
5041
5042 #[test]
5043 fn test_merge_environments_errors() {
5044 {
5045 let mut some = document(json!({"environments": [{"name": "one", "extends": "realm"}]}));
5046 let mut other = document(json!({"environments": [{"name": "one", "extends": "none"}]}));
5047 assert!(some.merge_from(&mut other, &Path::new("some/path")).is_err());
5048 }
5049 {
5050 let mut some =
5051 document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]}));
5052 let mut other =
5053 document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 20}]}));
5054 assert!(some.merge_from(&mut other, &Path::new("some/path")).is_err());
5055 }
5056
5057 {
5059 let mut some = document(json!({"environments": [{"name": "one", "extends": "realm"}]}));
5060 let mut other =
5061 document(json!({"environments": [{"name": "one", "extends": "realm"}]}));
5062 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5063 assert_eq!(
5064 to_value(some).unwrap(),
5065 json!({"environments": [{"name": "one", "extends": "realm"}]})
5066 );
5067 }
5068 {
5069 let mut some =
5070 document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]}));
5071 let mut other =
5072 document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]}));
5073 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5074 assert_eq!(
5075 to_value(some).unwrap(),
5076 json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]})
5077 );
5078 }
5079 }
5080
5081 #[test]
5082 fn test_merge_from_other_config() {
5083 let mut some = document(json!({}));
5084 let mut other = document(json!({ "config": { "bar": { "type": "bool" } } }));
5085
5086 some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5087 let expected = document(json!({ "config": { "bar": { "type": "bool" } } }));
5088 assert_eq!(some.config, expected.config);
5089 }
5090
5091 #[test]
5092 fn test_merge_from_some_config() {
5093 let mut some = document(json!({ "config": { "bar": { "type": "bool" } } }));
5094 let mut other = document(json!({}));
5095
5096 some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5097 let expected = document(json!({ "config": { "bar": { "type": "bool" } } }));
5098 assert_eq!(some.config, expected.config);
5099 }
5100
5101 #[test]
5102 fn test_merge_from_config() {
5103 let mut some = document(json!({ "config": { "foo": { "type": "bool" } } }));
5104 let mut other = document(json!({ "config": { "bar": { "type": "bool" } } }));
5105 some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5106
5107 assert_eq!(
5108 some,
5109 document(json!({
5110 "config": {
5111 "foo": { "type": "bool" },
5112 "bar": { "type": "bool" },
5113 }
5114 })),
5115 );
5116 }
5117
5118 #[test]
5119 fn test_merge_from_config_dedupe_identical_fields() {
5120 let mut some = document(json!({ "config": { "foo": { "type": "bool" } } }));
5121 let mut other = document(json!({ "config": { "foo": { "type": "bool" } } }));
5122 some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5123
5124 assert_eq!(some, document(json!({ "config": { "foo": { "type": "bool" } } })));
5125 }
5126
5127 #[test]
5128 fn test_merge_from_config_conflicting_keys() {
5129 let mut some = document(json!({ "config": { "foo": { "type": "bool" } } }));
5130 let mut other = document(json!({ "config": { "foo": { "type": "uint8" } } }));
5131
5132 assert_matches::assert_matches!(
5133 some.merge_from(&mut other, &path::Path::new("some/path")),
5134 Err(Error::Validate { err, .. })
5135 if err == "Found conflicting entry for config key `foo` in `some/path`."
5136 );
5137 }
5138
5139 #[test]
5140 fn test_canonicalize() {
5141 let mut some = document(json!({
5142 "children": [
5143 { "name": "b_child", "url": "http://foo/b" },
5145 { "name": "a_child", "url": "http://foo/a" },
5146 ],
5147 "environments": [
5148 { "name": "b_env" },
5150 { "name": "a_env" },
5151 ],
5152 "collections": [
5153 { "name": "b_coll", "durability": "transient" },
5155 { "name": "a_coll", "durability": "transient" },
5156 ],
5157 "capabilities": [
5160 { "protocol": ["foo"] },
5162 { "protocol": "bar" },
5163 { "protocol": "arg", "path": "/arg" },
5165 { "service": ["b", "a"] },
5167 { "event_stream": ["b", "a"] },
5169 { "runner": "myrunner" },
5170 { "runner": "mypathrunner1", "path": "/foo" },
5172 { "runner": "mypathrunner2", "path": "/foo" },
5173 ],
5174 "offer": [
5176 { "protocol": "baz", "from": "#a_child", "to": "#c_child" },
5178 { "protocol": ["foo"], "from": "#a_child", "to": "#b_child" },
5180 { "protocol": "bar", "from": "#a_child", "to": "#b_child" },
5181 { "service": ["b", "a"], "from": "#a_child", "to": "#b_child" },
5183 {
5185 "event_stream": ["b", "a"],
5186 "from": "#a_child",
5187 "to": "#b_child",
5188 "scope": ["#b", "#c", "#a"] },
5190 { "runner": [ "myrunner", "a" ], "from": "#a_child", "to": "#b_child" },
5191 { "runner": [ "b" ], "from": "#a_child", "to": "#b_child" },
5192 { "directory": [ "b" ], "from": "#a_child", "to": "#b_child" },
5193 ],
5194 "expose": [
5195 { "protocol": ["foo"], "from": "#a_child" },
5196 { "protocol": "bar", "from": "#a_child" }, { "service": ["b", "a"], "from": "#a_child" },
5199 {
5201 "event_stream": ["b", "a"],
5202 "from": "#a_child",
5203 "scope": ["#b", "#c", "#a"] },
5205 { "runner": [ "myrunner", "a" ], "from": "#a_child" },
5206 { "runner": [ "b" ], "from": "#a_child" },
5207 { "directory": [ "b" ], "from": "#a_child" },
5208 ],
5209 "use": [
5210 { "protocol": ["zazzle"], "path": "/zazbaz" },
5212 { "protocol": ["foo"] },
5214 { "protocol": "bar" },
5215 { "service": ["b", "a"] },
5217 { "event_stream": ["b", "a"], "scope": ["#b", "#a"] },
5219 ],
5220 }));
5221 some.canonicalize();
5222
5223 assert_json_eq!(
5224 some,
5225 document(json!({
5226 "children": [
5227 { "name": "a_child", "url": "http://foo/a" },
5228 { "name": "b_child", "url": "http://foo/b" },
5229 ],
5230 "collections": [
5231 { "name": "a_coll", "durability": "transient" },
5232 { "name": "b_coll", "durability": "transient" },
5233 ],
5234 "environments": [
5235 { "name": "a_env" },
5236 { "name": "b_env" },
5237 ],
5238 "capabilities": [
5239 { "event_stream": ["a", "b"] },
5240 { "protocol": "arg", "path": "/arg" },
5241 { "protocol": ["bar", "foo"] },
5242 { "runner": "mypathrunner1", "path": "/foo" },
5243 { "runner": "mypathrunner2", "path": "/foo" },
5244 { "runner": "myrunner" },
5245 { "service": ["a", "b"] },
5246 ],
5247 "use": [
5248 { "event_stream": ["a", "b"], "scope": ["#a", "#b"] },
5249 { "protocol": ["bar", "foo"] },
5250 { "protocol": "zazzle", "path": "/zazbaz" },
5251 { "service": ["a", "b"] },
5252 ],
5253 "offer": [
5254 { "directory": "b", "from": "#a_child", "to": "#b_child" },
5255 {
5256 "event_stream": ["a", "b"],
5257 "from": "#a_child",
5258 "to": "#b_child",
5259 "scope": ["#a", "#b", "#c"],
5260 },
5261 { "protocol": ["bar", "foo"], "from": "#a_child", "to": "#b_child" },
5262 { "protocol": "baz", "from": "#a_child", "to": "#c_child" },
5263 { "runner": [ "a", "b", "myrunner" ], "from": "#a_child", "to": "#b_child" },
5264 { "service": ["a", "b"], "from": "#a_child", "to": "#b_child" },
5265 ],
5266 "expose": [
5267 { "directory": "b", "from": "#a_child" },
5268 {
5269 "event_stream": ["a", "b"],
5270 "from": "#a_child",
5271 "scope": ["#a", "#b", "#c"],
5272 },
5273 { "protocol": ["bar", "foo"], "from": "#a_child" },
5274 { "runner": [ "a", "b", "myrunner" ], "from": "#a_child" },
5275 { "service": ["a", "b"], "from": "#a_child" },
5276 ],
5277 }))
5278 )
5279 }
5280
5281 #[test]
5282 fn deny_unknown_config_type_fields() {
5283 let input = json!({ "config": { "foo": { "type": "bool", "unknown": "should error" } } });
5284 serde_json5::from_str::<Document>(&input.to_string())
5285 .expect_err("must reject unknown config field attributes");
5286 }
5287
5288 #[test]
5289 fn deny_unknown_config_nested_type_fields() {
5290 let input = json!({
5291 "config": {
5292 "foo": {
5293 "type": "vector",
5294 "max_count": 10,
5295 "element": {
5296 "type": "bool",
5297 "unknown": "should error"
5298 },
5299
5300 }
5301 }
5302 });
5303 serde_json5::from_str::<Document>(&input.to_string())
5304 .expect_err("must reject unknown config field attributes");
5305 }
5306
5307 #[test]
5308 fn test_merge_from_program() {
5309 let mut some = document(json!({ "program": { "binary": "bin/hello_world" } }));
5310 let mut other = document(json!({ "program": { "runner": "elf" } }));
5311 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5312 let expected =
5313 document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5314 assert_eq!(some.program, expected.program);
5315 }
5316
5317 #[test]
5318 fn test_merge_from_program_without_runner() {
5319 let mut some =
5320 document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5321 let mut other = document(json!({ "program": {} }));
5324 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5325 let expected =
5326 document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5327 assert_eq!(some.program, expected.program);
5328 }
5329
5330 #[test]
5331 fn test_merge_from_program_overlapping_environ() {
5332 let mut some = document(json!({ "program": { "environ": ["1"] } }));
5334 let mut other = document(json!({ "program": { "environ": ["2"] } }));
5335 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5336 let expected = document(json!({ "program": { "environ": ["1", "2"] } }));
5337 assert_eq!(some.program, expected.program);
5338 }
5339
5340 #[test]
5341 fn test_merge_from_program_overlapping_runner() {
5342 let mut some =
5344 document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5345 let mut other = document(json!({ "program": { "runner": "elf" } }));
5346 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5347 let expected =
5348 document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5349 assert_eq!(some.program, expected.program);
5350 }
5351
5352 #[test]
5353 fn test_offer_would_duplicate() {
5354 let offer = create_offer(
5355 "fuchsia.logger.LegacyLog",
5356 OneOrMany::One(OfferFromRef::Parent {}),
5357 OneOrMany::One(OfferToRef::Named(Name::from_str("something").unwrap())),
5358 );
5359
5360 let offer_to_all = create_offer(
5361 "fuchsia.logger.LogSink",
5362 OneOrMany::One(OfferFromRef::Parent {}),
5363 OneOrMany::One(OfferToRef::All),
5364 );
5365
5366 assert!(!offer_to_all_would_duplicate(
5368 &offer_to_all,
5369 &offer,
5370 &Name::from_str("something").unwrap()
5371 )
5372 .unwrap());
5373
5374 let offer = create_offer(
5375 "fuchsia.logger.LogSink",
5376 OneOrMany::One(OfferFromRef::Parent {}),
5377 OneOrMany::One(OfferToRef::Named(Name::from_str("not-something").unwrap())),
5378 );
5379
5380 assert!(!offer_to_all_would_duplicate(
5382 &offer_to_all,
5383 &offer,
5384 &Name::from_str("something").unwrap()
5385 )
5386 .unwrap());
5387
5388 let mut offer = create_offer(
5389 "fuchsia.logger.LogSink",
5390 OneOrMany::One(OfferFromRef::Parent {}),
5391 OneOrMany::One(OfferToRef::Named(Name::from_str("something").unwrap())),
5392 );
5393
5394 offer.r#as = Some(Name::from_str("FakeLog").unwrap());
5395
5396 assert!(!offer_to_all_would_duplicate(
5398 &offer_to_all,
5399 &offer,
5400 &Name::from_str("something").unwrap()
5401 )
5402 .unwrap());
5403
5404 let offer = create_offer(
5405 "fuchsia.logger.LogSink",
5406 OneOrMany::One(OfferFromRef::Parent {}),
5407 OneOrMany::One(OfferToRef::Named(Name::from_str("something").unwrap())),
5408 );
5409
5410 assert!(offer_to_all_would_duplicate(
5411 &offer_to_all,
5412 &offer,
5413 &Name::from_str("something").unwrap()
5414 )
5415 .unwrap());
5416
5417 let offer = create_offer(
5418 "fuchsia.logger.LogSink",
5419 OneOrMany::One(OfferFromRef::Named(Name::from_str("other").unwrap())),
5420 OneOrMany::One(OfferToRef::Named(Name::from_str("something").unwrap())),
5421 );
5422
5423 assert!(offer_to_all_would_duplicate(
5424 &offer_to_all,
5425 &offer,
5426 &Name::from_str("something").unwrap()
5427 )
5428 .is_err());
5429 }
5430
5431 #[test_case(
5432 document(json!({ "program": { "runner": "elf" } })),
5433 document(json!({ "program": { "runner": "fle" } })),
5434 "runner"
5435 ; "when_runner_conflicts"
5436 )]
5437 #[test_case(
5438 document(json!({ "program": { "binary": "bin/hello_world" } })),
5439 document(json!({ "program": { "binary": "bin/hola_mundo" } })),
5440 "binary"
5441 ; "when_binary_conflicts"
5442 )]
5443 #[test_case(
5444 document(json!({ "program": { "args": ["a".to_owned()] } })),
5445 document(json!({ "program": { "args": ["b".to_owned()] } })),
5446 "args"
5447 ; "when_args_conflicts"
5448 )]
5449 fn test_merge_from_program_error(mut some: Document, mut other: Document, field: &str) {
5450 assert_matches::assert_matches!(
5451 some.merge_from(&mut other, &path::Path::new("some/path")),
5452 Err(Error::Validate { err, .. })
5453 if err == format!("manifest include had a conflicting `program.{}`: some/path", field)
5454 );
5455 }
5456
5457 #[test_case(
5458 document(json!({ "facets": { "my.key": "my.value" } })),
5459 document(json!({ "facets": { "other.key": "other.value" } })),
5460 document(json!({ "facets": { "my.key": "my.value", "other.key": "other.value" } }))
5461 ; "two separate keys"
5462 )]
5463 #[test_case(
5464 document(json!({ "facets": { "my.key": "my.value" } })),
5465 document(json!({ "facets": {} })),
5466 document(json!({ "facets": { "my.key": "my.value" } }))
5467 ; "empty other facet"
5468 )]
5469 #[test_case(
5470 document(json!({ "facets": {} })),
5471 document(json!({ "facets": { "other.key": "other.value" } })),
5472 document(json!({ "facets": { "other.key": "other.value" } }))
5473 ; "empty my facet"
5474 )]
5475 #[test_case(
5476 document(json!({ "facets": { "key": { "type": "some_type" } } })),
5477 document(json!({ "facets": { "key": { "runner": "some_runner"} } })),
5478 document(json!({ "facets": { "key": { "type": "some_type", "runner": "some_runner" } } }))
5479 ; "nested facet key"
5480 )]
5481 #[test_case(
5482 document(json!({ "facets": { "key": { "type": "some_type", "nested_key": { "type": "new type" }}}})),
5483 document(json!({ "facets": { "key": { "nested_key": { "runner": "some_runner" }} } })),
5484 document(json!({ "facets": { "key": { "type": "some_type", "nested_key": { "runner": "some_runner", "type": "new type" }}}}))
5485 ; "double nested facet key"
5486 )]
5487 #[test_case(
5488 document(json!({ "facets": { "key": { "array_key": ["value_1", "value_2"] } } })),
5489 document(json!({ "facets": { "key": { "array_key": ["value_3", "value_4"] } } })),
5490 document(json!({ "facets": { "key": { "array_key": ["value_1", "value_2", "value_3", "value_4"] } } }))
5491 ; "merge array values"
5492 )]
5493 fn test_merge_from_facets(mut my: Document, mut other: Document, expected: Document) {
5494 my.merge_from(&mut other, &Path::new("some/path")).unwrap();
5495 assert_eq!(my.facets, expected.facets);
5496 }
5497
5498 #[test_case(
5499 document(json!({ "facets": { "key": "my.value" }})),
5500 document(json!({ "facets": { "key": "other.value" }})),
5501 "facets.key"
5502 ; "conflict first level keys"
5503 )]
5504 #[test_case(
5505 document(json!({ "facets": { "key": {"type": "cts" }}})),
5506 document(json!({ "facets": { "key": {"type": "system" }}})),
5507 "facets.key.type"
5508 ; "conflict second level keys"
5509 )]
5510 #[test_case(
5511 document(json!({ "facets": { "key": {"type": {"key": "value" }}}})),
5512 document(json!({ "facets": { "key": {"type": "system" }}})),
5513 "facets.key.type"
5514 ; "incompatible self nested type"
5515 )]
5516 #[test_case(
5517 document(json!({ "facets": { "key": {"type": "system" }}})),
5518 document(json!({ "facets": { "key": {"type": {"key": "value" }}}})),
5519 "facets.key.type"
5520 ; "incompatible other nested type"
5521 )]
5522 #[test_case(
5523 document(json!({ "facets": { "key": {"type": {"key": "my.value" }}}})),
5524 document(json!({ "facets": { "key": {"type": {"key": "some.value" }}}})),
5525 "facets.key.type.key"
5526 ; "conflict third level keys"
5527 )]
5528 #[test_case(
5529 document(json!({ "facets": { "key": {"type": [ "value_1" ]}}})),
5530 document(json!({ "facets": { "key": {"type": "value_2" }}})),
5531 "facets.key.type"
5532 ; "incompatible keys"
5533 )]
5534 fn test_merge_from_facet_error(mut my: Document, mut other: Document, field: &str) {
5535 assert_matches::assert_matches!(
5536 my.merge_from(&mut other, &path::Path::new("some/path")),
5537 Err(Error::Validate { err, .. })
5538 if err == format!("manifest include had a conflicting `{}`: some/path", field)
5539 );
5540 }
5541
5542 #[test_case("protocol")]
5543 #[test_case("service")]
5544 #[test_case("event_stream")]
5545 fn test_merge_from_duplicate_use_array(typename: &str) {
5546 let mut my = document(json!({ "use": [{ typename: "a" }]}));
5547 let mut other = document(json!({ "use": [
5548 { typename: ["a", "b"], "availability": "optional"}
5549 ]}));
5550 let result = document(json!({ "use": [
5551 { typename: "a" },
5552 { typename: "b", "availability": "optional" },
5553 ]}));
5554
5555 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5556 assert_eq!(my, result);
5557 }
5558
5559 #[test_case("directory")]
5560 #[test_case("storage")]
5561 fn test_merge_from_duplicate_use_noarray(typename: &str) {
5562 let mut my = document(json!({ "use": [{ typename: "a", "path": "/a"}]}));
5563 let mut other = document(json!({ "use": [
5564 { typename: "a", "path": "/a", "availability": "optional" },
5565 { typename: "b", "path": "/b", "availability": "optional" },
5566 ]}));
5567 let result = document(json!({ "use": [
5568 { typename: "a", "path": "/a" },
5569 { typename: "b", "path": "/b", "availability": "optional" },
5570 ]}));
5571 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5572 assert_eq!(my, result);
5573 }
5574
5575 #[test_case("protocol")]
5576 #[test_case("service")]
5577 #[test_case("event_stream")]
5578 fn test_merge_from_duplicate_capabilities_array(typename: &str) {
5579 let mut my = document(json!({ "capabilities": [{ typename: "a" }]}));
5580 let mut other = document(json!({ "capabilities": [ { typename: ["a", "b"] } ]}));
5581 let result = document(json!({ "capabilities": [ { typename: "a" }, { typename: "b" } ]}));
5582
5583 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5584 assert_eq!(my, result);
5585 }
5586
5587 #[test_case("directory")]
5588 #[test_case("storage")]
5589 #[test_case("runner")]
5590 #[test_case("resolver")]
5591 fn test_merge_from_duplicate_capabilities_noarray(typename: &str) {
5592 let mut my = document(json!({ "capabilities": [{ typename: "a", "path": "/a"}]}));
5593 let mut other = document(json!({ "capabilities": [
5594 { typename: "a", "path": "/a" },
5595 { typename: "b", "path": "/b" },
5596 ]}));
5597 let result = document(json!({ "capabilities": [
5598 { typename: "a", "path": "/a" },
5599 { typename: "b", "path": "/b" },
5600 ]}));
5601 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5602 assert_eq!(my, result);
5603 }
5604
5605 #[test]
5606 fn test_merge_with_empty_names() {
5607 let mut my = document(json!({ "capabilities": [{ "path": "/a"}]}));
5609
5610 let mut other = document(json!({ "capabilities": [
5611 { "directory": "a", "path": "/a" },
5612 { "directory": "b", "path": "/b" },
5613 ]}));
5614 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap_err();
5615 }
5616
5617 #[test_case("protocol")]
5618 #[test_case("service")]
5619 #[test_case("event_stream")]
5620 #[test_case("directory")]
5621 #[test_case("storage")]
5622 #[test_case("runner")]
5623 #[test_case("resolver")]
5624 fn test_merge_from_duplicate_offers(typename: &str) {
5625 let mut my = document(json!({ "offer": [{ typename: "a", "from": "self", "to": "#c" }]}));
5626 let mut other = document(json!({ "offer": [
5627 { typename: ["a", "b"], "from": "self", "to": "#c", "availability": "optional" }
5628 ]}));
5629 let result = document(json!({ "offer": [
5630 { typename: "a", "from": "self", "to": "#c" },
5631 { typename: "b", "from": "self", "to": "#c", "availability": "optional" },
5632 ]}));
5633
5634 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5635 assert_eq!(my, result);
5636 }
5637
5638 #[test_case("protocol")]
5639 #[test_case("service")]
5640 #[test_case("event_stream")]
5641 #[test_case("directory")]
5642 #[test_case("runner")]
5643 #[test_case("resolver")]
5644 fn test_merge_from_duplicate_exposes(typename: &str) {
5645 let mut my = document(json!({ "expose": [{ typename: "a", "from": "self" }]}));
5646 let mut other = document(json!({ "expose": [
5647 { typename: ["a", "b"], "from": "self" }
5648 ]}));
5649 let result = document(json!({ "expose": [
5650 { typename: "a", "from": "self" },
5651 { typename: "b", "from": "self" },
5652 ]}));
5653
5654 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5655 assert_eq!(my, result);
5656 }
5657
5658 #[test_case(
5659 document(json!({ "use": [
5660 { "protocol": "a", "availability": "required" },
5661 { "protocol": "b", "availability": "optional" },
5662 { "protocol": "c", "availability": "transitional" },
5663 { "protocol": "d", "availability": "same_as_target" },
5664 ]})),
5665 document(json!({ "use": [
5666 { "protocol": ["a"], "availability": "required" },
5667 { "protocol": ["b"], "availability": "optional" },
5668 { "protocol": ["c"], "availability": "transitional" },
5669 { "protocol": ["d"], "availability": "same_as_target" },
5670 ]})),
5671 document(json!({ "use": [
5672 { "protocol": "a", "availability": "required" },
5673 { "protocol": "b", "availability": "optional" },
5674 { "protocol": "c", "availability": "transitional" },
5675 { "protocol": "d", "availability": "same_as_target" },
5676 ]}))
5677 ; "merge both same"
5678 )]
5679 #[test_case(
5680 document(json!({ "use": [
5681 { "protocol": "a", "availability": "optional" },
5682 { "protocol": "b", "availability": "transitional" },
5683 { "protocol": "c", "availability": "transitional" },
5684 ]})),
5685 document(json!({ "use": [
5686 { "protocol": ["a", "x"], "availability": "required" },
5687 { "protocol": ["b", "y"], "availability": "optional" },
5688 { "protocol": ["c", "z"], "availability": "required" },
5689 ]})),
5690 document(json!({ "use": [
5691 { "protocol": ["a", "x"], "availability": "required" },
5692 { "protocol": ["b", "y"], "availability": "optional" },
5693 { "protocol": ["c", "z"], "availability": "required" },
5694 ]}))
5695 ; "merge with upgrade"
5696 )]
5697 #[test_case(
5698 document(json!({ "use": [
5699 { "protocol": "a", "availability": "required" },
5700 { "protocol": "b", "availability": "optional" },
5701 { "protocol": "c", "availability": "required" },
5702 ]})),
5703 document(json!({ "use": [
5704 { "protocol": ["a", "x"], "availability": "optional" },
5705 { "protocol": ["b", "y"], "availability": "transitional" },
5706 { "protocol": ["c", "z"], "availability": "transitional" },
5707 ]})),
5708 document(json!({ "use": [
5709 { "protocol": "a", "availability": "required" },
5710 { "protocol": "b", "availability": "optional" },
5711 { "protocol": "c", "availability": "required" },
5712 { "protocol": "x", "availability": "optional" },
5713 { "protocol": "y", "availability": "transitional" },
5714 { "protocol": "z", "availability": "transitional" },
5715 ]}))
5716 ; "merge with downgrade"
5717 )]
5718 #[test_case(
5719 document(json!({ "use": [
5720 { "protocol": "a", "availability": "optional" },
5721 { "protocol": "b", "availability": "transitional" },
5722 { "protocol": "c", "availability": "transitional" },
5723 ]})),
5724 document(json!({ "use": [
5725 { "protocol": ["a", "x"], "availability": "same_as_target" },
5726 { "protocol": ["b", "y"], "availability": "same_as_target" },
5727 { "protocol": ["c", "z"], "availability": "same_as_target" },
5728 ]})),
5729 document(json!({ "use": [
5730 { "protocol": "a", "availability": "optional" },
5731 { "protocol": "b", "availability": "transitional" },
5732 { "protocol": "c", "availability": "transitional" },
5733 { "protocol": ["a", "x"], "availability": "same_as_target" },
5734 { "protocol": ["b", "y"], "availability": "same_as_target" },
5735 { "protocol": ["c", "z"], "availability": "same_as_target" },
5736 ]}))
5737 ; "merge with no replacement"
5738 )]
5739 #[test_case(
5740 document(json!({ "use": [
5741 { "protocol": ["a", "b", "c"], "availability": "optional" },
5742 { "protocol": "d", "availability": "same_as_target" },
5743 { "protocol": ["e", "f"] },
5744 ]})),
5745 document(json!({ "use": [
5746 { "protocol": ["c", "e", "g"] },
5747 { "protocol": ["d", "h"] },
5748 { "protocol": ["f", "i"], "availability": "transitional" },
5749 ]})),
5750 document(json!({ "use": [
5751 { "protocol": ["a", "b"], "availability": "optional" },
5752 { "protocol": "d", "availability": "same_as_target" },
5753 { "protocol": ["e", "f"] },
5754 { "protocol": ["c", "g"] },
5755 { "protocol": ["d", "h"] },
5756 { "protocol": "i", "availability": "transitional" },
5757 ]}))
5758 ; "merge multiple"
5759 )]
5760
5761 fn test_merge_from_duplicate_capability_availability(
5762 mut my: Document,
5763 mut other: Document,
5764 result: Document,
5765 ) {
5766 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5767 assert_eq!(my, result);
5768 }
5769
5770 #[test_case(
5771 document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
5772 document(json!({ "use": [{ "protocol": ["c", "d"] }]})),
5773 document(json!({ "use": [
5774 { "protocol": ["a", "b"] }, { "protocol": ["c", "d"] }
5775 ]}))
5776 ; "merge capabilities with disjoint sets"
5777 )]
5778 #[test_case(
5779 document(json!({ "use": [
5780 { "protocol": ["a"] },
5781 { "protocol": "b" },
5782 ]})),
5783 document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
5784 document(json!({ "use": [
5785 { "protocol": ["a"] }, { "protocol": "b" },
5786 ]}))
5787 ; "merge capabilities with equal set"
5788 )]
5789 #[test_case(
5790 document(json!({ "use": [
5791 { "protocol": ["a", "b"] },
5792 { "protocol": "c" },
5793 ]})),
5794 document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
5795 document(json!({ "use": [
5796 { "protocol": ["a", "b"] }, { "protocol": "c" },
5797 ]}))
5798 ; "merge capabilities with subset"
5799 )]
5800 #[test_case(
5801 document(json!({ "use": [
5802 { "protocol": ["a", "b"] },
5803 ]})),
5804 document(json!({ "use": [{ "protocol": ["a", "b", "c"] }]})),
5805 document(json!({ "use": [
5806 { "protocol": ["a", "b"] },
5807 { "protocol": "c" },
5808 ]}))
5809 ; "merge capabilities with superset"
5810 )]
5811 #[test_case(
5812 document(json!({ "use": [
5813 { "protocol": ["a", "b"] },
5814 ]})),
5815 document(json!({ "use": [{ "protocol": ["b", "c", "d"] }]})),
5816 document(json!({ "use": [
5817 { "protocol": ["a", "b"] }, { "protocol": ["c", "d"] }
5818 ]}))
5819 ; "merge capabilities with intersection"
5820 )]
5821 #[test_case(
5822 document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
5823 document(json!({ "use": [
5824 { "protocol": ["c", "b", "d"] },
5825 { "protocol": ["e", "d"] },
5826 ]})),
5827 document(json!({ "use": [
5828 {"protocol": ["a", "b"] },
5829 {"protocol": ["c", "d"] },
5830 {"protocol": "e" }]}))
5831 ; "merge capabilities from multiple arrays"
5832 )]
5833 #[test_case(
5834 document(json!({ "use": [{ "protocol": "foo.bar.Baz", "from": "self"}]})),
5835 document(json!({ "use": [{ "service": "foo.bar.Baz", "from": "self"}]})),
5836 document(json!({ "use": [
5837 {"protocol": "foo.bar.Baz", "from": "self"},
5838 {"service": "foo.bar.Baz", "from": "self"}]}))
5839 ; "merge capabilities, types don't match"
5840 )]
5841 #[test_case(
5842 document(json!({ "use": [{ "protocol": "foo.bar.Baz", "from": "self"}]})),
5843 document(json!({ "use": [{ "protocol": "foo.bar.Baz" }]})),
5844 document(json!({ "use": [
5845 {"protocol": "foo.bar.Baz", "from": "self"},
5846 {"protocol": "foo.bar.Baz"}]}))
5847 ; "merge capabilities, fields don't match"
5848 )]
5849
5850 fn test_merge_from_duplicate_capability(
5851 mut my: Document,
5852 mut other: Document,
5853 result: Document,
5854 ) {
5855 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5856 assert_eq!(my, result);
5857 }
5858
5859 #[test_case(&Right::Connect; "connect right")]
5860 #[test_case(&Right::Enumerate; "enumerate right")]
5861 #[test_case(&Right::Execute; "execute right")]
5862 #[test_case(&Right::GetAttributes; "getattr right")]
5863 #[test_case(&Right::ModifyDirectory; "modifydir right")]
5864 #[test_case(&Right::ReadBytes; "readbytes right")]
5865 #[test_case(&Right::Traverse; "traverse right")]
5866 #[test_case(&Right::UpdateAttributes; "updateattrs right")]
5867 #[test_case(&Right::WriteBytes; "writebytes right")]
5868 #[test_case(&Right::ReadAlias; "r right")]
5869 #[test_case(&Right::WriteAlias; "w right")]
5870 #[test_case(&Right::ExecuteAlias; "x right")]
5871 #[test_case(&Right::ReadWriteAlias; "rw right")]
5872 #[test_case(&Right::ReadExecuteAlias; "rx right")]
5873 #[test_case(&OfferFromRef::Self_; "offer from self")]
5874 #[test_case(&OfferFromRef::Parent; "offer from parent")]
5875 #[test_case(&OfferFromRef::Named(Name::new("child".to_string()).unwrap()); "offer from named")]
5876 #[test_case(
5877 &document(json!({}));
5878 "empty document"
5879 )]
5880 #[test_case(
5881 &document(json!({ "use": [{ "protocol": "foo.bar.Baz", "from": "self"}]}));
5882 "use one from self"
5883 )]
5884 #[test_case(
5885 &document(json!({ "use": [{ "protocol": ["foo.bar.Baz", "some.other.Protocol"], "from": "self"}]}));
5886 "use multiple from self"
5887 )]
5888 #[test_case(
5889 &document(json!({
5890 "offer": [{ "protocol": "foo.bar.Baz", "from": "self", "to": "#elements"}],
5891 "collections" :[{"name": "elements", "durability": "transient" }]
5892 }));
5893 "offer from self to collection"
5894 )]
5895 #[test_case(
5896 &document(json!({
5897 "offer": [
5898 { "service": "foo.bar.Baz", "from": "self", "to": "#elements" },
5899 { "service": "some.other.Service", "from": "self", "to": "#elements"},
5900 ],
5901 "collections":[ {"name": "elements", "durability": "transient"} ]}));
5902 "service offers"
5903 )]
5904 #[test_case(
5905 &document(json!({ "expose": [{ "protocol": ["foo.bar.Baz", "some.other.Protocol"], "from": "self"}]}));
5906 "expose protocols from self"
5907 )]
5908 #[test_case(
5909 &document(json!({ "expose": [{ "service": ["foo.bar.Baz", "some.other.Service"], "from": "self"}]}));
5910 "expose service from self"
5911 )]
5912 #[test_case(
5913 &document(json!({ "capabilities": [{ "protocol": "foo.bar.Baz", "from": "self"}]}));
5914 "capabilities from self"
5915 )]
5916 #[test_case(
5917 &document(json!({ "facets": { "my.key": "my.value" } }));
5918 "facets"
5919 )]
5920 #[test_case(
5921 &document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5922 "elf runner program"
5923 )]
5924 fn serialize_roundtrips<T>(val: &T)
5925 where
5926 T: serde::de::DeserializeOwned + Serialize + PartialEq + std::fmt::Debug,
5927 {
5928 let raw = serde_json::to_string(val).expect("serializing `val` should work");
5929 let parsed: T =
5930 serde_json::from_str(&raw).expect("must be able to parse back serialized value");
5931 assert_eq!(val, &parsed, "parsed value must equal original value");
5932 }
5933}