routing/
legacy_router.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Each routing method's name begins with `route_*`, and is an async function that returns
6//! [Result<CapabilitySource, RoutingError>], i.e. finds the capability source by walking the
7//! route declarations and resolving components if necessary. Routing always walks in the direction
8//! from the consuming side to the providing side.
9//!
10//! The most commonly used implementation is [route_from_use], which starts from a `Use`
11//! declaration, walks along the chain of `Offer`s, and then the chain of `Expose`s. Similarly,
12//! [route_from_registration] starts from a registration of a capability into an environment, then
13//! walks the `Offer`s and `Expose`s.
14//!
15//! You can also start walking from halfway in this chain, e.g. [route_from_offer],
16//! [route_from_expose].
17
18use crate::capability_source::{
19    AggregateCapability, AggregateMember, AnonymizedAggregateSource, BuiltinSource,
20    CapabilitySource, CapabilityToCapabilitySource, ComponentCapability, ComponentSource,
21    FilteredAggregateProviderSource, FilteredProviderSource, FrameworkSource, InternalCapability,
22    NamespaceSource, VoidSource,
23};
24use crate::component_instance::{
25    ComponentInstanceInterface, ExtendedInstanceInterface, ResolvedInstanceInterface,
26    TopInstanceInterface,
27};
28use crate::error::RoutingError;
29use crate::mapper::DebugRouteMapper;
30use crate::RegistrationDecl;
31use cm_rust::{
32    Availability, CapabilityDecl, CapabilityTypeName, ChildRef, ExposeDecl, ExposeDeclCommon,
33    ExposeSource, ExposeTarget, FidlIntoNative, NativeIntoFidl, OfferDecl, OfferDeclCommon,
34    OfferServiceDecl, OfferSource, OfferTarget, RegistrationDeclCommon, RegistrationSource,
35    SourceName, SourcePath, UseDecl, UseDeclCommon, UseSource,
36};
37use cm_rust_derive::FidlDecl;
38use cm_types::{LongName, Name};
39use fidl_fuchsia_component_internal as finternal;
40use moniker::{BorrowedChildName, ChildName, ExtendedMoniker, Moniker};
41use std::borrow::Borrow;
42use std::collections::HashSet;
43use std::marker::PhantomData;
44use std::sync::Arc;
45use std::{fmt, slice};
46
47#[cfg(feature = "serde")]
48use serde::{Deserialize, Serialize};
49
50/// Routes a capability from its `Use` declaration to its source by following `Offer` and `Expose`
51/// declarations.
52///
53/// `sources` defines what are the valid sources of the capability. See [`Sources`].
54/// `visitor` is invoked for each `Offer` and `Expose` declaration in the routing path, as well as
55/// the final `Capability` declaration if `sources` permits.
56pub 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
100/// Routes a capability from its environment `Registration` declaration to its source by following
101/// `Offer` and `Expose` declarations.
102///
103/// `sources` defines what are the valid sources of the capability. See [`Sources`].
104/// `visitor` is invoked for each `Offer` and `Expose` declaration in the routing path, as well as
105/// the final `Capability` declaration if `sources` permits.
106pub 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
139/// Routes a capability from its `Offer` declaration to its source by following `Offer` and `Expose`
140/// declarations.
141///
142/// `sources` defines what are the valid sources of the capability. See [`Sources`].
143/// `visitor` is invoked for each `Offer` and `Expose` declaration in the routing path, as well as
144/// the final `Capability` declaration if `sources` permits.
145pub 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                    // TODO(https://fxbug.dev/42179343) support collection sources as well.
182                    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            // Check that all of the service offers contain non-conflicting filter instances.
231            let mut seen_instances: HashSet<Name> = HashSet::new();
232            for o in offers.iter() {
233                if let OfferDecl::Service(offer_service_decl) = o.clone().into() {
234                    match offer_service_decl.source_instance_filter {
235                        None => {
236                            return Err(RoutingError::unsupported_route_source(
237                                aggregation_component.moniker().clone(),
238                                "Aggregate offers must be of service capabilities \
239                            with source_instance_filter set",
240                            ));
241                        }
242                        Some(allowed_instances) => {
243                            for instance in allowed_instances.iter() {
244                                if !seen_instances.insert(instance.clone()) {
245                                    return Err(RoutingError::unsupported_route_source(
246                                        aggregation_component.moniker().clone(),
247                                        format!(
248                                            "Instance {} found in multiple offers \
249                                                of the same service.",
250                                            instance
251                                        ),
252                                    ));
253                                }
254                            }
255                        }
256                    }
257                } else {
258                    return Err(RoutingError::unsupported_route_source(
259                        aggregation_component.moniker().clone(),
260                        "Aggregate source must consist of only service capabilities",
261                    ));
262                }
263            }
264            // "_unused" is a placeholder value required by fold(). Since `offers` is guaranteed to
265            // be nonempty, it will always be overwritten by the actual source name.
266            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            // TODO(https://fxbug.dev/42151281) Make the Collection CapabilitySource type generic
276            // for other types of aggregations.
277            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
287/// Routes a capability from its `Expose` declaration to its source by following `Expose`
288/// declarations.
289///
290/// `sources` defines what are the valid sources of the capability. See [`Sources`].
291/// `visitor` is invoked for each `Expose` declaration in the routing path, as well as the final
292/// `Capability` declaration if `sources` permits.
293pub 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
349/// Routes a capability from its `Use` declaration to its source by capabilities declarations, i.e.
350/// whatever capabilities that this component itself provides.
351///
352/// `sources` defines what are the valid sources of the capability. See [`Sources`].
353/// `visitor` is invoked for each `Capability` declaration if `sources` permits.
354pub 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
377/// Routes a capability from a capability name to its source by capabilities declarations, i.e.
378/// whatever capabilities that this component itself provides.
379///
380/// `sources` defines what are the valid sources of the capability. See [`Sources`].
381/// `visitor` is invoked for each `Capability` declaration if `sources` permits.
382pub 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/// Defines which capability source types are supported.
408#[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
421// Implementation of `Sources` that allows namespace, component, and/or built-in source
422// types.
423impl Sources {
424    /// Creates a new [`Sources`] that does not allow any capability source types.
425    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    /// Allows framework capability sources of the given type (`from: "framework"` in `CML`).
438    pub fn framework(self) -> Self {
439        Self { framework: true, ..self }
440    }
441
442    /// Allows capability source types that originate from other capabilities (`from: "#storage"` in
443    /// `CML`).
444    pub fn capability(self) -> Self {
445        Self { capability: true, ..self }
446    }
447
448    /// Allows capability sources to originate from a collection.
449    pub fn collection(self) -> Self {
450        Self { collection: true, ..self }
451    }
452
453    /// Allows namespace capability source types, which are capabilities that are installed in
454    /// component_manager's incoming namespace.
455    pub fn namespace(self) -> Self {
456        Self { namespace: true, ..self }
457    }
458
459    /// Allows component capability source types (`from: "self"` in `CML`).
460    pub fn component(self) -> Self {
461        Self { component: true, ..self }
462    }
463
464    /// Allows built-in capability source types (`from: "parent"` in `CML` where the parent component_instance is
465    /// component_manager).
466    pub fn builtin(self) -> Self {
467        Self { builtin: true, ..self }
468    }
469
470    /// Return the [`InternalCapability`] representing this framework capability source, or
471    /// [`RoutingError::UnsupportedRouteSource`] if unsupported.
472    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    /// Checks whether capability sources are supported, returning [`RoutingError::UnsupportedRouteSource`]
488    /// if they are not.
489    // TODO(https://fxbug.dev/42140194): Add route mapping for capability sources.
490    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    /// Checks whether namespace capability sources are supported.
499    pub fn is_namespace_supported(&self) -> bool {
500        self.namespace
501    }
502
503    /// Looks for a namespace capability in the list of capability sources.
504    /// If found, the declaration is visited by `visitor` and the declaration is wrapped
505    /// in a [`ComponentCapability`].
506    /// Returns [`RoutingError::UnsupportedRouteSource`] if namespace capabilities are unsupported.
507    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    /// Looks for a built-in capability in the list of capability sources.
539    /// If found, the capability's name is wrapped in an [`InternalCapability`].
540    /// Returns [`RoutingError::UnsupportedRouteSource`] if built-in capabilities are unsupported.
541    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    /// Looks for a component capability in the list of capability sources for the component instance
572    /// with moniker `moniker`.
573    /// If found, the declaration is visited by `visitor` and the declaration is wrapped
574    /// in a [`ComponentCapability`].
575    /// Returns [`RoutingError::UnsupportedRouteSource`] if component capabilities are unsupported.
576    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
606/// The result of routing a Use declaration to the next phase.
607enum UseResult<C: ComponentInstanceInterface + 'static> {
608    /// The source of the Use was found (Framework, AboveRoot, etc.)
609    Source(CapabilitySource),
610    /// The Use led to a parent offer.
611    OfferFromParent(RouteBundle<OfferDecl>, Arc<C>),
612    /// The Use led to a child Expose declaration.
613    /// Note: Instead of FromChild carrying an ExposeDecl of the matching child, it carries a
614    /// UseDecl. This is because some RoutingStrategy<> don't support Expose, but are still
615    /// required to enumerate over UseResult<>.
616    ExposeFromChild(UseDecl, Arc<C>),
617}
618
619impl Use {
620    /// Routes the capability starting from the `use_` declaration at `target` to either a valid
621    /// source (as defined by `sources`) or the Offer declaration that ends this phase of routing.
622    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                // This is not supported today. It might be worthwhile to support this if
727                // more than just protocol has a debug capability.
728                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                // This is not supported today. It might be worthwhile to support this if
756                // capabilities other than runner can be used from environment.
757                return Err(RoutingError::unsupported_route_source(
758                    target.moniker().clone(),
759                    "environment",
760                ));
761            }
762        }
763    }
764}
765
766/// The environment `Registration` phase of routing.
767pub struct Registration<R>(PhantomData<R>);
768
769#[allow(clippy::large_enum_variant)] // TODO(https://fxbug.dev/401087293)
770/// The result of routing a Registration declaration to the next phase.
771enum RegistrationResult<C: ComponentInstanceInterface + 'static, O: Clone + fmt::Debug> {
772    /// The source of the Registration was found (Framework, AboveRoot, etc.).
773    Source(CapabilitySource),
774    /// The Registration led to a parent Offer declaration.
775    FromParent(RouteBundle<O>, Arc<C>),
776    /// The Registration led to a child Expose declaration.
777    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    /// Routes the capability starting from the `registration` declaration at `target` to either a
789    /// valid source (as defined by `sources`) or the Offer or Expose declaration that ends this
790    /// phase of routing.
791    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(), &registration_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(&registration_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(&registration.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
903/// The `Offer` phase of routing.
904pub struct Offer();
905
906/// The result of routing an Offer declaration to the next phase.
907enum OfferResult<C: ComponentInstanceInterface + 'static> {
908    /// The source of the Offer was found (Framework, AboveRoot, Component, etc.).
909    Source(CapabilitySource),
910    /// The Offer led to an Offer-from-child declaration.
911    /// Not all capabilities can be exposed, so let the caller decide how to handle this.
912    OfferFromChild(OfferDecl, Arc<C>),
913    /// Offer from multiple static children, with filters.
914    OfferFromFilteredAggregate(RouteBundle<OfferDecl>, Arc<C>),
915    /// Offer from one or more collections and/or static children.
916    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    /// Routes the capability starting from the `offer` declaration at `target` to either a valid
926    /// source (as defined by `sources`) or the declaration that ends this phase of routing.
927    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                    // TODO(https://fxbug.dev/42124541): Visit routes in all aggregates.
944                    if offers.len() == 1 {
945                        Some(&offers[0])
946                    } else {
947                        None
948                    }
949                }
950            };
951            if let Some(visit_offer) = visit_offer {
952                mapper.add_offer(target.moniker().clone(), &visit_offer);
953                OfferVisitor::visit(visitor, &target.moniker().clone().into(), &visit_offer)?;
954            }
955
956            fn is_filtered_offer(o: &OfferDecl) -> bool {
957                if let OfferDecl::Service(offer_service) = o {
958                    if let Some(f) = offer_service.source_instance_filter.as_ref() {
959                        if !f.is_empty() {
960                            return true;
961                        }
962                    }
963                    if let Some(f) = offer_service.renamed_instances.as_ref() {
964                        if !f.is_empty() {
965                            return true;
966                        }
967                    }
968                }
969                false
970            }
971
972            // Make sure this isn't coming from a dictionary
973            for o in offer_bundle.iter() {
974                if !o.source_path().dirname.is_dot() {
975                    return Err(RoutingError::DictionariesNotSupported {
976                        moniker: target.moniker().clone(),
977                        cap_type: CapabilityTypeName::from(o),
978                    });
979                }
980            }
981
982            match offer_bundle {
983                RouteBundle::Single(offer) => {
984                    match Self::route_segment(offer, target, sources, visitor, mapper).await? {
985                        OfferSegment::Done(r) => return Ok(r),
986                        OfferSegment::Next(o, t) => {
987                            offer_bundle = o;
988                            target = t;
989                        }
990                    }
991                }
992                RouteBundle::Aggregate(_) => {
993                    if offer_bundle.iter().all(|o| !is_filtered_offer(o)) {
994                        return Ok(OfferResult::OfferFromAnonymizedAggregate(offer_bundle, target));
995                    } else {
996                        return Ok(OfferResult::OfferFromFilteredAggregate(offer_bundle, target));
997                    }
998                }
999            }
1000        }
1001    }
1002
1003    async fn route_segment<C, V>(
1004        offer: OfferDecl,
1005        target: Arc<C>,
1006        sources: &Sources,
1007        visitor: &mut V,
1008        mapper: &mut dyn DebugRouteMapper,
1009    ) -> Result<OfferSegment<C>, RoutingError>
1010    where
1011        C: ComponentInstanceInterface + 'static,
1012        V: OfferVisitor,
1013        V: CapabilityVisitor,
1014    {
1015        let res = match offer.source() {
1016            OfferSource::Void => {
1017                OfferSegment::Done(OfferResult::Source(CapabilitySource::Void(VoidSource {
1018                    capability: InternalCapability::new(
1019                        (&offer).into(),
1020                        offer.source_name().clone(),
1021                    ),
1022                    moniker: target.moniker().clone(),
1023                })))
1024            }
1025            OfferSource::Self_ => {
1026                let target_capabilities = target.lock_resolved_state().await?.capabilities();
1027                let capability = sources.find_component_source(
1028                    offer.source_name(),
1029                    target.moniker(),
1030                    &target_capabilities,
1031                    visitor,
1032                    mapper,
1033                )?;
1034                // if offerdecl is for a filtered service return the associated filtered source.
1035                let component = target.as_weak();
1036                let moniker = target.moniker().clone();
1037                let res = match offer.into() {
1038                    OfferDecl::Service(offer_service_decl) => {
1039                        if offer_service_decl.source_instance_filter.is_some()
1040                            || offer_service_decl.renamed_instances.is_some()
1041                        {
1042                            let source_name = offer_service_decl.source_name.clone();
1043                            OfferResult::Source(CapabilitySource::FilteredProvider(
1044                                FilteredProviderSource {
1045                                    capability: AggregateCapability::Service(source_name),
1046                                    moniker,
1047                                    service_capability: capability,
1048                                    offer_service_decl,
1049                                },
1050                            ))
1051                        } else {
1052                            OfferResult::Source(CapabilitySource::Component(ComponentSource {
1053                                capability,
1054                                moniker: component.moniker,
1055                            }))
1056                        }
1057                    }
1058                    _ => OfferResult::Source(CapabilitySource::Component(ComponentSource {
1059                        capability,
1060                        moniker: component.moniker,
1061                    })),
1062                };
1063                OfferSegment::Done(res)
1064            }
1065            OfferSource::Framework => OfferSegment::Done(OfferResult::Source(
1066                CapabilitySource::Framework(FrameworkSource {
1067                    capability: sources.framework_source(
1068                        target.moniker(),
1069                        offer.source_name().clone(),
1070                        mapper,
1071                    )?,
1072                    moniker: target.moniker().clone(),
1073                }),
1074            )),
1075            OfferSource::Capability(_) => {
1076                sources.capability_source(target.moniker())?;
1077                OfferSegment::Done(OfferResult::Source(CapabilitySource::Capability(
1078                    CapabilityToCapabilitySource {
1079                        source_capability: ComponentCapability::Offer(offer.into()),
1080                        moniker: target.moniker().clone(),
1081                    },
1082                )))
1083            }
1084            OfferSource::Parent => {
1085                let parent_component = match target.try_get_parent()? {
1086                    ExtendedInstanceInterface::<C>::AboveRoot(top_instance) => {
1087                        if sources.is_namespace_supported() {
1088                            if let Some(capability) = sources.find_namespace_source(
1089                                ExtendedMoniker::ComponentManager,
1090                                offer.source_name(),
1091                                top_instance.namespace_capabilities(),
1092                                visitor,
1093                                mapper,
1094                            )? {
1095                                return Ok(OfferSegment::Done(OfferResult::Source(
1096                                    CapabilitySource::Namespace(NamespaceSource { capability }),
1097                                )));
1098                            }
1099                        }
1100                        if let Some(capability) = sources.find_builtin_source(
1101                            ExtendedMoniker::ComponentManager,
1102                            offer.source_name(),
1103                            top_instance.builtin_capabilities(),
1104                            visitor,
1105                            mapper,
1106                        )? {
1107                            return Ok(OfferSegment::Done(OfferResult::Source(
1108                                CapabilitySource::Builtin(BuiltinSource { capability }),
1109                            )));
1110                        }
1111                        return Err(RoutingError::offer_from_component_manager_not_found(
1112                            offer.source_name().to_string(),
1113                        ));
1114                    }
1115                    ExtendedInstanceInterface::<C>::Component(component) => component,
1116                };
1117                let child_moniker = target.child_moniker().expect("ChildName should exist");
1118                let parent_offers = parent_component.lock_resolved_state().await?.offers();
1119                let parent_offers = find_matching_offers(
1120                    CapabilityTypeName::from(&offer),
1121                    offer.source_name(),
1122                    &child_moniker,
1123                    &parent_offers,
1124                )
1125                .ok_or_else(|| {
1126                    <OfferDecl as ErrorNotFoundFromParent>::error_not_found_from_parent(
1127                        target.moniker().clone(),
1128                        offer.source_name().clone(),
1129                    )
1130                })?;
1131                OfferSegment::Next(parent_offers, parent_component)
1132            }
1133            OfferSource::Child(_) => OfferSegment::Done(OfferResult::OfferFromChild(offer, target)),
1134            OfferSource::Collection(_) => OfferSegment::Done(
1135                OfferResult::OfferFromAnonymizedAggregate(RouteBundle::from_offer(offer), target),
1136            ),
1137        };
1138        Ok(res)
1139    }
1140}
1141
1142/// Finds the matching Expose declaration for an Offer-from-child, changing the
1143/// direction in which the Component Tree is being navigated (from up to down).
1144async fn change_directions<C>(
1145    offer: OfferDecl,
1146    component: Arc<C>,
1147) -> Result<(RouteBundle<ExposeDecl>, Arc<C>), RoutingError>
1148where
1149    C: ComponentInstanceInterface,
1150{
1151    match offer.source() {
1152        OfferSource::Child(child) => {
1153            let child_component = {
1154                let child_moniker = ChildName::try_new(
1155                    child.name.as_str(),
1156                    child.collection.as_ref().map(|s| s.as_str()),
1157                )
1158                .expect("discovered invalid child name, manifest validation should prevent this");
1159                component.lock_resolved_state().await?.get_child(&child_moniker).ok_or_else(
1160                    || RoutingError::OfferFromChildInstanceNotFound {
1161                        child_moniker,
1162                        moniker: component.moniker().clone(),
1163                        capability_id: offer.source_name().clone().into(),
1164                    },
1165                )?
1166            };
1167            let child_exposes = child_component.lock_resolved_state().await?.exposes();
1168            let child_exposes = find_matching_exposes(
1169                CapabilityTypeName::from(&offer),
1170                offer.source_name(),
1171                &child_exposes,
1172            )
1173            .ok_or_else(|| {
1174                let child_moniker =
1175                    child_component.child_moniker().expect("ChildName should exist");
1176                <OfferDecl as ErrorNotFoundInChild>::error_not_found_in_child(
1177                    component.moniker().clone(),
1178                    child_moniker.into(),
1179                    offer.source_name().clone(),
1180                )
1181            })?;
1182            Ok((child_exposes, child_component.clone()))
1183        }
1184        _ => panic!("change_direction called with offer that does not change direction"),
1185    }
1186}
1187
1188/// The `Expose` phase of routing.
1189#[derive(Debug)]
1190pub struct Expose();
1191
1192#[allow(clippy::large_enum_variant)] // TODO(https://fxbug.dev/401087293)
1193/// The result of routing an Expose declaration to the next phase.
1194enum ExposeResult<C: ComponentInstanceInterface + 'static> {
1195    /// The source of the Expose was found (Framework, Component, etc.).
1196    Source(CapabilitySource),
1197    /// The source of the Expose comes from an aggregation of collections and/or static children
1198    ExposeFromAnonymizedAggregate(RouteBundle<ExposeDecl>, Arc<C>),
1199}
1200
1201/// A bundle of one or more routing declarations to route together, that share the same target_name
1202#[derive(Clone, Debug)]
1203pub enum RouteBundle<T>
1204where
1205    T: Clone + fmt::Debug,
1206{
1207    /// A single route from a unique source.
1208    Single(T),
1209    /// A bundle of routes representing an aggregated capability. This can be a vector of one,
1210    /// e.g. exposing a service from a collection.
1211    Aggregate(Vec<T>),
1212}
1213
1214impl<T> RouteBundle<T>
1215where
1216    T: Clone + fmt::Debug,
1217{
1218    pub fn map<U: Clone + fmt::Debug>(self, mut f: impl FnMut(T) -> U) -> RouteBundle<U> {
1219        match self {
1220            RouteBundle::Single(r) => RouteBundle::Single(f(r)),
1221            RouteBundle::Aggregate(r) => {
1222                RouteBundle::Aggregate(r.into_iter().map(&mut f).collect())
1223            }
1224        }
1225    }
1226
1227    /// Returns an iterator over the values of `OneOrMany<T>`.
1228    pub fn iter(&self) -> RouteBundleIter<'_, T> {
1229        match self {
1230            Self::Single(item) => {
1231                RouteBundleIter { inner_single: Some(item), inner_aggregate: None }
1232            }
1233            Self::Aggregate(items) => {
1234                RouteBundleIter { inner_single: None, inner_aggregate: Some(items.iter()) }
1235            }
1236        }
1237    }
1238
1239    /// Returns the number of routes in this bundle.
1240    pub fn len(&self) -> usize {
1241        match self {
1242            Self::Single(_) => 1,
1243            Self::Aggregate(v) => v.len(),
1244        }
1245    }
1246
1247    /// Creates a `RouteBundle` from of a single offer routing declaration.
1248    pub fn from_offer(input: T) -> Self
1249    where
1250        T: OfferDeclCommon + Clone,
1251    {
1252        Self::from_offers(vec![input])
1253    }
1254
1255    /// Creates a `RouteBundle` from of a list of offer routing declarations.
1256    ///
1257    /// REQUIRES: `input` is nonempty.
1258    /// REQUIRES: All elements of `input` share the same `target_name`.
1259    pub fn from_offers(mut input: Vec<T>) -> Self
1260    where
1261        T: OfferDeclCommon + Clone,
1262    {
1263        match input.len() {
1264            1 => {
1265                let input = input.remove(0);
1266                match input.source() {
1267                    OfferSource::Collection(_) => Self::Aggregate(vec![input]),
1268                    _ => Self::Single(input),
1269                }
1270            }
1271            0 => panic!("empty bundles are not allowed"),
1272            _ => Self::Aggregate(input),
1273        }
1274    }
1275
1276    /// Creates a `RouteBundle` from of a single expose routing declaration.
1277    pub fn from_expose(input: T) -> Self
1278    where
1279        T: ExposeDeclCommon + Clone,
1280    {
1281        Self::from_exposes(vec![input])
1282    }
1283
1284    /// Creates a `RouteBundle` from of a list of expose routing declarations.
1285    ///
1286    /// REQUIRES: `input` is nonempty.
1287    /// REQUIRES: All elements of `input` share the same `target_name`.
1288    pub fn from_exposes(mut input: Vec<T>) -> Self
1289    where
1290        T: ExposeDeclCommon + Clone,
1291    {
1292        match input.len() {
1293            1 => {
1294                let input = input.remove(0);
1295                match input.source() {
1296                    ExposeSource::Collection(_) => Self::Aggregate(vec![input]),
1297                    _ => Self::Single(input),
1298                }
1299            }
1300            0 => panic!("empty bundles are not allowed"),
1301            _ => Self::Aggregate(input),
1302        }
1303    }
1304}
1305
1306impl<T> RouteBundle<T>
1307where
1308    T: ExposeDeclCommon + Clone,
1309{
1310    pub fn availability(&self) -> &Availability {
1311        match self {
1312            Self::Single(e) => e.availability(),
1313            Self::Aggregate(v) => {
1314                assert!(
1315                    v.iter().zip(v.iter().skip(1)).all(|(a, b)| a.availability() == b.availability()),
1316                    "CM validation should ensure all aggregated capabilities have the same availability");
1317                v[0].availability()
1318            }
1319        }
1320    }
1321}
1322
1323/// Immutable iterator over a `RouteBundle`.
1324/// This `struct` is created by [`RouteBundle::iter`].
1325///
1326/// [`RouteBundle::iter`]: struct.RouteBundle.html#method.iter
1327pub struct RouteBundleIter<'a, T> {
1328    inner_single: Option<&'a T>,
1329    inner_aggregate: Option<slice::Iter<'a, T>>,
1330}
1331
1332impl<'a, T> Iterator for RouteBundleIter<'a, T> {
1333    type Item = &'a T;
1334
1335    fn next(&mut self) -> Option<Self::Item> {
1336        if let Some(item) = self.inner_single.take() {
1337            Some(item)
1338        } else if let Some(ref mut iter) = &mut self.inner_aggregate {
1339            iter.next()
1340        } else {
1341            None
1342        }
1343    }
1344
1345    fn size_hint(&self) -> (usize, Option<usize>) {
1346        if let Some(_) = self.inner_single {
1347            (1, Some(1))
1348        } else if let Some(iter) = &self.inner_aggregate {
1349            iter.size_hint()
1350        } else {
1351            (0, Some(0))
1352        }
1353    }
1354}
1355
1356impl<'a, T> ExactSizeIterator for RouteBundleIter<'a, T> {}
1357
1358#[allow(clippy::large_enum_variant)] // TODO(https://fxbug.dev/401087293)
1359enum ExposeSegment<C: ComponentInstanceInterface + 'static> {
1360    Done(ExposeResult<C>),
1361    Next(RouteBundle<ExposeDecl>, Arc<C>),
1362}
1363
1364impl Expose {
1365    /// Routes the capability starting from the `expose` declaration at `target` to a valid source
1366    /// (as defined by `sources`).
1367    async fn route<C, V>(
1368        mut expose_bundle: RouteBundle<ExposeDecl>,
1369        mut target: Arc<C>,
1370        sources: &Sources,
1371        visitor: &mut V,
1372        mapper: &mut dyn DebugRouteMapper,
1373    ) -> Result<ExposeResult<C>, RoutingError>
1374    where
1375        C: ComponentInstanceInterface + 'static,
1376        V: ExposeVisitor,
1377        V: CapabilityVisitor,
1378    {
1379        loop {
1380            let visit_expose = match &expose_bundle {
1381                RouteBundle::Single(expose) => Some(expose),
1382                RouteBundle::Aggregate(exposes) => {
1383                    // TODO(https://fxbug.dev/42124541): Visit routes in all aggregates.
1384                    if exposes.len() == 1 {
1385                        Some(&exposes[0])
1386                    } else {
1387                        None
1388                    }
1389                }
1390            };
1391            if let Some(visit_expose) = visit_expose {
1392                mapper.add_expose(target.moniker().clone(), visit_expose.clone().into());
1393                ExposeVisitor::visit(visitor, &target.moniker().clone().into(), &visit_expose)?;
1394            }
1395
1396            // Make sure this isn't coming from a dictionary
1397            for e in expose_bundle.iter() {
1398                if !e.source_path().dirname.is_dot() {
1399                    return Err(RoutingError::DictionariesNotSupported {
1400                        moniker: target.moniker().clone(),
1401                        cap_type: CapabilityTypeName::from(e),
1402                    });
1403                }
1404            }
1405
1406            match expose_bundle {
1407                RouteBundle::Single(expose) => {
1408                    match Self::route_segment(expose, target, sources, visitor, mapper).await? {
1409                        ExposeSegment::Done(r) => return Ok(r),
1410                        ExposeSegment::Next(e, t) => {
1411                            expose_bundle = e;
1412                            target = t;
1413                        }
1414                    }
1415                }
1416                RouteBundle::Aggregate(_) => {
1417                    return Ok(ExposeResult::ExposeFromAnonymizedAggregate(expose_bundle, target));
1418                }
1419            }
1420        }
1421    }
1422
1423    async fn route_segment<C, V>(
1424        expose: ExposeDecl,
1425        target: Arc<C>,
1426        sources: &Sources,
1427        visitor: &mut V,
1428        mapper: &mut dyn DebugRouteMapper,
1429    ) -> Result<ExposeSegment<C>, RoutingError>
1430    where
1431        C: ComponentInstanceInterface + 'static,
1432        V: ExposeVisitor,
1433        V: CapabilityVisitor,
1434    {
1435        let res = match expose.source() {
1436            ExposeSource::Void => {
1437                ExposeSegment::Done(ExposeResult::Source(CapabilitySource::Void(VoidSource {
1438                    capability: InternalCapability::new(
1439                        (&expose).into(),
1440                        expose.source_name().clone(),
1441                    ),
1442                    moniker: target.moniker().clone(),
1443                })))
1444            }
1445            ExposeSource::Self_ => {
1446                let target_capabilities = target.lock_resolved_state().await?.capabilities();
1447                ExposeSegment::Done(ExposeResult::Source(CapabilitySource::Component(
1448                    ComponentSource {
1449                        capability: sources.find_component_source(
1450                            expose.source_name(),
1451                            target.moniker(),
1452                            &target_capabilities,
1453                            visitor,
1454                            mapper,
1455                        )?,
1456                        moniker: target.moniker().clone(),
1457                    },
1458                )))
1459            }
1460            ExposeSource::Framework => ExposeSegment::Done(ExposeResult::Source(
1461                CapabilitySource::Framework(FrameworkSource {
1462                    capability: sources.framework_source(
1463                        target.moniker(),
1464                        expose.source_name().clone(),
1465                        mapper,
1466                    )?,
1467                    moniker: target.moniker().clone(),
1468                }),
1469            )),
1470            ExposeSource::Capability(_) => {
1471                sources.capability_source(target.moniker())?;
1472                ExposeSegment::Done(ExposeResult::Source(CapabilitySource::Capability(
1473                    CapabilityToCapabilitySource {
1474                        source_capability: ComponentCapability::Expose(expose.into()),
1475                        moniker: target.moniker().clone(),
1476                    },
1477                )))
1478            }
1479            ExposeSource::Child(child) => {
1480                let child_component = {
1481                    let child_moniker = ChildName::new(child.clone().into(), None);
1482                    target.lock_resolved_state().await?.get_child(&child_moniker).ok_or_else(
1483                        || RoutingError::ExposeFromChildInstanceNotFound {
1484                            child_moniker,
1485                            moniker: target.moniker().clone(),
1486                            capability_id: expose.source_name().clone().into(),
1487                        },
1488                    )?
1489                };
1490                let child_exposes = child_component.lock_resolved_state().await?.exposes();
1491                let child_exposes = find_matching_exposes(
1492                    CapabilityTypeName::from(&expose),
1493                    expose.source_name(),
1494                    &child_exposes,
1495                )
1496                .ok_or_else(|| {
1497                    let child_moniker =
1498                        child_component.child_moniker().expect("ChildName should exist");
1499                    <ExposeDecl as ErrorNotFoundInChild>::error_not_found_in_child(
1500                        target.moniker().clone(),
1501                        child_moniker.into(),
1502                        expose.source_name().clone(),
1503                    )
1504                })?;
1505                ExposeSegment::Next(child_exposes, child_component)
1506            }
1507            ExposeSource::Collection(_) => {
1508                ExposeSegment::Done(ExposeResult::ExposeFromAnonymizedAggregate(
1509                    RouteBundle::from_expose(expose),
1510                    target,
1511                ))
1512            }
1513        };
1514        Ok(res)
1515    }
1516}
1517
1518fn target_matches_moniker(target: &OfferTarget, child_moniker: &BorrowedChildName) -> bool {
1519    match target {
1520        OfferTarget::Child(target_ref) => {
1521            &target_ref.name == child_moniker.name()
1522                && target_ref.collection.as_ref().map(Borrow::borrow) == child_moniker.collection()
1523        }
1524        OfferTarget::Collection(target_collection) => {
1525            Some(target_collection.borrow()) == child_moniker.collection()
1526        }
1527        OfferTarget::Capability(_) => false,
1528    }
1529}
1530
1531/// Visitor pattern trait for visiting all [`OfferDecl`] during a route.
1532pub trait OfferVisitor {
1533    fn visit(&mut self, moniker: &ExtendedMoniker, offer: &OfferDecl) -> Result<(), RoutingError>;
1534}
1535
1536/// Visitor pattern trait for visiting all [`ExposeDecl`] during a route.
1537pub trait ExposeVisitor {
1538    /// Visit each [`ExposeDecl`] on the route.
1539    /// Returning an `Err` cancels visitation.
1540    fn visit(&mut self, moniker: &ExtendedMoniker, expose: &ExposeDecl)
1541        -> Result<(), RoutingError>;
1542}
1543
1544/// Visitor pattern trait for visiting all [`CapabilityDecl`] during a route.
1545pub trait CapabilityVisitor {
1546    /// Visit each [`CapabilityDecl`] on the route.
1547    /// Returning an `Err` cancels visitation.
1548    fn visit(
1549        &mut self,
1550        moniker: &ExtendedMoniker,
1551        capability: &CapabilityDecl,
1552    ) -> Result<(), RoutingError>;
1553}
1554
1555pub fn find_matching_offers(
1556    capability_type: CapabilityTypeName,
1557    source_name: &Name,
1558    child_moniker: &BorrowedChildName,
1559    offers: &Vec<OfferDecl>,
1560) -> Option<RouteBundle<OfferDecl>> {
1561    let offers: Vec<_> = offers
1562        .iter()
1563        .filter(|offer: &&OfferDecl| {
1564            capability_type == CapabilityTypeName::from(*offer)
1565                && *offer.target_name() == *source_name
1566                && target_matches_moniker(offer.target(), child_moniker)
1567        })
1568        .cloned()
1569        .collect();
1570    if offers.is_empty() {
1571        return None;
1572    }
1573    Some(RouteBundle::from_offers(offers))
1574}
1575
1576pub fn find_matching_exposes(
1577    capability_type: CapabilityTypeName,
1578    source_name: &Name,
1579    exposes: &Vec<ExposeDecl>,
1580) -> Option<RouteBundle<ExposeDecl>> {
1581    let exposes: Vec<_> = exposes
1582        .iter()
1583        .filter(|expose: &&ExposeDecl| {
1584            capability_type == CapabilityTypeName::from(*expose)
1585                && *expose.target_name() == *source_name
1586                && *expose.target() == ExposeTarget::Parent
1587        })
1588        .cloned()
1589        .collect();
1590    if exposes.is_empty() {
1591        return None;
1592    }
1593    Some(RouteBundle::from_exposes(exposes))
1594}
1595
1596/// Implemented by declaration types to emit a proper error when a matching offer is not found in the parent.
1597pub trait ErrorNotFoundFromParent {
1598    fn error_not_found_from_parent(
1599        decl_site_moniker: Moniker,
1600        capability_name: Name,
1601    ) -> RoutingError;
1602}
1603
1604/// Implemented by declaration types to emit a proper error when a matching expose is not found in the child.
1605pub trait ErrorNotFoundInChild {
1606    fn error_not_found_in_child(
1607        decl_site_moniker: Moniker,
1608        child_moniker: ChildName,
1609        capability_name: Name,
1610    ) -> RoutingError;
1611}
1612
1613#[derive(Clone)]
1614pub struct NoopVisitor {}
1615
1616impl NoopVisitor {
1617    pub fn new() -> NoopVisitor {
1618        NoopVisitor {}
1619    }
1620}
1621
1622impl OfferVisitor for NoopVisitor {
1623    fn visit(&mut self, _: &ExtendedMoniker, _: &OfferDecl) -> Result<(), RoutingError> {
1624        Ok(())
1625    }
1626}
1627
1628impl ExposeVisitor for NoopVisitor {
1629    fn visit(&mut self, _: &ExtendedMoniker, _: &ExposeDecl) -> Result<(), RoutingError> {
1630        Ok(())
1631    }
1632}
1633
1634impl CapabilityVisitor for NoopVisitor {
1635    fn visit(&mut self, _: &ExtendedMoniker, _: &CapabilityDecl) -> Result<(), RoutingError> {
1636        Ok(())
1637    }
1638}
1639
1640#[cfg(test)]
1641mod tests {
1642    use super::*;
1643    use assert_matches::assert_matches;
1644    use cm_rust::ExposeServiceDecl;
1645    use cm_rust_testing::*;
1646
1647    #[test]
1648    fn route_bundle_iter_single() {
1649        let v = RouteBundle::Single(34);
1650        let mut iter = v.iter();
1651        assert_matches!(iter.next(), Some(&34));
1652        assert_matches!(iter.next(), None);
1653    }
1654
1655    #[test]
1656    fn route_bundle_iter_many() {
1657        let v = RouteBundle::Aggregate(vec![1, 2, 3]);
1658        let mut iter = v.iter();
1659        assert_matches!(iter.next(), Some(&1));
1660        assert_matches!(iter.next(), Some(&2));
1661        assert_matches!(iter.next(), Some(&3));
1662        assert_matches!(iter.next(), None);
1663    }
1664
1665    #[test]
1666    fn route_bundle_from_offers() {
1667        let parent_offers: Vec<_> = [1, 2, 3]
1668            .into_iter()
1669            .map(|i| OfferServiceDecl {
1670                source: OfferSource::Parent,
1671                source_name: format!("foo_source_{}", i).parse().unwrap(),
1672                source_dictionary: Default::default(),
1673                target: OfferTarget::Collection("coll".parse().unwrap()),
1674                target_name: "foo_target".parse().unwrap(),
1675                source_instance_filter: None,
1676                renamed_instances: None,
1677                availability: Availability::Required,
1678                dependency_type: Default::default(),
1679            })
1680            .collect();
1681        let collection_offer = OfferServiceDecl {
1682            source: OfferSource::Collection("coll".parse().unwrap()),
1683            source_name: "foo_source".parse().unwrap(),
1684            source_dictionary: Default::default(),
1685            target: offer_target_static_child("target"),
1686            target_name: "foo_target".parse().unwrap(),
1687            source_instance_filter: None,
1688            renamed_instances: None,
1689            availability: Availability::Required,
1690            dependency_type: Default::default(),
1691        };
1692        assert_matches!(
1693            RouteBundle::from_offer(parent_offers[0].clone()),
1694            RouteBundle::Single(o) if o == parent_offers[0]
1695        );
1696        assert_matches!(
1697            RouteBundle::from_offers(vec![parent_offers[0].clone()]),
1698            RouteBundle::Single(o) if o == parent_offers[0]
1699        );
1700        assert_matches!(
1701            RouteBundle::from_offers(parent_offers.clone()),
1702            RouteBundle::Aggregate(v) if v == parent_offers
1703        );
1704        assert_matches!(
1705            RouteBundle::from_offer(collection_offer.clone()),
1706            RouteBundle::Aggregate(v) if v == vec![collection_offer.clone()]
1707        );
1708    }
1709
1710    #[test]
1711    fn route_bundle_from_exposes() {
1712        let child_exposes: Vec<_> = [1, 2, 3]
1713            .into_iter()
1714            .map(|i| ExposeServiceDecl {
1715                source: ExposeSource::Child("source".parse().unwrap()),
1716                source_name: format!("foo_source_{}", i).parse().unwrap(),
1717                source_dictionary: Default::default(),
1718                target: ExposeTarget::Parent,
1719                target_name: "foo_target".parse().unwrap(),
1720                availability: Availability::Required,
1721            })
1722            .collect();
1723        let collection_expose = ExposeServiceDecl {
1724            source: ExposeSource::Collection("coll".parse().unwrap()),
1725            source_name: "foo_source".parse().unwrap(),
1726            source_dictionary: Default::default(),
1727            target: ExposeTarget::Parent,
1728            target_name: "foo_target".parse().unwrap(),
1729            availability: Availability::Required,
1730        };
1731        assert_matches!(
1732            RouteBundle::from_expose(child_exposes[0].clone()),
1733            RouteBundle::Single(o) if o == child_exposes[0]
1734        );
1735        assert_matches!(
1736            RouteBundle::from_exposes(vec![child_exposes[0].clone()]),
1737            RouteBundle::Single(o) if o == child_exposes[0]
1738        );
1739        assert_matches!(
1740            RouteBundle::from_exposes(child_exposes.clone()),
1741            RouteBundle::Aggregate(v) if v == child_exposes
1742        );
1743        assert_matches!(
1744            RouteBundle::from_expose(collection_expose.clone()),
1745            RouteBundle::Aggregate(v) if v == vec![collection_expose.clone()]
1746        );
1747    }
1748}