1use crate::RegistrationDecl;
19use crate::capability_source::{
20 AggregateCapability, AggregateMember, AnonymizedAggregateSource, BuiltinSource,
21 CapabilitySource, CapabilityToCapabilitySource, ComponentCapability, ComponentSource,
22 FilteredAggregateProviderSource, FilteredProviderSource, FrameworkSource, InternalCapability,
23 NamespaceSource, VoidSource,
24};
25use crate::component_instance::{
26 ComponentInstanceInterface, ExtendedInstanceInterface, ResolvedInstanceInterface,
27 TopInstanceInterface,
28};
29use crate::error::RoutingError;
30use crate::mapper::DebugRouteMapper;
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.as_ref() {
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 {
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
769enum RegistrationResult<C: ComponentInstanceInterface + 'static, O: Clone + fmt::Debug> {
771 Source(Box<CapabilitySource>),
773 FromParent(Box<RouteBundle<O>>, Arc<C>),
775 FromChild(Box<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(Box::new(CapabilitySource::Component(
807 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 }
819 RegistrationSource::Parent => match target.try_get_parent()? {
820 ExtendedInstanceInterface::<C>::AboveRoot(top_instance) => {
821 if sources.is_namespace_supported() {
822 if let Some(capability) = sources.find_namespace_source(
823 ExtendedMoniker::ComponentManager,
824 registration.source_name(),
825 top_instance.namespace_capabilities(),
826 visitor,
827 mapper,
828 )? {
829 return Ok(RegistrationResult::Source(Box::new(
830 CapabilitySource::Namespace(NamespaceSource { capability }),
831 )));
832 }
833 }
834 if let Some(capability) = sources.find_builtin_source(
835 ExtendedMoniker::ComponentManager,
836 registration.source_name(),
837 top_instance.builtin_capabilities(),
838 visitor,
839 mapper,
840 )? {
841 return Ok(RegistrationResult::Source(Box::new(
842 CapabilitySource::Builtin(BuiltinSource { capability }),
843 )));
844 }
845 Err(RoutingError::register_from_component_manager_not_found(
846 registration.source_name().to_string(),
847 ))
848 }
849 ExtendedInstanceInterface::<C>::Component(parent_component) => {
850 let parent_offers = parent_component.lock_resolved_state().await?.offers();
851 let child_moniker = target.child_moniker().expect("ChildName should exist");
852 let parent_offers = find_matching_offers(
853 CapabilityTypeName::from(®istration_decl),
854 registration.source_name(),
855 &child_moniker,
856 &parent_offers,
857 )
858 .ok_or_else(|| {
859 <R as ErrorNotFoundFromParent>::error_not_found_from_parent(
860 target.moniker().clone(),
861 registration.source_name().clone(),
862 )
863 })?;
864 Ok(RegistrationResult::FromParent(Box::new(parent_offers), parent_component))
865 }
866 },
867 RegistrationSource::Child(child) => {
868 let child_component = {
869 let child_moniker = ChildName::try_new(child, None).expect(
870 "discovered invalid child name, manifest validation should prevent this",
871 );
872 target.lock_resolved_state().await?.get_child(&child_moniker).ok_or_else(
873 || RoutingError::EnvironmentFromChildInstanceNotFound {
874 child_moniker,
875 moniker: target.moniker().clone(),
876 capability_name: registration.source_name().clone(),
877 capability_type: R::TYPE.to_string(),
878 },
879 )?
880 };
881
882 let child_exposes = child_component.lock_resolved_state().await?.exposes();
883 let capability_type = CapabilityTypeName::from(®istration.clone().into());
884 let child_exposes = find_matching_exposes(
885 capability_type,
886 registration.source_name(),
887 &child_exposes,
888 )
889 .ok_or_else(|| {
890 let child_moniker =
891 child_component.child_moniker().expect("ChildName should exist");
892 <R as ErrorNotFoundInChild>::error_not_found_in_child(
893 target.moniker().clone(),
894 child_moniker.into(),
895 registration.source_name().clone(),
896 )
897 })?;
898 Ok(RegistrationResult::FromChild(Box::new(child_exposes), child_component.clone()))
899 }
900 }
901 }
902}
903
904pub struct Offer();
906
907enum OfferResult<C: ComponentInstanceInterface + 'static> {
909 Source(Box<CapabilitySource>),
911 OfferFromChild(OfferDecl, Arc<C>),
914 OfferFromFilteredAggregate(RouteBundle<OfferDecl>, Arc<C>),
916 OfferFromAnonymizedAggregate(RouteBundle<OfferDecl>, Arc<C>),
918}
919
920enum OfferSegment<C: ComponentInstanceInterface + 'static> {
921 Done(OfferResult<C>),
922 Next(Box<RouteBundle<OfferDecl>>, Arc<C>),
923}
924
925impl Offer {
926 async fn route<C, V>(
929 mut offer_bundle: RouteBundle<OfferDecl>,
930 mut target: Arc<C>,
931 sources: &Sources,
932 visitor: &mut V,
933 mapper: &mut dyn DebugRouteMapper,
934 ) -> Result<OfferResult<C>, RoutingError>
935 where
936 C: ComponentInstanceInterface + 'static,
937 V: OfferVisitor,
938 V: CapabilityVisitor,
939 {
940 loop {
941 let visit_offer = match &offer_bundle {
942 RouteBundle::Single(offer) => Some(offer),
943 RouteBundle::Aggregate(offers) => {
944 if offers.len() == 1 { Some(&offers[0]) } else { None }
946 }
947 };
948 if let Some(visit_offer) = visit_offer {
949 mapper.add_offer(target.moniker().clone(), &visit_offer);
950 OfferVisitor::visit(visitor, &target.moniker().clone().into(), &visit_offer)?;
951 }
952
953 fn is_filtered_offer(o: &OfferDecl) -> bool {
954 if let OfferDecl::Service(offer_service) = o {
955 if let Some(f) = offer_service.source_instance_filter.as_ref() {
956 if !f.is_empty() {
957 return true;
958 }
959 }
960 if let Some(f) = offer_service.renamed_instances.as_ref() {
961 if !f.is_empty() {
962 return true;
963 }
964 }
965 }
966 false
967 }
968
969 for o in offer_bundle.iter() {
971 if !o.source_path().dirname.is_dot() {
972 return Err(RoutingError::DictionariesNotSupported {
973 moniker: target.moniker().clone(),
974 cap_type: CapabilityTypeName::from(o),
975 });
976 }
977 }
978
979 match offer_bundle {
980 RouteBundle::Single(offer) => {
981 match Self::route_segment(offer, target, sources, visitor, mapper).await? {
982 OfferSegment::Done(r) => return Ok(r),
983 OfferSegment::Next(o, t) => {
984 offer_bundle = *o;
985 target = t;
986 }
987 }
988 }
989 RouteBundle::Aggregate(_) => {
990 if offer_bundle.iter().all(|o| !is_filtered_offer(o)) {
991 return Ok(OfferResult::OfferFromAnonymizedAggregate(offer_bundle, target));
992 } else {
993 return Ok(OfferResult::OfferFromFilteredAggregate(offer_bundle, target));
994 }
995 }
996 }
997 }
998 }
999
1000 async fn route_segment<C, V>(
1001 offer: OfferDecl,
1002 target: Arc<C>,
1003 sources: &Sources,
1004 visitor: &mut V,
1005 mapper: &mut dyn DebugRouteMapper,
1006 ) -> Result<OfferSegment<C>, RoutingError>
1007 where
1008 C: ComponentInstanceInterface + 'static,
1009 V: OfferVisitor,
1010 V: CapabilityVisitor,
1011 {
1012 let res = match offer.source() {
1013 OfferSource::Void => OfferSegment::Done(OfferResult::Source(Box::new(
1014 CapabilitySource::Void(VoidSource {
1015 capability: InternalCapability::new(
1016 (&offer).into(),
1017 offer.source_name().clone(),
1018 ),
1019 moniker: target.moniker().clone(),
1020 }),
1021 ))),
1022 OfferSource::Self_ => {
1023 let target_capabilities = target.lock_resolved_state().await?.capabilities();
1024 let capability = sources.find_component_source(
1025 offer.source_name(),
1026 target.moniker(),
1027 &target_capabilities,
1028 visitor,
1029 mapper,
1030 )?;
1031 let component = target.as_weak();
1033 let moniker = target.moniker().clone();
1034 let res = match offer.into() {
1035 OfferDecl::Service(offer_service_decl) => {
1036 if offer_service_decl.source_instance_filter.is_some()
1037 || offer_service_decl.renamed_instances.is_some()
1038 {
1039 let source_name = offer_service_decl.source_name.clone();
1040 OfferResult::Source(Box::new(CapabilitySource::FilteredProvider(
1041 FilteredProviderSource {
1042 capability: AggregateCapability::Service(source_name),
1043 moniker,
1044 service_capability: capability,
1045 offer_service_decl,
1046 },
1047 )))
1048 } else {
1049 OfferResult::Source(Box::new(CapabilitySource::Component(
1050 ComponentSource { capability, moniker: component.moniker },
1051 )))
1052 }
1053 }
1054 _ => OfferResult::Source(Box::new(CapabilitySource::Component(
1055 ComponentSource { capability, moniker: component.moniker },
1056 ))),
1057 };
1058 OfferSegment::Done(res)
1059 }
1060 OfferSource::Framework => OfferSegment::Done(OfferResult::Source(Box::new(
1061 CapabilitySource::Framework(FrameworkSource {
1062 capability: sources.framework_source(
1063 target.moniker(),
1064 offer.source_name().clone(),
1065 mapper,
1066 )?,
1067 moniker: target.moniker().clone(),
1068 }),
1069 ))),
1070 OfferSource::Capability(_) => {
1071 sources.capability_source(target.moniker())?;
1072 OfferSegment::Done(OfferResult::Source(Box::new(CapabilitySource::Capability(
1073 CapabilityToCapabilitySource {
1074 source_capability: ComponentCapability::Offer(offer.into()),
1075 moniker: target.moniker().clone(),
1076 },
1077 ))))
1078 }
1079 OfferSource::Parent => {
1080 let parent_component = match target.try_get_parent()? {
1081 ExtendedInstanceInterface::<C>::AboveRoot(top_instance) => {
1082 if sources.is_namespace_supported() {
1083 if let Some(capability) = sources.find_namespace_source(
1084 ExtendedMoniker::ComponentManager,
1085 offer.source_name(),
1086 top_instance.namespace_capabilities(),
1087 visitor,
1088 mapper,
1089 )? {
1090 return Ok(OfferSegment::Done(OfferResult::Source(Box::new(
1091 CapabilitySource::Namespace(NamespaceSource { capability }),
1092 ))));
1093 }
1094 }
1095 if let Some(capability) = sources.find_builtin_source(
1096 ExtendedMoniker::ComponentManager,
1097 offer.source_name(),
1098 top_instance.builtin_capabilities(),
1099 visitor,
1100 mapper,
1101 )? {
1102 return Ok(OfferSegment::Done(OfferResult::Source(Box::new(
1103 CapabilitySource::Builtin(BuiltinSource { capability }),
1104 ))));
1105 }
1106 return Err(RoutingError::offer_from_component_manager_not_found(
1107 offer.source_name().to_string(),
1108 ));
1109 }
1110 ExtendedInstanceInterface::<C>::Component(component) => component,
1111 };
1112 let child_moniker = target.child_moniker().expect("ChildName should exist");
1113 let parent_offers = parent_component.lock_resolved_state().await?.offers();
1114 let parent_offers = find_matching_offers(
1115 CapabilityTypeName::from(&offer),
1116 offer.source_name(),
1117 &child_moniker,
1118 &parent_offers,
1119 )
1120 .ok_or_else(|| {
1121 <OfferDecl as ErrorNotFoundFromParent>::error_not_found_from_parent(
1122 target.moniker().clone(),
1123 offer.source_name().clone(),
1124 )
1125 })?;
1126 OfferSegment::Next(Box::new(parent_offers), parent_component)
1127 }
1128 OfferSource::Child(_) => OfferSegment::Done(OfferResult::OfferFromChild(offer, target)),
1129 OfferSource::Collection(_) => OfferSegment::Done(
1130 OfferResult::OfferFromAnonymizedAggregate(RouteBundle::from_offer(offer), target),
1131 ),
1132 };
1133 Ok(res)
1134 }
1135}
1136
1137async fn change_directions<C>(
1140 offer: OfferDecl,
1141 component: Arc<C>,
1142) -> Result<(RouteBundle<ExposeDecl>, Arc<C>), RoutingError>
1143where
1144 C: ComponentInstanceInterface,
1145{
1146 match offer.source() {
1147 OfferSource::Child(child) => {
1148 let child_component = {
1149 let child_moniker = ChildName::try_new(
1150 child.name.as_str(),
1151 child.collection.as_ref().map(|s| s.as_str()),
1152 )
1153 .expect("discovered invalid child name, manifest validation should prevent this");
1154 component.lock_resolved_state().await?.get_child(&child_moniker).ok_or_else(
1155 || RoutingError::OfferFromChildInstanceNotFound {
1156 child_moniker,
1157 moniker: component.moniker().clone(),
1158 capability_id: offer.source_name().clone().into(),
1159 },
1160 )?
1161 };
1162 let child_exposes = child_component.lock_resolved_state().await?.exposes();
1163 let child_exposes = find_matching_exposes(
1164 CapabilityTypeName::from(&offer),
1165 offer.source_name(),
1166 &child_exposes,
1167 )
1168 .ok_or_else(|| {
1169 let child_moniker =
1170 child_component.child_moniker().expect("ChildName should exist");
1171 <OfferDecl as ErrorNotFoundInChild>::error_not_found_in_child(
1172 component.moniker().clone(),
1173 child_moniker.into(),
1174 offer.source_name().clone(),
1175 )
1176 })?;
1177 Ok((child_exposes, child_component.clone()))
1178 }
1179 _ => panic!("change_direction called with offer that does not change direction"),
1180 }
1181}
1182
1183#[derive(Debug)]
1185pub struct Expose();
1186
1187enum ExposeResult<C: ComponentInstanceInterface + 'static> {
1189 Source(Box<CapabilitySource>),
1191 ExposeFromAnonymizedAggregate(Box<RouteBundle<ExposeDecl>>, Arc<C>),
1193}
1194
1195#[derive(Clone, Debug)]
1197pub enum RouteBundle<T>
1198where
1199 T: Clone + fmt::Debug,
1200{
1201 Single(T),
1203 Aggregate(Vec<T>),
1206}
1207
1208impl<T> RouteBundle<T>
1209where
1210 T: Clone + fmt::Debug,
1211{
1212 pub fn map<U: Clone + fmt::Debug>(self, mut f: impl FnMut(T) -> U) -> RouteBundle<U> {
1213 match self {
1214 RouteBundle::Single(r) => RouteBundle::Single(f(r)),
1215 RouteBundle::Aggregate(r) => {
1216 RouteBundle::Aggregate(r.into_iter().map(&mut f).collect())
1217 }
1218 }
1219 }
1220
1221 pub fn iter(&self) -> RouteBundleIter<'_, T> {
1223 match self {
1224 Self::Single(item) => {
1225 RouteBundleIter { inner_single: Some(item), inner_aggregate: None }
1226 }
1227 Self::Aggregate(items) => {
1228 RouteBundleIter { inner_single: None, inner_aggregate: Some(items.iter()) }
1229 }
1230 }
1231 }
1232
1233 pub fn len(&self) -> usize {
1235 match self {
1236 Self::Single(_) => 1,
1237 Self::Aggregate(v) => v.len(),
1238 }
1239 }
1240
1241 pub fn from_offer(input: T) -> Self
1243 where
1244 T: OfferDeclCommon + Clone,
1245 {
1246 Self::from_offers(vec![input])
1247 }
1248
1249 pub fn from_offers(mut input: Vec<T>) -> Self
1254 where
1255 T: OfferDeclCommon + Clone,
1256 {
1257 match input.len() {
1258 1 => {
1259 let input = input.remove(0);
1260 match input.source() {
1261 OfferSource::Collection(_) => Self::Aggregate(vec![input]),
1262 _ => Self::Single(input),
1263 }
1264 }
1265 0 => panic!("empty bundles are not allowed"),
1266 _ => Self::Aggregate(input),
1267 }
1268 }
1269
1270 pub fn from_expose(input: T) -> Self
1272 where
1273 T: ExposeDeclCommon + Clone,
1274 {
1275 Self::from_exposes(vec![input])
1276 }
1277
1278 pub fn from_exposes(mut input: Vec<T>) -> Self
1283 where
1284 T: ExposeDeclCommon + Clone,
1285 {
1286 match input.len() {
1287 1 => {
1288 let input = input.remove(0);
1289 match input.source() {
1290 ExposeSource::Collection(_) => Self::Aggregate(vec![input]),
1291 _ => Self::Single(input),
1292 }
1293 }
1294 0 => panic!("empty bundles are not allowed"),
1295 _ => Self::Aggregate(input),
1296 }
1297 }
1298}
1299
1300impl<T> RouteBundle<T>
1301where
1302 T: ExposeDeclCommon + Clone,
1303{
1304 pub fn availability(&self) -> &Availability {
1305 match self {
1306 Self::Single(e) => e.availability(),
1307 Self::Aggregate(v) => {
1308 assert!(
1309 v.iter()
1310 .zip(v.iter().skip(1))
1311 .all(|(a, b)| a.availability() == b.availability()),
1312 "CM validation should ensure all aggregated capabilities have the same availability"
1313 );
1314 v[0].availability()
1315 }
1316 }
1317 }
1318}
1319
1320pub struct RouteBundleIter<'a, T> {
1325 inner_single: Option<&'a T>,
1326 inner_aggregate: Option<slice::Iter<'a, T>>,
1327}
1328
1329impl<'a, T> Iterator for RouteBundleIter<'a, T> {
1330 type Item = &'a T;
1331
1332 fn next(&mut self) -> Option<Self::Item> {
1333 if let Some(item) = self.inner_single.take() {
1334 Some(item)
1335 } else if let Some(iter) = &mut self.inner_aggregate {
1336 iter.next()
1337 } else {
1338 None
1339 }
1340 }
1341
1342 fn size_hint(&self) -> (usize, Option<usize>) {
1343 if let Some(_) = self.inner_single {
1344 (1, Some(1))
1345 } else if let Some(iter) = &self.inner_aggregate {
1346 iter.size_hint()
1347 } else {
1348 (0, Some(0))
1349 }
1350 }
1351}
1352
1353impl<'a, T> ExactSizeIterator for RouteBundleIter<'a, T> {}
1354
1355enum ExposeSegment<C: ComponentInstanceInterface + 'static> {
1356 Done(ExposeResult<C>),
1357 Next(Box<RouteBundle<ExposeDecl>>, Arc<C>),
1358}
1359
1360impl Expose {
1361 async fn route<C, V>(
1364 mut expose_bundle: RouteBundle<ExposeDecl>,
1365 mut target: Arc<C>,
1366 sources: &Sources,
1367 visitor: &mut V,
1368 mapper: &mut dyn DebugRouteMapper,
1369 ) -> Result<ExposeResult<C>, RoutingError>
1370 where
1371 C: ComponentInstanceInterface + 'static,
1372 V: ExposeVisitor,
1373 V: CapabilityVisitor,
1374 {
1375 loop {
1376 let visit_expose = match &expose_bundle {
1377 RouteBundle::Single(expose) => Some(expose),
1378 RouteBundle::Aggregate(exposes) => {
1379 if exposes.len() == 1 { Some(&exposes[0]) } else { None }
1381 }
1382 };
1383 if let Some(visit_expose) = visit_expose {
1384 mapper.add_expose(target.moniker().clone(), visit_expose.clone().into());
1385 ExposeVisitor::visit(visitor, &target.moniker().clone().into(), &visit_expose)?;
1386 }
1387
1388 for e in expose_bundle.iter() {
1390 if !e.source_path().dirname.is_dot() {
1391 return Err(RoutingError::DictionariesNotSupported {
1392 moniker: target.moniker().clone(),
1393 cap_type: CapabilityTypeName::from(e),
1394 });
1395 }
1396 }
1397
1398 match expose_bundle {
1399 RouteBundle::Single(expose) => {
1400 match Self::route_segment(expose, target, sources, visitor, mapper).await? {
1401 ExposeSegment::Done(r) => return Ok(r),
1402 ExposeSegment::Next(e, t) => {
1403 expose_bundle = *e;
1404 target = t;
1405 }
1406 }
1407 }
1408 RouteBundle::Aggregate(_) => {
1409 return Ok(ExposeResult::ExposeFromAnonymizedAggregate(
1410 Box::new(expose_bundle),
1411 target,
1412 ));
1413 }
1414 }
1415 }
1416 }
1417
1418 async fn route_segment<C, V>(
1419 expose: ExposeDecl,
1420 target: Arc<C>,
1421 sources: &Sources,
1422 visitor: &mut V,
1423 mapper: &mut dyn DebugRouteMapper,
1424 ) -> Result<ExposeSegment<C>, RoutingError>
1425 where
1426 C: ComponentInstanceInterface + 'static,
1427 V: ExposeVisitor,
1428 V: CapabilityVisitor,
1429 {
1430 let res = match expose.source() {
1431 ExposeSource::Void => ExposeSegment::Done(ExposeResult::Source(Box::new(
1432 CapabilitySource::Void(VoidSource {
1433 capability: InternalCapability::new(
1434 (&expose).into(),
1435 expose.source_name().clone(),
1436 ),
1437 moniker: target.moniker().clone(),
1438 }),
1439 ))),
1440 ExposeSource::Self_ => {
1441 let target_capabilities = target.lock_resolved_state().await?.capabilities();
1442 ExposeSegment::Done(ExposeResult::Source(Box::new(CapabilitySource::Component(
1443 ComponentSource {
1444 capability: sources.find_component_source(
1445 expose.source_name(),
1446 target.moniker(),
1447 &target_capabilities,
1448 visitor,
1449 mapper,
1450 )?,
1451 moniker: target.moniker().clone(),
1452 },
1453 ))))
1454 }
1455 ExposeSource::Framework => ExposeSegment::Done(ExposeResult::Source(Box::new(
1456 CapabilitySource::Framework(FrameworkSource {
1457 capability: sources.framework_source(
1458 target.moniker(),
1459 expose.source_name().clone(),
1460 mapper,
1461 )?,
1462 moniker: target.moniker().clone(),
1463 }),
1464 ))),
1465 ExposeSource::Capability(_) => {
1466 sources.capability_source(target.moniker())?;
1467 ExposeSegment::Done(ExposeResult::Source(Box::new(CapabilitySource::Capability(
1468 CapabilityToCapabilitySource {
1469 source_capability: ComponentCapability::Expose(expose.into()),
1470 moniker: target.moniker().clone(),
1471 },
1472 ))))
1473 }
1474 ExposeSource::Child(child) => {
1475 let child_component = {
1476 let child_moniker = ChildName::new(child.clone().into(), None);
1477 target.lock_resolved_state().await?.get_child(&child_moniker).ok_or_else(
1478 || RoutingError::ExposeFromChildInstanceNotFound {
1479 child_moniker,
1480 moniker: target.moniker().clone(),
1481 capability_id: expose.source_name().clone().into(),
1482 },
1483 )?
1484 };
1485 let child_exposes = child_component.lock_resolved_state().await?.exposes();
1486 let child_exposes = find_matching_exposes(
1487 CapabilityTypeName::from(&expose),
1488 expose.source_name(),
1489 &child_exposes,
1490 )
1491 .ok_or_else(|| {
1492 let child_moniker =
1493 child_component.child_moniker().expect("ChildName should exist");
1494 <ExposeDecl as ErrorNotFoundInChild>::error_not_found_in_child(
1495 target.moniker().clone(),
1496 child_moniker.into(),
1497 expose.source_name().clone(),
1498 )
1499 })?;
1500 ExposeSegment::Next(Box::new(child_exposes), child_component)
1501 }
1502 ExposeSource::Collection(_) => {
1503 ExposeSegment::Done(ExposeResult::ExposeFromAnonymizedAggregate(
1504 Box::new(RouteBundle::from_expose(expose)),
1505 target,
1506 ))
1507 }
1508 };
1509 Ok(res)
1510 }
1511}
1512
1513fn target_matches_moniker(target: &OfferTarget, child_moniker: &BorrowedChildName) -> bool {
1514 match target {
1515 OfferTarget::Child(target_ref) => {
1516 &target_ref.name == child_moniker.name()
1517 && target_ref.collection.as_ref().map(Borrow::borrow) == child_moniker.collection()
1518 }
1519 OfferTarget::Collection(target_collection) => {
1520 Some(target_collection.borrow()) == child_moniker.collection()
1521 }
1522 OfferTarget::Capability(_) => false,
1523 }
1524}
1525
1526pub trait OfferVisitor {
1528 fn visit(&mut self, moniker: &ExtendedMoniker, offer: &OfferDecl) -> Result<(), RoutingError>;
1529}
1530
1531pub trait ExposeVisitor {
1533 fn visit(&mut self, moniker: &ExtendedMoniker, expose: &ExposeDecl)
1536 -> Result<(), RoutingError>;
1537}
1538
1539pub trait CapabilityVisitor {
1541 fn visit(
1544 &mut self,
1545 moniker: &ExtendedMoniker,
1546 capability: &CapabilityDecl,
1547 ) -> Result<(), RoutingError>;
1548}
1549
1550pub fn find_matching_offers(
1551 capability_type: CapabilityTypeName,
1552 source_name: &Name,
1553 child_moniker: &BorrowedChildName,
1554 offers: &[OfferDecl],
1555) -> Option<RouteBundle<OfferDecl>> {
1556 let offers: Vec<_> = offers
1557 .iter()
1558 .filter(|offer: &&OfferDecl| {
1559 capability_type == CapabilityTypeName::from(*offer)
1560 && *offer.target_name() == *source_name
1561 && target_matches_moniker(offer.target(), child_moniker)
1562 })
1563 .cloned()
1564 .collect();
1565 if offers.is_empty() {
1566 return None;
1567 }
1568 Some(RouteBundle::from_offers(offers))
1569}
1570
1571pub fn find_matching_exposes(
1572 capability_type: CapabilityTypeName,
1573 source_name: &Name,
1574 exposes: &[ExposeDecl],
1575) -> Option<RouteBundle<ExposeDecl>> {
1576 let exposes: Vec<_> = exposes
1577 .iter()
1578 .filter(|expose: &&ExposeDecl| {
1579 capability_type == CapabilityTypeName::from(*expose)
1580 && *expose.target_name() == *source_name
1581 && *expose.target() == ExposeTarget::Parent
1582 })
1583 .cloned()
1584 .collect();
1585 if exposes.is_empty() {
1586 return None;
1587 }
1588 Some(RouteBundle::from_exposes(exposes))
1589}
1590
1591pub trait ErrorNotFoundFromParent {
1593 fn error_not_found_from_parent(
1594 decl_site_moniker: Moniker,
1595 capability_name: Name,
1596 ) -> RoutingError;
1597}
1598
1599pub trait ErrorNotFoundInChild {
1601 fn error_not_found_in_child(
1602 decl_site_moniker: Moniker,
1603 child_moniker: ChildName,
1604 capability_name: Name,
1605 ) -> RoutingError;
1606}
1607
1608#[derive(Clone)]
1609pub struct NoopVisitor {}
1610
1611impl NoopVisitor {
1612 pub fn new() -> NoopVisitor {
1613 NoopVisitor {}
1614 }
1615}
1616
1617impl OfferVisitor for NoopVisitor {
1618 fn visit(&mut self, _: &ExtendedMoniker, _: &OfferDecl) -> Result<(), RoutingError> {
1619 Ok(())
1620 }
1621}
1622
1623impl ExposeVisitor for NoopVisitor {
1624 fn visit(&mut self, _: &ExtendedMoniker, _: &ExposeDecl) -> Result<(), RoutingError> {
1625 Ok(())
1626 }
1627}
1628
1629impl CapabilityVisitor for NoopVisitor {
1630 fn visit(&mut self, _: &ExtendedMoniker, _: &CapabilityDecl) -> Result<(), RoutingError> {
1631 Ok(())
1632 }
1633}
1634
1635#[cfg(test)]
1636mod tests {
1637 use super::*;
1638 use assert_matches::assert_matches;
1639 use cm_rust::ExposeServiceDecl;
1640 use cm_rust_testing::*;
1641
1642 #[test]
1643 fn route_bundle_iter_single() {
1644 let v = RouteBundle::Single(34);
1645 let mut iter = v.iter();
1646 assert_matches!(iter.next(), Some(&34));
1647 assert_matches!(iter.next(), None);
1648 }
1649
1650 #[test]
1651 fn route_bundle_iter_many() {
1652 let v = RouteBundle::Aggregate(vec![1, 2, 3]);
1653 let mut iter = v.iter();
1654 assert_matches!(iter.next(), Some(&1));
1655 assert_matches!(iter.next(), Some(&2));
1656 assert_matches!(iter.next(), Some(&3));
1657 assert_matches!(iter.next(), None);
1658 }
1659
1660 #[test]
1661 fn route_bundle_from_offers() {
1662 let parent_offers: Vec<_> = [1, 2, 3]
1663 .into_iter()
1664 .map(|i| OfferServiceDecl {
1665 source: OfferSource::Parent,
1666 source_name: format!("foo_source_{}", i).parse().unwrap(),
1667 source_dictionary: Default::default(),
1668 target: OfferTarget::Collection("coll".parse().unwrap()),
1669 target_name: "foo_target".parse().unwrap(),
1670 source_instance_filter: None,
1671 renamed_instances: None,
1672 availability: Availability::Required,
1673 dependency_type: Default::default(),
1674 })
1675 .collect();
1676 let collection_offer = OfferServiceDecl {
1677 source: OfferSource::Collection("coll".parse().unwrap()),
1678 source_name: "foo_source".parse().unwrap(),
1679 source_dictionary: Default::default(),
1680 target: offer_target_static_child("target"),
1681 target_name: "foo_target".parse().unwrap(),
1682 source_instance_filter: None,
1683 renamed_instances: None,
1684 availability: Availability::Required,
1685 dependency_type: Default::default(),
1686 };
1687 assert_matches!(
1688 RouteBundle::from_offer(parent_offers[0].clone()),
1689 RouteBundle::Single(o) if o == parent_offers[0]
1690 );
1691 assert_matches!(
1692 RouteBundle::from_offers(vec![parent_offers[0].clone()]),
1693 RouteBundle::Single(o) if o == parent_offers[0]
1694 );
1695 assert_matches!(
1696 RouteBundle::from_offers(parent_offers.clone()),
1697 RouteBundle::Aggregate(v) if v == parent_offers
1698 );
1699 assert_matches!(
1700 RouteBundle::from_offer(collection_offer.clone()),
1701 RouteBundle::Aggregate(v) if v == vec![collection_offer.clone()]
1702 );
1703 }
1704
1705 #[test]
1706 fn route_bundle_from_exposes() {
1707 let child_exposes: Vec<_> = [1, 2, 3]
1708 .into_iter()
1709 .map(|i| ExposeServiceDecl {
1710 source: ExposeSource::Child("source".parse().unwrap()),
1711 source_name: format!("foo_source_{}", i).parse().unwrap(),
1712 source_dictionary: Default::default(),
1713 target: ExposeTarget::Parent,
1714 target_name: "foo_target".parse().unwrap(),
1715 availability: Availability::Required,
1716 })
1717 .collect();
1718 let collection_expose = ExposeServiceDecl {
1719 source: ExposeSource::Collection("coll".parse().unwrap()),
1720 source_name: "foo_source".parse().unwrap(),
1721 source_dictionary: Default::default(),
1722 target: ExposeTarget::Parent,
1723 target_name: "foo_target".parse().unwrap(),
1724 availability: Availability::Required,
1725 };
1726 assert_matches!(
1727 RouteBundle::from_expose(child_exposes[0].clone()),
1728 RouteBundle::Single(o) if o == child_exposes[0]
1729 );
1730 assert_matches!(
1731 RouteBundle::from_exposes(vec![child_exposes[0].clone()]),
1732 RouteBundle::Single(o) if o == child_exposes[0]
1733 );
1734 assert_matches!(
1735 RouteBundle::from_exposes(child_exposes.clone()),
1736 RouteBundle::Aggregate(v) if v == child_exposes
1737 );
1738 assert_matches!(
1739 RouteBundle::from_expose(collection_expose.clone()),
1740 RouteBundle::Aggregate(v) if v == vec![collection_expose.clone()]
1741 );
1742 }
1743}