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, DeliveryType, DependencyType, Durability, Name, NamespacePath,
40 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 Name),
90 Protocol(&'a Name),
91 Directory(&'a Name),
92 UsedService(Path),
94 UsedProtocol(Path),
96 UsedDirectory(Path),
98 UsedStorage(Path),
100 UsedEventStream(Path),
102 UsedConfiguration(&'a Name),
104 UsedRunner(&'a Name),
105 Storage(&'a Name),
106 Runner(&'a Name),
107 Resolver(&'a Name),
108 EventStream(&'a Name),
109 Dictionary(&'a Name),
110 Configuration(&'a Name),
111}
112
113macro_rules! capability_ids_from_names {
115 ($name:ident, $variant:expr) => {
116 fn $name(names: Vec<&'a Name>) -> 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 Name>,
408 alias: Option<&'b Name>,
409 capability_type: &str,
410 ) -> Result<Vec<&'b Name>, Error> {
411 let names: Vec<&Name> = 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<&Name>,
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 Name),
605 Parent,
607 Framework,
609 Debug,
611 Self_,
613 Void,
615 Dictionary(&'a DictionaryRef),
617 OwnDictionary(&'a Name),
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 = c.names().into_iter().cloned().collect();
1437 let mut copy = 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<_> = ours.names().into_iter().cloned().collect();
1567 let mut their_names: Vec<_> = theirs.names().into_iter().cloned().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.group_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<&Name> {
1876 if let Some(children) = self.children.as_ref() {
1877 children.iter().map(|c| &c.name).collect()
1878 } else {
1879 vec![]
1880 }
1881 }
1882
1883 pub fn all_collection_names(&self) -> Vec<&Name> {
1884 if let Some(collections) = self.collections.as_ref() {
1885 collections.iter().map(|c| &c.name).collect()
1886 } else {
1887 vec![]
1888 }
1889 }
1890
1891 pub fn all_storage_names(&self) -> Vec<&Name> {
1892 if let Some(capabilities) = self.capabilities.as_ref() {
1893 capabilities.iter().filter_map(|c| c.storage.as_ref()).collect()
1894 } else {
1895 vec![]
1896 }
1897 }
1898
1899 pub fn all_storage_with_sources<'a>(&'a self) -> HashMap<&'a Name, &'a CapabilityFromRef> {
1900 if let Some(capabilities) = self.capabilities.as_ref() {
1901 capabilities
1902 .iter()
1903 .filter_map(|c| match (c.storage.as_ref(), c.from.as_ref()) {
1904 (Some(s), Some(f)) => Some((s, f)),
1905 _ => None,
1906 })
1907 .collect()
1908 } else {
1909 HashMap::new()
1910 }
1911 }
1912
1913 pub fn all_service_names(&self) -> Vec<&Name> {
1914 self.capabilities
1915 .as_ref()
1916 .map(|c| {
1917 c.iter().filter_map(|c| c.service.as_ref()).map(|p| p.iter()).flatten().collect()
1918 })
1919 .unwrap_or_else(|| vec![])
1920 }
1921
1922 pub fn all_protocol_names(&self) -> Vec<&Name> {
1923 self.capabilities
1924 .as_ref()
1925 .map(|c| {
1926 c.iter().filter_map(|c| c.protocol.as_ref()).map(|p| p.iter()).flatten().collect()
1927 })
1928 .unwrap_or_else(|| vec![])
1929 }
1930
1931 pub fn all_directory_names(&self) -> Vec<&Name> {
1932 self.capabilities
1933 .as_ref()
1934 .map(|c| c.iter().filter_map(|c| c.directory.as_ref()).collect())
1935 .unwrap_or_else(|| vec![])
1936 }
1937
1938 pub fn all_runner_names(&self) -> Vec<&Name> {
1939 self.capabilities
1940 .as_ref()
1941 .map(|c| c.iter().filter_map(|c| c.runner.as_ref()).collect())
1942 .unwrap_or_else(|| vec![])
1943 }
1944
1945 pub fn all_resolver_names(&self) -> Vec<&Name> {
1946 self.capabilities
1947 .as_ref()
1948 .map(|c| c.iter().filter_map(|c| c.resolver.as_ref()).collect())
1949 .unwrap_or_else(|| vec![])
1950 }
1951
1952 pub fn all_dictionary_names(&self) -> Vec<&Name> {
1953 if let Some(capabilities) = self.capabilities.as_ref() {
1954 capabilities.iter().filter_map(|c| c.dictionary.as_ref()).collect()
1955 } else {
1956 vec![]
1957 }
1958 }
1959
1960 pub fn all_dictionaries<'a>(&'a self) -> HashMap<&'a Name, &'a Capability> {
1961 if let Some(capabilities) = self.capabilities.as_ref() {
1962 capabilities
1963 .iter()
1964 .filter_map(|c| match c.dictionary.as_ref() {
1965 Some(s) => Some((s, c)),
1966 _ => None,
1967 })
1968 .collect()
1969 } else {
1970 HashMap::new()
1971 }
1972 }
1973
1974 pub fn all_config_names(&self) -> Vec<&Name> {
1975 self.capabilities
1976 .as_ref()
1977 .map(|c| c.iter().filter_map(|c| c.config.as_ref()).collect())
1978 .unwrap_or_else(|| vec![])
1979 }
1980
1981 pub fn all_environment_names(&self) -> Vec<&Name> {
1982 self.environments
1983 .as_ref()
1984 .map(|c| c.iter().map(|s| &s.name).collect())
1985 .unwrap_or_else(|| vec![])
1986 }
1987
1988 pub fn all_capability_names(&self) -> HashSet<&Name> {
1989 self.capabilities
1990 .as_ref()
1991 .map(|c| {
1992 c.iter().fold(HashSet::new(), |mut acc, capability| {
1993 acc.extend(capability.names());
1994 acc
1995 })
1996 })
1997 .unwrap_or_default()
1998 }
1999}
2000
2001trait ValueMap {
2003 fn get_mut(&mut self, key: &str) -> Option<&mut Value>;
2004 fn insert(&mut self, key: String, val: Value);
2005}
2006
2007impl ValueMap for Map<String, Value> {
2008 fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
2009 self.get_mut(key)
2010 }
2011
2012 fn insert(&mut self, key: String, val: Value) {
2013 self.insert(key, val);
2014 }
2015}
2016
2017impl ValueMap for IndexMap<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
2027#[derive(Deserialize, Debug, PartialEq, Serialize)]
2028#[serde(rename_all = "lowercase")]
2029pub enum EnvironmentExtends {
2030 Realm,
2031 None,
2032}
2033
2034#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
2058#[serde(deny_unknown_fields)]
2059#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
2060pub struct Environment {
2061 pub name: Name,
2065
2066 #[serde(skip_serializing_if = "Option::is_none")]
2070 pub extends: Option<EnvironmentExtends>,
2071
2072 #[reference_doc(recurse)]
2075 #[serde(skip_serializing_if = "Option::is_none")]
2076 pub runners: Option<Vec<RunnerRegistration>>,
2077
2078 #[reference_doc(recurse)]
2081 #[serde(skip_serializing_if = "Option::is_none")]
2082 pub resolvers: Option<Vec<ResolverRegistration>>,
2083
2084 #[reference_doc(recurse)]
2087 #[serde(skip_serializing_if = "Option::is_none")]
2088 pub debug: Option<Vec<DebugRegistration>>,
2089
2090 #[serde(rename = "__stop_timeout_ms")]
2094 #[reference_doc(json_type = "number", rename = "__stop_timeout_ms")]
2095 #[serde(skip_serializing_if = "Option::is_none")]
2096 pub stop_timeout_ms: Option<StopTimeoutMs>,
2097}
2098
2099impl Environment {
2100 pub fn merge_from(&mut self, other: &mut Self) -> Result<(), Error> {
2101 if self.extends.is_none() {
2102 self.extends = other.extends.take();
2103 } else if other.extends.is_some() && other.extends != self.extends {
2104 return Err(Error::validate(
2105 "cannot merge `environments` that declare conflicting `extends`",
2106 ));
2107 }
2108
2109 if self.stop_timeout_ms.is_none() {
2110 self.stop_timeout_ms = other.stop_timeout_ms;
2111 } else if other.stop_timeout_ms.is_some() && other.stop_timeout_ms != self.stop_timeout_ms {
2112 return Err(Error::validate(
2113 "cannot merge `environments` that declare conflicting `stop_timeout_ms`",
2114 ));
2115 }
2116
2117 match &mut self.runners {
2120 Some(r) => {
2121 if let Some(o) = &mut other.runners {
2122 r.append(o);
2123 }
2124 }
2125 None => self.runners = other.runners.take(),
2126 }
2127
2128 match &mut self.resolvers {
2129 Some(r) => {
2130 if let Some(o) = &mut other.resolvers {
2131 r.append(o);
2132 }
2133 }
2134 None => self.resolvers = other.resolvers.take(),
2135 }
2136
2137 match &mut self.debug {
2138 Some(r) => {
2139 if let Some(o) = &mut other.debug {
2140 r.append(o);
2141 }
2142 }
2143 None => self.debug = other.debug.take(),
2144 }
2145 Ok(())
2146 }
2147}
2148
2149#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
2150#[serde(rename_all = "snake_case")]
2151pub enum ConfigType {
2152 Bool,
2153 Uint8,
2154 Uint16,
2155 Uint32,
2156 Uint64,
2157 Int8,
2158 Int16,
2159 Int32,
2160 Int64,
2161 String,
2162 Vector,
2163}
2164
2165impl From<&cm_rust::ConfigValueType> for ConfigType {
2166 fn from(value: &cm_rust::ConfigValueType) -> Self {
2167 match value {
2168 cm_rust::ConfigValueType::Bool => ConfigType::Bool,
2169 cm_rust::ConfigValueType::Uint8 => ConfigType::Uint8,
2170 cm_rust::ConfigValueType::Int8 => ConfigType::Int8,
2171 cm_rust::ConfigValueType::Uint16 => ConfigType::Uint16,
2172 cm_rust::ConfigValueType::Int16 => ConfigType::Int16,
2173 cm_rust::ConfigValueType::Uint32 => ConfigType::Uint32,
2174 cm_rust::ConfigValueType::Int32 => ConfigType::Int32,
2175 cm_rust::ConfigValueType::Uint64 => ConfigType::Uint64,
2176 cm_rust::ConfigValueType::Int64 => ConfigType::Int64,
2177 cm_rust::ConfigValueType::String { .. } => ConfigType::String,
2178 cm_rust::ConfigValueType::Vector { .. } => ConfigType::Vector,
2179 }
2180 }
2181}
2182
2183#[derive(Clone, Hash, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize)]
2184pub struct ConfigKey(String);
2185
2186impl ConfigKey {
2187 pub fn as_str(&self) -> &str {
2188 self.0.as_str()
2189 }
2190}
2191
2192impl std::fmt::Display for ConfigKey {
2193 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2194 write!(f, "{}", self.0)
2195 }
2196}
2197
2198impl FromStr for ConfigKey {
2199 type Err = ParseError;
2200
2201 fn from_str(s: &str) -> Result<Self, ParseError> {
2202 let length = s.len();
2203 if length == 0 {
2204 return Err(ParseError::Empty);
2205 }
2206 if length > 64 {
2207 return Err(ParseError::TooLong);
2208 }
2209
2210 let first_is_letter = s.chars().next().expect("non-empty string").is_ascii_lowercase();
2212 let contains_invalid_chars =
2214 s.chars().any(|c| !(c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_'));
2215 let last_is_underscore = s.chars().next_back().expect("non-empty string") == '_';
2217
2218 if !first_is_letter || contains_invalid_chars || last_is_underscore {
2219 return Err(ParseError::InvalidValue);
2220 }
2221
2222 Ok(Self(s.to_string()))
2223 }
2224}
2225
2226impl<'de> de::Deserialize<'de> for ConfigKey {
2227 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2228 where
2229 D: de::Deserializer<'de>,
2230 {
2231 struct Visitor;
2232
2233 impl<'de> de::Visitor<'de> for Visitor {
2234 type Value = ConfigKey;
2235
2236 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2237 f.write_str(
2238 "a non-empty string no more than 64 characters in length, which must \
2239 start with a letter, can contain letters, numbers, and underscores, \
2240 but cannot end with an underscore",
2241 )
2242 }
2243
2244 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
2245 where
2246 E: de::Error,
2247 {
2248 s.parse().map_err(|err| match err {
2249 ParseError::InvalidValue => E::invalid_value(
2250 de::Unexpected::Str(s),
2251 &"a name which must start with a letter, can contain letters, \
2252 numbers, and underscores, but cannot end with an underscore",
2253 ),
2254 ParseError::TooLong | ParseError::Empty => E::invalid_length(
2255 s.len(),
2256 &"a non-empty name no more than 64 characters in length",
2257 ),
2258 e => {
2259 panic!("unexpected parse error: {:?}", e);
2260 }
2261 })
2262 }
2263 }
2264 deserializer.deserialize_string(Visitor)
2265 }
2266}
2267
2268#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
2269#[serde(deny_unknown_fields, rename_all = "lowercase")]
2270pub enum ConfigRuntimeSource {
2271 Parent,
2272}
2273
2274#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
2275#[serde(tag = "type", deny_unknown_fields, rename_all = "lowercase")]
2276pub enum ConfigValueType {
2277 Bool {
2278 mutability: Option<Vec<ConfigRuntimeSource>>,
2279 },
2280 Uint8 {
2281 mutability: Option<Vec<ConfigRuntimeSource>>,
2282 },
2283 Uint16 {
2284 mutability: Option<Vec<ConfigRuntimeSource>>,
2285 },
2286 Uint32 {
2287 mutability: Option<Vec<ConfigRuntimeSource>>,
2288 },
2289 Uint64 {
2290 mutability: Option<Vec<ConfigRuntimeSource>>,
2291 },
2292 Int8 {
2293 mutability: Option<Vec<ConfigRuntimeSource>>,
2294 },
2295 Int16 {
2296 mutability: Option<Vec<ConfigRuntimeSource>>,
2297 },
2298 Int32 {
2299 mutability: Option<Vec<ConfigRuntimeSource>>,
2300 },
2301 Int64 {
2302 mutability: Option<Vec<ConfigRuntimeSource>>,
2303 },
2304 String {
2305 max_size: NonZeroU32,
2306 mutability: Option<Vec<ConfigRuntimeSource>>,
2307 },
2308 Vector {
2309 max_count: NonZeroU32,
2310 element: ConfigNestedValueType,
2311 mutability: Option<Vec<ConfigRuntimeSource>>,
2312 },
2313}
2314
2315impl ConfigValueType {
2316 pub fn update_digest(&self, hasher: &mut impl sha2::Digest) {
2318 let val = match self {
2319 ConfigValueType::Bool { .. } => 0u8,
2320 ConfigValueType::Uint8 { .. } => 1u8,
2321 ConfigValueType::Uint16 { .. } => 2u8,
2322 ConfigValueType::Uint32 { .. } => 3u8,
2323 ConfigValueType::Uint64 { .. } => 4u8,
2324 ConfigValueType::Int8 { .. } => 5u8,
2325 ConfigValueType::Int16 { .. } => 6u8,
2326 ConfigValueType::Int32 { .. } => 7u8,
2327 ConfigValueType::Int64 { .. } => 8u8,
2328 ConfigValueType::String { max_size, .. } => {
2329 hasher.update(max_size.get().to_le_bytes());
2330 9u8
2331 }
2332 ConfigValueType::Vector { max_count, element, .. } => {
2333 hasher.update(max_count.get().to_le_bytes());
2334 element.update_digest(hasher);
2335 10u8
2336 }
2337 };
2338 hasher.update([val])
2339 }
2340}
2341
2342impl From<ConfigValueType> for cm_rust::ConfigValueType {
2343 fn from(value: ConfigValueType) -> Self {
2344 match value {
2345 ConfigValueType::Bool { .. } => cm_rust::ConfigValueType::Bool,
2346 ConfigValueType::Uint8 { .. } => cm_rust::ConfigValueType::Uint8,
2347 ConfigValueType::Uint16 { .. } => cm_rust::ConfigValueType::Uint16,
2348 ConfigValueType::Uint32 { .. } => cm_rust::ConfigValueType::Uint32,
2349 ConfigValueType::Uint64 { .. } => cm_rust::ConfigValueType::Uint64,
2350 ConfigValueType::Int8 { .. } => cm_rust::ConfigValueType::Int8,
2351 ConfigValueType::Int16 { .. } => cm_rust::ConfigValueType::Int16,
2352 ConfigValueType::Int32 { .. } => cm_rust::ConfigValueType::Int32,
2353 ConfigValueType::Int64 { .. } => cm_rust::ConfigValueType::Int64,
2354 ConfigValueType::String { max_size, .. } => {
2355 cm_rust::ConfigValueType::String { max_size: max_size.into() }
2356 }
2357 ConfigValueType::Vector { max_count, element, .. } => {
2358 cm_rust::ConfigValueType::Vector {
2359 max_count: max_count.into(),
2360 nested_type: element.into(),
2361 }
2362 }
2363 }
2364 }
2365}
2366
2367#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
2368#[serde(tag = "type", deny_unknown_fields, rename_all = "lowercase")]
2369pub enum ConfigNestedValueType {
2370 Bool {},
2371 Uint8 {},
2372 Uint16 {},
2373 Uint32 {},
2374 Uint64 {},
2375 Int8 {},
2376 Int16 {},
2377 Int32 {},
2378 Int64 {},
2379 String { max_size: NonZeroU32 },
2380}
2381
2382impl ConfigNestedValueType {
2383 pub fn update_digest(&self, hasher: &mut impl sha2::Digest) {
2385 let val = match self {
2386 ConfigNestedValueType::Bool {} => 0u8,
2387 ConfigNestedValueType::Uint8 {} => 1u8,
2388 ConfigNestedValueType::Uint16 {} => 2u8,
2389 ConfigNestedValueType::Uint32 {} => 3u8,
2390 ConfigNestedValueType::Uint64 {} => 4u8,
2391 ConfigNestedValueType::Int8 {} => 5u8,
2392 ConfigNestedValueType::Int16 {} => 6u8,
2393 ConfigNestedValueType::Int32 {} => 7u8,
2394 ConfigNestedValueType::Int64 {} => 8u8,
2395 ConfigNestedValueType::String { max_size } => {
2396 hasher.update(max_size.get().to_le_bytes());
2397 9u8
2398 }
2399 };
2400 hasher.update([val])
2401 }
2402}
2403
2404impl From<ConfigNestedValueType> for cm_rust::ConfigNestedValueType {
2405 fn from(value: ConfigNestedValueType) -> Self {
2406 match value {
2407 ConfigNestedValueType::Bool {} => cm_rust::ConfigNestedValueType::Bool,
2408 ConfigNestedValueType::Uint8 {} => cm_rust::ConfigNestedValueType::Uint8,
2409 ConfigNestedValueType::Uint16 {} => cm_rust::ConfigNestedValueType::Uint16,
2410 ConfigNestedValueType::Uint32 {} => cm_rust::ConfigNestedValueType::Uint32,
2411 ConfigNestedValueType::Uint64 {} => cm_rust::ConfigNestedValueType::Uint64,
2412 ConfigNestedValueType::Int8 {} => cm_rust::ConfigNestedValueType::Int8,
2413 ConfigNestedValueType::Int16 {} => cm_rust::ConfigNestedValueType::Int16,
2414 ConfigNestedValueType::Int32 {} => cm_rust::ConfigNestedValueType::Int32,
2415 ConfigNestedValueType::Int64 {} => cm_rust::ConfigNestedValueType::Int64,
2416 ConfigNestedValueType::String { max_size } => {
2417 cm_rust::ConfigNestedValueType::String { max_size: max_size.into() }
2418 }
2419 }
2420 }
2421}
2422
2423impl TryFrom<&cm_rust::ConfigNestedValueType> for ConfigNestedValueType {
2424 type Error = ();
2425 fn try_from(nested: &cm_rust::ConfigNestedValueType) -> Result<Self, ()> {
2426 Ok(match nested {
2427 cm_rust::ConfigNestedValueType::Bool => ConfigNestedValueType::Bool {},
2428 cm_rust::ConfigNestedValueType::Uint8 => ConfigNestedValueType::Uint8 {},
2429 cm_rust::ConfigNestedValueType::Int8 => ConfigNestedValueType::Int8 {},
2430 cm_rust::ConfigNestedValueType::Uint16 => ConfigNestedValueType::Uint16 {},
2431 cm_rust::ConfigNestedValueType::Int16 => ConfigNestedValueType::Int16 {},
2432 cm_rust::ConfigNestedValueType::Uint32 => ConfigNestedValueType::Uint32 {},
2433 cm_rust::ConfigNestedValueType::Int32 => ConfigNestedValueType::Int32 {},
2434 cm_rust::ConfigNestedValueType::Uint64 => ConfigNestedValueType::Uint64 {},
2435 cm_rust::ConfigNestedValueType::Int64 => ConfigNestedValueType::Int64 {},
2436 cm_rust::ConfigNestedValueType::String { max_size } => {
2437 ConfigNestedValueType::String { max_size: NonZeroU32::new(*max_size).ok_or(())? }
2438 }
2439 })
2440 }
2441}
2442
2443#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
2444#[serde(deny_unknown_fields)]
2445#[reference_doc(fields_as = "list")]
2446pub struct RunnerRegistration {
2447 pub runner: Name,
2449
2450 pub from: RegistrationRef,
2456
2457 #[serde(skip_serializing_if = "Option::is_none")]
2460 pub r#as: Option<Name>,
2461}
2462
2463#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
2464#[serde(deny_unknown_fields)]
2465#[reference_doc(fields_as = "list")]
2466pub struct ResolverRegistration {
2467 pub resolver: Name,
2470
2471 pub from: RegistrationRef,
2477
2478 pub scheme: cm_types::UrlScheme,
2481}
2482
2483#[derive(Deserialize, Debug, PartialEq, Clone, ReferenceDoc, Serialize, Default)]
2484#[serde(deny_unknown_fields)]
2485#[reference_doc(fields_as = "list")]
2486pub struct Capability {
2487 #[serde(skip_serializing_if = "Option::is_none")]
2490 #[reference_doc(skip = true)]
2491 pub service: Option<OneOrMany<Name>>,
2492
2493 #[serde(skip_serializing_if = "Option::is_none")]
2496 #[reference_doc(skip = true)]
2497 pub protocol: Option<OneOrMany<Name>>,
2498
2499 #[serde(skip_serializing_if = "Option::is_none")]
2501 #[reference_doc(skip = true)]
2502 pub directory: Option<Name>,
2503
2504 #[serde(skip_serializing_if = "Option::is_none")]
2506 #[reference_doc(skip = true)]
2507 pub storage: Option<Name>,
2508
2509 #[serde(skip_serializing_if = "Option::is_none")]
2511 #[reference_doc(skip = true)]
2512 pub runner: Option<Name>,
2513
2514 #[serde(skip_serializing_if = "Option::is_none")]
2516 #[reference_doc(skip = true)]
2517 pub resolver: Option<Name>,
2518
2519 #[serde(skip_serializing_if = "Option::is_none")]
2521 #[reference_doc(skip = true)]
2522 pub event_stream: Option<OneOrMany<Name>>,
2523
2524 #[serde(skip_serializing_if = "Option::is_none")]
2526 #[reference_doc(skip = true)]
2527 pub dictionary: Option<Name>,
2528
2529 #[serde(skip_serializing_if = "Option::is_none")]
2531 #[reference_doc(skip = true)]
2532 pub config: Option<Name>,
2533
2534 #[serde(skip_serializing_if = "Option::is_none")]
2556 pub path: Option<Path>,
2557
2558 #[serde(skip_serializing_if = "Option::is_none")]
2561 #[reference_doc(json_type = "array of string")]
2562 pub rights: Option<Rights>,
2563
2564 #[serde(skip_serializing_if = "Option::is_none")]
2571 pub from: Option<CapabilityFromRef>,
2572
2573 #[serde(skip_serializing_if = "Option::is_none")]
2576 pub backing_dir: Option<Name>,
2577
2578 #[serde(skip_serializing_if = "Option::is_none")]
2581 pub subdir: Option<RelativePath>,
2582
2583 #[serde(skip_serializing_if = "Option::is_none")]
2592 pub storage_id: Option<StorageId>,
2593
2594 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
2607 #[reference_doc(rename = "type")]
2608 pub config_type: Option<ConfigType>,
2609
2610 #[serde(rename = "max_size", skip_serializing_if = "Option::is_none")]
2613 #[reference_doc(rename = "max_size")]
2614 pub config_max_size: Option<NonZeroU32>,
2615
2616 #[serde(rename = "max_count", skip_serializing_if = "Option::is_none")]
2619 #[reference_doc(rename = "max_count")]
2620 pub config_max_count: Option<NonZeroU32>,
2621
2622 #[serde(rename = "element", skip_serializing_if = "Option::is_none")]
2640 #[reference_doc(rename = "element", json_type = "object")]
2641 pub config_element_type: Option<ConfigNestedValueType>,
2642
2643 #[serde(skip_serializing_if = "Option::is_none")]
2645 pub value: Option<serde_json::Value>,
2646
2647 #[serde(skip_serializing_if = "Option::is_none")]
2657 pub delivery: Option<DeliveryType>,
2658}
2659
2660#[derive(Deserialize, Debug, Clone, PartialEq, ReferenceDoc, Serialize)]
2661#[serde(deny_unknown_fields)]
2662#[reference_doc(fields_as = "list")]
2663pub struct DebugRegistration {
2664 pub protocol: Option<OneOrMany<Name>>,
2666
2667 pub from: OfferFromRef,
2673
2674 #[serde(skip_serializing_if = "Option::is_none")]
2677 pub r#as: Option<Name>,
2678}
2679
2680#[derive(Debug, PartialEq, Default, Serialize)]
2681pub struct Program {
2682 #[serde(skip_serializing_if = "Option::is_none")]
2683 pub runner: Option<Name>,
2684 #[serde(flatten)]
2685 pub info: IndexMap<String, Value>,
2686}
2687
2688impl<'de> de::Deserialize<'de> for Program {
2689 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2690 where
2691 D: de::Deserializer<'de>,
2692 {
2693 struct Visitor;
2694
2695 const EXPECTED_PROGRAM: &'static str =
2696 "a JSON object that includes a `runner` string property";
2697 const EXPECTED_RUNNER: &'static str =
2698 "a non-empty `runner` string property no more than 255 characters in length \
2699 that consists of [A-Za-z0-9_.-] and starts with [A-Za-z0-9_]";
2700
2701 impl<'de> de::Visitor<'de> for Visitor {
2702 type Value = Program;
2703
2704 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2705 f.write_str(EXPECTED_PROGRAM)
2706 }
2707
2708 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
2709 where
2710 A: de::MapAccess<'de>,
2711 {
2712 let mut info = IndexMap::new();
2713 let mut runner = None;
2714 while let Some(e) = map.next_entry::<String, Value>()? {
2715 let (k, v) = e;
2716 if &k == "runner" {
2717 if let Value::String(s) = v {
2718 runner = Some(s);
2719 } else {
2720 return Err(de::Error::invalid_value(
2721 de::Unexpected::Map,
2722 &EXPECTED_RUNNER,
2723 ));
2724 }
2725 } else {
2726 info.insert(k, v);
2727 }
2728 }
2729 let runner = runner
2730 .map(|r| {
2731 Name::new(r.clone()).map_err(|e| match e {
2732 ParseError::InvalidValue => de::Error::invalid_value(
2733 serde::de::Unexpected::Str(&r),
2734 &EXPECTED_RUNNER,
2735 ),
2736 ParseError::TooLong | ParseError::Empty => {
2737 de::Error::invalid_length(r.len(), &EXPECTED_RUNNER)
2738 }
2739 _ => {
2740 panic!("unexpected parse error: {:?}", e);
2741 }
2742 })
2743 })
2744 .transpose()?;
2745 Ok(Program { runner, info })
2746 }
2747 }
2748
2749 deserializer.deserialize_map(Visitor)
2750 }
2751}
2752
2753#[derive(Deserialize, Debug, Default, PartialEq, Clone, ReferenceDoc, Serialize)]
2786#[serde(deny_unknown_fields)]
2787#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
2788pub struct Use {
2789 #[serde(skip_serializing_if = "Option::is_none")]
2791 #[reference_doc(skip = true)]
2792 pub service: Option<OneOrMany<Name>>,
2793
2794 #[serde(skip_serializing_if = "Option::is_none")]
2796 #[reference_doc(skip = true)]
2797 pub protocol: Option<OneOrMany<Name>>,
2798
2799 #[serde(skip_serializing_if = "Option::is_none")]
2801 #[reference_doc(skip = true)]
2802 pub directory: Option<Name>,
2803
2804 #[serde(skip_serializing_if = "Option::is_none")]
2806 #[reference_doc(skip = true)]
2807 pub storage: Option<Name>,
2808
2809 #[serde(skip_serializing_if = "Option::is_none")]
2811 #[reference_doc(skip = true)]
2812 pub event_stream: Option<OneOrMany<Name>>,
2813
2814 #[serde(skip_serializing_if = "Option::is_none")]
2816 #[reference_doc(skip = true)]
2817 pub runner: Option<Name>,
2818
2819 #[serde(skip_serializing_if = "Option::is_none")]
2821 #[reference_doc(skip = true)]
2822 pub config: Option<Name>,
2823
2824 #[serde(skip_serializing_if = "Option::is_none")]
2837 pub from: Option<UseFromRef>,
2838
2839 #[serde(skip_serializing_if = "Option::is_none")]
2843 pub path: Option<Path>,
2844
2845 #[serde(skip_serializing_if = "Option::is_none")]
2848 #[reference_doc(json_type = "array of string")]
2849 pub rights: Option<Rights>,
2850
2851 #[serde(skip_serializing_if = "Option::is_none")]
2854 pub subdir: Option<RelativePath>,
2855
2856 #[serde(skip_serializing_if = "Option::is_none")]
2859 pub scope: Option<OneOrMany<EventScope>>,
2860
2861 #[serde(skip_serializing_if = "Option::is_none")]
2865 pub filter: Option<Map<String, Value>>,
2866
2867 #[serde(skip_serializing_if = "Option::is_none")]
2877 pub dependency: Option<DependencyType>,
2878
2879 #[serde(skip_serializing_if = "Option::is_none")]
2893 pub availability: Option<Availability>,
2894
2895 #[serde(skip_serializing_if = "Option::is_none")]
2898 pub key: Option<Name>,
2899
2900 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
2913 #[reference_doc(rename = "type")]
2914 pub config_type: Option<ConfigType>,
2915
2916 #[serde(rename = "max_size", skip_serializing_if = "Option::is_none")]
2919 #[reference_doc(rename = "max_size")]
2920 pub config_max_size: Option<NonZeroU32>,
2921
2922 #[serde(rename = "max_count", skip_serializing_if = "Option::is_none")]
2925 #[reference_doc(rename = "max_count")]
2926 pub config_max_count: Option<NonZeroU32>,
2927
2928 #[serde(rename = "element", skip_serializing_if = "Option::is_none")]
2946 #[reference_doc(rename = "element", json_type = "object")]
2947 pub config_element_type: Option<ConfigNestedValueType>,
2948
2949 #[serde(rename = "default", skip_serializing_if = "Option::is_none")]
2953 #[reference_doc(rename = "default")]
2954 pub config_default: Option<serde_json::Value>,
2955}
2956
2957#[derive(Deserialize, Debug, PartialEq, Clone, ReferenceDoc, Serialize)]
2989#[serde(deny_unknown_fields)]
2990#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
2991pub struct Expose {
2992 #[serde(skip_serializing_if = "Option::is_none")]
2994 #[reference_doc(skip = true)]
2995 pub service: Option<OneOrMany<Name>>,
2996
2997 #[serde(skip_serializing_if = "Option::is_none")]
2999 #[reference_doc(skip = true)]
3000 pub protocol: Option<OneOrMany<Name>>,
3001
3002 #[serde(skip_serializing_if = "Option::is_none")]
3004 #[reference_doc(skip = true)]
3005 pub directory: Option<OneOrMany<Name>>,
3006
3007 #[serde(skip_serializing_if = "Option::is_none")]
3009 #[reference_doc(skip = true)]
3010 pub runner: Option<OneOrMany<Name>>,
3011
3012 #[serde(skip_serializing_if = "Option::is_none")]
3014 #[reference_doc(skip = true)]
3015 pub resolver: Option<OneOrMany<Name>>,
3016
3017 #[serde(skip_serializing_if = "Option::is_none")]
3019 #[reference_doc(skip = true)]
3020 pub dictionary: Option<OneOrMany<Name>>,
3021
3022 #[serde(skip_serializing_if = "Option::is_none")]
3024 #[reference_doc(skip = true)]
3025 pub config: Option<OneOrMany<Name>>,
3026
3027 pub from: OneOrMany<ExposeFromRef>,
3034
3035 #[serde(skip_serializing_if = "Option::is_none")]
3039 pub r#as: Option<Name>,
3040
3041 #[serde(skip_serializing_if = "Option::is_none")]
3043 pub to: Option<ExposeToRef>,
3044
3045 #[serde(skip_serializing_if = "Option::is_none")]
3048 #[reference_doc(json_type = "array of string")]
3049 pub rights: Option<Rights>,
3050
3051 #[serde(skip_serializing_if = "Option::is_none")]
3054 pub subdir: Option<RelativePath>,
3055
3056 #[serde(skip_serializing_if = "Option::is_none")]
3058 pub event_stream: Option<OneOrMany<Name>>,
3059
3060 #[serde(skip_serializing_if = "Option::is_none")]
3064 pub scope: Option<OneOrMany<EventScope>>,
3065
3066 #[serde(skip_serializing_if = "Option::is_none")]
3083 pub availability: Option<Availability>,
3084
3085 #[serde(skip_serializing_if = "Option::is_none")]
3090 pub source_availability: Option<SourceAvailability>,
3091}
3092
3093impl Expose {
3094 pub fn new_from(from: OneOrMany<ExposeFromRef>) -> Self {
3095 Self {
3096 from,
3097 service: None,
3098 protocol: None,
3099 directory: None,
3100 config: None,
3101 runner: None,
3102 resolver: None,
3103 dictionary: None,
3104 r#as: None,
3105 to: None,
3106 rights: None,
3107 subdir: None,
3108 event_stream: None,
3109 scope: None,
3110 availability: None,
3111 source_availability: None,
3112 }
3113 }
3114}
3115
3116#[derive(Deserialize, Debug, PartialEq, Clone, ReferenceDoc, Serialize)]
3169#[serde(deny_unknown_fields)]
3170#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
3171pub struct Offer {
3172 #[serde(skip_serializing_if = "Option::is_none")]
3174 pub service: Option<OneOrMany<Name>>,
3175
3176 #[serde(skip_serializing_if = "Option::is_none")]
3178 pub protocol: Option<OneOrMany<Name>>,
3179
3180 #[serde(skip_serializing_if = "Option::is_none")]
3182 pub directory: Option<OneOrMany<Name>>,
3183
3184 #[serde(skip_serializing_if = "Option::is_none")]
3186 pub runner: Option<OneOrMany<Name>>,
3187
3188 #[serde(skip_serializing_if = "Option::is_none")]
3190 pub resolver: Option<OneOrMany<Name>>,
3191
3192 #[serde(skip_serializing_if = "Option::is_none")]
3194 pub storage: Option<OneOrMany<Name>>,
3195
3196 #[serde(skip_serializing_if = "Option::is_none")]
3198 pub dictionary: Option<OneOrMany<Name>>,
3199
3200 #[serde(skip_serializing_if = "Option::is_none")]
3202 pub config: Option<OneOrMany<Name>>,
3203
3204 pub from: OneOrMany<OfferFromRef>,
3216
3217 pub to: OneOrMany<OfferToRef>,
3222
3223 #[serde(skip_serializing_if = "Option::is_none")]
3227 pub r#as: Option<Name>,
3228
3229 #[serde(skip_serializing_if = "Option::is_none")]
3239 pub dependency: Option<DependencyType>,
3240
3241 #[serde(skip_serializing_if = "Option::is_none")]
3244 #[reference_doc(json_type = "array of string")]
3245 pub rights: Option<Rights>,
3246
3247 #[serde(skip_serializing_if = "Option::is_none")]
3250 pub subdir: Option<RelativePath>,
3251
3252 #[serde(skip_serializing_if = "Option::is_none")]
3254 pub event_stream: Option<OneOrMany<Name>>,
3255
3256 #[serde(skip_serializing_if = "Option::is_none")]
3259 pub scope: Option<OneOrMany<EventScope>>,
3260
3261 #[serde(skip_serializing_if = "Option::is_none")]
3278 pub availability: Option<Availability>,
3279
3280 #[serde(skip_serializing_if = "Option::is_none")]
3285 pub source_availability: Option<SourceAvailability>,
3286}
3287
3288#[derive(ReferenceDoc, Deserialize, Debug, PartialEq, Serialize)]
3312#[serde(deny_unknown_fields)]
3313#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
3314pub struct Child {
3315 pub name: Name,
3319
3320 pub url: Url,
3322
3323 #[serde(default)]
3329 #[serde(skip_serializing_if = "StartupMode::is_lazy")]
3330 pub startup: StartupMode,
3331
3332 #[serde(skip_serializing_if = "Option::is_none")]
3339 pub on_terminate: Option<OnTerminate>,
3340
3341 #[serde(skip_serializing_if = "Option::is_none")]
3345 pub environment: Option<EnvironmentRef>,
3346}
3347
3348#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
3349#[serde(deny_unknown_fields)]
3350#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
3351pub struct Collection {
3362 pub name: Name,
3366
3367 pub durability: Durability,
3373
3374 pub environment: Option<EnvironmentRef>,
3379
3380 pub allowed_offers: Option<AllowedOffers>,
3387
3388 pub allow_long_names: Option<bool>,
3391
3392 pub persistent_storage: Option<bool>,
3396}
3397
3398pub trait FromClause {
3399 fn from_(&self) -> OneOrMany<AnyRef<'_>>;
3400}
3401
3402pub trait CapabilityClause: Clone + PartialEq + std::fmt::Debug {
3403 fn service(&self) -> Option<OneOrMany<&Name>>;
3404 fn protocol(&self) -> Option<OneOrMany<&Name>>;
3405 fn directory(&self) -> Option<OneOrMany<&Name>>;
3406 fn storage(&self) -> Option<OneOrMany<&Name>>;
3407 fn runner(&self) -> Option<OneOrMany<&Name>>;
3408 fn resolver(&self) -> Option<OneOrMany<&Name>>;
3409 fn event_stream(&self) -> Option<OneOrMany<&Name>>;
3410 fn dictionary(&self) -> Option<OneOrMany<&Name>>;
3411 fn config(&self) -> Option<OneOrMany<&Name>>;
3412 fn set_service(&mut self, o: Option<OneOrMany<Name>>);
3413 fn set_protocol(&mut self, o: Option<OneOrMany<Name>>);
3414 fn set_directory(&mut self, o: Option<OneOrMany<Name>>);
3415 fn set_storage(&mut self, o: Option<OneOrMany<Name>>);
3416 fn set_runner(&mut self, o: Option<OneOrMany<Name>>);
3417 fn set_resolver(&mut self, o: Option<OneOrMany<Name>>);
3418 fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>);
3419 fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>);
3420 fn set_config(&mut self, o: Option<OneOrMany<Name>>);
3421
3422 fn availability(&self) -> Option<Availability>;
3423 fn set_availability(&mut self, a: Option<Availability>);
3424
3425 fn capability_type(&self) -> Result<&'static str, Error> {
3430 let mut types = Vec::new();
3431 if self.service().is_some() {
3432 types.push("service");
3433 }
3434 if self.protocol().is_some() {
3435 types.push("protocol");
3436 }
3437 if self.directory().is_some() {
3438 types.push("directory");
3439 }
3440 if self.storage().is_some() {
3441 types.push("storage");
3442 }
3443 if self.event_stream().is_some() {
3444 types.push("event_stream");
3445 }
3446 if self.runner().is_some() {
3447 types.push("runner");
3448 }
3449 if self.config().is_some() {
3450 types.push("config");
3451 }
3452 if self.resolver().is_some() {
3453 types.push("resolver");
3454 }
3455 if self.dictionary().is_some() {
3456 types.push("dictionary");
3457 }
3458 match types.len() {
3459 0 => {
3460 let supported_keywords = self
3461 .supported()
3462 .into_iter()
3463 .map(|k| format!("\"{}\"", k))
3464 .collect::<Vec<_>>()
3465 .join(", ");
3466 Err(Error::validate(format!(
3467 "`{}` declaration is missing a capability keyword, one of: {}",
3468 self.decl_type(),
3469 supported_keywords,
3470 )))
3471 }
3472 1 => Ok(types[0]),
3473 _ => Err(Error::validate(format!(
3474 "{} declaration has multiple capability types defined: {:?}",
3475 self.decl_type(),
3476 types
3477 ))),
3478 }
3479 }
3480
3481 fn are_many_names_allowed(&self) -> bool;
3483
3484 fn decl_type(&self) -> &'static str;
3485 fn supported(&self) -> &[&'static str];
3486
3487 fn names(&self) -> Vec<&Name> {
3490 let res = vec![
3491 self.service(),
3492 self.protocol(),
3493 self.directory(),
3494 self.storage(),
3495 self.runner(),
3496 self.config(),
3497 self.resolver(),
3498 self.event_stream(),
3499 self.dictionary(),
3500 ];
3501 res.into_iter()
3502 .map(|o| o.map(|o| o.into_iter().collect::<Vec<&Name>>()).unwrap_or(vec![]))
3503 .flatten()
3504 .collect()
3505 }
3506
3507 fn set_names(&mut self, names: Vec<Name>) {
3508 let names = match names.len() {
3509 0 => None,
3510 1 => Some(OneOrMany::One(names.first().unwrap().clone())),
3511 _ => Some(OneOrMany::Many(names)),
3512 };
3513
3514 let cap_type = self.capability_type().unwrap();
3515 if cap_type == "protocol" {
3516 self.set_protocol(names);
3517 } else if cap_type == "service" {
3518 self.set_service(names);
3519 } else if cap_type == "directory" {
3520 self.set_directory(names);
3521 } else if cap_type == "storage" {
3522 self.set_storage(names);
3523 } else if cap_type == "runner" {
3524 self.set_runner(names);
3525 } else if cap_type == "resolver" {
3526 self.set_resolver(names);
3527 } else if cap_type == "event_stream" {
3528 self.set_event_stream(names);
3529 } else if cap_type == "dictionary" {
3530 self.set_dictionary(names);
3531 } else if cap_type == "config" {
3532 self.set_config(names);
3533 } else {
3534 panic!("Unknown capability type {}", cap_type);
3535 }
3536 }
3537}
3538
3539trait Canonicalize {
3540 fn canonicalize(&mut self);
3541}
3542
3543pub trait AsClause {
3544 fn r#as(&self) -> Option<&Name>;
3545}
3546
3547pub trait PathClause {
3548 fn path(&self) -> Option<&Path>;
3549}
3550
3551pub trait FilterClause {
3552 fn filter(&self) -> Option<&Map<String, Value>>;
3553}
3554
3555pub trait RightsClause {
3556 fn rights(&self) -> Option<&Rights>;
3557}
3558
3559fn always_one<T>(o: Option<OneOrMany<T>>) -> Option<T> {
3560 o.map(|o| match o {
3561 OneOrMany::One(o) => o,
3562 OneOrMany::Many(_) => panic!("many is impossible"),
3563 })
3564}
3565
3566impl Canonicalize for Capability {
3567 fn canonicalize(&mut self) {
3568 if let Some(service) = &mut self.service {
3570 service.canonicalize()
3571 } else if let Some(protocol) = &mut self.protocol {
3572 protocol.canonicalize()
3573 } else if let Some(event_stream) = &mut self.event_stream {
3574 event_stream.canonicalize()
3575 }
3576 }
3577}
3578
3579fn option_one_or_many_as_ref<T>(o: &Option<OneOrMany<T>>) -> Option<OneOrMany<&T>> {
3580 o.as_ref().map(|o| o.as_ref())
3581}
3582
3583impl CapabilityClause for Capability {
3584 fn service(&self) -> Option<OneOrMany<&Name>> {
3585 option_one_or_many_as_ref(&self.service)
3586 }
3587 fn protocol(&self) -> Option<OneOrMany<&Name>> {
3588 option_one_or_many_as_ref(&self.protocol)
3589 }
3590 fn directory(&self) -> Option<OneOrMany<&Name>> {
3591 self.directory.as_ref().map(|n| OneOrMany::One(n))
3592 }
3593 fn storage(&self) -> Option<OneOrMany<&Name>> {
3594 self.storage.as_ref().map(|n| OneOrMany::One(n))
3595 }
3596 fn runner(&self) -> Option<OneOrMany<&Name>> {
3597 self.runner.as_ref().map(|n| OneOrMany::One(n))
3598 }
3599 fn resolver(&self) -> Option<OneOrMany<&Name>> {
3600 self.resolver.as_ref().map(|n| OneOrMany::One(n))
3601 }
3602 fn event_stream(&self) -> Option<OneOrMany<&Name>> {
3603 option_one_or_many_as_ref(&self.event_stream)
3604 }
3605 fn dictionary(&self) -> Option<OneOrMany<&Name>> {
3606 self.dictionary.as_ref().map(|n| OneOrMany::One(n))
3607 }
3608 fn config(&self) -> Option<OneOrMany<&Name>> {
3609 self.config.as_ref().map(|n| OneOrMany::One(n))
3610 }
3611
3612 fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
3613 self.service = o;
3614 }
3615 fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
3616 self.protocol = o;
3617 }
3618 fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
3619 self.directory = always_one(o);
3620 }
3621 fn set_storage(&mut self, o: Option<OneOrMany<Name>>) {
3622 self.storage = always_one(o);
3623 }
3624 fn set_runner(&mut self, o: Option<OneOrMany<Name>>) {
3625 self.runner = always_one(o);
3626 }
3627 fn set_resolver(&mut self, o: Option<OneOrMany<Name>>) {
3628 self.resolver = always_one(o);
3629 }
3630 fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
3631 self.event_stream = o;
3632 }
3633 fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>) {
3634 self.dictionary = always_one(o);
3635 }
3636
3637 fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
3638 self.config = always_one(o);
3639 }
3640
3641 fn availability(&self) -> Option<Availability> {
3642 None
3643 }
3644 fn set_availability(&mut self, _a: Option<Availability>) {}
3645
3646 fn decl_type(&self) -> &'static str {
3647 "capability"
3648 }
3649 fn supported(&self) -> &[&'static str] {
3650 &[
3651 "service",
3652 "protocol",
3653 "directory",
3654 "storage",
3655 "runner",
3656 "resolver",
3657 "event_stream",
3658 "dictionary",
3659 "config",
3660 ]
3661 }
3662 fn are_many_names_allowed(&self) -> bool {
3663 ["service", "protocol", "event_stream"].contains(&self.capability_type().unwrap())
3664 }
3665}
3666
3667impl AsClause for Capability {
3668 fn r#as(&self) -> Option<&Name> {
3669 None
3670 }
3671}
3672
3673impl PathClause for Capability {
3674 fn path(&self) -> Option<&Path> {
3675 self.path.as_ref()
3676 }
3677}
3678
3679impl FilterClause for Capability {
3680 fn filter(&self) -> Option<&Map<String, Value>> {
3681 None
3682 }
3683}
3684
3685impl RightsClause for Capability {
3686 fn rights(&self) -> Option<&Rights> {
3687 self.rights.as_ref()
3688 }
3689}
3690
3691impl CapabilityClause for DebugRegistration {
3692 fn service(&self) -> Option<OneOrMany<&Name>> {
3693 None
3694 }
3695 fn protocol(&self) -> Option<OneOrMany<&Name>> {
3696 option_one_or_many_as_ref(&self.protocol)
3697 }
3698 fn directory(&self) -> Option<OneOrMany<&Name>> {
3699 None
3700 }
3701 fn storage(&self) -> Option<OneOrMany<&Name>> {
3702 None
3703 }
3704 fn runner(&self) -> Option<OneOrMany<&Name>> {
3705 None
3706 }
3707 fn resolver(&self) -> Option<OneOrMany<&Name>> {
3708 None
3709 }
3710 fn event_stream(&self) -> Option<OneOrMany<&Name>> {
3711 None
3712 }
3713 fn dictionary(&self) -> Option<OneOrMany<&Name>> {
3714 None
3715 }
3716 fn config(&self) -> Option<OneOrMany<&Name>> {
3717 None
3718 }
3719
3720 fn set_service(&mut self, _o: Option<OneOrMany<Name>>) {}
3721 fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
3722 self.protocol = o;
3723 }
3724 fn set_directory(&mut self, _o: Option<OneOrMany<Name>>) {}
3725 fn set_storage(&mut self, _o: Option<OneOrMany<Name>>) {}
3726 fn set_runner(&mut self, _o: Option<OneOrMany<Name>>) {}
3727 fn set_resolver(&mut self, _o: Option<OneOrMany<Name>>) {}
3728 fn set_event_stream(&mut self, _o: Option<OneOrMany<Name>>) {}
3729 fn set_dictionary(&mut self, _o: Option<OneOrMany<Name>>) {}
3730 fn set_config(&mut self, _o: Option<OneOrMany<Name>>) {}
3731
3732 fn availability(&self) -> Option<Availability> {
3733 None
3734 }
3735 fn set_availability(&mut self, _a: Option<Availability>) {}
3736
3737 fn decl_type(&self) -> &'static str {
3738 "debug"
3739 }
3740 fn supported(&self) -> &[&'static str] {
3741 &["service", "protocol"]
3742 }
3743 fn are_many_names_allowed(&self) -> bool {
3744 ["protocol"].contains(&self.capability_type().unwrap())
3745 }
3746}
3747
3748impl AsClause for DebugRegistration {
3749 fn r#as(&self) -> Option<&Name> {
3750 self.r#as.as_ref()
3751 }
3752}
3753
3754impl PathClause for DebugRegistration {
3755 fn path(&self) -> Option<&Path> {
3756 None
3757 }
3758}
3759
3760impl FromClause for DebugRegistration {
3761 fn from_(&self) -> OneOrMany<AnyRef<'_>> {
3762 OneOrMany::One(AnyRef::from(&self.from))
3763 }
3764}
3765
3766impl Canonicalize for Use {
3767 fn canonicalize(&mut self) {
3768 if let Some(service) = &mut self.service {
3770 service.canonicalize();
3771 } else if let Some(protocol) = &mut self.protocol {
3772 protocol.canonicalize();
3773 } else if let Some(event_stream) = &mut self.event_stream {
3774 event_stream.canonicalize();
3775 if let Some(scope) = &mut self.scope {
3776 scope.canonicalize();
3777 }
3778 }
3779 }
3780}
3781
3782impl CapabilityClause for Use {
3783 fn service(&self) -> Option<OneOrMany<&Name>> {
3784 option_one_or_many_as_ref(&self.service)
3785 }
3786 fn protocol(&self) -> Option<OneOrMany<&Name>> {
3787 option_one_or_many_as_ref(&self.protocol)
3788 }
3789 fn directory(&self) -> Option<OneOrMany<&Name>> {
3790 self.directory.as_ref().map(|n| OneOrMany::One(n))
3791 }
3792 fn storage(&self) -> Option<OneOrMany<&Name>> {
3793 self.storage.as_ref().map(|n| OneOrMany::One(n))
3794 }
3795 fn runner(&self) -> Option<OneOrMany<&Name>> {
3796 self.runner.as_ref().map(|n| OneOrMany::One(n))
3797 }
3798 fn resolver(&self) -> Option<OneOrMany<&Name>> {
3799 None
3800 }
3801 fn event_stream(&self) -> Option<OneOrMany<&Name>> {
3802 option_one_or_many_as_ref(&self.event_stream)
3803 }
3804 fn dictionary(&self) -> Option<OneOrMany<&Name>> {
3805 None
3806 }
3807 fn config(&self) -> Option<OneOrMany<&Name>> {
3808 self.config.as_ref().map(|n| OneOrMany::One(n))
3809 }
3810
3811 fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
3812 self.service = o;
3813 }
3814 fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
3815 self.protocol = o;
3816 }
3817 fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
3818 self.directory = always_one(o);
3819 }
3820 fn set_storage(&mut self, o: Option<OneOrMany<Name>>) {
3821 self.storage = always_one(o);
3822 }
3823 fn set_runner(&mut self, _o: Option<OneOrMany<Name>>) {}
3824 fn set_resolver(&mut self, _o: Option<OneOrMany<Name>>) {}
3825 fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
3826 self.event_stream = o;
3827 }
3828 fn set_dictionary(&mut self, _o: Option<OneOrMany<Name>>) {}
3829 fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
3830 self.config = always_one(o);
3831 }
3832
3833 fn availability(&self) -> Option<Availability> {
3834 self.availability
3835 }
3836 fn set_availability(&mut self, a: Option<Availability>) {
3837 self.availability = a;
3838 }
3839
3840 fn decl_type(&self) -> &'static str {
3841 "use"
3842 }
3843 fn supported(&self) -> &[&'static str] {
3844 &["service", "protocol", "directory", "storage", "event_stream", "runner", "config"]
3845 }
3846 fn are_many_names_allowed(&self) -> bool {
3847 ["service", "protocol", "event_stream"].contains(&self.capability_type().unwrap())
3848 }
3849}
3850
3851impl FilterClause for Use {
3852 fn filter(&self) -> Option<&Map<String, Value>> {
3853 self.filter.as_ref()
3854 }
3855}
3856
3857impl PathClause for Use {
3858 fn path(&self) -> Option<&Path> {
3859 self.path.as_ref()
3860 }
3861}
3862
3863impl FromClause for Use {
3864 fn from_(&self) -> OneOrMany<AnyRef<'_>> {
3865 let one = match &self.from {
3866 Some(from) => AnyRef::from(from),
3867 None => AnyRef::Parent,
3869 };
3870 OneOrMany::One(one)
3871 }
3872}
3873
3874impl FromClause for Expose {
3875 fn from_(&self) -> OneOrMany<AnyRef<'_>> {
3876 one_or_many_from_impl(&self.from)
3877 }
3878}
3879
3880impl RightsClause for Use {
3881 fn rights(&self) -> Option<&Rights> {
3882 self.rights.as_ref()
3883 }
3884}
3885
3886impl Canonicalize for Expose {
3887 fn canonicalize(&mut self) {
3888 if let Some(service) = &mut self.service {
3890 service.canonicalize();
3891 } else if let Some(protocol) = &mut self.protocol {
3892 protocol.canonicalize();
3893 } else if let Some(directory) = &mut self.directory {
3894 directory.canonicalize();
3895 } else if let Some(runner) = &mut self.runner {
3896 runner.canonicalize();
3897 } else if let Some(resolver) = &mut self.resolver {
3898 resolver.canonicalize();
3899 } else if let Some(event_stream) = &mut self.event_stream {
3900 event_stream.canonicalize();
3901 if let Some(scope) = &mut self.scope {
3902 scope.canonicalize();
3903 }
3904 }
3905 }
3907}
3908
3909impl CapabilityClause for Expose {
3910 fn service(&self) -> Option<OneOrMany<&Name>> {
3911 option_one_or_many_as_ref(&self.service)
3912 }
3913 fn protocol(&self) -> Option<OneOrMany<&Name>> {
3914 option_one_or_many_as_ref(&self.protocol)
3915 }
3916 fn directory(&self) -> Option<OneOrMany<&Name>> {
3917 option_one_or_many_as_ref(&self.directory)
3918 }
3919 fn storage(&self) -> Option<OneOrMany<&Name>> {
3920 None
3921 }
3922 fn runner(&self) -> Option<OneOrMany<&Name>> {
3923 option_one_or_many_as_ref(&self.runner)
3924 }
3925 fn resolver(&self) -> Option<OneOrMany<&Name>> {
3926 option_one_or_many_as_ref(&self.resolver)
3927 }
3928 fn event_stream(&self) -> Option<OneOrMany<&Name>> {
3929 option_one_or_many_as_ref(&self.event_stream)
3930 }
3931 fn dictionary(&self) -> Option<OneOrMany<&Name>> {
3932 option_one_or_many_as_ref(&self.dictionary)
3933 }
3934 fn config(&self) -> Option<OneOrMany<&Name>> {
3935 option_one_or_many_as_ref(&self.config)
3936 }
3937
3938 fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
3939 self.service = o;
3940 }
3941 fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
3942 self.protocol = o;
3943 }
3944 fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
3945 self.directory = o;
3946 }
3947 fn set_storage(&mut self, _o: Option<OneOrMany<Name>>) {}
3948 fn set_runner(&mut self, o: Option<OneOrMany<Name>>) {
3949 self.runner = o;
3950 }
3951 fn set_resolver(&mut self, o: Option<OneOrMany<Name>>) {
3952 self.resolver = o;
3953 }
3954 fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
3955 self.event_stream = o;
3956 }
3957 fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>) {
3958 self.dictionary = o;
3959 }
3960 fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
3961 self.config = o;
3962 }
3963
3964 fn availability(&self) -> Option<Availability> {
3965 None
3966 }
3967 fn set_availability(&mut self, _a: Option<Availability>) {}
3968
3969 fn decl_type(&self) -> &'static str {
3970 "expose"
3971 }
3972 fn supported(&self) -> &[&'static str] {
3973 &[
3974 "service",
3975 "protocol",
3976 "directory",
3977 "runner",
3978 "resolver",
3979 "event_stream",
3980 "dictionary",
3981 "config",
3982 ]
3983 }
3984 fn are_many_names_allowed(&self) -> bool {
3985 [
3986 "service",
3987 "protocol",
3988 "directory",
3989 "runner",
3990 "resolver",
3991 "event_stream",
3992 "dictionary",
3993 "config",
3994 ]
3995 .contains(&self.capability_type().unwrap())
3996 }
3997}
3998
3999impl AsClause for Expose {
4000 fn r#as(&self) -> Option<&Name> {
4001 self.r#as.as_ref()
4002 }
4003}
4004
4005impl PathClause for Expose {
4006 fn path(&self) -> Option<&Path> {
4007 None
4008 }
4009}
4010
4011impl FilterClause for Expose {
4012 fn filter(&self) -> Option<&Map<String, Value>> {
4013 None
4014 }
4015}
4016
4017impl RightsClause for Expose {
4018 fn rights(&self) -> Option<&Rights> {
4019 self.rights.as_ref()
4020 }
4021}
4022
4023impl FromClause for Offer {
4024 fn from_(&self) -> OneOrMany<AnyRef<'_>> {
4025 one_or_many_from_impl(&self.from)
4026 }
4027}
4028
4029impl Canonicalize for Offer {
4030 fn canonicalize(&mut self) {
4031 if let Some(service) = &mut self.service {
4033 service.canonicalize();
4034 } else if let Some(protocol) = &mut self.protocol {
4035 protocol.canonicalize();
4036 } else if let Some(directory) = &mut self.directory {
4037 directory.canonicalize();
4038 } else if let Some(runner) = &mut self.runner {
4039 runner.canonicalize();
4040 } else if let Some(resolver) = &mut self.resolver {
4041 resolver.canonicalize();
4042 } else if let Some(storage) = &mut self.storage {
4043 storage.canonicalize();
4044 } else if let Some(event_stream) = &mut self.event_stream {
4045 event_stream.canonicalize();
4046 if let Some(scope) = &mut self.scope {
4047 scope.canonicalize();
4048 }
4049 }
4050 }
4051}
4052
4053impl CapabilityClause for Offer {
4054 fn service(&self) -> Option<OneOrMany<&Name>> {
4055 option_one_or_many_as_ref(&self.service)
4056 }
4057 fn protocol(&self) -> Option<OneOrMany<&Name>> {
4058 option_one_or_many_as_ref(&self.protocol)
4059 }
4060 fn directory(&self) -> Option<OneOrMany<&Name>> {
4061 option_one_or_many_as_ref(&self.directory)
4062 }
4063 fn storage(&self) -> Option<OneOrMany<&Name>> {
4064 option_one_or_many_as_ref(&self.storage)
4065 }
4066 fn runner(&self) -> Option<OneOrMany<&Name>> {
4067 option_one_or_many_as_ref(&self.runner)
4068 }
4069 fn resolver(&self) -> Option<OneOrMany<&Name>> {
4070 option_one_or_many_as_ref(&self.resolver)
4071 }
4072 fn event_stream(&self) -> Option<OneOrMany<&Name>> {
4073 option_one_or_many_as_ref(&self.event_stream)
4074 }
4075 fn dictionary(&self) -> Option<OneOrMany<&Name>> {
4076 option_one_or_many_as_ref(&self.dictionary)
4077 }
4078 fn config(&self) -> Option<OneOrMany<&Name>> {
4079 option_one_or_many_as_ref(&self.config)
4080 }
4081
4082 fn set_service(&mut self, o: Option<OneOrMany<Name>>) {
4083 self.service = o;
4084 }
4085 fn set_protocol(&mut self, o: Option<OneOrMany<Name>>) {
4086 self.protocol = o;
4087 }
4088 fn set_directory(&mut self, o: Option<OneOrMany<Name>>) {
4089 self.directory = o;
4090 }
4091 fn set_storage(&mut self, o: Option<OneOrMany<Name>>) {
4092 self.storage = o;
4093 }
4094 fn set_runner(&mut self, o: Option<OneOrMany<Name>>) {
4095 self.runner = o;
4096 }
4097 fn set_resolver(&mut self, o: Option<OneOrMany<Name>>) {
4098 self.resolver = o;
4099 }
4100 fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>) {
4101 self.event_stream = o;
4102 }
4103 fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>) {
4104 self.dictionary = o;
4105 }
4106 fn set_config(&mut self, o: Option<OneOrMany<Name>>) {
4107 self.config = o
4108 }
4109
4110 fn availability(&self) -> Option<Availability> {
4111 self.availability
4112 }
4113 fn set_availability(&mut self, a: Option<Availability>) {
4114 self.availability = a;
4115 }
4116
4117 fn decl_type(&self) -> &'static str {
4118 "offer"
4119 }
4120 fn supported(&self) -> &[&'static str] {
4121 &[
4122 "service",
4123 "protocol",
4124 "directory",
4125 "storage",
4126 "runner",
4127 "resolver",
4128 "event_stream",
4129 "config",
4130 ]
4131 }
4132 fn are_many_names_allowed(&self) -> bool {
4133 [
4134 "service",
4135 "protocol",
4136 "directory",
4137 "storage",
4138 "runner",
4139 "resolver",
4140 "event_stream",
4141 "config",
4142 ]
4143 .contains(&self.capability_type().unwrap())
4144 }
4145}
4146
4147impl AsClause for Offer {
4148 fn r#as(&self) -> Option<&Name> {
4149 self.r#as.as_ref()
4150 }
4151}
4152
4153impl PathClause for Offer {
4154 fn path(&self) -> Option<&Path> {
4155 None
4156 }
4157}
4158
4159impl RightsClause for Offer {
4160 fn rights(&self) -> Option<&Rights> {
4161 self.rights.as_ref()
4162 }
4163}
4164
4165impl FromClause for RunnerRegistration {
4166 fn from_(&self) -> OneOrMany<AnyRef<'_>> {
4167 OneOrMany::One(AnyRef::from(&self.from))
4168 }
4169}
4170
4171impl FromClause for ResolverRegistration {
4172 fn from_(&self) -> OneOrMany<AnyRef<'_>> {
4173 OneOrMany::One(AnyRef::from(&self.from))
4174 }
4175}
4176
4177fn one_or_many_from_impl<'a, T>(from: &'a OneOrMany<T>) -> OneOrMany<AnyRef<'a>>
4178where
4179 AnyRef<'a>: From<&'a T>,
4180 T: 'a,
4181{
4182 let r = match from {
4183 OneOrMany::One(r) => OneOrMany::One(r.into()),
4184 OneOrMany::Many(v) => OneOrMany::Many(v.into_iter().map(|r| r.into()).collect()),
4185 };
4186 r.into()
4187}
4188
4189pub fn alias_or_name<'a>(alias: Option<&'a Name>, name: &'a Name) -> &'a Name {
4190 alias.unwrap_or(name)
4191}
4192
4193pub fn alias_or_path<'a>(alias: Option<&'a Path>, path: &'a Path) -> &'a Path {
4194 alias.unwrap_or(path)
4195}
4196
4197pub fn format_cml(buffer: &str, file: Option<&std::path::Path>) -> Result<Vec<u8>, Error> {
4198 let general_order = PathOption::PropertyNameOrder(vec![
4199 "name",
4200 "url",
4201 "startup",
4202 "environment",
4203 "config",
4204 "dictionary",
4205 "durability",
4206 "service",
4207 "protocol",
4208 "directory",
4209 "storage",
4210 "runner",
4211 "resolver",
4212 "event",
4213 "event_stream",
4214 "from",
4215 "as",
4216 "to",
4217 "rights",
4218 "path",
4219 "subdir",
4220 "filter",
4221 "dependency",
4222 "extends",
4223 "runners",
4224 "resolvers",
4225 "debug",
4226 ]);
4227 let options = FormatOptions {
4228 collapse_containers_of_one: true,
4229 sort_array_items: true, options_by_path: hashmap! {
4231 "/*" => hashset! {
4232 PathOption::PropertyNameOrder(vec![
4233 "include",
4234 "program",
4235 "children",
4236 "collections",
4237 "capabilities",
4238 "use",
4239 "offer",
4240 "expose",
4241 "environments",
4242 "facets",
4243 ])
4244 },
4245 "/*/program" => hashset! {
4246 PathOption::CollapseContainersOfOne(false),
4247 PathOption::PropertyNameOrder(vec![
4248 "runner",
4249 "binary",
4250 "args",
4251 ]),
4252 },
4253 "/*/program/*" => hashset! {
4254 PathOption::SortArrayItems(false),
4255 },
4256 "/*/*/*" => hashset! {
4257 general_order.clone()
4258 },
4259 "/*/*/*/*/*" => hashset! {
4260 general_order
4261 },
4262 },
4263 ..Default::default()
4264 };
4265
4266 json5format::format(buffer, file.map(|f| f.to_string_lossy().to_string()), Some(options))
4267 .map_err(|e| Error::json5(e, file))
4268}
4269
4270pub fn offer_to_all_and_component_diff_sources_message<'a>(
4271 capability: impl Iterator<Item = OfferToAllCapability<'a>>,
4272 component: &str,
4273) -> String {
4274 let mut output = String::new();
4275 let mut capability = capability.peekable();
4276 write!(&mut output, "{} ", capability.peek().unwrap().offer_type()).unwrap();
4277 for (i, capability) in capability.enumerate() {
4278 if i > 0 {
4279 write!(&mut output, ", ").unwrap();
4280 }
4281 write!(&mut output, "{}", capability.name()).unwrap();
4282 }
4283 write!(
4284 &mut output,
4285 r#" is offered to both "all" and child component "{}" with different sources"#,
4286 component
4287 )
4288 .unwrap();
4289 output
4290}
4291
4292pub fn offer_to_all_and_component_diff_capabilities_message<'a>(
4293 capability: impl Iterator<Item = OfferToAllCapability<'a>>,
4294 component: &str,
4295) -> String {
4296 let mut output = String::new();
4297 let mut capability_peek = capability.peekable();
4298
4299 let first_offer_to_all = capability_peek.peek().unwrap().clone();
4303 write!(&mut output, "{} ", first_offer_to_all.offer_type()).unwrap();
4304 for (i, capability) in capability_peek.enumerate() {
4305 if i > 0 {
4306 write!(&mut output, ", ").unwrap();
4307 }
4308 write!(&mut output, "{}", capability.name()).unwrap();
4309 }
4310 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();
4311 output
4312}
4313
4314pub fn offer_to_all_would_duplicate(
4319 offer_to_all: &Offer,
4320 specific_offer: &Offer,
4321 target: &cm_types::Name,
4322) -> Result<bool, Error> {
4323 assert!(offer_to_all.protocol.is_some() || offer_to_all.dictionary.is_some());
4325
4326 if CapabilityId::from_offer_expose(specific_offer).iter().flatten().all(
4329 |specific_offer_cap_id| {
4330 CapabilityId::from_offer_expose(offer_to_all)
4331 .iter()
4332 .flatten()
4333 .all(|offer_to_all_cap_id| offer_to_all_cap_id != specific_offer_cap_id)
4334 },
4335 ) {
4336 return Ok(false);
4337 }
4338
4339 let to_field_matches = specific_offer
4340 .to
4341 .iter()
4342 .any(|specific_offer_to| matches!(specific_offer_to, OfferToRef::Named(c) if c == target));
4343
4344 if !to_field_matches {
4345 return Ok(false);
4346 }
4347
4348 if offer_to_all.from != specific_offer.from {
4349 return Err(Error::validate(offer_to_all_and_component_diff_sources_message(
4350 offer_to_all_from_offer(offer_to_all),
4351 target.as_str(),
4352 )));
4353 }
4354
4355 if offer_to_all_from_offer(offer_to_all).all(|to_all_protocol| {
4357 offer_to_all_from_offer(specific_offer)
4358 .all(|to_specific_protocol| to_all_protocol != to_specific_protocol)
4359 }) {
4360 return Err(Error::validate(offer_to_all_and_component_diff_capabilities_message(
4361 offer_to_all_from_offer(offer_to_all),
4362 target.as_str(),
4363 )));
4364 }
4365
4366 Ok(true)
4367}
4368
4369impl Offer {
4370 pub fn empty(from: OneOrMany<OfferFromRef>, to: OneOrMany<OfferToRef>) -> Offer {
4373 Self {
4374 protocol: None,
4375 from,
4376 to,
4377 r#as: None,
4378 service: None,
4379 directory: None,
4380 config: None,
4381 runner: None,
4382 resolver: None,
4383 storage: None,
4384 dictionary: None,
4385 dependency: None,
4386 rights: None,
4387 subdir: None,
4388 event_stream: None,
4389 scope: None,
4390 availability: None,
4391 source_availability: None,
4392 }
4393 }
4394}
4395
4396#[cfg(test)]
4397pub fn create_offer(
4398 protocol_name: &str,
4399 from: OneOrMany<OfferFromRef>,
4400 to: OneOrMany<OfferToRef>,
4401) -> Offer {
4402 Offer {
4403 protocol: Some(OneOrMany::One(Name::from_str(protocol_name).unwrap())),
4404 ..Offer::empty(from, to)
4405 }
4406}
4407
4408#[cfg(test)]
4409mod tests {
4410 use super::*;
4411 use assert_matches::assert_matches;
4412 use difference::Changeset;
4413 use serde_json::{json, to_string_pretty, to_value};
4414 use std::path::Path;
4415 use test_case::test_case;
4416
4417 macro_rules! assert_json_eq {
4418 ($a:expr, $e:expr) => {{
4419 if $a != $e {
4420 let expected = to_string_pretty(&$e).unwrap();
4421 let actual = to_string_pretty(&$a).unwrap();
4422 assert_eq!(
4423 $a,
4424 $e,
4425 "JSON actual != expected. Diffs:\n\n{}",
4426 Changeset::new(&actual, &expected, "\n")
4427 );
4428 }
4429 }};
4430 }
4431
4432 #[test]
4436 fn test_parse_named_reference() {
4437 assert_matches!("#some-child".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "some-child");
4438 assert_matches!("#A".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "A");
4439 assert_matches!("#7".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "7");
4440 assert_matches!("#_".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "_");
4441
4442 assert_matches!("#-".parse::<OfferFromRef>(), Err(_));
4443 assert_matches!("#.".parse::<OfferFromRef>(), Err(_));
4444 assert_matches!("#".parse::<OfferFromRef>(), Err(_));
4445 assert_matches!("some-child".parse::<OfferFromRef>(), Err(_));
4446 }
4447
4448 #[test]
4449 fn test_parse_reference_test() {
4450 assert_matches!("parent".parse::<OfferFromRef>(), Ok(OfferFromRef::Parent));
4451 assert_matches!("framework".parse::<OfferFromRef>(), Ok(OfferFromRef::Framework));
4452 assert_matches!("self".parse::<OfferFromRef>(), Ok(OfferFromRef::Self_));
4453 assert_matches!("#child".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "child");
4454
4455 assert_matches!("invalid".parse::<OfferFromRef>(), Err(_));
4456 assert_matches!("#invalid-child^".parse::<OfferFromRef>(), Err(_));
4457 }
4458
4459 fn json_value_from_str(json: &str, filename: &Path) -> Result<Value, Error> {
4460 serde_json::from_str(json).map_err(|e| {
4461 Error::parse(
4462 format!("Couldn't read input as JSON: {}", e),
4463 Some(Location { line: e.line(), column: e.column() }),
4464 Some(filename),
4465 )
4466 })
4467 }
4468
4469 fn parse_as_ref(input: &str) -> Result<OfferFromRef, Error> {
4470 serde_json::from_value::<OfferFromRef>(json_value_from_str(input, &Path::new("test.cml"))?)
4471 .map_err(|e| Error::parse(format!("{}", e), None, None))
4472 }
4473
4474 #[test]
4475 fn test_deserialize_ref() -> Result<(), Error> {
4476 assert_matches!(parse_as_ref("\"self\""), Ok(OfferFromRef::Self_));
4477 assert_matches!(parse_as_ref("\"parent\""), Ok(OfferFromRef::Parent));
4478 assert_matches!(parse_as_ref("\"#child\""), Ok(OfferFromRef::Named(name)) if name == "child");
4479
4480 assert_matches!(parse_as_ref(r#""invalid""#), Err(_));
4481
4482 Ok(())
4483 }
4484
4485 macro_rules! test_parse_rights {
4486 (
4487 $(
4488 ($input:expr, $expected:expr),
4489 )+
4490 ) => {
4491 #[test]
4492 fn parse_rights() {
4493 $(
4494 parse_rights_test($input, $expected);
4495 )+
4496 }
4497 }
4498 }
4499
4500 fn parse_rights_test(input: &str, expected: Right) {
4501 let r: Right = serde_json5::from_str(&format!("\"{}\"", input)).expect("invalid json");
4502 assert_eq!(r, expected);
4503 }
4504
4505 test_parse_rights! {
4506 ("connect", Right::Connect),
4507 ("enumerate", Right::Enumerate),
4508 ("execute", Right::Execute),
4509 ("get_attributes", Right::GetAttributes),
4510 ("modify_directory", Right::ModifyDirectory),
4511 ("read_bytes", Right::ReadBytes),
4512 ("traverse", Right::Traverse),
4513 ("update_attributes", Right::UpdateAttributes),
4514 ("write_bytes", Right::WriteBytes),
4515 ("r*", Right::ReadAlias),
4516 ("w*", Right::WriteAlias),
4517 ("x*", Right::ExecuteAlias),
4518 ("rw*", Right::ReadWriteAlias),
4519 ("rx*", Right::ReadExecuteAlias),
4520 }
4521
4522 macro_rules! test_expand_rights {
4523 (
4524 $(
4525 ($input:expr, $expected:expr),
4526 )+
4527 ) => {
4528 #[test]
4529 fn expand_rights() {
4530 $(
4531 expand_rights_test($input, $expected);
4532 )+
4533 }
4534 }
4535 }
4536
4537 fn expand_rights_test(input: Right, expected: Vec<fio::Operations>) {
4538 assert_eq!(input.expand(), expected);
4539 }
4540
4541 test_expand_rights! {
4542 (Right::Connect, vec![fio::Operations::CONNECT]),
4543 (Right::Enumerate, vec![fio::Operations::ENUMERATE]),
4544 (Right::Execute, vec![fio::Operations::EXECUTE]),
4545 (Right::GetAttributes, vec![fio::Operations::GET_ATTRIBUTES]),
4546 (Right::ModifyDirectory, vec![fio::Operations::MODIFY_DIRECTORY]),
4547 (Right::ReadBytes, vec![fio::Operations::READ_BYTES]),
4548 (Right::Traverse, vec![fio::Operations::TRAVERSE]),
4549 (Right::UpdateAttributes, vec![fio::Operations::UPDATE_ATTRIBUTES]),
4550 (Right::WriteBytes, vec![fio::Operations::WRITE_BYTES]),
4551 (Right::ReadAlias, vec![
4552 fio::Operations::CONNECT,
4553 fio::Operations::ENUMERATE,
4554 fio::Operations::TRAVERSE,
4555 fio::Operations::READ_BYTES,
4556 fio::Operations::GET_ATTRIBUTES,
4557 ]),
4558 (Right::WriteAlias, vec![
4559 fio::Operations::CONNECT,
4560 fio::Operations::ENUMERATE,
4561 fio::Operations::TRAVERSE,
4562 fio::Operations::WRITE_BYTES,
4563 fio::Operations::MODIFY_DIRECTORY,
4564 fio::Operations::UPDATE_ATTRIBUTES,
4565 ]),
4566 (Right::ExecuteAlias, vec![
4567 fio::Operations::CONNECT,
4568 fio::Operations::ENUMERATE,
4569 fio::Operations::TRAVERSE,
4570 fio::Operations::EXECUTE,
4571 ]),
4572 (Right::ReadWriteAlias, vec![
4573 fio::Operations::CONNECT,
4574 fio::Operations::ENUMERATE,
4575 fio::Operations::TRAVERSE,
4576 fio::Operations::READ_BYTES,
4577 fio::Operations::WRITE_BYTES,
4578 fio::Operations::MODIFY_DIRECTORY,
4579 fio::Operations::GET_ATTRIBUTES,
4580 fio::Operations::UPDATE_ATTRIBUTES,
4581 ]),
4582 (Right::ReadExecuteAlias, vec![
4583 fio::Operations::CONNECT,
4584 fio::Operations::ENUMERATE,
4585 fio::Operations::TRAVERSE,
4586 fio::Operations::READ_BYTES,
4587 fio::Operations::GET_ATTRIBUTES,
4588 fio::Operations::EXECUTE,
4589 ]),
4590 }
4591
4592 #[test]
4593 fn test_deny_unknown_fields() {
4594 assert_matches!(serde_json5::from_str::<Document>("{ unknown: \"\" }"), Err(_));
4595 assert_matches!(serde_json5::from_str::<Environment>("{ unknown: \"\" }"), Err(_));
4596 assert_matches!(serde_json5::from_str::<RunnerRegistration>("{ unknown: \"\" }"), Err(_));
4597 assert_matches!(serde_json5::from_str::<ResolverRegistration>("{ unknown: \"\" }"), Err(_));
4598 assert_matches!(serde_json5::from_str::<Use>("{ unknown: \"\" }"), Err(_));
4599 assert_matches!(serde_json5::from_str::<Expose>("{ unknown: \"\" }"), Err(_));
4600 assert_matches!(serde_json5::from_str::<Offer>("{ unknown: \"\" }"), Err(_));
4601 assert_matches!(serde_json5::from_str::<Capability>("{ unknown: \"\" }"), Err(_));
4602 assert_matches!(serde_json5::from_str::<Child>("{ unknown: \"\" }"), Err(_));
4603 assert_matches!(serde_json5::from_str::<Collection>("{ unknown: \"\" }"), Err(_));
4604 }
4605
4606 fn empty_offer() -> Offer {
4609 Offer {
4610 service: None,
4611 protocol: None,
4612 directory: None,
4613 storage: None,
4614 runner: None,
4615 resolver: None,
4616 dictionary: None,
4617 config: None,
4618 from: OneOrMany::One(OfferFromRef::Self_),
4619 to: OneOrMany::Many(vec![]),
4620 r#as: None,
4621 rights: None,
4622 subdir: None,
4623 dependency: None,
4624 event_stream: None,
4625 scope: None,
4626 availability: None,
4627 source_availability: None,
4628 }
4629 }
4630
4631 fn empty_use() -> Use {
4632 Use {
4633 service: None,
4634 protocol: None,
4635 scope: None,
4636 directory: None,
4637 storage: None,
4638 config: None,
4639 key: None,
4640 from: None,
4641 path: None,
4642 rights: None,
4643 subdir: None,
4644 event_stream: None,
4645 runner: None,
4646 filter: None,
4647 dependency: None,
4648 availability: None,
4649 config_element_type: None,
4650 config_max_count: None,
4651 config_max_size: None,
4652 config_type: None,
4653 config_default: None,
4654 }
4655 }
4656
4657 #[test]
4658 fn test_capability_id() -> Result<(), Error> {
4659 let a: Name = "a".parse().unwrap();
4661 let b: Name = "b".parse().unwrap();
4662 assert_eq!(
4663 CapabilityId::from_offer_expose(&Offer {
4664 service: Some(OneOrMany::One(a.clone())),
4665 ..empty_offer()
4666 },)?,
4667 vec![CapabilityId::Service(&a)]
4668 );
4669 assert_eq!(
4670 CapabilityId::from_offer_expose(&Offer {
4671 service: Some(OneOrMany::Many(vec![a.clone(), b.clone()],)),
4672 ..empty_offer()
4673 },)?,
4674 vec![CapabilityId::Service(&a), CapabilityId::Service(&b)]
4675 );
4676 assert_eq!(
4677 CapabilityId::from_use(&Use {
4678 service: Some(OneOrMany::One(a.clone())),
4679 ..empty_use()
4680 },)?,
4681 vec![CapabilityId::UsedService("/svc/a".parse().unwrap())]
4682 );
4683 assert_eq!(
4684 CapabilityId::from_use(&Use {
4685 service: Some(OneOrMany::Many(vec![a.clone(), b.clone(),],)),
4686 ..empty_use()
4687 },)?,
4688 vec![
4689 CapabilityId::UsedService("/svc/a".parse().unwrap()),
4690 CapabilityId::UsedService("/svc/b".parse().unwrap())
4691 ]
4692 );
4693 assert_eq!(
4694 CapabilityId::from_use(&Use {
4695 event_stream: Some(OneOrMany::One(Name::new("test".to_string()).unwrap())),
4696 path: Some(cm_types::Path::new("/svc/myevent".to_string()).unwrap()),
4697 ..empty_use()
4698 },)?,
4699 vec![CapabilityId::UsedEventStream("/svc/myevent".parse().unwrap()),]
4700 );
4701 assert_eq!(
4702 CapabilityId::from_use(&Use {
4703 event_stream: Some(OneOrMany::One(Name::new("test".to_string()).unwrap())),
4704 ..empty_use()
4705 },)?,
4706 vec![CapabilityId::UsedEventStream(
4707 "/svc/fuchsia.component.EventStream".parse().unwrap()
4708 ),]
4709 );
4710 assert_eq!(
4711 CapabilityId::from_use(&Use {
4712 service: Some(OneOrMany::One(a.clone())),
4713 path: Some("/b".parse().unwrap()),
4714 ..empty_use()
4715 },)?,
4716 vec![CapabilityId::UsedService("/b".parse().unwrap())]
4717 );
4718
4719 assert_eq!(
4721 CapabilityId::from_offer_expose(&Offer {
4722 protocol: Some(OneOrMany::One(a.clone())),
4723 ..empty_offer()
4724 },)?,
4725 vec![CapabilityId::Protocol(&a)]
4726 );
4727 assert_eq!(
4728 CapabilityId::from_offer_expose(&Offer {
4729 protocol: Some(OneOrMany::Many(vec![a.clone(), b.clone()],)),
4730 ..empty_offer()
4731 },)?,
4732 vec![CapabilityId::Protocol(&a), CapabilityId::Protocol(&b)]
4733 );
4734 assert_eq!(
4735 CapabilityId::from_use(&Use {
4736 protocol: Some(OneOrMany::One(a.clone())),
4737 ..empty_use()
4738 },)?,
4739 vec![CapabilityId::UsedProtocol("/svc/a".parse().unwrap())]
4740 );
4741 assert_eq!(
4742 CapabilityId::from_use(&Use {
4743 protocol: Some(OneOrMany::Many(vec![a.clone(), b.clone(),],)),
4744 ..empty_use()
4745 },)?,
4746 vec![
4747 CapabilityId::UsedProtocol("/svc/a".parse().unwrap()),
4748 CapabilityId::UsedProtocol("/svc/b".parse().unwrap())
4749 ]
4750 );
4751 assert_eq!(
4752 CapabilityId::from_use(&Use {
4753 protocol: Some(OneOrMany::One(a.clone())),
4754 path: Some("/b".parse().unwrap()),
4755 ..empty_use()
4756 },)?,
4757 vec![CapabilityId::UsedProtocol("/b".parse().unwrap())]
4758 );
4759
4760 assert_eq!(
4762 CapabilityId::from_offer_expose(&Offer {
4763 directory: Some(OneOrMany::One(a.clone())),
4764 ..empty_offer()
4765 },)?,
4766 vec![CapabilityId::Directory(&a)]
4767 );
4768 assert_eq!(
4769 CapabilityId::from_offer_expose(&Offer {
4770 directory: Some(OneOrMany::Many(vec![a.clone(), b.clone()])),
4771 ..empty_offer()
4772 },)?,
4773 vec![CapabilityId::Directory(&a), CapabilityId::Directory(&b),]
4774 );
4775 assert_eq!(
4776 CapabilityId::from_use(&Use {
4777 directory: Some(a.clone()),
4778 path: Some("/b".parse().unwrap()),
4779 ..empty_use()
4780 },)?,
4781 vec![CapabilityId::UsedDirectory("/b".parse().unwrap())]
4782 );
4783
4784 assert_eq!(
4786 CapabilityId::from_offer_expose(&Offer {
4787 storage: Some(OneOrMany::One(a.clone())),
4788 ..empty_offer()
4789 },)?,
4790 vec![CapabilityId::Storage(&a)]
4791 );
4792 assert_eq!(
4793 CapabilityId::from_offer_expose(&Offer {
4794 storage: Some(OneOrMany::Many(vec![a.clone(), b.clone()])),
4795 ..empty_offer()
4796 },)?,
4797 vec![CapabilityId::Storage(&a), CapabilityId::Storage(&b),]
4798 );
4799 assert_eq!(
4800 CapabilityId::from_use(&Use {
4801 storage: Some(a.clone()),
4802 path: Some("/b".parse().unwrap()),
4803 ..empty_use()
4804 },)?,
4805 vec![CapabilityId::UsedStorage("/b".parse().unwrap())]
4806 );
4807
4808 assert_eq!(
4810 CapabilityId::from_use(&Use { runner: Some("elf".parse().unwrap()), ..empty_use() },)?,
4811 vec![CapabilityId::UsedRunner(&"elf".parse().unwrap())]
4812 );
4813
4814 assert_eq!(
4816 CapabilityId::from_offer_expose(&Offer {
4817 service: Some(OneOrMany::One(a.clone())),
4818 r#as: Some(b.clone()),
4819 ..empty_offer()
4820 },)?,
4821 vec![CapabilityId::Service(&b)]
4822 );
4823
4824 assert_matches!(CapabilityId::from_offer_expose(&empty_offer()), Err(_));
4826
4827 Ok(())
4828 }
4829
4830 fn document(contents: serde_json::Value) -> Document {
4831 serde_json5::from_str::<Document>(&contents.to_string()).unwrap()
4832 }
4833
4834 #[test]
4835 fn test_includes() {
4836 assert_eq!(document(json!({})).includes(), Vec::<String>::new());
4837 assert_eq!(document(json!({ "include": []})).includes(), Vec::<String>::new());
4838 assert_eq!(
4839 document(json!({ "include": [ "foo.cml", "bar.cml" ]})).includes(),
4840 vec!["foo.cml", "bar.cml"]
4841 );
4842 }
4843
4844 #[test]
4845 fn test_merge_same_section() {
4846 let mut some = document(json!({ "use": [{ "protocol": "foo" }] }));
4847 let mut other = document(json!({ "use": [{ "protocol": "bar" }] }));
4848 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
4849 let uses = some.r#use.as_ref().unwrap();
4850 assert_eq!(uses.len(), 2);
4851 assert_eq!(
4852 uses[0].protocol.as_ref().unwrap(),
4853 &OneOrMany::One("foo".parse::<Name>().unwrap())
4854 );
4855 assert_eq!(
4856 uses[1].protocol.as_ref().unwrap(),
4857 &OneOrMany::One("bar".parse::<Name>().unwrap())
4858 );
4859 }
4860
4861 #[test]
4862 fn test_merge_upgraded_availability() {
4863 let mut some =
4864 document(json!({ "use": [{ "protocol": "foo", "availability": "optional" }] }));
4865 let mut other1 = document(json!({ "use": [{ "protocol": "foo" }] }));
4866 let mut other2 =
4867 document(json!({ "use": [{ "protocol": "foo", "availability": "transitional" }] }));
4868 let mut other3 =
4869 document(json!({ "use": [{ "protocol": "foo", "availability": "same_as_target" }] }));
4870 some.merge_from(&mut other1, &Path::new("some/path")).unwrap();
4871 some.merge_from(&mut other2, &Path::new("some/path")).unwrap();
4872 some.merge_from(&mut other3, &Path::new("some/path")).unwrap();
4873 let uses = some.r#use.as_ref().unwrap();
4874 assert_eq!(uses.len(), 2);
4875 assert_eq!(
4876 uses[0].protocol.as_ref().unwrap(),
4877 &OneOrMany::One("foo".parse::<Name>().unwrap())
4878 );
4879 assert!(uses[0].availability.is_none());
4880 assert_eq!(
4881 uses[1].protocol.as_ref().unwrap(),
4882 &OneOrMany::One("foo".parse::<Name>().unwrap())
4883 );
4884 assert_eq!(uses[1].availability.as_ref().unwrap(), &Availability::SameAsTarget,);
4885 }
4886
4887 #[test]
4888 fn test_merge_different_sections() {
4889 let mut some = document(json!({ "use": [{ "protocol": "foo" }] }));
4890 let mut other = document(json!({ "expose": [{ "protocol": "bar", "from": "self" }] }));
4891 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
4892 let uses = some.r#use.as_ref().unwrap();
4893 let exposes = some.expose.as_ref().unwrap();
4894 assert_eq!(uses.len(), 1);
4895 assert_eq!(exposes.len(), 1);
4896 assert_eq!(
4897 uses[0].protocol.as_ref().unwrap(),
4898 &OneOrMany::One("foo".parse::<Name>().unwrap())
4899 );
4900 assert_eq!(
4901 exposes[0].protocol.as_ref().unwrap(),
4902 &OneOrMany::One("bar".parse::<Name>().unwrap())
4903 );
4904 }
4905
4906 #[test]
4907 fn test_merge_environments() {
4908 let mut some = document(json!({ "environments": [
4909 {
4910 "name": "one",
4911 "extends": "realm",
4912 },
4913 {
4914 "name": "two",
4915 "extends": "none",
4916 "runners": [
4917 {
4918 "runner": "r1",
4919 "from": "#c1",
4920 },
4921 {
4922 "runner": "r2",
4923 "from": "#c2",
4924 },
4925 ],
4926 "resolvers": [
4927 {
4928 "resolver": "res1",
4929 "from": "#c1",
4930 "scheme": "foo",
4931 },
4932 ],
4933 "debug": [
4934 {
4935 "protocol": "baz",
4936 "from": "#c2"
4937 }
4938 ]
4939 },
4940 ]}));
4941 let mut other = document(json!({ "environments": [
4942 {
4943 "name": "two",
4944 "__stop_timeout_ms": 100,
4945 "runners": [
4946 {
4947 "runner": "r3",
4948 "from": "#c3",
4949 },
4950 ],
4951 "resolvers": [
4952 {
4953 "resolver": "res2",
4954 "from": "#c1",
4955 "scheme": "bar",
4956 },
4957 ],
4958 "debug": [
4959 {
4960 "protocol": "faz",
4961 "from": "#c2"
4962 }
4963 ]
4964 },
4965 {
4966 "name": "three",
4967 "__stop_timeout_ms": 1000,
4968 },
4969 ]}));
4970 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
4971 assert_eq!(
4972 to_value(some).unwrap(),
4973 json!({"environments": [
4974 {
4975 "name": "one",
4976 "extends": "realm",
4977 },
4978 {
4979 "name": "three",
4980 "__stop_timeout_ms": 1000,
4981 },
4982 {
4983 "name": "two",
4984 "extends": "none",
4985 "__stop_timeout_ms": 100,
4986 "runners": [
4987 {
4988 "runner": "r1",
4989 "from": "#c1",
4990 },
4991 {
4992 "runner": "r2",
4993 "from": "#c2",
4994 },
4995 {
4996 "runner": "r3",
4997 "from": "#c3",
4998 },
4999 ],
5000 "resolvers": [
5001 {
5002 "resolver": "res1",
5003 "from": "#c1",
5004 "scheme": "foo",
5005 },
5006 {
5007 "resolver": "res2",
5008 "from": "#c1",
5009 "scheme": "bar",
5010 },
5011 ],
5012 "debug": [
5013 {
5014 "protocol": "baz",
5015 "from": "#c2"
5016 },
5017 {
5018 "protocol": "faz",
5019 "from": "#c2"
5020 }
5021 ]
5022 },
5023 ]})
5024 );
5025 }
5026
5027 #[test]
5028 fn test_merge_environments_errors() {
5029 {
5030 let mut some = document(json!({"environments": [{"name": "one", "extends": "realm"}]}));
5031 let mut other = document(json!({"environments": [{"name": "one", "extends": "none"}]}));
5032 assert!(some.merge_from(&mut other, &Path::new("some/path")).is_err());
5033 }
5034 {
5035 let mut some =
5036 document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]}));
5037 let mut other =
5038 document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 20}]}));
5039 assert!(some.merge_from(&mut other, &Path::new("some/path")).is_err());
5040 }
5041
5042 {
5044 let mut some = document(json!({"environments": [{"name": "one", "extends": "realm"}]}));
5045 let mut other =
5046 document(json!({"environments": [{"name": "one", "extends": "realm"}]}));
5047 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5048 assert_eq!(
5049 to_value(some).unwrap(),
5050 json!({"environments": [{"name": "one", "extends": "realm"}]})
5051 );
5052 }
5053 {
5054 let mut some =
5055 document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]}));
5056 let mut other =
5057 document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]}));
5058 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5059 assert_eq!(
5060 to_value(some).unwrap(),
5061 json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]})
5062 );
5063 }
5064 }
5065
5066 #[test]
5067 fn test_merge_from_other_config() {
5068 let mut some = document(json!({}));
5069 let mut other = document(json!({ "config": { "bar": { "type": "bool" } } }));
5070
5071 some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5072 let expected = document(json!({ "config": { "bar": { "type": "bool" } } }));
5073 assert_eq!(some.config, expected.config);
5074 }
5075
5076 #[test]
5077 fn test_merge_from_some_config() {
5078 let mut some = document(json!({ "config": { "bar": { "type": "bool" } } }));
5079 let mut other = document(json!({}));
5080
5081 some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5082 let expected = document(json!({ "config": { "bar": { "type": "bool" } } }));
5083 assert_eq!(some.config, expected.config);
5084 }
5085
5086 #[test]
5087 fn test_merge_from_config() {
5088 let mut some = document(json!({ "config": { "foo": { "type": "bool" } } }));
5089 let mut other = document(json!({ "config": { "bar": { "type": "bool" } } }));
5090 some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5091
5092 assert_eq!(
5093 some,
5094 document(json!({
5095 "config": {
5096 "foo": { "type": "bool" },
5097 "bar": { "type": "bool" },
5098 }
5099 })),
5100 );
5101 }
5102
5103 #[test]
5104 fn test_merge_from_config_dedupe_identical_fields() {
5105 let mut some = document(json!({ "config": { "foo": { "type": "bool" } } }));
5106 let mut other = document(json!({ "config": { "foo": { "type": "bool" } } }));
5107 some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5108
5109 assert_eq!(some, document(json!({ "config": { "foo": { "type": "bool" } } })));
5110 }
5111
5112 #[test]
5113 fn test_merge_from_config_conflicting_keys() {
5114 let mut some = document(json!({ "config": { "foo": { "type": "bool" } } }));
5115 let mut other = document(json!({ "config": { "foo": { "type": "uint8" } } }));
5116
5117 assert_matches::assert_matches!(
5118 some.merge_from(&mut other, &path::Path::new("some/path")),
5119 Err(Error::Validate { err, .. })
5120 if err == "Found conflicting entry for config key `foo` in `some/path`."
5121 );
5122 }
5123
5124 #[test]
5125 fn test_canonicalize() {
5126 let mut some = document(json!({
5127 "children": [
5128 { "name": "b_child", "url": "http://foo/b" },
5130 { "name": "a_child", "url": "http://foo/a" },
5131 ],
5132 "environments": [
5133 { "name": "b_env" },
5135 { "name": "a_env" },
5136 ],
5137 "collections": [
5138 { "name": "b_coll", "durability": "transient" },
5140 { "name": "a_coll", "durability": "transient" },
5141 ],
5142 "capabilities": [
5145 { "protocol": ["foo"] },
5147 { "protocol": "bar" },
5148 { "protocol": "arg", "path": "/arg" },
5150 { "service": ["b", "a"] },
5152 { "event_stream": ["b", "a"] },
5154 { "runner": "myrunner" },
5155 { "runner": "mypathrunner1", "path": "/foo" },
5157 { "runner": "mypathrunner2", "path": "/foo" },
5158 ],
5159 "offer": [
5161 { "protocol": "baz", "from": "#a_child", "to": "#c_child" },
5163 { "protocol": ["foo"], "from": "#a_child", "to": "#b_child" },
5165 { "protocol": "bar", "from": "#a_child", "to": "#b_child" },
5166 { "service": ["b", "a"], "from": "#a_child", "to": "#b_child" },
5168 {
5170 "event_stream": ["b", "a"],
5171 "from": "#a_child",
5172 "to": "#b_child",
5173 "scope": ["#b", "#c", "#a"] },
5175 { "runner": [ "myrunner", "a" ], "from": "#a_child", "to": "#b_child" },
5176 { "runner": [ "b" ], "from": "#a_child", "to": "#b_child" },
5177 { "directory": [ "b" ], "from": "#a_child", "to": "#b_child" },
5178 ],
5179 "expose": [
5180 { "protocol": ["foo"], "from": "#a_child" },
5181 { "protocol": "bar", "from": "#a_child" }, { "service": ["b", "a"], "from": "#a_child" },
5184 {
5186 "event_stream": ["b", "a"],
5187 "from": "#a_child",
5188 "scope": ["#b", "#c", "#a"] },
5190 { "runner": [ "myrunner", "a" ], "from": "#a_child" },
5191 { "runner": [ "b" ], "from": "#a_child" },
5192 { "directory": [ "b" ], "from": "#a_child" },
5193 ],
5194 "use": [
5195 { "protocol": ["zazzle"], "path": "/zazbaz" },
5197 { "protocol": ["foo"] },
5199 { "protocol": "bar" },
5200 { "service": ["b", "a"] },
5202 { "event_stream": ["b", "a"], "scope": ["#b", "#a"] },
5204 ],
5205 }));
5206 some.canonicalize();
5207
5208 assert_json_eq!(
5209 some,
5210 document(json!({
5211 "children": [
5212 { "name": "a_child", "url": "http://foo/a" },
5213 { "name": "b_child", "url": "http://foo/b" },
5214 ],
5215 "collections": [
5216 { "name": "a_coll", "durability": "transient" },
5217 { "name": "b_coll", "durability": "transient" },
5218 ],
5219 "environments": [
5220 { "name": "a_env" },
5221 { "name": "b_env" },
5222 ],
5223 "capabilities": [
5224 { "event_stream": ["a", "b"] },
5225 { "protocol": "arg", "path": "/arg" },
5226 { "protocol": ["bar", "foo"] },
5227 { "runner": "mypathrunner1", "path": "/foo" },
5228 { "runner": "mypathrunner2", "path": "/foo" },
5229 { "runner": "myrunner" },
5230 { "service": ["a", "b"] },
5231 ],
5232 "use": [
5233 { "event_stream": ["a", "b"], "scope": ["#a", "#b"] },
5234 { "protocol": ["bar", "foo"] },
5235 { "protocol": "zazzle", "path": "/zazbaz" },
5236 { "service": ["a", "b"] },
5237 ],
5238 "offer": [
5239 { "directory": "b", "from": "#a_child", "to": "#b_child" },
5240 {
5241 "event_stream": ["a", "b"],
5242 "from": "#a_child",
5243 "to": "#b_child",
5244 "scope": ["#a", "#b", "#c"],
5245 },
5246 { "protocol": ["bar", "foo"], "from": "#a_child", "to": "#b_child" },
5247 { "protocol": "baz", "from": "#a_child", "to": "#c_child" },
5248 { "runner": [ "a", "b", "myrunner" ], "from": "#a_child", "to": "#b_child" },
5249 { "service": ["a", "b"], "from": "#a_child", "to": "#b_child" },
5250 ],
5251 "expose": [
5252 { "directory": "b", "from": "#a_child" },
5253 {
5254 "event_stream": ["a", "b"],
5255 "from": "#a_child",
5256 "scope": ["#a", "#b", "#c"],
5257 },
5258 { "protocol": ["bar", "foo"], "from": "#a_child" },
5259 { "runner": [ "a", "b", "myrunner" ], "from": "#a_child" },
5260 { "service": ["a", "b"], "from": "#a_child" },
5261 ],
5262 }))
5263 )
5264 }
5265
5266 #[test]
5267 fn deny_unknown_config_type_fields() {
5268 let input = json!({ "config": { "foo": { "type": "bool", "unknown": "should error" } } });
5269 serde_json5::from_str::<Document>(&input.to_string())
5270 .expect_err("must reject unknown config field attributes");
5271 }
5272
5273 #[test]
5274 fn deny_unknown_config_nested_type_fields() {
5275 let input = json!({
5276 "config": {
5277 "foo": {
5278 "type": "vector",
5279 "max_count": 10,
5280 "element": {
5281 "type": "bool",
5282 "unknown": "should error"
5283 },
5284
5285 }
5286 }
5287 });
5288 serde_json5::from_str::<Document>(&input.to_string())
5289 .expect_err("must reject unknown config field attributes");
5290 }
5291
5292 #[test]
5293 fn test_merge_from_program() {
5294 let mut some = document(json!({ "program": { "binary": "bin/hello_world" } }));
5295 let mut other = document(json!({ "program": { "runner": "elf" } }));
5296 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5297 let expected =
5298 document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5299 assert_eq!(some.program, expected.program);
5300 }
5301
5302 #[test]
5303 fn test_merge_from_program_without_runner() {
5304 let mut some =
5305 document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5306 let mut other = document(json!({ "program": {} }));
5309 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5310 let expected =
5311 document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5312 assert_eq!(some.program, expected.program);
5313 }
5314
5315 #[test]
5316 fn test_merge_from_program_overlapping_environ() {
5317 let mut some = document(json!({ "program": { "environ": ["1"] } }));
5319 let mut other = document(json!({ "program": { "environ": ["2"] } }));
5320 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5321 let expected = document(json!({ "program": { "environ": ["1", "2"] } }));
5322 assert_eq!(some.program, expected.program);
5323 }
5324
5325 #[test]
5326 fn test_merge_from_program_overlapping_runner() {
5327 let mut some =
5329 document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5330 let mut other = document(json!({ "program": { "runner": "elf" } }));
5331 some.merge_from(&mut other, &Path::new("some/path")).unwrap();
5332 let expected =
5333 document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5334 assert_eq!(some.program, expected.program);
5335 }
5336
5337 #[test]
5338 fn test_offer_would_duplicate() {
5339 let offer = create_offer(
5340 "fuchsia.logger.LegacyLog",
5341 OneOrMany::One(OfferFromRef::Parent {}),
5342 OneOrMany::One(OfferToRef::Named(Name::from_str("something").unwrap())),
5343 );
5344
5345 let offer_to_all = create_offer(
5346 "fuchsia.logger.LogSink",
5347 OneOrMany::One(OfferFromRef::Parent {}),
5348 OneOrMany::One(OfferToRef::All),
5349 );
5350
5351 assert!(!offer_to_all_would_duplicate(
5353 &offer_to_all,
5354 &offer,
5355 &Name::from_str("something").unwrap()
5356 )
5357 .unwrap());
5358
5359 let offer = create_offer(
5360 "fuchsia.logger.LogSink",
5361 OneOrMany::One(OfferFromRef::Parent {}),
5362 OneOrMany::One(OfferToRef::Named(Name::from_str("not-something").unwrap())),
5363 );
5364
5365 assert!(!offer_to_all_would_duplicate(
5367 &offer_to_all,
5368 &offer,
5369 &Name::from_str("something").unwrap()
5370 )
5371 .unwrap());
5372
5373 let mut offer = create_offer(
5374 "fuchsia.logger.LogSink",
5375 OneOrMany::One(OfferFromRef::Parent {}),
5376 OneOrMany::One(OfferToRef::Named(Name::from_str("something").unwrap())),
5377 );
5378
5379 offer.r#as = Some(Name::from_str("FakeLog").unwrap());
5380
5381 assert!(!offer_to_all_would_duplicate(
5383 &offer_to_all,
5384 &offer,
5385 &Name::from_str("something").unwrap()
5386 )
5387 .unwrap());
5388
5389 let offer = create_offer(
5390 "fuchsia.logger.LogSink",
5391 OneOrMany::One(OfferFromRef::Parent {}),
5392 OneOrMany::One(OfferToRef::Named(Name::from_str("something").unwrap())),
5393 );
5394
5395 assert!(offer_to_all_would_duplicate(
5396 &offer_to_all,
5397 &offer,
5398 &Name::from_str("something").unwrap()
5399 )
5400 .unwrap());
5401
5402 let offer = create_offer(
5403 "fuchsia.logger.LogSink",
5404 OneOrMany::One(OfferFromRef::Named(Name::from_str("other").unwrap())),
5405 OneOrMany::One(OfferToRef::Named(Name::from_str("something").unwrap())),
5406 );
5407
5408 assert!(offer_to_all_would_duplicate(
5409 &offer_to_all,
5410 &offer,
5411 &Name::from_str("something").unwrap()
5412 )
5413 .is_err());
5414 }
5415
5416 #[test_case(
5417 document(json!({ "program": { "runner": "elf" } })),
5418 document(json!({ "program": { "runner": "fle" } })),
5419 "runner"
5420 ; "when_runner_conflicts"
5421 )]
5422 #[test_case(
5423 document(json!({ "program": { "binary": "bin/hello_world" } })),
5424 document(json!({ "program": { "binary": "bin/hola_mundo" } })),
5425 "binary"
5426 ; "when_binary_conflicts"
5427 )]
5428 #[test_case(
5429 document(json!({ "program": { "args": ["a".to_owned()] } })),
5430 document(json!({ "program": { "args": ["b".to_owned()] } })),
5431 "args"
5432 ; "when_args_conflicts"
5433 )]
5434 fn test_merge_from_program_error(mut some: Document, mut other: Document, field: &str) {
5435 assert_matches::assert_matches!(
5436 some.merge_from(&mut other, &path::Path::new("some/path")),
5437 Err(Error::Validate { err, .. })
5438 if err == format!("manifest include had a conflicting `program.{}`: some/path", field)
5439 );
5440 }
5441
5442 #[test_case(
5443 document(json!({ "facets": { "my.key": "my.value" } })),
5444 document(json!({ "facets": { "other.key": "other.value" } })),
5445 document(json!({ "facets": { "my.key": "my.value", "other.key": "other.value" } }))
5446 ; "two separate keys"
5447 )]
5448 #[test_case(
5449 document(json!({ "facets": { "my.key": "my.value" } })),
5450 document(json!({ "facets": {} })),
5451 document(json!({ "facets": { "my.key": "my.value" } }))
5452 ; "empty other facet"
5453 )]
5454 #[test_case(
5455 document(json!({ "facets": {} })),
5456 document(json!({ "facets": { "other.key": "other.value" } })),
5457 document(json!({ "facets": { "other.key": "other.value" } }))
5458 ; "empty my facet"
5459 )]
5460 #[test_case(
5461 document(json!({ "facets": { "key": { "type": "some_type" } } })),
5462 document(json!({ "facets": { "key": { "runner": "some_runner"} } })),
5463 document(json!({ "facets": { "key": { "type": "some_type", "runner": "some_runner" } } }))
5464 ; "nested facet key"
5465 )]
5466 #[test_case(
5467 document(json!({ "facets": { "key": { "type": "some_type", "nested_key": { "type": "new type" }}}})),
5468 document(json!({ "facets": { "key": { "nested_key": { "runner": "some_runner" }} } })),
5469 document(json!({ "facets": { "key": { "type": "some_type", "nested_key": { "runner": "some_runner", "type": "new type" }}}}))
5470 ; "double nested facet key"
5471 )]
5472 #[test_case(
5473 document(json!({ "facets": { "key": { "array_key": ["value_1", "value_2"] } } })),
5474 document(json!({ "facets": { "key": { "array_key": ["value_3", "value_4"] } } })),
5475 document(json!({ "facets": { "key": { "array_key": ["value_1", "value_2", "value_3", "value_4"] } } }))
5476 ; "merge array values"
5477 )]
5478 fn test_merge_from_facets(mut my: Document, mut other: Document, expected: Document) {
5479 my.merge_from(&mut other, &Path::new("some/path")).unwrap();
5480 assert_eq!(my.facets, expected.facets);
5481 }
5482
5483 #[test_case(
5484 document(json!({ "facets": { "key": "my.value" }})),
5485 document(json!({ "facets": { "key": "other.value" }})),
5486 "facets.key"
5487 ; "conflict first level keys"
5488 )]
5489 #[test_case(
5490 document(json!({ "facets": { "key": {"type": "cts" }}})),
5491 document(json!({ "facets": { "key": {"type": "system" }}})),
5492 "facets.key.type"
5493 ; "conflict second level keys"
5494 )]
5495 #[test_case(
5496 document(json!({ "facets": { "key": {"type": {"key": "value" }}}})),
5497 document(json!({ "facets": { "key": {"type": "system" }}})),
5498 "facets.key.type"
5499 ; "incompatible self nested type"
5500 )]
5501 #[test_case(
5502 document(json!({ "facets": { "key": {"type": "system" }}})),
5503 document(json!({ "facets": { "key": {"type": {"key": "value" }}}})),
5504 "facets.key.type"
5505 ; "incompatible other nested type"
5506 )]
5507 #[test_case(
5508 document(json!({ "facets": { "key": {"type": {"key": "my.value" }}}})),
5509 document(json!({ "facets": { "key": {"type": {"key": "some.value" }}}})),
5510 "facets.key.type.key"
5511 ; "conflict third level keys"
5512 )]
5513 #[test_case(
5514 document(json!({ "facets": { "key": {"type": [ "value_1" ]}}})),
5515 document(json!({ "facets": { "key": {"type": "value_2" }}})),
5516 "facets.key.type"
5517 ; "incompatible keys"
5518 )]
5519 fn test_merge_from_facet_error(mut my: Document, mut other: Document, field: &str) {
5520 assert_matches::assert_matches!(
5521 my.merge_from(&mut other, &path::Path::new("some/path")),
5522 Err(Error::Validate { err, .. })
5523 if err == format!("manifest include had a conflicting `{}`: some/path", field)
5524 );
5525 }
5526
5527 #[test_case("protocol")]
5528 #[test_case("service")]
5529 #[test_case("event_stream")]
5530 fn test_merge_from_duplicate_use_array(typename: &str) {
5531 let mut my = document(json!({ "use": [{ typename: "a" }]}));
5532 let mut other = document(json!({ "use": [
5533 { typename: ["a", "b"], "availability": "optional"}
5534 ]}));
5535 let result = document(json!({ "use": [
5536 { typename: "a" },
5537 { typename: "b", "availability": "optional" },
5538 ]}));
5539
5540 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5541 assert_eq!(my, result);
5542 }
5543
5544 #[test_case("directory")]
5545 #[test_case("storage")]
5546 fn test_merge_from_duplicate_use_noarray(typename: &str) {
5547 let mut my = document(json!({ "use": [{ typename: "a", "path": "/a"}]}));
5548 let mut other = document(json!({ "use": [
5549 { typename: "a", "path": "/a", "availability": "optional" },
5550 { typename: "b", "path": "/b", "availability": "optional" },
5551 ]}));
5552 let result = document(json!({ "use": [
5553 { typename: "a", "path": "/a" },
5554 { typename: "b", "path": "/b", "availability": "optional" },
5555 ]}));
5556 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5557 assert_eq!(my, result);
5558 }
5559
5560 #[test_case("protocol")]
5561 #[test_case("service")]
5562 #[test_case("event_stream")]
5563 fn test_merge_from_duplicate_capabilities_array(typename: &str) {
5564 let mut my = document(json!({ "capabilities": [{ typename: "a" }]}));
5565 let mut other = document(json!({ "capabilities": [ { typename: ["a", "b"] } ]}));
5566 let result = document(json!({ "capabilities": [ { typename: "a" }, { typename: "b" } ]}));
5567
5568 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5569 assert_eq!(my, result);
5570 }
5571
5572 #[test_case("directory")]
5573 #[test_case("storage")]
5574 #[test_case("runner")]
5575 #[test_case("resolver")]
5576 fn test_merge_from_duplicate_capabilities_noarray(typename: &str) {
5577 let mut my = document(json!({ "capabilities": [{ typename: "a", "path": "/a"}]}));
5578 let mut other = document(json!({ "capabilities": [
5579 { typename: "a", "path": "/a" },
5580 { typename: "b", "path": "/b" },
5581 ]}));
5582 let result = document(json!({ "capabilities": [
5583 { typename: "a", "path": "/a" },
5584 { typename: "b", "path": "/b" },
5585 ]}));
5586 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5587 assert_eq!(my, result);
5588 }
5589
5590 #[test]
5591 fn test_merge_with_empty_names() {
5592 let mut my = document(json!({ "capabilities": [{ "path": "/a"}]}));
5594
5595 let mut other = document(json!({ "capabilities": [
5596 { "directory": "a", "path": "/a" },
5597 { "directory": "b", "path": "/b" },
5598 ]}));
5599 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap_err();
5600 }
5601
5602 #[test_case("protocol")]
5603 #[test_case("service")]
5604 #[test_case("event_stream")]
5605 #[test_case("directory")]
5606 #[test_case("storage")]
5607 #[test_case("runner")]
5608 #[test_case("resolver")]
5609 fn test_merge_from_duplicate_offers(typename: &str) {
5610 let mut my = document(json!({ "offer": [{ typename: "a", "from": "self", "to": "#c" }]}));
5611 let mut other = document(json!({ "offer": [
5612 { typename: ["a", "b"], "from": "self", "to": "#c", "availability": "optional" }
5613 ]}));
5614 let result = document(json!({ "offer": [
5615 { typename: "a", "from": "self", "to": "#c" },
5616 { typename: "b", "from": "self", "to": "#c", "availability": "optional" },
5617 ]}));
5618
5619 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5620 assert_eq!(my, result);
5621 }
5622
5623 #[test_case("protocol")]
5624 #[test_case("service")]
5625 #[test_case("event_stream")]
5626 #[test_case("directory")]
5627 #[test_case("runner")]
5628 #[test_case("resolver")]
5629 fn test_merge_from_duplicate_exposes(typename: &str) {
5630 let mut my = document(json!({ "expose": [{ typename: "a", "from": "self" }]}));
5631 let mut other = document(json!({ "expose": [
5632 { typename: ["a", "b"], "from": "self" }
5633 ]}));
5634 let result = document(json!({ "expose": [
5635 { typename: "a", "from": "self" },
5636 { typename: "b", "from": "self" },
5637 ]}));
5638
5639 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5640 assert_eq!(my, result);
5641 }
5642
5643 #[test_case(
5644 document(json!({ "use": [
5645 { "protocol": "a", "availability": "required" },
5646 { "protocol": "b", "availability": "optional" },
5647 { "protocol": "c", "availability": "transitional" },
5648 { "protocol": "d", "availability": "same_as_target" },
5649 ]})),
5650 document(json!({ "use": [
5651 { "protocol": ["a"], "availability": "required" },
5652 { "protocol": ["b"], "availability": "optional" },
5653 { "protocol": ["c"], "availability": "transitional" },
5654 { "protocol": ["d"], "availability": "same_as_target" },
5655 ]})),
5656 document(json!({ "use": [
5657 { "protocol": "a", "availability": "required" },
5658 { "protocol": "b", "availability": "optional" },
5659 { "protocol": "c", "availability": "transitional" },
5660 { "protocol": "d", "availability": "same_as_target" },
5661 ]}))
5662 ; "merge both same"
5663 )]
5664 #[test_case(
5665 document(json!({ "use": [
5666 { "protocol": "a", "availability": "optional" },
5667 { "protocol": "b", "availability": "transitional" },
5668 { "protocol": "c", "availability": "transitional" },
5669 ]})),
5670 document(json!({ "use": [
5671 { "protocol": ["a", "x"], "availability": "required" },
5672 { "protocol": ["b", "y"], "availability": "optional" },
5673 { "protocol": ["c", "z"], "availability": "required" },
5674 ]})),
5675 document(json!({ "use": [
5676 { "protocol": ["a", "x"], "availability": "required" },
5677 { "protocol": ["b", "y"], "availability": "optional" },
5678 { "protocol": ["c", "z"], "availability": "required" },
5679 ]}))
5680 ; "merge with upgrade"
5681 )]
5682 #[test_case(
5683 document(json!({ "use": [
5684 { "protocol": "a", "availability": "required" },
5685 { "protocol": "b", "availability": "optional" },
5686 { "protocol": "c", "availability": "required" },
5687 ]})),
5688 document(json!({ "use": [
5689 { "protocol": ["a", "x"], "availability": "optional" },
5690 { "protocol": ["b", "y"], "availability": "transitional" },
5691 { "protocol": ["c", "z"], "availability": "transitional" },
5692 ]})),
5693 document(json!({ "use": [
5694 { "protocol": "a", "availability": "required" },
5695 { "protocol": "b", "availability": "optional" },
5696 { "protocol": "c", "availability": "required" },
5697 { "protocol": "x", "availability": "optional" },
5698 { "protocol": "y", "availability": "transitional" },
5699 { "protocol": "z", "availability": "transitional" },
5700 ]}))
5701 ; "merge with downgrade"
5702 )]
5703 #[test_case(
5704 document(json!({ "use": [
5705 { "protocol": "a", "availability": "optional" },
5706 { "protocol": "b", "availability": "transitional" },
5707 { "protocol": "c", "availability": "transitional" },
5708 ]})),
5709 document(json!({ "use": [
5710 { "protocol": ["a", "x"], "availability": "same_as_target" },
5711 { "protocol": ["b", "y"], "availability": "same_as_target" },
5712 { "protocol": ["c", "z"], "availability": "same_as_target" },
5713 ]})),
5714 document(json!({ "use": [
5715 { "protocol": "a", "availability": "optional" },
5716 { "protocol": "b", "availability": "transitional" },
5717 { "protocol": "c", "availability": "transitional" },
5718 { "protocol": ["a", "x"], "availability": "same_as_target" },
5719 { "protocol": ["b", "y"], "availability": "same_as_target" },
5720 { "protocol": ["c", "z"], "availability": "same_as_target" },
5721 ]}))
5722 ; "merge with no replacement"
5723 )]
5724 #[test_case(
5725 document(json!({ "use": [
5726 { "protocol": ["a", "b", "c"], "availability": "optional" },
5727 { "protocol": "d", "availability": "same_as_target" },
5728 { "protocol": ["e", "f"] },
5729 ]})),
5730 document(json!({ "use": [
5731 { "protocol": ["c", "e", "g"] },
5732 { "protocol": ["d", "h"] },
5733 { "protocol": ["f", "i"], "availability": "transitional" },
5734 ]})),
5735 document(json!({ "use": [
5736 { "protocol": ["a", "b"], "availability": "optional" },
5737 { "protocol": "d", "availability": "same_as_target" },
5738 { "protocol": ["e", "f"] },
5739 { "protocol": ["c", "g"] },
5740 { "protocol": ["d", "h"] },
5741 { "protocol": "i", "availability": "transitional" },
5742 ]}))
5743 ; "merge multiple"
5744 )]
5745
5746 fn test_merge_from_duplicate_capability_availability(
5747 mut my: Document,
5748 mut other: Document,
5749 result: Document,
5750 ) {
5751 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5752 assert_eq!(my, result);
5753 }
5754
5755 #[test_case(
5756 document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
5757 document(json!({ "use": [{ "protocol": ["c", "d"] }]})),
5758 document(json!({ "use": [
5759 { "protocol": ["a", "b"] }, { "protocol": ["c", "d"] }
5760 ]}))
5761 ; "merge capabilities with disjoint sets"
5762 )]
5763 #[test_case(
5764 document(json!({ "use": [
5765 { "protocol": ["a"] },
5766 { "protocol": "b" },
5767 ]})),
5768 document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
5769 document(json!({ "use": [
5770 { "protocol": ["a"] }, { "protocol": "b" },
5771 ]}))
5772 ; "merge capabilities with equal set"
5773 )]
5774 #[test_case(
5775 document(json!({ "use": [
5776 { "protocol": ["a", "b"] },
5777 { "protocol": "c" },
5778 ]})),
5779 document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
5780 document(json!({ "use": [
5781 { "protocol": ["a", "b"] }, { "protocol": "c" },
5782 ]}))
5783 ; "merge capabilities with subset"
5784 )]
5785 #[test_case(
5786 document(json!({ "use": [
5787 { "protocol": ["a", "b"] },
5788 ]})),
5789 document(json!({ "use": [{ "protocol": ["a", "b", "c"] }]})),
5790 document(json!({ "use": [
5791 { "protocol": ["a", "b"] },
5792 { "protocol": "c" },
5793 ]}))
5794 ; "merge capabilities with superset"
5795 )]
5796 #[test_case(
5797 document(json!({ "use": [
5798 { "protocol": ["a", "b"] },
5799 ]})),
5800 document(json!({ "use": [{ "protocol": ["b", "c", "d"] }]})),
5801 document(json!({ "use": [
5802 { "protocol": ["a", "b"] }, { "protocol": ["c", "d"] }
5803 ]}))
5804 ; "merge capabilities with intersection"
5805 )]
5806 #[test_case(
5807 document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
5808 document(json!({ "use": [
5809 { "protocol": ["c", "b", "d"] },
5810 { "protocol": ["e", "d"] },
5811 ]})),
5812 document(json!({ "use": [
5813 {"protocol": ["a", "b"] },
5814 {"protocol": ["c", "d"] },
5815 {"protocol": "e" }]}))
5816 ; "merge capabilities from multiple arrays"
5817 )]
5818 #[test_case(
5819 document(json!({ "use": [{ "protocol": "foo.bar.Baz", "from": "self"}]})),
5820 document(json!({ "use": [{ "service": "foo.bar.Baz", "from": "self"}]})),
5821 document(json!({ "use": [
5822 {"protocol": "foo.bar.Baz", "from": "self"},
5823 {"service": "foo.bar.Baz", "from": "self"}]}))
5824 ; "merge capabilities, types don't match"
5825 )]
5826 #[test_case(
5827 document(json!({ "use": [{ "protocol": "foo.bar.Baz", "from": "self"}]})),
5828 document(json!({ "use": [{ "protocol": "foo.bar.Baz" }]})),
5829 document(json!({ "use": [
5830 {"protocol": "foo.bar.Baz", "from": "self"},
5831 {"protocol": "foo.bar.Baz"}]}))
5832 ; "merge capabilities, fields don't match"
5833 )]
5834
5835 fn test_merge_from_duplicate_capability(
5836 mut my: Document,
5837 mut other: Document,
5838 result: Document,
5839 ) {
5840 my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
5841 assert_eq!(my, result);
5842 }
5843
5844 #[test_case(&Right::Connect; "connect right")]
5845 #[test_case(&Right::Enumerate; "enumerate right")]
5846 #[test_case(&Right::Execute; "execute right")]
5847 #[test_case(&Right::GetAttributes; "getattr right")]
5848 #[test_case(&Right::ModifyDirectory; "modifydir right")]
5849 #[test_case(&Right::ReadBytes; "readbytes right")]
5850 #[test_case(&Right::Traverse; "traverse right")]
5851 #[test_case(&Right::UpdateAttributes; "updateattrs right")]
5852 #[test_case(&Right::WriteBytes; "writebytes right")]
5853 #[test_case(&Right::ReadAlias; "r right")]
5854 #[test_case(&Right::WriteAlias; "w right")]
5855 #[test_case(&Right::ExecuteAlias; "x right")]
5856 #[test_case(&Right::ReadWriteAlias; "rw right")]
5857 #[test_case(&Right::ReadExecuteAlias; "rx right")]
5858 #[test_case(&OfferFromRef::Self_; "offer from self")]
5859 #[test_case(&OfferFromRef::Parent; "offer from parent")]
5860 #[test_case(&OfferFromRef::Named(Name::new("child".to_string()).unwrap()); "offer from named")]
5861 #[test_case(
5862 &document(json!({}));
5863 "empty document"
5864 )]
5865 #[test_case(
5866 &document(json!({ "use": [{ "protocol": "foo.bar.Baz", "from": "self"}]}));
5867 "use one from self"
5868 )]
5869 #[test_case(
5870 &document(json!({ "use": [{ "protocol": ["foo.bar.Baz", "some.other.Protocol"], "from": "self"}]}));
5871 "use multiple from self"
5872 )]
5873 #[test_case(
5874 &document(json!({
5875 "offer": [{ "protocol": "foo.bar.Baz", "from": "self", "to": "#elements"}],
5876 "collections" :[{"name": "elements", "durability": "transient" }]
5877 }));
5878 "offer from self to collection"
5879 )]
5880 #[test_case(
5881 &document(json!({
5882 "offer": [
5883 { "service": "foo.bar.Baz", "from": "self", "to": "#elements" },
5884 { "service": "some.other.Service", "from": "self", "to": "#elements"},
5885 ],
5886 "collections":[ {"name": "elements", "durability": "transient"} ]}));
5887 "service offers"
5888 )]
5889 #[test_case(
5890 &document(json!({ "expose": [{ "protocol": ["foo.bar.Baz", "some.other.Protocol"], "from": "self"}]}));
5891 "expose protocols from self"
5892 )]
5893 #[test_case(
5894 &document(json!({ "expose": [{ "service": ["foo.bar.Baz", "some.other.Service"], "from": "self"}]}));
5895 "expose service from self"
5896 )]
5897 #[test_case(
5898 &document(json!({ "capabilities": [{ "protocol": "foo.bar.Baz", "from": "self"}]}));
5899 "capabilities from self"
5900 )]
5901 #[test_case(
5902 &document(json!({ "facets": { "my.key": "my.value" } }));
5903 "facets"
5904 )]
5905 #[test_case(
5906 &document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
5907 "elf runner program"
5908 )]
5909 fn serialize_roundtrips<T>(val: &T)
5910 where
5911 T: serde::de::DeserializeOwned + Serialize + PartialEq + std::fmt::Debug,
5912 {
5913 let raw = serde_json::to_string(val).expect("serializing `val` should work");
5914 let parsed: T =
5915 serde_json::from_str(&raw).expect("must be able to parse back serialized value");
5916 assert_eq!(val, &parsed, "parsed value must equal original value");
5917 }
5918}