Skip to main content

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::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
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.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            // "_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/// The result of routing a Registration declaration to the next phase.
770enum RegistrationResult<C: ComponentInstanceInterface + 'static, O: Clone + fmt::Debug> {
771    /// The source of the Registration was found (Framework, AboveRoot, etc.).
772    Source(Box<CapabilitySource>),
773    /// The Registration led to a parent Offer declaration.
774    FromParent(Box<RouteBundle<O>>, Arc<C>),
775    /// The Registration led to a child Expose declaration.
776    FromChild(Box<RouteBundle<ExposeDecl>>, Arc<C>),
777}
778
779impl<R> Registration<R>
780where
781    R: RegistrationDeclCommon
782        + ErrorNotFoundFromParent
783        + ErrorNotFoundInChild
784        + Into<RegistrationDecl>
785        + Clone,
786{
787    /// Routes the capability starting from the `registration` declaration at `target` to either a
788    /// valid source (as defined by `sources`) or the Offer or Expose declaration that ends this
789    /// phase of routing.
790    async fn route<C, V>(
791        registration: R,
792        target: Arc<C>,
793        sources: &Sources,
794        visitor: &mut V,
795        mapper: &mut dyn DebugRouteMapper,
796    ) -> Result<RegistrationResult<C, OfferDecl>, RoutingError>
797    where
798        C: ComponentInstanceInterface + 'static,
799        V: CapabilityVisitor,
800    {
801        let registration_decl: RegistrationDecl = registration.clone().into();
802        mapper.add_registration(target.moniker().clone(), &registration_decl);
803        match registration.source() {
804            RegistrationSource::Self_ => {
805                let target_capabilities = target.lock_resolved_state().await?.capabilities();
806                Ok(RegistrationResult::Source(Box::new(CapabilitySource::Component(
807                    ComponentSource {
808                        capability: sources.find_component_source(
809                            registration.source_name(),
810                            target.moniker(),
811                            &target_capabilities,
812                            visitor,
813                            mapper,
814                        )?,
815                        moniker: target.moniker().clone(),
816                    },
817                ))))
818            }
819            RegistrationSource::Parent => match target.try_get_parent()? {
820                ExtendedInstanceInterface::<C>::AboveRoot(top_instance) => {
821                    if sources.is_namespace_supported() {
822                        if let Some(capability) = sources.find_namespace_source(
823                            ExtendedMoniker::ComponentManager,
824                            registration.source_name(),
825                            top_instance.namespace_capabilities(),
826                            visitor,
827                            mapper,
828                        )? {
829                            return Ok(RegistrationResult::Source(Box::new(
830                                CapabilitySource::Namespace(NamespaceSource { capability }),
831                            )));
832                        }
833                    }
834                    if let Some(capability) = sources.find_builtin_source(
835                        ExtendedMoniker::ComponentManager,
836                        registration.source_name(),
837                        top_instance.builtin_capabilities(),
838                        visitor,
839                        mapper,
840                    )? {
841                        return Ok(RegistrationResult::Source(Box::new(
842                            CapabilitySource::Builtin(BuiltinSource { capability }),
843                        )));
844                    }
845                    Err(RoutingError::register_from_component_manager_not_found(
846                        registration.source_name().to_string(),
847                    ))
848                }
849                ExtendedInstanceInterface::<C>::Component(parent_component) => {
850                    let parent_offers = parent_component.lock_resolved_state().await?.offers();
851                    let child_moniker = target.child_moniker().expect("ChildName should exist");
852                    let parent_offers = find_matching_offers(
853                        CapabilityTypeName::from(&registration_decl),
854                        registration.source_name(),
855                        &child_moniker,
856                        &parent_offers,
857                    )
858                    .ok_or_else(|| {
859                        <R as ErrorNotFoundFromParent>::error_not_found_from_parent(
860                            target.moniker().clone(),
861                            registration.source_name().clone(),
862                        )
863                    })?;
864                    Ok(RegistrationResult::FromParent(Box::new(parent_offers), parent_component))
865                }
866            },
867            RegistrationSource::Child(child) => {
868                let child_component = {
869                    let child_moniker = ChildName::try_new(child, None).expect(
870                        "discovered invalid child name, manifest validation should prevent this",
871                    );
872                    target.lock_resolved_state().await?.get_child(&child_moniker).ok_or_else(
873                        || RoutingError::EnvironmentFromChildInstanceNotFound {
874                            child_moniker,
875                            moniker: target.moniker().clone(),
876                            capability_name: registration.source_name().clone(),
877                            capability_type: R::TYPE.to_string(),
878                        },
879                    )?
880                };
881
882                let child_exposes = child_component.lock_resolved_state().await?.exposes();
883                let capability_type = CapabilityTypeName::from(&registration.clone().into());
884                let child_exposes = find_matching_exposes(
885                    capability_type,
886                    registration.source_name(),
887                    &child_exposes,
888                )
889                .ok_or_else(|| {
890                    let child_moniker =
891                        child_component.child_moniker().expect("ChildName should exist");
892                    <R as ErrorNotFoundInChild>::error_not_found_in_child(
893                        target.moniker().clone(),
894                        child_moniker.into(),
895                        registration.source_name().clone(),
896                    )
897                })?;
898                Ok(RegistrationResult::FromChild(Box::new(child_exposes), child_component.clone()))
899            }
900        }
901    }
902}
903
904/// The `Offer` phase of routing.
905pub struct Offer();
906
907/// The result of routing an Offer declaration to the next phase.
908enum OfferResult<C: ComponentInstanceInterface + 'static> {
909    /// The source of the Offer was found (Framework, AboveRoot, Component, etc.).
910    Source(Box<CapabilitySource>),
911    /// The Offer led to an Offer-from-child declaration.
912    /// Not all capabilities can be exposed, so let the caller decide how to handle this.
913    OfferFromChild(OfferDecl, Arc<C>),
914    /// Offer from multiple static children, with filters.
915    OfferFromFilteredAggregate(RouteBundle<OfferDecl>, Arc<C>),
916    /// Offer from one or more collections and/or static children.
917    OfferFromAnonymizedAggregate(RouteBundle<OfferDecl>, Arc<C>),
918}
919
920enum OfferSegment<C: ComponentInstanceInterface + 'static> {
921    Done(OfferResult<C>),
922    Next(Box<RouteBundle<OfferDecl>>, Arc<C>),
923}
924
925impl Offer {
926    /// Routes the capability starting from the `offer` declaration at `target` to either a valid
927    /// source (as defined by `sources`) or the declaration that ends this phase of routing.
928    async fn route<C, V>(
929        mut offer_bundle: RouteBundle<OfferDecl>,
930        mut target: Arc<C>,
931        sources: &Sources,
932        visitor: &mut V,
933        mapper: &mut dyn DebugRouteMapper,
934    ) -> Result<OfferResult<C>, RoutingError>
935    where
936        C: ComponentInstanceInterface + 'static,
937        V: OfferVisitor,
938        V: CapabilityVisitor,
939    {
940        loop {
941            let visit_offer = match &offer_bundle {
942                RouteBundle::Single(offer) => Some(offer),
943                RouteBundle::Aggregate(offers) => {
944                    // TODO(https://fxbug.dev/42124541): Visit routes in all aggregates.
945                    if offers.len() == 1 { Some(&offers[0]) } else { None }
946                }
947            };
948            if let Some(visit_offer) = visit_offer {
949                mapper.add_offer(target.moniker().clone(), &visit_offer);
950                OfferVisitor::visit(visitor, &target.moniker().clone().into(), &visit_offer)?;
951            }
952
953            fn is_filtered_offer(o: &OfferDecl) -> bool {
954                if let OfferDecl::Service(offer_service) = o {
955                    if let Some(f) = offer_service.source_instance_filter.as_ref() {
956                        if !f.is_empty() {
957                            return true;
958                        }
959                    }
960                    if let Some(f) = offer_service.renamed_instances.as_ref() {
961                        if !f.is_empty() {
962                            return true;
963                        }
964                    }
965                }
966                false
967            }
968
969            // Make sure this isn't coming from a dictionary
970            for o in offer_bundle.iter() {
971                if !o.source_path().dirname.is_dot() {
972                    return Err(RoutingError::DictionariesNotSupported {
973                        moniker: target.moniker().clone(),
974                        cap_type: CapabilityTypeName::from(o),
975                    });
976                }
977            }
978
979            match offer_bundle {
980                RouteBundle::Single(offer) => {
981                    match Self::route_segment(offer, target, sources, visitor, mapper).await? {
982                        OfferSegment::Done(r) => return Ok(r),
983                        OfferSegment::Next(o, t) => {
984                            offer_bundle = *o;
985                            target = t;
986                        }
987                    }
988                }
989                RouteBundle::Aggregate(_) => {
990                    if offer_bundle.iter().all(|o| !is_filtered_offer(o)) {
991                        return Ok(OfferResult::OfferFromAnonymizedAggregate(offer_bundle, target));
992                    } else {
993                        return Ok(OfferResult::OfferFromFilteredAggregate(offer_bundle, target));
994                    }
995                }
996            }
997        }
998    }
999
1000    async fn route_segment<C, V>(
1001        offer: OfferDecl,
1002        target: Arc<C>,
1003        sources: &Sources,
1004        visitor: &mut V,
1005        mapper: &mut dyn DebugRouteMapper,
1006    ) -> Result<OfferSegment<C>, RoutingError>
1007    where
1008        C: ComponentInstanceInterface + 'static,
1009        V: OfferVisitor,
1010        V: CapabilityVisitor,
1011    {
1012        let res = match offer.source() {
1013            OfferSource::Void => OfferSegment::Done(OfferResult::Source(Box::new(
1014                CapabilitySource::Void(VoidSource {
1015                    capability: InternalCapability::new(
1016                        (&offer).into(),
1017                        offer.source_name().clone(),
1018                    ),
1019                    moniker: target.moniker().clone(),
1020                }),
1021            ))),
1022            OfferSource::Self_ => {
1023                let target_capabilities = target.lock_resolved_state().await?.capabilities();
1024                let capability = sources.find_component_source(
1025                    offer.source_name(),
1026                    target.moniker(),
1027                    &target_capabilities,
1028                    visitor,
1029                    mapper,
1030                )?;
1031                // if offerdecl is for a filtered service return the associated filtered source.
1032                let component = target.as_weak();
1033                let moniker = target.moniker().clone();
1034                let res = match offer.into() {
1035                    OfferDecl::Service(offer_service_decl) => {
1036                        if offer_service_decl.source_instance_filter.is_some()
1037                            || offer_service_decl.renamed_instances.is_some()
1038                        {
1039                            let source_name = offer_service_decl.source_name.clone();
1040                            OfferResult::Source(Box::new(CapabilitySource::FilteredProvider(
1041                                FilteredProviderSource {
1042                                    capability: AggregateCapability::Service(source_name),
1043                                    moniker,
1044                                    service_capability: capability,
1045                                    offer_service_decl,
1046                                },
1047                            )))
1048                        } else {
1049                            OfferResult::Source(Box::new(CapabilitySource::Component(
1050                                ComponentSource { capability, moniker: component.moniker },
1051                            )))
1052                        }
1053                    }
1054                    _ => OfferResult::Source(Box::new(CapabilitySource::Component(
1055                        ComponentSource { capability, moniker: component.moniker },
1056                    ))),
1057                };
1058                OfferSegment::Done(res)
1059            }
1060            OfferSource::Framework => OfferSegment::Done(OfferResult::Source(Box::new(
1061                CapabilitySource::Framework(FrameworkSource {
1062                    capability: sources.framework_source(
1063                        target.moniker(),
1064                        offer.source_name().clone(),
1065                        mapper,
1066                    )?,
1067                    moniker: target.moniker().clone(),
1068                }),
1069            ))),
1070            OfferSource::Capability(_) => {
1071                sources.capability_source(target.moniker())?;
1072                OfferSegment::Done(OfferResult::Source(Box::new(CapabilitySource::Capability(
1073                    CapabilityToCapabilitySource {
1074                        source_capability: ComponentCapability::Offer(offer.into()),
1075                        moniker: target.moniker().clone(),
1076                    },
1077                ))))
1078            }
1079            OfferSource::Parent => {
1080                let parent_component = match target.try_get_parent()? {
1081                    ExtendedInstanceInterface::<C>::AboveRoot(top_instance) => {
1082                        if sources.is_namespace_supported() {
1083                            if let Some(capability) = sources.find_namespace_source(
1084                                ExtendedMoniker::ComponentManager,
1085                                offer.source_name(),
1086                                top_instance.namespace_capabilities(),
1087                                visitor,
1088                                mapper,
1089                            )? {
1090                                return Ok(OfferSegment::Done(OfferResult::Source(Box::new(
1091                                    CapabilitySource::Namespace(NamespaceSource { capability }),
1092                                ))));
1093                            }
1094                        }
1095                        if let Some(capability) = sources.find_builtin_source(
1096                            ExtendedMoniker::ComponentManager,
1097                            offer.source_name(),
1098                            top_instance.builtin_capabilities(),
1099                            visitor,
1100                            mapper,
1101                        )? {
1102                            return Ok(OfferSegment::Done(OfferResult::Source(Box::new(
1103                                CapabilitySource::Builtin(BuiltinSource { capability }),
1104                            ))));
1105                        }
1106                        return Err(RoutingError::offer_from_component_manager_not_found(
1107                            offer.source_name().to_string(),
1108                        ));
1109                    }
1110                    ExtendedInstanceInterface::<C>::Component(component) => component,
1111                };
1112                let child_moniker = target.child_moniker().expect("ChildName should exist");
1113                let parent_offers = parent_component.lock_resolved_state().await?.offers();
1114                let parent_offers = find_matching_offers(
1115                    CapabilityTypeName::from(&offer),
1116                    offer.source_name(),
1117                    &child_moniker,
1118                    &parent_offers,
1119                )
1120                .ok_or_else(|| {
1121                    <OfferDecl as ErrorNotFoundFromParent>::error_not_found_from_parent(
1122                        target.moniker().clone(),
1123                        offer.source_name().clone(),
1124                    )
1125                })?;
1126                OfferSegment::Next(Box::new(parent_offers), parent_component)
1127            }
1128            OfferSource::Child(_) => OfferSegment::Done(OfferResult::OfferFromChild(offer, target)),
1129            OfferSource::Collection(_) => OfferSegment::Done(
1130                OfferResult::OfferFromAnonymizedAggregate(RouteBundle::from_offer(offer), target),
1131            ),
1132        };
1133        Ok(res)
1134    }
1135}
1136
1137/// Finds the matching Expose declaration for an Offer-from-child, changing the
1138/// direction in which the Component Tree is being navigated (from up to down).
1139async fn change_directions<C>(
1140    offer: OfferDecl,
1141    component: Arc<C>,
1142) -> Result<(RouteBundle<ExposeDecl>, Arc<C>), RoutingError>
1143where
1144    C: ComponentInstanceInterface,
1145{
1146    match offer.source() {
1147        OfferSource::Child(child) => {
1148            let child_component = {
1149                let child_moniker = ChildName::try_new(
1150                    child.name.as_str(),
1151                    child.collection.as_ref().map(|s| s.as_str()),
1152                )
1153                .expect("discovered invalid child name, manifest validation should prevent this");
1154                component.lock_resolved_state().await?.get_child(&child_moniker).ok_or_else(
1155                    || RoutingError::OfferFromChildInstanceNotFound {
1156                        child_moniker,
1157                        moniker: component.moniker().clone(),
1158                        capability_id: offer.source_name().clone().into(),
1159                    },
1160                )?
1161            };
1162            let child_exposes = child_component.lock_resolved_state().await?.exposes();
1163            let child_exposes = find_matching_exposes(
1164                CapabilityTypeName::from(&offer),
1165                offer.source_name(),
1166                &child_exposes,
1167            )
1168            .ok_or_else(|| {
1169                let child_moniker =
1170                    child_component.child_moniker().expect("ChildName should exist");
1171                <OfferDecl as ErrorNotFoundInChild>::error_not_found_in_child(
1172                    component.moniker().clone(),
1173                    child_moniker.into(),
1174                    offer.source_name().clone(),
1175                )
1176            })?;
1177            Ok((child_exposes, child_component.clone()))
1178        }
1179        _ => panic!("change_direction called with offer that does not change direction"),
1180    }
1181}
1182
1183/// The `Expose` phase of routing.
1184#[derive(Debug)]
1185pub struct Expose();
1186
1187/// The result of routing an Expose declaration to the next phase.
1188enum ExposeResult<C: ComponentInstanceInterface + 'static> {
1189    /// The source of the Expose was found (Framework, Component, etc.).
1190    Source(Box<CapabilitySource>),
1191    /// The source of the Expose comes from an aggregation of collections and/or static children
1192    ExposeFromAnonymizedAggregate(Box<RouteBundle<ExposeDecl>>, Arc<C>),
1193}
1194
1195/// A bundle of one or more routing declarations to route together, that share the same target_name
1196#[derive(Clone, Debug)]
1197pub enum RouteBundle<T>
1198where
1199    T: Clone + fmt::Debug,
1200{
1201    /// A single route from a unique source.
1202    Single(T),
1203    /// A bundle of routes representing an aggregated capability. This can be a vector of one,
1204    /// e.g. exposing a service from a collection.
1205    Aggregate(Vec<T>),
1206}
1207
1208impl<T> RouteBundle<T>
1209where
1210    T: Clone + fmt::Debug,
1211{
1212    pub fn map<U: Clone + fmt::Debug>(self, mut f: impl FnMut(T) -> U) -> RouteBundle<U> {
1213        match self {
1214            RouteBundle::Single(r) => RouteBundle::Single(f(r)),
1215            RouteBundle::Aggregate(r) => {
1216                RouteBundle::Aggregate(r.into_iter().map(&mut f).collect())
1217            }
1218        }
1219    }
1220
1221    /// Returns an iterator over the values of `OneOrMany<T>`.
1222    pub fn iter(&self) -> RouteBundleIter<'_, T> {
1223        match self {
1224            Self::Single(item) => {
1225                RouteBundleIter { inner_single: Some(item), inner_aggregate: None }
1226            }
1227            Self::Aggregate(items) => {
1228                RouteBundleIter { inner_single: None, inner_aggregate: Some(items.iter()) }
1229            }
1230        }
1231    }
1232
1233    /// Returns the number of routes in this bundle.
1234    pub fn len(&self) -> usize {
1235        match self {
1236            Self::Single(_) => 1,
1237            Self::Aggregate(v) => v.len(),
1238        }
1239    }
1240
1241    /// Creates a `RouteBundle` from of a single offer routing declaration.
1242    pub fn from_offer(input: T) -> Self
1243    where
1244        T: OfferDeclCommon + Clone,
1245    {
1246        Self::from_offers(vec![input])
1247    }
1248
1249    /// Creates a `RouteBundle` from of a list of offer routing declarations.
1250    ///
1251    /// REQUIRES: `input` is nonempty.
1252    /// REQUIRES: All elements of `input` share the same `target_name`.
1253    pub fn from_offers(mut input: Vec<T>) -> Self
1254    where
1255        T: OfferDeclCommon + Clone,
1256    {
1257        match input.len() {
1258            1 => {
1259                let input = input.remove(0);
1260                match input.source() {
1261                    OfferSource::Collection(_) => Self::Aggregate(vec![input]),
1262                    _ => Self::Single(input),
1263                }
1264            }
1265            0 => panic!("empty bundles are not allowed"),
1266            _ => Self::Aggregate(input),
1267        }
1268    }
1269
1270    /// Creates a `RouteBundle` from of a single expose routing declaration.
1271    pub fn from_expose(input: T) -> Self
1272    where
1273        T: ExposeDeclCommon + Clone,
1274    {
1275        Self::from_exposes(vec![input])
1276    }
1277
1278    /// Creates a `RouteBundle` from of a list of expose routing declarations.
1279    ///
1280    /// REQUIRES: `input` is nonempty.
1281    /// REQUIRES: All elements of `input` share the same `target_name`.
1282    pub fn from_exposes(mut input: Vec<T>) -> Self
1283    where
1284        T: ExposeDeclCommon + Clone,
1285    {
1286        match input.len() {
1287            1 => {
1288                let input = input.remove(0);
1289                match input.source() {
1290                    ExposeSource::Collection(_) => Self::Aggregate(vec![input]),
1291                    _ => Self::Single(input),
1292                }
1293            }
1294            0 => panic!("empty bundles are not allowed"),
1295            _ => Self::Aggregate(input),
1296        }
1297    }
1298}
1299
1300impl<T> RouteBundle<T>
1301where
1302    T: ExposeDeclCommon + Clone,
1303{
1304    pub fn availability(&self) -> &Availability {
1305        match self {
1306            Self::Single(e) => e.availability(),
1307            Self::Aggregate(v) => {
1308                assert!(
1309                    v.iter()
1310                        .zip(v.iter().skip(1))
1311                        .all(|(a, b)| a.availability() == b.availability()),
1312                    "CM validation should ensure all aggregated capabilities have the same availability"
1313                );
1314                v[0].availability()
1315            }
1316        }
1317    }
1318}
1319
1320/// Immutable iterator over a `RouteBundle`.
1321/// This `struct` is created by [`RouteBundle::iter`].
1322///
1323/// [`RouteBundle::iter`]: struct.RouteBundle.html#method.iter
1324pub struct RouteBundleIter<'a, T> {
1325    inner_single: Option<&'a T>,
1326    inner_aggregate: Option<slice::Iter<'a, T>>,
1327}
1328
1329impl<'a, T> Iterator for RouteBundleIter<'a, T> {
1330    type Item = &'a T;
1331
1332    fn next(&mut self) -> Option<Self::Item> {
1333        if let Some(item) = self.inner_single.take() {
1334            Some(item)
1335        } else if let Some(iter) = &mut self.inner_aggregate {
1336            iter.next()
1337        } else {
1338            None
1339        }
1340    }
1341
1342    fn size_hint(&self) -> (usize, Option<usize>) {
1343        if let Some(_) = self.inner_single {
1344            (1, Some(1))
1345        } else if let Some(iter) = &self.inner_aggregate {
1346            iter.size_hint()
1347        } else {
1348            (0, Some(0))
1349        }
1350    }
1351}
1352
1353impl<'a, T> ExactSizeIterator for RouteBundleIter<'a, T> {}
1354
1355enum ExposeSegment<C: ComponentInstanceInterface + 'static> {
1356    Done(ExposeResult<C>),
1357    Next(Box<RouteBundle<ExposeDecl>>, Arc<C>),
1358}
1359
1360impl Expose {
1361    /// Routes the capability starting from the `expose` declaration at `target` to a valid source
1362    /// (as defined by `sources`).
1363    async fn route<C, V>(
1364        mut expose_bundle: RouteBundle<ExposeDecl>,
1365        mut target: Arc<C>,
1366        sources: &Sources,
1367        visitor: &mut V,
1368        mapper: &mut dyn DebugRouteMapper,
1369    ) -> Result<ExposeResult<C>, RoutingError>
1370    where
1371        C: ComponentInstanceInterface + 'static,
1372        V: ExposeVisitor,
1373        V: CapabilityVisitor,
1374    {
1375        loop {
1376            let visit_expose = match &expose_bundle {
1377                RouteBundle::Single(expose) => Some(expose),
1378                RouteBundle::Aggregate(exposes) => {
1379                    // TODO(https://fxbug.dev/42124541): Visit routes in all aggregates.
1380                    if exposes.len() == 1 { Some(&exposes[0]) } else { None }
1381                }
1382            };
1383            if let Some(visit_expose) = visit_expose {
1384                mapper.add_expose(target.moniker().clone(), visit_expose.clone().into());
1385                ExposeVisitor::visit(visitor, &target.moniker().clone().into(), &visit_expose)?;
1386            }
1387
1388            // Make sure this isn't coming from a dictionary
1389            for e in expose_bundle.iter() {
1390                if !e.source_path().dirname.is_dot() {
1391                    return Err(RoutingError::DictionariesNotSupported {
1392                        moniker: target.moniker().clone(),
1393                        cap_type: CapabilityTypeName::from(e),
1394                    });
1395                }
1396            }
1397
1398            match expose_bundle {
1399                RouteBundle::Single(expose) => {
1400                    match Self::route_segment(expose, target, sources, visitor, mapper).await? {
1401                        ExposeSegment::Done(r) => return Ok(r),
1402                        ExposeSegment::Next(e, t) => {
1403                            expose_bundle = *e;
1404                            target = t;
1405                        }
1406                    }
1407                }
1408                RouteBundle::Aggregate(_) => {
1409                    return Ok(ExposeResult::ExposeFromAnonymizedAggregate(
1410                        Box::new(expose_bundle),
1411                        target,
1412                    ));
1413                }
1414            }
1415        }
1416    }
1417
1418    async fn route_segment<C, V>(
1419        expose: ExposeDecl,
1420        target: Arc<C>,
1421        sources: &Sources,
1422        visitor: &mut V,
1423        mapper: &mut dyn DebugRouteMapper,
1424    ) -> Result<ExposeSegment<C>, RoutingError>
1425    where
1426        C: ComponentInstanceInterface + 'static,
1427        V: ExposeVisitor,
1428        V: CapabilityVisitor,
1429    {
1430        let res = match expose.source() {
1431            ExposeSource::Void => ExposeSegment::Done(ExposeResult::Source(Box::new(
1432                CapabilitySource::Void(VoidSource {
1433                    capability: InternalCapability::new(
1434                        (&expose).into(),
1435                        expose.source_name().clone(),
1436                    ),
1437                    moniker: target.moniker().clone(),
1438                }),
1439            ))),
1440            ExposeSource::Self_ => {
1441                let target_capabilities = target.lock_resolved_state().await?.capabilities();
1442                ExposeSegment::Done(ExposeResult::Source(Box::new(CapabilitySource::Component(
1443                    ComponentSource {
1444                        capability: sources.find_component_source(
1445                            expose.source_name(),
1446                            target.moniker(),
1447                            &target_capabilities,
1448                            visitor,
1449                            mapper,
1450                        )?,
1451                        moniker: target.moniker().clone(),
1452                    },
1453                ))))
1454            }
1455            ExposeSource::Framework => ExposeSegment::Done(ExposeResult::Source(Box::new(
1456                CapabilitySource::Framework(FrameworkSource {
1457                    capability: sources.framework_source(
1458                        target.moniker(),
1459                        expose.source_name().clone(),
1460                        mapper,
1461                    )?,
1462                    moniker: target.moniker().clone(),
1463                }),
1464            ))),
1465            ExposeSource::Capability(_) => {
1466                sources.capability_source(target.moniker())?;
1467                ExposeSegment::Done(ExposeResult::Source(Box::new(CapabilitySource::Capability(
1468                    CapabilityToCapabilitySource {
1469                        source_capability: ComponentCapability::Expose(expose.into()),
1470                        moniker: target.moniker().clone(),
1471                    },
1472                ))))
1473            }
1474            ExposeSource::Child(child) => {
1475                let child_component = {
1476                    let child_moniker = ChildName::new(child.clone().into(), None);
1477                    target.lock_resolved_state().await?.get_child(&child_moniker).ok_or_else(
1478                        || RoutingError::ExposeFromChildInstanceNotFound {
1479                            child_moniker,
1480                            moniker: target.moniker().clone(),
1481                            capability_id: expose.source_name().clone().into(),
1482                        },
1483                    )?
1484                };
1485                let child_exposes = child_component.lock_resolved_state().await?.exposes();
1486                let child_exposes = find_matching_exposes(
1487                    CapabilityTypeName::from(&expose),
1488                    expose.source_name(),
1489                    &child_exposes,
1490                )
1491                .ok_or_else(|| {
1492                    let child_moniker =
1493                        child_component.child_moniker().expect("ChildName should exist");
1494                    <ExposeDecl as ErrorNotFoundInChild>::error_not_found_in_child(
1495                        target.moniker().clone(),
1496                        child_moniker.into(),
1497                        expose.source_name().clone(),
1498                    )
1499                })?;
1500                ExposeSegment::Next(Box::new(child_exposes), child_component)
1501            }
1502            ExposeSource::Collection(_) => {
1503                ExposeSegment::Done(ExposeResult::ExposeFromAnonymizedAggregate(
1504                    Box::new(RouteBundle::from_expose(expose)),
1505                    target,
1506                ))
1507            }
1508        };
1509        Ok(res)
1510    }
1511}
1512
1513fn target_matches_moniker(target: &OfferTarget, child_moniker: &BorrowedChildName) -> bool {
1514    match target {
1515        OfferTarget::Child(target_ref) => {
1516            &target_ref.name == child_moniker.name()
1517                && target_ref.collection.as_ref().map(Borrow::borrow) == child_moniker.collection()
1518        }
1519        OfferTarget::Collection(target_collection) => {
1520            Some(target_collection.borrow()) == child_moniker.collection()
1521        }
1522        OfferTarget::Capability(_) => false,
1523    }
1524}
1525
1526/// Visitor pattern trait for visiting all [`OfferDecl`] during a route.
1527pub trait OfferVisitor {
1528    fn visit(&mut self, moniker: &ExtendedMoniker, offer: &OfferDecl) -> Result<(), RoutingError>;
1529}
1530
1531/// Visitor pattern trait for visiting all [`ExposeDecl`] during a route.
1532pub trait ExposeVisitor {
1533    /// Visit each [`ExposeDecl`] on the route.
1534    /// Returning an `Err` cancels visitation.
1535    fn visit(&mut self, moniker: &ExtendedMoniker, expose: &ExposeDecl)
1536    -> Result<(), RoutingError>;
1537}
1538
1539/// Visitor pattern trait for visiting all [`CapabilityDecl`] during a route.
1540pub trait CapabilityVisitor {
1541    /// Visit each [`CapabilityDecl`] on the route.
1542    /// Returning an `Err` cancels visitation.
1543    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
1591/// Implemented by declaration types to emit a proper error when a matching offer is not found in the parent.
1592pub trait ErrorNotFoundFromParent {
1593    fn error_not_found_from_parent(
1594        decl_site_moniker: Moniker,
1595        capability_name: Name,
1596    ) -> RoutingError;
1597}
1598
1599/// Implemented by declaration types to emit a proper error when a matching expose is not found in the child.
1600pub 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}