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