1use crate::capability_source::{
19 AggregateCapability, AggregateMember, AnonymizedAggregateSource, BuiltinSource,
20 CapabilitySource, CapabilityToCapabilitySource, ComponentCapability, ComponentSource,
21 FilteredAggregateProviderSource, FilteredProviderSource, FrameworkSource, InternalCapability,
22 NamespaceSource, VoidSource,
23};
24use crate::component_instance::{
25 ComponentInstanceInterface, ExtendedInstanceInterface, ResolvedInstanceInterface,
26 TopInstanceInterface,
27};
28use crate::error::RoutingError;
29use crate::mapper::DebugRouteMapper;
30use crate::RegistrationDecl;
31use cm_rust::{
32 Availability, CapabilityDecl, CapabilityTypeName, ChildRef, ExposeDecl, ExposeDeclCommon,
33 ExposeSource, ExposeTarget, FidlIntoNative, NativeIntoFidl, OfferDecl, OfferDeclCommon,
34 OfferServiceDecl, OfferSource, OfferTarget, RegistrationDeclCommon, RegistrationSource,
35 SourceName, SourcePath, UseDecl, UseDeclCommon, UseSource,
36};
37use cm_rust_derive::FidlDecl;
38use cm_types::{LongName, Name};
39use fidl_fuchsia_component_internal as finternal;
40use moniker::{ChildName, ExtendedMoniker, Moniker};
41use std::collections::HashSet;
42use std::marker::PhantomData;
43use std::sync::Arc;
44use std::{fmt, slice};
45
46#[cfg(feature = "serde")]
47use serde::{Deserialize, Serialize};
48
49pub async fn route_from_use<C, V>(
56 use_decl: UseDecl,
57 use_target: Arc<C>,
58 sources: Sources,
59 visitor: &mut V,
60 mapper: &mut dyn DebugRouteMapper,
61) -> Result<CapabilitySource, RoutingError>
62where
63 C: ComponentInstanceInterface + 'static,
64 V: OfferVisitor,
65 V: ExposeVisitor,
66 V: CapabilityVisitor,
67 V: Clone + Send + Sync + 'static,
68{
69 let cap_type = CapabilityTypeName::from(&use_decl);
70 if !use_decl.source_path().dirname.is_dot() {
71 return Err(RoutingError::DictionariesNotSupported {
72 cap_type,
73 moniker: use_target.moniker().clone(),
74 });
75 }
76 match Use::route(use_decl, use_target.clone(), &sources, visitor, mapper).await? {
77 UseResult::Source(source) => return Ok(source),
78 UseResult::OfferFromParent(offer, component) => {
79 route_from_offer(offer, component, sources, visitor, mapper).await
80 }
81 UseResult::ExposeFromChild(use_decl, child_component) => {
82 let child_exposes = child_component.lock_resolved_state().await?.exposes();
83 let child_exposes =
84 find_matching_exposes(cap_type, use_decl.source_name(), &child_exposes)
85 .ok_or_else(|| {
86 let child_moniker =
87 child_component.child_moniker().expect("ChildName should exist");
88 <UseDecl as ErrorNotFoundInChild>::error_not_found_in_child(
89 use_target.moniker().clone(),
90 child_moniker.clone(),
91 use_decl.source_name().clone(),
92 )
93 })?;
94 route_from_expose(child_exposes, child_component, sources, visitor, mapper).await
95 }
96 }
97}
98
99pub async fn route_from_registration<R, C, V>(
106 registration_decl: R,
107 registration_target: Arc<C>,
108 sources: Sources,
109 visitor: &mut V,
110 mapper: &mut dyn DebugRouteMapper,
111) -> Result<CapabilitySource, RoutingError>
112where
113 R: RegistrationDeclCommon
114 + ErrorNotFoundFromParent
115 + ErrorNotFoundInChild
116 + Into<RegistrationDecl>
117 + Clone
118 + 'static,
119 C: ComponentInstanceInterface + 'static,
120 V: OfferVisitor,
121 V: ExposeVisitor,
122 V: CapabilityVisitor,
123 V: Clone + Send + Sync + 'static,
124{
125 match Registration::route(registration_decl, registration_target, &sources, visitor, mapper)
126 .await?
127 {
128 RegistrationResult::Source(source) => return Ok(source),
129 RegistrationResult::FromParent(offer, component) => {
130 route_from_offer(offer, component, sources, visitor, mapper).await
131 }
132 RegistrationResult::FromChild(expose, component) => {
133 route_from_expose(expose, component, sources, visitor, mapper).await
134 }
135 }
136}
137
138pub async fn route_from_offer<C, V>(
145 offer: RouteBundle<OfferDecl>,
146 offer_target: Arc<C>,
147 sources: Sources,
148 visitor: &mut V,
149 mapper: &mut dyn DebugRouteMapper,
150) -> Result<CapabilitySource, RoutingError>
151where
152 C: ComponentInstanceInterface + 'static,
153 V: OfferVisitor,
154 V: ExposeVisitor,
155 V: CapabilityVisitor,
156 V: Clone + Send + Sync + 'static,
157{
158 let cap_type = CapabilityTypeName::from(offer.iter().next().unwrap());
159 for offer in offer.iter() {
160 if !offer.source_path().dirname.is_dot() {
161 return Err(RoutingError::DictionariesNotSupported {
162 cap_type,
163 moniker: offer_target.moniker().clone(),
164 });
165 }
166 }
167 match Offer::route(offer, offer_target.clone(), &sources, visitor, mapper).await? {
168 OfferResult::Source(source) => return Ok(source),
169 OfferResult::OfferFromChild(offer, component) => {
170 let offer_decl: OfferDecl = offer.clone().into();
171
172 let (exposes, component) = change_directions::<C>(offer, component).await?;
173
174 let capability_source =
175 route_from_expose(exposes, component, sources, visitor, mapper).await?;
176 if let OfferDecl::Service(offer_service_decl) = offer_decl {
177 if offer_service_decl.source_instance_filter.is_some()
178 || offer_service_decl.renamed_instances.is_some()
179 {
180 if let CapabilitySource::Component(ComponentSource { capability, moniker }) =
182 capability_source
183 {
184 let source_name = offer_service_decl.source_name.clone();
185 return Ok(CapabilitySource::FilteredProvider(FilteredProviderSource {
186 capability: AggregateCapability::Service(source_name),
187 moniker: moniker,
188 service_capability: capability,
189 offer_service_decl,
190 }));
191 }
192 }
193 }
194 Ok(capability_source)
195 }
196 OfferResult::OfferFromAnonymizedAggregate(offers, aggregation_component) => {
197 let mut members = vec![];
198 for o in offers.iter() {
199 match o.source() {
200 OfferSource::Collection(n) => {
201 members.push(AggregateMember::Collection(n.clone()));
202 }
203 OfferSource::Child(c) => {
204 assert!(
205 c.collection.is_none(),
206 "Anonymized offer source contained a dynamic child"
207 );
208 members.push(AggregateMember::Child(c.clone()));
209 }
210 OfferSource::Parent => {
211 members.push(AggregateMember::Parent);
212 }
213 OfferSource::Self_ => {
214 members.push(AggregateMember::Self_);
215 }
216 _ => unreachable!("impossible source"),
217 }
218 }
219 let first_offer = offers.iter().next().unwrap();
220 Ok(CapabilitySource::AnonymizedAggregate(AnonymizedAggregateSource {
221 capability: AggregateCapability::Service(first_offer.source_name().clone()),
222 moniker: aggregation_component.moniker().clone(),
223 sources: sources.clone(),
224 members,
225 instances: vec![],
226 }))
227 }
228 OfferResult::OfferFromFilteredAggregate(offers, aggregation_component) => {
229 let mut seen_instances: HashSet<Name> = HashSet::new();
231 for o in offers.iter() {
232 if let OfferDecl::Service(offer_service_decl) = o.clone().into() {
233 match offer_service_decl.source_instance_filter {
234 None => {
235 return Err(RoutingError::unsupported_route_source(
236 aggregation_component.moniker().clone(),
237 "Aggregate offers must be of service capabilities \
238 with source_instance_filter set",
239 ));
240 }
241 Some(allowed_instances) => {
242 for instance in allowed_instances.iter() {
243 if !seen_instances.insert(instance.clone()) {
244 return Err(RoutingError::unsupported_route_source(
245 aggregation_component.moniker().clone(),
246 format!(
247 "Instance {} found in multiple offers \
248 of the same service.",
249 instance
250 ),
251 ));
252 }
253 }
254 }
255 }
256 } else {
257 return Err(RoutingError::unsupported_route_source(
258 aggregation_component.moniker().clone(),
259 "Aggregate source must consist of only service capabilities",
260 ));
261 }
262 }
263 let (source_name, offer_service_decls) = offers.iter().fold(
266 ("_unused".parse().unwrap(), Vec::<OfferServiceDecl>::new()),
267 |(_, mut decls), o| {
268 if let OfferDecl::Service(offer_service_decl) = o.clone().into() {
269 decls.push(offer_service_decl);
270 }
271 (o.source_name().clone(), decls)
272 },
273 );
274 Ok(CapabilitySource::FilteredAggregateProvider(FilteredAggregateProviderSource {
277 capability: AggregateCapability::Service(source_name),
278 moniker: aggregation_component.moniker().clone(),
279 offer_service_decls,
280 sources: sources.clone(),
281 }))
282 }
283 }
284}
285
286pub async fn route_from_expose<C, V>(
293 expose: RouteBundle<ExposeDecl>,
294 expose_target: Arc<C>,
295 sources: Sources,
296 visitor: &mut V,
297 mapper: &mut dyn DebugRouteMapper,
298) -> Result<CapabilitySource, RoutingError>
299where
300 C: ComponentInstanceInterface + 'static,
301 V: OfferVisitor,
302 V: ExposeVisitor,
303 V: CapabilityVisitor,
304 V: Clone + Send + Sync + 'static,
305{
306 let cap_type = CapabilityTypeName::from(expose.iter().next().unwrap());
307 for expose in expose.iter() {
308 if !expose.source_path().dirname.is_dot() {
309 return Err(RoutingError::DictionariesNotSupported {
310 cap_type,
311 moniker: expose_target.moniker().clone(),
312 });
313 }
314 }
315 match Expose::route(expose, expose_target, &sources, visitor, mapper).await? {
316 ExposeResult::Source(source) => Ok(source),
317 ExposeResult::ExposeFromAnonymizedAggregate(expose, aggregation_component) => {
318 let mut members = vec![];
319 for e in expose.iter() {
320 match e.source() {
321 ExposeSource::Collection(n) => {
322 members.push(AggregateMember::Collection(n.clone()));
323 }
324 ExposeSource::Child(n) => {
325 members.push(AggregateMember::Child(ChildRef {
326 name: LongName::new(n.clone()).unwrap(),
327 collection: None,
328 }));
329 }
330 ExposeSource::Self_ => {
331 members.push(AggregateMember::Self_);
332 }
333 _ => unreachable!("this was checked before"),
334 }
335 }
336 let first_expose = expose.iter().next().expect("empty bundle");
337 Ok(CapabilitySource::AnonymizedAggregate(AnonymizedAggregateSource {
338 capability: AggregateCapability::Service(first_expose.source_name().clone()),
339 moniker: aggregation_component.moniker().clone(),
340 sources: sources.clone(),
341 members,
342 instances: vec![],
343 }))
344 }
345 }
346}
347
348pub async fn route_from_self<C, V>(
354 use_decl: UseDecl,
355 target: Arc<C>,
356 sources: Sources,
357 visitor: &mut V,
358 mapper: &mut dyn DebugRouteMapper,
359) -> Result<CapabilitySource, RoutingError>
360where
361 C: ComponentInstanceInterface + 'static,
362 V: CapabilityVisitor,
363 V: Clone + Send + Sync + 'static,
364{
365 let cap_type = CapabilityTypeName::from(&use_decl);
366 if !use_decl.source_path().dirname.is_dot() {
367 return Err(RoutingError::DictionariesNotSupported {
368 cap_type,
369 moniker: target.moniker().clone(),
370 });
371 }
372 mapper.add_use(target.moniker().clone(), &use_decl.clone().into());
373 route_from_self_by_name(use_decl.source_name(), target, sources, visitor, mapper).await
374}
375
376pub async fn route_from_self_by_name<C, V>(
382 name: &Name,
383 target: Arc<C>,
384 sources: Sources,
385 visitor: &mut V,
386 mapper: &mut dyn DebugRouteMapper,
387) -> Result<CapabilitySource, RoutingError>
388where
389 C: ComponentInstanceInterface + 'static,
390 V: CapabilityVisitor,
391 V: Clone + Send + Sync + 'static,
392{
393 let target_capabilities = target.lock_resolved_state().await?.capabilities();
394 Ok(CapabilitySource::Component(ComponentSource {
395 capability: sources.find_component_source(
396 name,
397 target.moniker(),
398 &target_capabilities,
399 visitor,
400 mapper,
401 )?,
402 moniker: target.moniker().clone(),
403 }))
404}
405
406#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
408#[derive(FidlDecl, Debug, PartialEq, Clone)]
409#[fidl_decl(fidl_table = "finternal::Sources")]
410pub struct Sources {
411 framework: bool,
412 builtin: bool,
413 capability: bool,
414 collection: bool,
415 namespace: bool,
416 component: bool,
417 capability_type: CapabilityTypeName,
418}
419
420impl Sources {
423 pub fn new(capability: CapabilityTypeName) -> Self {
425 Self {
426 framework: false,
427 builtin: false,
428 capability: false,
429 collection: false,
430 namespace: false,
431 component: false,
432 capability_type: capability,
433 }
434 }
435
436 pub fn framework(self) -> Self {
438 Self { framework: true, ..self }
439 }
440
441 pub fn capability(self) -> Self {
444 Self { capability: true, ..self }
445 }
446
447 pub fn collection(self) -> Self {
449 Self { collection: true, ..self }
450 }
451
452 pub fn namespace(self) -> Self {
455 Self { namespace: true, ..self }
456 }
457
458 pub fn component(self) -> Self {
460 Self { component: true, ..self }
461 }
462
463 pub fn builtin(self) -> Self {
466 Self { builtin: true, ..self }
467 }
468
469 pub fn framework_source(
472 &self,
473 moniker: &Moniker,
474 name: Name,
475 mapper: &mut dyn DebugRouteMapper,
476 ) -> Result<InternalCapability, RoutingError> {
477 if self.framework {
478 let capability = InternalCapability::new(self.capability_type, name.clone());
479 mapper.add_framework_capability(name);
480 Ok(capability)
481 } else {
482 Err(RoutingError::unsupported_route_source(moniker.clone(), "framework"))
483 }
484 }
485
486 pub fn capability_source(&self, moniker: &Moniker) -> Result<(), RoutingError> {
490 if self.capability {
491 Ok(())
492 } else {
493 Err(RoutingError::unsupported_route_source(moniker.clone(), "capability"))
494 }
495 }
496
497 pub fn is_namespace_supported(&self) -> bool {
499 self.namespace
500 }
501
502 pub fn find_namespace_source<V>(
507 &self,
508 moniker: impl Into<ExtendedMoniker>,
509 name: &Name,
510 capabilities: &[CapabilityDecl],
511 visitor: &mut V,
512 mapper: &mut dyn DebugRouteMapper,
513 ) -> Result<Option<ComponentCapability>, RoutingError>
514 where
515 V: CapabilityVisitor,
516 {
517 if self.namespace {
518 if let Some(decl) = capabilities
519 .iter()
520 .find(|decl: &&CapabilityDecl| {
521 self.capability_type == CapabilityTypeName::from(*decl) && decl.name() == name
522 })
523 .cloned()
524 {
525 let moniker = moniker.into();
526 visitor.visit(&moniker.into(), &decl)?;
527 mapper.add_namespace_capability(&decl);
528 Ok(Some(decl.into()))
529 } else {
530 Ok(None)
531 }
532 } else {
533 Err(RoutingError::unsupported_route_source(moniker, "namespace"))
534 }
535 }
536
537 pub fn find_builtin_source<V>(
541 &self,
542 moniker: impl Into<ExtendedMoniker>,
543 name: &Name,
544 capabilities: &[CapabilityDecl],
545 visitor: &mut V,
546 mapper: &mut dyn DebugRouteMapper,
547 ) -> Result<Option<InternalCapability>, RoutingError>
548 where
549 V: CapabilityVisitor,
550 {
551 if self.builtin {
552 if let Some(decl) = capabilities
553 .iter()
554 .find(|decl: &&CapabilityDecl| {
555 self.capability_type == CapabilityTypeName::from(*decl) && decl.name() == name
556 })
557 .cloned()
558 {
559 visitor.visit(&moniker.into(), &decl)?;
560 mapper.add_builtin_capability(&decl);
561 Ok(Some(decl.into()))
562 } else {
563 Ok(None)
564 }
565 } else {
566 Err(RoutingError::unsupported_route_source(moniker, "built-in"))
567 }
568 }
569
570 pub fn find_component_source<V>(
576 &self,
577 name: &Name,
578 moniker: &Moniker,
579 capabilities: &[CapabilityDecl],
580 visitor: &mut V,
581 mapper: &mut dyn DebugRouteMapper,
582 ) -> Result<ComponentCapability, RoutingError>
583 where
584 V: CapabilityVisitor,
585 {
586 if self.component {
587 let decl = capabilities
588 .iter()
589 .find(|decl: &&CapabilityDecl| {
590 self.capability_type == CapabilityTypeName::from(*decl) && decl.name() == name
591 })
592 .cloned()
593 .expect("CapabilityDecl missing, FIDL validation should catch this");
594 visitor.visit(&moniker.clone().into(), &decl)?;
595 mapper.add_component_capability(moniker.clone(), &decl);
596 Ok(decl.into())
597 } else {
598 Err(RoutingError::unsupported_route_source(moniker.clone(), "component"))
599 }
600 }
601}
602
603pub struct Use();
604
605enum UseResult<C: ComponentInstanceInterface + 'static> {
607 Source(CapabilitySource),
609 OfferFromParent(RouteBundle<OfferDecl>, Arc<C>),
611 ExposeFromChild(UseDecl, Arc<C>),
616}
617
618impl Use {
619 async fn route<C, V>(
622 use_: UseDecl,
623 target: Arc<C>,
624 sources: &Sources,
625 visitor: &mut V,
626 mapper: &mut dyn DebugRouteMapper,
627 ) -> Result<UseResult<C>, RoutingError>
628 where
629 C: ComponentInstanceInterface + 'static,
630 V: CapabilityVisitor,
631 {
632 mapper.add_use(target.moniker().clone(), &use_);
633 match use_.source() {
634 UseSource::Framework => {
635 Ok(UseResult::Source(CapabilitySource::Framework(FrameworkSource {
636 capability: sources.framework_source(
637 target.moniker(),
638 use_.source_name().clone(),
639 mapper,
640 )?,
641 moniker: target.moniker().clone(),
642 })))
643 }
644 UseSource::Capability(_) => {
645 sources.capability_source(target.moniker())?;
646 Ok(UseResult::Source(CapabilitySource::Capability(CapabilityToCapabilitySource {
647 moniker: target.moniker().clone(),
648 source_capability: ComponentCapability::Use_(use_.into()),
649 })))
650 }
651 UseSource::Parent => match target.try_get_parent()? {
652 ExtendedInstanceInterface::<C>::AboveRoot(top_instance) => {
653 if sources.is_namespace_supported() {
654 if let Some(capability) = sources.find_namespace_source(
655 ExtendedMoniker::ComponentManager,
656 use_.source_name(),
657 top_instance.namespace_capabilities(),
658 visitor,
659 mapper,
660 )? {
661 return Ok(UseResult::Source(CapabilitySource::Namespace(
662 NamespaceSource { capability },
663 )));
664 }
665 }
666 if let Some(capability) = sources.find_builtin_source(
667 ExtendedMoniker::ComponentManager,
668 use_.source_name(),
669 top_instance.builtin_capabilities(),
670 visitor,
671 mapper,
672 )? {
673 return Ok(UseResult::Source(CapabilitySource::Builtin(BuiltinSource {
674 capability,
675 })));
676 }
677 Err(RoutingError::use_from_component_manager_not_found(
678 use_.source_name().to_string(),
679 ))
680 }
681 ExtendedInstanceInterface::<C>::Component(parent_component) => {
682 let parent_offers = parent_component.lock_resolved_state().await?.offers();
683 let child_moniker = target.child_moniker().expect("ChildName should exist");
684 let parent_offers = find_matching_offers(
685 CapabilityTypeName::from(&use_),
686 use_.source_name(),
687 &child_moniker,
688 &parent_offers,
689 )
690 .ok_or_else(|| {
691 <UseDecl as ErrorNotFoundFromParent>::error_not_found_from_parent(
692 target.moniker().clone(),
693 use_.source_name().clone(),
694 )
695 })?;
696 Ok(UseResult::OfferFromParent(parent_offers, parent_component))
697 }
698 },
699 UseSource::Child(name) => {
700 let moniker = target.moniker();
701 let child_component = {
702 let child_moniker = ChildName::new(name.clone().into(), None);
703 target.lock_resolved_state().await?.get_child(&child_moniker).ok_or_else(
704 || {
705 RoutingError::use_from_child_instance_not_found(
706 &child_moniker,
707 moniker,
708 name.clone(),
709 )
710 },
711 )?
712 };
713 Ok(UseResult::ExposeFromChild(use_, child_component))
714 }
715 UseSource::Collection(name) => Ok(UseResult::Source(
716 CapabilitySource::AnonymizedAggregate(AnonymizedAggregateSource {
717 capability: AggregateCapability::Service(use_.source_name().clone()),
718 moniker: target.moniker().clone(),
719 sources: sources.clone(),
720 members: vec![AggregateMember::Collection(name.clone())],
721 instances: vec![],
722 }),
723 )),
724 UseSource::Debug => {
725 return Err(RoutingError::unsupported_route_source(
728 target.moniker().clone(),
729 "debug capability",
730 ));
731 }
732 UseSource::Self_ => {
733 let use_: UseDecl = use_.into();
734 if let UseDecl::Config(config) = use_ {
735 sources.capability_source(target.moniker())?;
736 let target_capabilities = target.lock_resolved_state().await?.capabilities();
737 return Ok(UseResult::Source(CapabilitySource::Component(ComponentSource {
738 capability: sources.find_component_source(
739 config.source_name(),
740 target.moniker(),
741 &target_capabilities,
742 visitor,
743 mapper,
744 )?,
745 moniker: target.moniker().clone(),
746 })));
747 }
748 return Err(RoutingError::unsupported_route_source(
749 target.moniker().clone(),
750 "self",
751 ));
752 }
753 UseSource::Environment => {
754 return Err(RoutingError::unsupported_route_source(
757 target.moniker().clone(),
758 "environment",
759 ));
760 }
761 }
762 }
763}
764
765pub struct Registration<R>(PhantomData<R>);
767
768#[allow(clippy::large_enum_variant)] enum RegistrationResult<C: ComponentInstanceInterface + 'static, O: Clone + fmt::Debug> {
771 Source(CapabilitySource),
773 FromParent(RouteBundle<O>, Arc<C>),
775 FromChild(RouteBundle<ExposeDecl>, Arc<C>),
777}
778
779impl<R> Registration<R>
780where
781 R: RegistrationDeclCommon
782 + ErrorNotFoundFromParent
783 + ErrorNotFoundInChild
784 + Into<RegistrationDecl>
785 + Clone,
786{
787 async fn route<C, V>(
791 registration: R,
792 target: Arc<C>,
793 sources: &Sources,
794 visitor: &mut V,
795 mapper: &mut dyn DebugRouteMapper,
796 ) -> Result<RegistrationResult<C, OfferDecl>, RoutingError>
797 where
798 C: ComponentInstanceInterface + 'static,
799 V: CapabilityVisitor,
800 {
801 let registration_decl: RegistrationDecl = registration.clone().into();
802 mapper.add_registration(target.moniker().clone(), ®istration_decl);
803 match registration.source() {
804 RegistrationSource::Self_ => {
805 let target_capabilities = target.lock_resolved_state().await?.capabilities();
806 Ok(RegistrationResult::Source(CapabilitySource::Component(ComponentSource {
807 capability: sources.find_component_source(
808 registration.source_name(),
809 target.moniker(),
810 &target_capabilities,
811 visitor,
812 mapper,
813 )?,
814 moniker: target.moniker().clone(),
815 })))
816 }
817 RegistrationSource::Parent => match target.try_get_parent()? {
818 ExtendedInstanceInterface::<C>::AboveRoot(top_instance) => {
819 if sources.is_namespace_supported() {
820 if let Some(capability) = sources.find_namespace_source(
821 ExtendedMoniker::ComponentManager,
822 registration.source_name(),
823 top_instance.namespace_capabilities(),
824 visitor,
825 mapper,
826 )? {
827 return Ok(RegistrationResult::Source(CapabilitySource::Namespace(
828 NamespaceSource { capability },
829 )));
830 }
831 }
832 if let Some(capability) = sources.find_builtin_source(
833 ExtendedMoniker::ComponentManager,
834 registration.source_name(),
835 top_instance.builtin_capabilities(),
836 visitor,
837 mapper,
838 )? {
839 return Ok(RegistrationResult::Source(CapabilitySource::Builtin(
840 BuiltinSource { capability },
841 )));
842 }
843 Err(RoutingError::register_from_component_manager_not_found(
844 registration.source_name().to_string(),
845 ))
846 }
847 ExtendedInstanceInterface::<C>::Component(parent_component) => {
848 let parent_offers = parent_component.lock_resolved_state().await?.offers();
849 let child_moniker = target.child_moniker().expect("ChildName should exist");
850 let parent_offers = find_matching_offers(
851 CapabilityTypeName::from(®istration_decl),
852 registration.source_name(),
853 &child_moniker,
854 &parent_offers,
855 )
856 .ok_or_else(|| {
857 <R as ErrorNotFoundFromParent>::error_not_found_from_parent(
858 target.moniker().clone(),
859 registration.source_name().clone(),
860 )
861 })?;
862 Ok(RegistrationResult::FromParent(parent_offers, parent_component))
863 }
864 },
865 RegistrationSource::Child(child) => {
866 let child_component = {
867 let child_moniker = ChildName::try_new(child, None).expect(
868 "discovered invalid child name, manifest validation should prevent this",
869 );
870 target.lock_resolved_state().await?.get_child(&child_moniker).ok_or_else(
871 || RoutingError::EnvironmentFromChildInstanceNotFound {
872 child_moniker,
873 moniker: target.moniker().clone(),
874 capability_name: registration.source_name().clone(),
875 capability_type: R::TYPE.to_string(),
876 },
877 )?
878 };
879
880 let child_exposes = child_component.lock_resolved_state().await?.exposes();
881 let capability_type = CapabilityTypeName::from(®istration.clone().into());
882 let child_exposes = find_matching_exposes(
883 capability_type,
884 registration.source_name(),
885 &child_exposes,
886 )
887 .ok_or_else(|| {
888 let child_moniker =
889 child_component.child_moniker().expect("ChildName should exist");
890 <R as ErrorNotFoundInChild>::error_not_found_in_child(
891 target.moniker().clone(),
892 child_moniker.clone(),
893 registration.source_name().clone(),
894 )
895 })?;
896 Ok(RegistrationResult::FromChild(child_exposes, child_component.clone()))
897 }
898 }
899 }
900}
901
902pub struct Offer();
904
905enum OfferResult<C: ComponentInstanceInterface + 'static> {
907 Source(CapabilitySource),
909 OfferFromChild(OfferDecl, Arc<C>),
912 OfferFromFilteredAggregate(RouteBundle<OfferDecl>, Arc<C>),
914 OfferFromAnonymizedAggregate(RouteBundle<OfferDecl>, Arc<C>),
916}
917
918enum OfferSegment<C: ComponentInstanceInterface + 'static> {
919 Done(OfferResult<C>),
920 Next(RouteBundle<OfferDecl>, Arc<C>),
921}
922
923impl Offer {
924 async fn route<C, V>(
927 mut offer_bundle: RouteBundle<OfferDecl>,
928 mut target: Arc<C>,
929 sources: &Sources,
930 visitor: &mut V,
931 mapper: &mut dyn DebugRouteMapper,
932 ) -> Result<OfferResult<C>, RoutingError>
933 where
934 C: ComponentInstanceInterface + 'static,
935 V: OfferVisitor,
936 V: CapabilityVisitor,
937 {
938 loop {
939 let visit_offer = match &offer_bundle {
940 RouteBundle::Single(offer) => Some(offer),
941 RouteBundle::Aggregate(offers) => {
942 if offers.len() == 1 {
944 Some(&offers[0])
945 } else {
946 None
947 }
948 }
949 };
950 if let Some(visit_offer) = visit_offer {
951 mapper.add_offer(target.moniker().clone(), &visit_offer);
952 OfferVisitor::visit(visitor, &target.moniker().clone().into(), &visit_offer)?;
953 }
954
955 fn is_filtered_offer(o: &OfferDecl) -> bool {
956 if let OfferDecl::Service(offer_service) = o {
957 if let Some(f) = offer_service.source_instance_filter.as_ref() {
958 if !f.is_empty() {
959 return true;
960 }
961 }
962 if let Some(f) = offer_service.renamed_instances.as_ref() {
963 if !f.is_empty() {
964 return true;
965 }
966 }
967 }
968 false
969 }
970
971 for o in offer_bundle.iter() {
973 if !o.source_path().dirname.is_dot() {
974 return Err(RoutingError::DictionariesNotSupported {
975 moniker: target.moniker().clone(),
976 cap_type: CapabilityTypeName::from(o),
977 });
978 }
979 }
980
981 match offer_bundle {
982 RouteBundle::Single(offer) => {
983 match Self::route_segment(offer, target, sources, visitor, mapper).await? {
984 OfferSegment::Done(r) => return Ok(r),
985 OfferSegment::Next(o, t) => {
986 offer_bundle = o;
987 target = t;
988 }
989 }
990 }
991 RouteBundle::Aggregate(_) => {
992 if offer_bundle.iter().all(|o| !is_filtered_offer(o)) {
993 return Ok(OfferResult::OfferFromAnonymizedAggregate(offer_bundle, target));
994 } else {
995 return Ok(OfferResult::OfferFromFilteredAggregate(offer_bundle, target));
996 }
997 }
998 }
999 }
1000 }
1001
1002 async fn route_segment<C, V>(
1003 offer: OfferDecl,
1004 target: Arc<C>,
1005 sources: &Sources,
1006 visitor: &mut V,
1007 mapper: &mut dyn DebugRouteMapper,
1008 ) -> Result<OfferSegment<C>, RoutingError>
1009 where
1010 C: ComponentInstanceInterface + 'static,
1011 V: OfferVisitor,
1012 V: CapabilityVisitor,
1013 {
1014 let res = match offer.source() {
1015 OfferSource::Void => {
1016 OfferSegment::Done(OfferResult::Source(CapabilitySource::Void(VoidSource {
1017 capability: InternalCapability::new(
1018 (&offer).into(),
1019 offer.source_name().clone(),
1020 ),
1021 moniker: target.moniker().clone(),
1022 })))
1023 }
1024 OfferSource::Self_ => {
1025 let target_capabilities = target.lock_resolved_state().await?.capabilities();
1026 let capability = sources.find_component_source(
1027 offer.source_name(),
1028 target.moniker(),
1029 &target_capabilities,
1030 visitor,
1031 mapper,
1032 )?;
1033 let component = target.as_weak();
1035 let moniker = target.moniker().clone();
1036 let res = match offer.into() {
1037 OfferDecl::Service(offer_service_decl) => {
1038 if offer_service_decl.source_instance_filter.is_some()
1039 || offer_service_decl.renamed_instances.is_some()
1040 {
1041 let source_name = offer_service_decl.source_name.clone();
1042 OfferResult::Source(CapabilitySource::FilteredProvider(
1043 FilteredProviderSource {
1044 capability: AggregateCapability::Service(source_name),
1045 moniker,
1046 service_capability: capability,
1047 offer_service_decl,
1048 },
1049 ))
1050 } else {
1051 OfferResult::Source(CapabilitySource::Component(ComponentSource {
1052 capability,
1053 moniker: component.moniker,
1054 }))
1055 }
1056 }
1057 _ => OfferResult::Source(CapabilitySource::Component(ComponentSource {
1058 capability,
1059 moniker: component.moniker,
1060 })),
1061 };
1062 OfferSegment::Done(res)
1063 }
1064 OfferSource::Framework => OfferSegment::Done(OfferResult::Source(
1065 CapabilitySource::Framework(FrameworkSource {
1066 capability: sources.framework_source(
1067 target.moniker(),
1068 offer.source_name().clone(),
1069 mapper,
1070 )?,
1071 moniker: target.moniker().clone(),
1072 }),
1073 )),
1074 OfferSource::Capability(_) => {
1075 sources.capability_source(target.moniker())?;
1076 OfferSegment::Done(OfferResult::Source(CapabilitySource::Capability(
1077 CapabilityToCapabilitySource {
1078 source_capability: ComponentCapability::Offer(offer.into()),
1079 moniker: target.moniker().clone(),
1080 },
1081 )))
1082 }
1083 OfferSource::Parent => {
1084 let parent_component = match target.try_get_parent()? {
1085 ExtendedInstanceInterface::<C>::AboveRoot(top_instance) => {
1086 if sources.is_namespace_supported() {
1087 if let Some(capability) = sources.find_namespace_source(
1088 ExtendedMoniker::ComponentManager,
1089 offer.source_name(),
1090 top_instance.namespace_capabilities(),
1091 visitor,
1092 mapper,
1093 )? {
1094 return Ok(OfferSegment::Done(OfferResult::Source(
1095 CapabilitySource::Namespace(NamespaceSource { capability }),
1096 )));
1097 }
1098 }
1099 if let Some(capability) = sources.find_builtin_source(
1100 ExtendedMoniker::ComponentManager,
1101 offer.source_name(),
1102 top_instance.builtin_capabilities(),
1103 visitor,
1104 mapper,
1105 )? {
1106 return Ok(OfferSegment::Done(OfferResult::Source(
1107 CapabilitySource::Builtin(BuiltinSource { capability }),
1108 )));
1109 }
1110 return Err(RoutingError::offer_from_component_manager_not_found(
1111 offer.source_name().to_string(),
1112 ));
1113 }
1114 ExtendedInstanceInterface::<C>::Component(component) => component,
1115 };
1116 let child_moniker = target.child_moniker().expect("ChildName should exist");
1117 let parent_offers = parent_component.lock_resolved_state().await?.offers();
1118 let parent_offers = find_matching_offers(
1119 CapabilityTypeName::from(&offer),
1120 offer.source_name(),
1121 &child_moniker,
1122 &parent_offers,
1123 )
1124 .ok_or_else(|| {
1125 <OfferDecl as ErrorNotFoundFromParent>::error_not_found_from_parent(
1126 target.moniker().clone(),
1127 offer.source_name().clone(),
1128 )
1129 })?;
1130 OfferSegment::Next(parent_offers, parent_component)
1131 }
1132 OfferSource::Child(_) => OfferSegment::Done(OfferResult::OfferFromChild(offer, target)),
1133 OfferSource::Collection(_) => OfferSegment::Done(
1134 OfferResult::OfferFromAnonymizedAggregate(RouteBundle::from_offer(offer), target),
1135 ),
1136 };
1137 Ok(res)
1138 }
1139}
1140
1141async fn change_directions<C>(
1144 offer: OfferDecl,
1145 component: Arc<C>,
1146) -> Result<(RouteBundle<ExposeDecl>, Arc<C>), RoutingError>
1147where
1148 C: ComponentInstanceInterface,
1149{
1150 match offer.source() {
1151 OfferSource::Child(child) => {
1152 let child_component = {
1153 let child_moniker = ChildName::try_new(
1154 child.name.as_str(),
1155 child.collection.as_ref().map(|s| s.as_str()),
1156 )
1157 .expect("discovered invalid child name, manifest validation should prevent this");
1158 component.lock_resolved_state().await?.get_child(&child_moniker).ok_or_else(
1159 || RoutingError::OfferFromChildInstanceNotFound {
1160 child_moniker,
1161 moniker: component.moniker().clone(),
1162 capability_id: offer.source_name().clone().into(),
1163 },
1164 )?
1165 };
1166 let child_exposes = child_component.lock_resolved_state().await?.exposes();
1167 let child_exposes = find_matching_exposes(
1168 CapabilityTypeName::from(&offer),
1169 offer.source_name(),
1170 &child_exposes,
1171 )
1172 .ok_or_else(|| {
1173 let child_moniker =
1174 child_component.child_moniker().expect("ChildName should exist");
1175 <OfferDecl as ErrorNotFoundInChild>::error_not_found_in_child(
1176 component.moniker().clone(),
1177 child_moniker.clone(),
1178 offer.source_name().clone(),
1179 )
1180 })?;
1181 Ok((child_exposes, child_component.clone()))
1182 }
1183 _ => panic!("change_direction called with offer that does not change direction"),
1184 }
1185}
1186
1187#[derive(Debug)]
1189pub struct Expose();
1190
1191#[allow(clippy::large_enum_variant)] enum ExposeResult<C: ComponentInstanceInterface + 'static> {
1194 Source(CapabilitySource),
1196 ExposeFromAnonymizedAggregate(RouteBundle<ExposeDecl>, Arc<C>),
1198}
1199
1200#[derive(Clone, Debug)]
1202pub enum RouteBundle<T>
1203where
1204 T: Clone + fmt::Debug,
1205{
1206 Single(T),
1208 Aggregate(Vec<T>),
1211}
1212
1213impl<T> RouteBundle<T>
1214where
1215 T: Clone + fmt::Debug,
1216{
1217 pub fn map<U: Clone + fmt::Debug>(self, mut f: impl FnMut(T) -> U) -> RouteBundle<U> {
1218 match self {
1219 RouteBundle::Single(r) => RouteBundle::Single(f(r)),
1220 RouteBundle::Aggregate(r) => {
1221 RouteBundle::Aggregate(r.into_iter().map(&mut f).collect())
1222 }
1223 }
1224 }
1225
1226 pub fn iter(&self) -> RouteBundleIter<'_, T> {
1228 match self {
1229 Self::Single(item) => {
1230 RouteBundleIter { inner_single: Some(item), inner_aggregate: None }
1231 }
1232 Self::Aggregate(items) => {
1233 RouteBundleIter { inner_single: None, inner_aggregate: Some(items.iter()) }
1234 }
1235 }
1236 }
1237
1238 pub fn len(&self) -> usize {
1240 match self {
1241 Self::Single(_) => 1,
1242 Self::Aggregate(v) => v.len(),
1243 }
1244 }
1245
1246 pub fn from_offer(input: T) -> Self
1248 where
1249 T: OfferDeclCommon + Clone,
1250 {
1251 Self::from_offers(vec![input])
1252 }
1253
1254 pub fn from_offers(mut input: Vec<T>) -> Self
1259 where
1260 T: OfferDeclCommon + Clone,
1261 {
1262 match input.len() {
1263 1 => {
1264 let input = input.remove(0);
1265 match input.source() {
1266 OfferSource::Collection(_) => Self::Aggregate(vec![input]),
1267 _ => Self::Single(input),
1268 }
1269 }
1270 0 => panic!("empty bundles are not allowed"),
1271 _ => Self::Aggregate(input),
1272 }
1273 }
1274
1275 pub fn from_expose(input: T) -> Self
1277 where
1278 T: ExposeDeclCommon + Clone,
1279 {
1280 Self::from_exposes(vec![input])
1281 }
1282
1283 pub fn from_exposes(mut input: Vec<T>) -> Self
1288 where
1289 T: ExposeDeclCommon + Clone,
1290 {
1291 match input.len() {
1292 1 => {
1293 let input = input.remove(0);
1294 match input.source() {
1295 ExposeSource::Collection(_) => Self::Aggregate(vec![input]),
1296 _ => Self::Single(input),
1297 }
1298 }
1299 0 => panic!("empty bundles are not allowed"),
1300 _ => Self::Aggregate(input),
1301 }
1302 }
1303}
1304
1305impl<T> RouteBundle<T>
1306where
1307 T: ExposeDeclCommon + Clone,
1308{
1309 pub fn availability(&self) -> &Availability {
1310 match self {
1311 Self::Single(e) => e.availability(),
1312 Self::Aggregate(v) => {
1313 assert!(
1314 v.iter().zip(v.iter().skip(1)).all(|(a, b)| a.availability() == b.availability()),
1315 "CM validation should ensure all aggregated capabilities have the same availability");
1316 v[0].availability()
1317 }
1318 }
1319 }
1320}
1321
1322pub struct RouteBundleIter<'a, T> {
1327 inner_single: Option<&'a T>,
1328 inner_aggregate: Option<slice::Iter<'a, T>>,
1329}
1330
1331impl<'a, T> Iterator for RouteBundleIter<'a, T> {
1332 type Item = &'a T;
1333
1334 fn next(&mut self) -> Option<Self::Item> {
1335 if let Some(item) = self.inner_single.take() {
1336 Some(item)
1337 } else if let Some(ref mut iter) = &mut self.inner_aggregate {
1338 iter.next()
1339 } else {
1340 None
1341 }
1342 }
1343
1344 fn size_hint(&self) -> (usize, Option<usize>) {
1345 if let Some(_) = self.inner_single {
1346 (1, Some(1))
1347 } else if let Some(iter) = &self.inner_aggregate {
1348 iter.size_hint()
1349 } else {
1350 (0, Some(0))
1351 }
1352 }
1353}
1354
1355impl<'a, T> ExactSizeIterator for RouteBundleIter<'a, T> {}
1356
1357#[allow(clippy::large_enum_variant)] enum ExposeSegment<C: ComponentInstanceInterface + 'static> {
1359 Done(ExposeResult<C>),
1360 Next(RouteBundle<ExposeDecl>, Arc<C>),
1361}
1362
1363impl Expose {
1364 async fn route<C, V>(
1367 mut expose_bundle: RouteBundle<ExposeDecl>,
1368 mut target: Arc<C>,
1369 sources: &Sources,
1370 visitor: &mut V,
1371 mapper: &mut dyn DebugRouteMapper,
1372 ) -> Result<ExposeResult<C>, RoutingError>
1373 where
1374 C: ComponentInstanceInterface + 'static,
1375 V: ExposeVisitor,
1376 V: CapabilityVisitor,
1377 {
1378 loop {
1379 let visit_expose = match &expose_bundle {
1380 RouteBundle::Single(expose) => Some(expose),
1381 RouteBundle::Aggregate(exposes) => {
1382 if exposes.len() == 1 {
1384 Some(&exposes[0])
1385 } else {
1386 None
1387 }
1388 }
1389 };
1390 if let Some(visit_expose) = visit_expose {
1391 mapper.add_expose(target.moniker().clone(), visit_expose.clone().into());
1392 ExposeVisitor::visit(visitor, &target.moniker().clone().into(), &visit_expose)?;
1393 }
1394
1395 for e in expose_bundle.iter() {
1397 if !e.source_path().dirname.is_dot() {
1398 return Err(RoutingError::DictionariesNotSupported {
1399 moniker: target.moniker().clone(),
1400 cap_type: CapabilityTypeName::from(e),
1401 });
1402 }
1403 }
1404
1405 match expose_bundle {
1406 RouteBundle::Single(expose) => {
1407 match Self::route_segment(expose, target, sources, visitor, mapper).await? {
1408 ExposeSegment::Done(r) => return Ok(r),
1409 ExposeSegment::Next(e, t) => {
1410 expose_bundle = e;
1411 target = t;
1412 }
1413 }
1414 }
1415 RouteBundle::Aggregate(_) => {
1416 return Ok(ExposeResult::ExposeFromAnonymizedAggregate(expose_bundle, target));
1417 }
1418 }
1419 }
1420 }
1421
1422 async fn route_segment<C, V>(
1423 expose: ExposeDecl,
1424 target: Arc<C>,
1425 sources: &Sources,
1426 visitor: &mut V,
1427 mapper: &mut dyn DebugRouteMapper,
1428 ) -> Result<ExposeSegment<C>, RoutingError>
1429 where
1430 C: ComponentInstanceInterface + 'static,
1431 V: ExposeVisitor,
1432 V: CapabilityVisitor,
1433 {
1434 let res = match expose.source() {
1435 ExposeSource::Void => {
1436 ExposeSegment::Done(ExposeResult::Source(CapabilitySource::Void(VoidSource {
1437 capability: InternalCapability::new(
1438 (&expose).into(),
1439 expose.source_name().clone(),
1440 ),
1441 moniker: target.moniker().clone(),
1442 })))
1443 }
1444 ExposeSource::Self_ => {
1445 let target_capabilities = target.lock_resolved_state().await?.capabilities();
1446 ExposeSegment::Done(ExposeResult::Source(CapabilitySource::Component(
1447 ComponentSource {
1448 capability: sources.find_component_source(
1449 expose.source_name(),
1450 target.moniker(),
1451 &target_capabilities,
1452 visitor,
1453 mapper,
1454 )?,
1455 moniker: target.moniker().clone(),
1456 },
1457 )))
1458 }
1459 ExposeSource::Framework => ExposeSegment::Done(ExposeResult::Source(
1460 CapabilitySource::Framework(FrameworkSource {
1461 capability: sources.framework_source(
1462 target.moniker(),
1463 expose.source_name().clone(),
1464 mapper,
1465 )?,
1466 moniker: target.moniker().clone(),
1467 }),
1468 )),
1469 ExposeSource::Capability(_) => {
1470 sources.capability_source(target.moniker())?;
1471 ExposeSegment::Done(ExposeResult::Source(CapabilitySource::Capability(
1472 CapabilityToCapabilitySource {
1473 source_capability: ComponentCapability::Expose(expose.into()),
1474 moniker: target.moniker().clone(),
1475 },
1476 )))
1477 }
1478 ExposeSource::Child(child) => {
1479 let child_component = {
1480 let child_moniker = ChildName::new(child.clone().into(), None);
1481 target.lock_resolved_state().await?.get_child(&child_moniker).ok_or_else(
1482 || RoutingError::ExposeFromChildInstanceNotFound {
1483 child_moniker,
1484 moniker: target.moniker().clone(),
1485 capability_id: expose.source_name().clone().into(),
1486 },
1487 )?
1488 };
1489 let child_exposes = child_component.lock_resolved_state().await?.exposes();
1490 let child_exposes = find_matching_exposes(
1491 CapabilityTypeName::from(&expose),
1492 expose.source_name(),
1493 &child_exposes,
1494 )
1495 .ok_or_else(|| {
1496 let child_moniker =
1497 child_component.child_moniker().expect("ChildName should exist");
1498 <ExposeDecl as ErrorNotFoundInChild>::error_not_found_in_child(
1499 target.moniker().clone(),
1500 child_moniker.clone(),
1501 expose.source_name().clone(),
1502 )
1503 })?;
1504 ExposeSegment::Next(child_exposes, child_component)
1505 }
1506 ExposeSource::Collection(_) => {
1507 ExposeSegment::Done(ExposeResult::ExposeFromAnonymizedAggregate(
1508 RouteBundle::from_expose(expose),
1509 target,
1510 ))
1511 }
1512 };
1513 Ok(res)
1514 }
1515}
1516
1517fn target_matches_moniker(target: &OfferTarget, child_moniker: &ChildName) -> bool {
1518 match target {
1519 OfferTarget::Child(target_ref) => {
1520 &target_ref.name == child_moniker.name()
1521 && target_ref.collection.as_ref() == child_moniker.collection()
1522 }
1523 OfferTarget::Collection(target_collection) => {
1524 Some(target_collection) == child_moniker.collection()
1525 }
1526 OfferTarget::Capability(_) => false,
1527 }
1528}
1529
1530pub trait OfferVisitor {
1532 fn visit(&mut self, moniker: &ExtendedMoniker, offer: &OfferDecl) -> Result<(), RoutingError>;
1533}
1534
1535pub trait ExposeVisitor {
1537 fn visit(&mut self, moniker: &ExtendedMoniker, expose: &ExposeDecl)
1540 -> Result<(), RoutingError>;
1541}
1542
1543pub trait CapabilityVisitor {
1545 fn visit(
1548 &mut self,
1549 moniker: &ExtendedMoniker,
1550 capability: &CapabilityDecl,
1551 ) -> Result<(), RoutingError>;
1552}
1553
1554pub fn find_matching_offers(
1555 capability_type: CapabilityTypeName,
1556 source_name: &Name,
1557 child_moniker: &ChildName,
1558 offers: &Vec<OfferDecl>,
1559) -> Option<RouteBundle<OfferDecl>> {
1560 let offers: Vec<_> = offers
1561 .iter()
1562 .filter(|offer: &&OfferDecl| {
1563 capability_type == CapabilityTypeName::from(*offer)
1564 && *offer.target_name() == *source_name
1565 && target_matches_moniker(offer.target(), &child_moniker)
1566 })
1567 .cloned()
1568 .collect();
1569 if offers.is_empty() {
1570 return None;
1571 }
1572 Some(RouteBundle::from_offers(offers))
1573}
1574
1575pub fn find_matching_exposes(
1576 capability_type: CapabilityTypeName,
1577 source_name: &Name,
1578 exposes: &Vec<ExposeDecl>,
1579) -> Option<RouteBundle<ExposeDecl>> {
1580 let exposes: Vec<_> = exposes
1581 .iter()
1582 .filter(|expose: &&ExposeDecl| {
1583 capability_type == CapabilityTypeName::from(*expose)
1584 && *expose.target_name() == *source_name
1585 && *expose.target() == ExposeTarget::Parent
1586 })
1587 .cloned()
1588 .collect();
1589 if exposes.is_empty() {
1590 return None;
1591 }
1592 Some(RouteBundle::from_exposes(exposes))
1593}
1594
1595pub trait ErrorNotFoundFromParent {
1597 fn error_not_found_from_parent(
1598 decl_site_moniker: Moniker,
1599 capability_name: Name,
1600 ) -> RoutingError;
1601}
1602
1603pub trait ErrorNotFoundInChild {
1605 fn error_not_found_in_child(
1606 decl_site_moniker: Moniker,
1607 child_moniker: ChildName,
1608 capability_name: Name,
1609 ) -> RoutingError;
1610}
1611
1612#[derive(Clone)]
1613pub struct NoopVisitor {}
1614
1615impl NoopVisitor {
1616 pub fn new() -> NoopVisitor {
1617 NoopVisitor {}
1618 }
1619}
1620
1621impl OfferVisitor for NoopVisitor {
1622 fn visit(&mut self, _: &ExtendedMoniker, _: &OfferDecl) -> Result<(), RoutingError> {
1623 Ok(())
1624 }
1625}
1626
1627impl ExposeVisitor for NoopVisitor {
1628 fn visit(&mut self, _: &ExtendedMoniker, _: &ExposeDecl) -> Result<(), RoutingError> {
1629 Ok(())
1630 }
1631}
1632
1633impl CapabilityVisitor for NoopVisitor {
1634 fn visit(&mut self, _: &ExtendedMoniker, _: &CapabilityDecl) -> Result<(), RoutingError> {
1635 Ok(())
1636 }
1637}
1638
1639#[cfg(test)]
1640mod tests {
1641 use super::*;
1642 use assert_matches::assert_matches;
1643 use cm_rust::ExposeServiceDecl;
1644 use cm_rust_testing::*;
1645
1646 #[test]
1647 fn route_bundle_iter_single() {
1648 let v = RouteBundle::Single(34);
1649 let mut iter = v.iter();
1650 assert_matches!(iter.next(), Some(&34));
1651 assert_matches!(iter.next(), None);
1652 }
1653
1654 #[test]
1655 fn route_bundle_iter_many() {
1656 let v = RouteBundle::Aggregate(vec![1, 2, 3]);
1657 let mut iter = v.iter();
1658 assert_matches!(iter.next(), Some(&1));
1659 assert_matches!(iter.next(), Some(&2));
1660 assert_matches!(iter.next(), Some(&3));
1661 assert_matches!(iter.next(), None);
1662 }
1663
1664 #[test]
1665 fn route_bundle_from_offers() {
1666 let parent_offers: Vec<_> = [1, 2, 3]
1667 .into_iter()
1668 .map(|i| OfferServiceDecl {
1669 source: OfferSource::Parent,
1670 source_name: format!("foo_source_{}", i).parse().unwrap(),
1671 source_dictionary: Default::default(),
1672 target: OfferTarget::Collection("coll".parse().unwrap()),
1673 target_name: "foo_target".parse().unwrap(),
1674 source_instance_filter: None,
1675 renamed_instances: None,
1676 availability: Availability::Required,
1677 dependency_type: Default::default(),
1678 })
1679 .collect();
1680 let collection_offer = OfferServiceDecl {
1681 source: OfferSource::Collection("coll".parse().unwrap()),
1682 source_name: "foo_source".parse().unwrap(),
1683 source_dictionary: Default::default(),
1684 target: offer_target_static_child("target"),
1685 target_name: "foo_target".parse().unwrap(),
1686 source_instance_filter: None,
1687 renamed_instances: None,
1688 availability: Availability::Required,
1689 dependency_type: Default::default(),
1690 };
1691 assert_matches!(
1692 RouteBundle::from_offer(parent_offers[0].clone()),
1693 RouteBundle::Single(o) if o == parent_offers[0]
1694 );
1695 assert_matches!(
1696 RouteBundle::from_offers(vec![parent_offers[0].clone()]),
1697 RouteBundle::Single(o) if o == parent_offers[0]
1698 );
1699 assert_matches!(
1700 RouteBundle::from_offers(parent_offers.clone()),
1701 RouteBundle::Aggregate(v) if v == parent_offers
1702 );
1703 assert_matches!(
1704 RouteBundle::from_offer(collection_offer.clone()),
1705 RouteBundle::Aggregate(v) if v == vec![collection_offer.clone()]
1706 );
1707 }
1708
1709 #[test]
1710 fn route_bundle_from_exposes() {
1711 let child_exposes: Vec<_> = [1, 2, 3]
1712 .into_iter()
1713 .map(|i| ExposeServiceDecl {
1714 source: ExposeSource::Child("source".parse().unwrap()),
1715 source_name: format!("foo_source_{}", i).parse().unwrap(),
1716 source_dictionary: Default::default(),
1717 target: ExposeTarget::Parent,
1718 target_name: "foo_target".parse().unwrap(),
1719 availability: Availability::Required,
1720 })
1721 .collect();
1722 let collection_expose = ExposeServiceDecl {
1723 source: ExposeSource::Collection("coll".parse().unwrap()),
1724 source_name: "foo_source".parse().unwrap(),
1725 source_dictionary: Default::default(),
1726 target: ExposeTarget::Parent,
1727 target_name: "foo_target".parse().unwrap(),
1728 availability: Availability::Required,
1729 };
1730 assert_matches!(
1731 RouteBundle::from_expose(child_exposes[0].clone()),
1732 RouteBundle::Single(o) if o == child_exposes[0]
1733 );
1734 assert_matches!(
1735 RouteBundle::from_exposes(vec![child_exposes[0].clone()]),
1736 RouteBundle::Single(o) if o == child_exposes[0]
1737 );
1738 assert_matches!(
1739 RouteBundle::from_exposes(child_exposes.clone()),
1740 RouteBundle::Aggregate(v) if v == child_exposes
1741 );
1742 assert_matches!(
1743 RouteBundle::from_expose(collection_expose.clone()),
1744 RouteBundle::Aggregate(v) if v == vec![collection_expose.clone()]
1745 );
1746 }
1747}