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
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 { Some(&offers[0]) } else { None }
945 }
946 };
947 if let Some(visit_offer) = visit_offer {
948 mapper.add_offer(target.moniker().clone(), &visit_offer);
949 OfferVisitor::visit(visitor, &target.moniker().clone().into(), &visit_offer)?;
950 }
951
952 fn is_filtered_offer(o: &OfferDecl) -> bool {
953 if let OfferDecl::Service(offer_service) = o {
954 if let Some(f) = offer_service.source_instance_filter.as_ref() {
955 if !f.is_empty() {
956 return true;
957 }
958 }
959 if let Some(f) = offer_service.renamed_instances.as_ref() {
960 if !f.is_empty() {
961 return true;
962 }
963 }
964 }
965 false
966 }
967
968 for o in offer_bundle.iter() {
970 if !o.source_path().dirname.is_dot() {
971 return Err(RoutingError::DictionariesNotSupported {
972 moniker: target.moniker().clone(),
973 cap_type: CapabilityTypeName::from(o),
974 });
975 }
976 }
977
978 match offer_bundle {
979 RouteBundle::Single(offer) => {
980 match Self::route_segment(offer, target, sources, visitor, mapper).await? {
981 OfferSegment::Done(r) => return Ok(r),
982 OfferSegment::Next(o, t) => {
983 offer_bundle = o;
984 target = t;
985 }
986 }
987 }
988 RouteBundle::Aggregate(_) => {
989 if offer_bundle.iter().all(|o| !is_filtered_offer(o)) {
990 return Ok(OfferResult::OfferFromAnonymizedAggregate(offer_bundle, target));
991 } else {
992 return Ok(OfferResult::OfferFromFilteredAggregate(offer_bundle, target));
993 }
994 }
995 }
996 }
997 }
998
999 async fn route_segment<C, V>(
1000 offer: OfferDecl,
1001 target: Arc<C>,
1002 sources: &Sources,
1003 visitor: &mut V,
1004 mapper: &mut dyn DebugRouteMapper,
1005 ) -> Result<OfferSegment<C>, RoutingError>
1006 where
1007 C: ComponentInstanceInterface + 'static,
1008 V: OfferVisitor,
1009 V: CapabilityVisitor,
1010 {
1011 let res = match offer.source() {
1012 OfferSource::Void => {
1013 OfferSegment::Done(OfferResult::Source(CapabilitySource::Void(VoidSource {
1014 capability: InternalCapability::new(
1015 (&offer).into(),
1016 offer.source_name().clone(),
1017 ),
1018 moniker: target.moniker().clone(),
1019 })))
1020 }
1021 OfferSource::Self_ => {
1022 let target_capabilities = target.lock_resolved_state().await?.capabilities();
1023 let capability = sources.find_component_source(
1024 offer.source_name(),
1025 target.moniker(),
1026 &target_capabilities,
1027 visitor,
1028 mapper,
1029 )?;
1030 let component = target.as_weak();
1032 let moniker = target.moniker().clone();
1033 let res = match offer.into() {
1034 OfferDecl::Service(offer_service_decl) => {
1035 if offer_service_decl.source_instance_filter.is_some()
1036 || offer_service_decl.renamed_instances.is_some()
1037 {
1038 let source_name = offer_service_decl.source_name.clone();
1039 OfferResult::Source(CapabilitySource::FilteredProvider(
1040 FilteredProviderSource {
1041 capability: AggregateCapability::Service(source_name),
1042 moniker,
1043 service_capability: capability,
1044 offer_service_decl,
1045 },
1046 ))
1047 } else {
1048 OfferResult::Source(CapabilitySource::Component(ComponentSource {
1049 capability,
1050 moniker: component.moniker,
1051 }))
1052 }
1053 }
1054 _ => OfferResult::Source(CapabilitySource::Component(ComponentSource {
1055 capability,
1056 moniker: component.moniker,
1057 })),
1058 };
1059 OfferSegment::Done(res)
1060 }
1061 OfferSource::Framework => OfferSegment::Done(OfferResult::Source(
1062 CapabilitySource::Framework(FrameworkSource {
1063 capability: sources.framework_source(
1064 target.moniker(),
1065 offer.source_name().clone(),
1066 mapper,
1067 )?,
1068 moniker: target.moniker().clone(),
1069 }),
1070 )),
1071 OfferSource::Capability(_) => {
1072 sources.capability_source(target.moniker())?;
1073 OfferSegment::Done(OfferResult::Source(CapabilitySource::Capability(
1074 CapabilityToCapabilitySource {
1075 source_capability: ComponentCapability::Offer(offer.into()),
1076 moniker: target.moniker().clone(),
1077 },
1078 )))
1079 }
1080 OfferSource::Parent => {
1081 let parent_component = match target.try_get_parent()? {
1082 ExtendedInstanceInterface::<C>::AboveRoot(top_instance) => {
1083 if sources.is_namespace_supported() {
1084 if let Some(capability) = sources.find_namespace_source(
1085 ExtendedMoniker::ComponentManager,
1086 offer.source_name(),
1087 top_instance.namespace_capabilities(),
1088 visitor,
1089 mapper,
1090 )? {
1091 return Ok(OfferSegment::Done(OfferResult::Source(
1092 CapabilitySource::Namespace(NamespaceSource { capability }),
1093 )));
1094 }
1095 }
1096 if let Some(capability) = sources.find_builtin_source(
1097 ExtendedMoniker::ComponentManager,
1098 offer.source_name(),
1099 top_instance.builtin_capabilities(),
1100 visitor,
1101 mapper,
1102 )? {
1103 return Ok(OfferSegment::Done(OfferResult::Source(
1104 CapabilitySource::Builtin(BuiltinSource { capability }),
1105 )));
1106 }
1107 return Err(RoutingError::offer_from_component_manager_not_found(
1108 offer.source_name().to_string(),
1109 ));
1110 }
1111 ExtendedInstanceInterface::<C>::Component(component) => component,
1112 };
1113 let child_moniker = target.child_moniker().expect("ChildName should exist");
1114 let parent_offers = parent_component.lock_resolved_state().await?.offers();
1115 let parent_offers = find_matching_offers(
1116 CapabilityTypeName::from(&offer),
1117 offer.source_name(),
1118 &child_moniker,
1119 &parent_offers,
1120 )
1121 .ok_or_else(|| {
1122 <OfferDecl as ErrorNotFoundFromParent>::error_not_found_from_parent(
1123 target.moniker().clone(),
1124 offer.source_name().clone(),
1125 )
1126 })?;
1127 OfferSegment::Next(parent_offers, parent_component)
1128 }
1129 OfferSource::Child(_) => OfferSegment::Done(OfferResult::OfferFromChild(offer, target)),
1130 OfferSource::Collection(_) => OfferSegment::Done(
1131 OfferResult::OfferFromAnonymizedAggregate(RouteBundle::from_offer(offer), target),
1132 ),
1133 };
1134 Ok(res)
1135 }
1136}
1137
1138async fn change_directions<C>(
1141 offer: OfferDecl,
1142 component: Arc<C>,
1143) -> Result<(RouteBundle<ExposeDecl>, Arc<C>), RoutingError>
1144where
1145 C: ComponentInstanceInterface,
1146{
1147 match offer.source() {
1148 OfferSource::Child(child) => {
1149 let child_component = {
1150 let child_moniker = ChildName::try_new(
1151 child.name.as_str(),
1152 child.collection.as_ref().map(|s| s.as_str()),
1153 )
1154 .expect("discovered invalid child name, manifest validation should prevent this");
1155 component.lock_resolved_state().await?.get_child(&child_moniker).ok_or_else(
1156 || RoutingError::OfferFromChildInstanceNotFound {
1157 child_moniker,
1158 moniker: component.moniker().clone(),
1159 capability_id: offer.source_name().clone().into(),
1160 },
1161 )?
1162 };
1163 let child_exposes = child_component.lock_resolved_state().await?.exposes();
1164 let child_exposes = find_matching_exposes(
1165 CapabilityTypeName::from(&offer),
1166 offer.source_name(),
1167 &child_exposes,
1168 )
1169 .ok_or_else(|| {
1170 let child_moniker =
1171 child_component.child_moniker().expect("ChildName should exist");
1172 <OfferDecl as ErrorNotFoundInChild>::error_not_found_in_child(
1173 component.moniker().clone(),
1174 child_moniker.into(),
1175 offer.source_name().clone(),
1176 )
1177 })?;
1178 Ok((child_exposes, child_component.clone()))
1179 }
1180 _ => panic!("change_direction called with offer that does not change direction"),
1181 }
1182}
1183
1184#[derive(Debug)]
1186pub struct Expose();
1187
1188#[allow(clippy::large_enum_variant)] enum ExposeResult<C: ComponentInstanceInterface + 'static> {
1191 Source(CapabilitySource),
1193 ExposeFromAnonymizedAggregate(RouteBundle<ExposeDecl>, Arc<C>),
1195}
1196
1197#[derive(Clone, Debug)]
1199pub enum RouteBundle<T>
1200where
1201 T: Clone + fmt::Debug,
1202{
1203 Single(T),
1205 Aggregate(Vec<T>),
1208}
1209
1210impl<T> RouteBundle<T>
1211where
1212 T: Clone + fmt::Debug,
1213{
1214 pub fn map<U: Clone + fmt::Debug>(self, mut f: impl FnMut(T) -> U) -> RouteBundle<U> {
1215 match self {
1216 RouteBundle::Single(r) => RouteBundle::Single(f(r)),
1217 RouteBundle::Aggregate(r) => {
1218 RouteBundle::Aggregate(r.into_iter().map(&mut f).collect())
1219 }
1220 }
1221 }
1222
1223 pub fn iter(&self) -> RouteBundleIter<'_, T> {
1225 match self {
1226 Self::Single(item) => {
1227 RouteBundleIter { inner_single: Some(item), inner_aggregate: None }
1228 }
1229 Self::Aggregate(items) => {
1230 RouteBundleIter { inner_single: None, inner_aggregate: Some(items.iter()) }
1231 }
1232 }
1233 }
1234
1235 pub fn len(&self) -> usize {
1237 match self {
1238 Self::Single(_) => 1,
1239 Self::Aggregate(v) => v.len(),
1240 }
1241 }
1242
1243 pub fn from_offer(input: T) -> Self
1245 where
1246 T: OfferDeclCommon + Clone,
1247 {
1248 Self::from_offers(vec![input])
1249 }
1250
1251 pub fn from_offers(mut input: Vec<T>) -> Self
1256 where
1257 T: OfferDeclCommon + Clone,
1258 {
1259 match input.len() {
1260 1 => {
1261 let input = input.remove(0);
1262 match input.source() {
1263 OfferSource::Collection(_) => Self::Aggregate(vec![input]),
1264 _ => Self::Single(input),
1265 }
1266 }
1267 0 => panic!("empty bundles are not allowed"),
1268 _ => Self::Aggregate(input),
1269 }
1270 }
1271
1272 pub fn from_expose(input: T) -> Self
1274 where
1275 T: ExposeDeclCommon + Clone,
1276 {
1277 Self::from_exposes(vec![input])
1278 }
1279
1280 pub fn from_exposes(mut input: Vec<T>) -> Self
1285 where
1286 T: ExposeDeclCommon + Clone,
1287 {
1288 match input.len() {
1289 1 => {
1290 let input = input.remove(0);
1291 match input.source() {
1292 ExposeSource::Collection(_) => Self::Aggregate(vec![input]),
1293 _ => Self::Single(input),
1294 }
1295 }
1296 0 => panic!("empty bundles are not allowed"),
1297 _ => Self::Aggregate(input),
1298 }
1299 }
1300}
1301
1302impl<T> RouteBundle<T>
1303where
1304 T: ExposeDeclCommon + Clone,
1305{
1306 pub fn availability(&self) -> &Availability {
1307 match self {
1308 Self::Single(e) => e.availability(),
1309 Self::Aggregate(v) => {
1310 assert!(
1311 v.iter()
1312 .zip(v.iter().skip(1))
1313 .all(|(a, b)| a.availability() == b.availability()),
1314 "CM validation should ensure all aggregated capabilities have the same availability"
1315 );
1316 v[0].availability()
1317 }
1318 }
1319 }
1320}
1321
1322pub struct RouteBundleIter<'a, T> {
1327 inner_single: Option<&'a T>,
1328 inner_aggregate: Option<slice::Iter<'a, T>>,
1329}
1330
1331impl<'a, T> Iterator for RouteBundleIter<'a, T> {
1332 type Item = &'a T;
1333
1334 fn next(&mut self) -> Option<Self::Item> {
1335 if let Some(item) = self.inner_single.take() {
1336 Some(item)
1337 } else if let Some(iter) = &mut self.inner_aggregate {
1338 iter.next()
1339 } else {
1340 None
1341 }
1342 }
1343
1344 fn size_hint(&self) -> (usize, Option<usize>) {
1345 if let Some(_) = self.inner_single {
1346 (1, Some(1))
1347 } else if let Some(iter) = &self.inner_aggregate {
1348 iter.size_hint()
1349 } else {
1350 (0, Some(0))
1351 }
1352 }
1353}
1354
1355impl<'a, T> ExactSizeIterator for RouteBundleIter<'a, T> {}
1356
1357#[allow(clippy::large_enum_variant)] enum ExposeSegment<C: ComponentInstanceInterface + 'static> {
1359 Done(ExposeResult<C>),
1360 Next(RouteBundle<ExposeDecl>, Arc<C>),
1361}
1362
1363impl Expose {
1364 async fn route<C, V>(
1367 mut expose_bundle: RouteBundle<ExposeDecl>,
1368 mut target: Arc<C>,
1369 sources: &Sources,
1370 visitor: &mut V,
1371 mapper: &mut dyn DebugRouteMapper,
1372 ) -> Result<ExposeResult<C>, RoutingError>
1373 where
1374 C: ComponentInstanceInterface + 'static,
1375 V: ExposeVisitor,
1376 V: CapabilityVisitor,
1377 {
1378 loop {
1379 let visit_expose = match &expose_bundle {
1380 RouteBundle::Single(expose) => Some(expose),
1381 RouteBundle::Aggregate(exposes) => {
1382 if exposes.len() == 1 { Some(&exposes[0]) } else { None }
1384 }
1385 };
1386 if let Some(visit_expose) = visit_expose {
1387 mapper.add_expose(target.moniker().clone(), visit_expose.clone().into());
1388 ExposeVisitor::visit(visitor, &target.moniker().clone().into(), &visit_expose)?;
1389 }
1390
1391 for e in expose_bundle.iter() {
1393 if !e.source_path().dirname.is_dot() {
1394 return Err(RoutingError::DictionariesNotSupported {
1395 moniker: target.moniker().clone(),
1396 cap_type: CapabilityTypeName::from(e),
1397 });
1398 }
1399 }
1400
1401 match expose_bundle {
1402 RouteBundle::Single(expose) => {
1403 match Self::route_segment(expose, target, sources, visitor, mapper).await? {
1404 ExposeSegment::Done(r) => return Ok(r),
1405 ExposeSegment::Next(e, t) => {
1406 expose_bundle = e;
1407 target = t;
1408 }
1409 }
1410 }
1411 RouteBundle::Aggregate(_) => {
1412 return Ok(ExposeResult::ExposeFromAnonymizedAggregate(expose_bundle, target));
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 => {
1432 ExposeSegment::Done(ExposeResult::Source(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(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(
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(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(child_exposes, child_component)
1501 }
1502 ExposeSource::Collection(_) => {
1503 ExposeSegment::Done(ExposeResult::ExposeFromAnonymizedAggregate(
1504 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}