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#[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 { Some(&offers[0]) } else { None }
945                }
946            };
947            if let Some(visit_offer) = visit_offer {
948                mapper.add_offer(target.moniker().clone(), &visit_offer);
949                OfferVisitor::visit(visitor, &target.moniker().clone().into(), &visit_offer)?;
950            }
951
952            fn is_filtered_offer(o: &OfferDecl) -> bool {
953                if let OfferDecl::Service(offer_service) = o {
954                    if let Some(f) = offer_service.source_instance_filter.as_ref() {
955                        if !f.is_empty() {
956                            return true;
957                        }
958                    }
959                    if let Some(f) = offer_service.renamed_instances.as_ref() {
960                        if !f.is_empty() {
961                            return true;
962                        }
963                    }
964                }
965                false
966            }
967
968            // Make sure this isn't coming from a dictionary
969            for o in offer_bundle.iter() {
970                if !o.source_path().dirname.is_dot() {
971                    return Err(RoutingError::DictionariesNotSupported {
972                        moniker: target.moniker().clone(),
973                        cap_type: CapabilityTypeName::from(o),
974                    });
975                }
976            }
977
978            match offer_bundle {
979                RouteBundle::Single(offer) => {
980                    match Self::route_segment(offer, target, sources, visitor, mapper).await? {
981                        OfferSegment::Done(r) => return Ok(r),
982                        OfferSegment::Next(o, t) => {
983                            offer_bundle = o;
984                            target = t;
985                        }
986                    }
987                }
988                RouteBundle::Aggregate(_) => {
989                    if offer_bundle.iter().all(|o| !is_filtered_offer(o)) {
990                        return Ok(OfferResult::OfferFromAnonymizedAggregate(offer_bundle, target));
991                    } else {
992                        return Ok(OfferResult::OfferFromFilteredAggregate(offer_bundle, target));
993                    }
994                }
995            }
996        }
997    }
998
999    async fn route_segment<C, V>(
1000        offer: OfferDecl,
1001        target: Arc<C>,
1002        sources: &Sources,
1003        visitor: &mut V,
1004        mapper: &mut dyn DebugRouteMapper,
1005    ) -> Result<OfferSegment<C>, RoutingError>
1006    where
1007        C: ComponentInstanceInterface + 'static,
1008        V: OfferVisitor,
1009        V: CapabilityVisitor,
1010    {
1011        let res = match offer.source() {
1012            OfferSource::Void => {
1013                OfferSegment::Done(OfferResult::Source(CapabilitySource::Void(VoidSource {
1014                    capability: InternalCapability::new(
1015                        (&offer).into(),
1016                        offer.source_name().clone(),
1017                    ),
1018                    moniker: target.moniker().clone(),
1019                })))
1020            }
1021            OfferSource::Self_ => {
1022                let target_capabilities = target.lock_resolved_state().await?.capabilities();
1023                let capability = sources.find_component_source(
1024                    offer.source_name(),
1025                    target.moniker(),
1026                    &target_capabilities,
1027                    visitor,
1028                    mapper,
1029                )?;
1030                // if offerdecl is for a filtered service return the associated filtered source.
1031                let component = target.as_weak();
1032                let moniker = target.moniker().clone();
1033                let res = match offer.into() {
1034                    OfferDecl::Service(offer_service_decl) => {
1035                        if offer_service_decl.source_instance_filter.is_some()
1036                            || offer_service_decl.renamed_instances.is_some()
1037                        {
1038                            let source_name = offer_service_decl.source_name.clone();
1039                            OfferResult::Source(CapabilitySource::FilteredProvider(
1040                                FilteredProviderSource {
1041                                    capability: AggregateCapability::Service(source_name),
1042                                    moniker,
1043                                    service_capability: capability,
1044                                    offer_service_decl,
1045                                },
1046                            ))
1047                        } else {
1048                            OfferResult::Source(CapabilitySource::Component(ComponentSource {
1049                                capability,
1050                                moniker: component.moniker,
1051                            }))
1052                        }
1053                    }
1054                    _ => OfferResult::Source(CapabilitySource::Component(ComponentSource {
1055                        capability,
1056                        moniker: component.moniker,
1057                    })),
1058                };
1059                OfferSegment::Done(res)
1060            }
1061            OfferSource::Framework => OfferSegment::Done(OfferResult::Source(
1062                CapabilitySource::Framework(FrameworkSource {
1063                    capability: sources.framework_source(
1064                        target.moniker(),
1065                        offer.source_name().clone(),
1066                        mapper,
1067                    )?,
1068                    moniker: target.moniker().clone(),
1069                }),
1070            )),
1071            OfferSource::Capability(_) => {
1072                sources.capability_source(target.moniker())?;
1073                OfferSegment::Done(OfferResult::Source(CapabilitySource::Capability(
1074                    CapabilityToCapabilitySource {
1075                        source_capability: ComponentCapability::Offer(offer.into()),
1076                        moniker: target.moniker().clone(),
1077                    },
1078                )))
1079            }
1080            OfferSource::Parent => {
1081                let parent_component = match target.try_get_parent()? {
1082                    ExtendedInstanceInterface::<C>::AboveRoot(top_instance) => {
1083                        if sources.is_namespace_supported() {
1084                            if let Some(capability) = sources.find_namespace_source(
1085                                ExtendedMoniker::ComponentManager,
1086                                offer.source_name(),
1087                                top_instance.namespace_capabilities(),
1088                                visitor,
1089                                mapper,
1090                            )? {
1091                                return Ok(OfferSegment::Done(OfferResult::Source(
1092                                    CapabilitySource::Namespace(NamespaceSource { capability }),
1093                                )));
1094                            }
1095                        }
1096                        if let Some(capability) = sources.find_builtin_source(
1097                            ExtendedMoniker::ComponentManager,
1098                            offer.source_name(),
1099                            top_instance.builtin_capabilities(),
1100                            visitor,
1101                            mapper,
1102                        )? {
1103                            return Ok(OfferSegment::Done(OfferResult::Source(
1104                                CapabilitySource::Builtin(BuiltinSource { capability }),
1105                            )));
1106                        }
1107                        return Err(RoutingError::offer_from_component_manager_not_found(
1108                            offer.source_name().to_string(),
1109                        ));
1110                    }
1111                    ExtendedInstanceInterface::<C>::Component(component) => component,
1112                };
1113                let child_moniker = target.child_moniker().expect("ChildName should exist");
1114                let parent_offers = parent_component.lock_resolved_state().await?.offers();
1115                let parent_offers = find_matching_offers(
1116                    CapabilityTypeName::from(&offer),
1117                    offer.source_name(),
1118                    &child_moniker,
1119                    &parent_offers,
1120                )
1121                .ok_or_else(|| {
1122                    <OfferDecl as ErrorNotFoundFromParent>::error_not_found_from_parent(
1123                        target.moniker().clone(),
1124                        offer.source_name().clone(),
1125                    )
1126                })?;
1127                OfferSegment::Next(parent_offers, parent_component)
1128            }
1129            OfferSource::Child(_) => OfferSegment::Done(OfferResult::OfferFromChild(offer, target)),
1130            OfferSource::Collection(_) => OfferSegment::Done(
1131                OfferResult::OfferFromAnonymizedAggregate(RouteBundle::from_offer(offer), target),
1132            ),
1133        };
1134        Ok(res)
1135    }
1136}
1137
1138/// Finds the matching Expose declaration for an Offer-from-child, changing the
1139/// direction in which the Component Tree is being navigated (from up to down).
1140async fn change_directions<C>(
1141    offer: OfferDecl,
1142    component: Arc<C>,
1143) -> Result<(RouteBundle<ExposeDecl>, Arc<C>), RoutingError>
1144where
1145    C: ComponentInstanceInterface,
1146{
1147    match offer.source() {
1148        OfferSource::Child(child) => {
1149            let child_component = {
1150                let child_moniker = ChildName::try_new(
1151                    child.name.as_str(),
1152                    child.collection.as_ref().map(|s| s.as_str()),
1153                )
1154                .expect("discovered invalid child name, manifest validation should prevent this");
1155                component.lock_resolved_state().await?.get_child(&child_moniker).ok_or_else(
1156                    || RoutingError::OfferFromChildInstanceNotFound {
1157                        child_moniker,
1158                        moniker: component.moniker().clone(),
1159                        capability_id: offer.source_name().clone().into(),
1160                    },
1161                )?
1162            };
1163            let child_exposes = child_component.lock_resolved_state().await?.exposes();
1164            let child_exposes = find_matching_exposes(
1165                CapabilityTypeName::from(&offer),
1166                offer.source_name(),
1167                &child_exposes,
1168            )
1169            .ok_or_else(|| {
1170                let child_moniker =
1171                    child_component.child_moniker().expect("ChildName should exist");
1172                <OfferDecl as ErrorNotFoundInChild>::error_not_found_in_child(
1173                    component.moniker().clone(),
1174                    child_moniker.into(),
1175                    offer.source_name().clone(),
1176                )
1177            })?;
1178            Ok((child_exposes, child_component.clone()))
1179        }
1180        _ => panic!("change_direction called with offer that does not change direction"),
1181    }
1182}
1183
1184/// The `Expose` phase of routing.
1185#[derive(Debug)]
1186pub struct Expose();
1187
1188#[allow(clippy::large_enum_variant)] // TODO(https://fxbug.dev/401087293)
1189/// The result of routing an Expose declaration to the next phase.
1190enum ExposeResult<C: ComponentInstanceInterface + 'static> {
1191    /// The source of the Expose was found (Framework, Component, etc.).
1192    Source(CapabilitySource),
1193    /// The source of the Expose comes from an aggregation of collections and/or static children
1194    ExposeFromAnonymizedAggregate(RouteBundle<ExposeDecl>, Arc<C>),
1195}
1196
1197/// A bundle of one or more routing declarations to route together, that share the same target_name
1198#[derive(Clone, Debug)]
1199pub enum RouteBundle<T>
1200where
1201    T: Clone + fmt::Debug,
1202{
1203    /// A single route from a unique source.
1204    Single(T),
1205    /// A bundle of routes representing an aggregated capability. This can be a vector of one,
1206    /// e.g. exposing a service from a collection.
1207    Aggregate(Vec<T>),
1208}
1209
1210impl<T> RouteBundle<T>
1211where
1212    T: Clone + fmt::Debug,
1213{
1214    pub fn map<U: Clone + fmt::Debug>(self, mut f: impl FnMut(T) -> U) -> RouteBundle<U> {
1215        match self {
1216            RouteBundle::Single(r) => RouteBundle::Single(f(r)),
1217            RouteBundle::Aggregate(r) => {
1218                RouteBundle::Aggregate(r.into_iter().map(&mut f).collect())
1219            }
1220        }
1221    }
1222
1223    /// Returns an iterator over the values of `OneOrMany<T>`.
1224    pub fn iter(&self) -> RouteBundleIter<'_, T> {
1225        match self {
1226            Self::Single(item) => {
1227                RouteBundleIter { inner_single: Some(item), inner_aggregate: None }
1228            }
1229            Self::Aggregate(items) => {
1230                RouteBundleIter { inner_single: None, inner_aggregate: Some(items.iter()) }
1231            }
1232        }
1233    }
1234
1235    /// Returns the number of routes in this bundle.
1236    pub fn len(&self) -> usize {
1237        match self {
1238            Self::Single(_) => 1,
1239            Self::Aggregate(v) => v.len(),
1240        }
1241    }
1242
1243    /// Creates a `RouteBundle` from of a single offer routing declaration.
1244    pub fn from_offer(input: T) -> Self
1245    where
1246        T: OfferDeclCommon + Clone,
1247    {
1248        Self::from_offers(vec![input])
1249    }
1250
1251    /// Creates a `RouteBundle` from of a list of offer routing declarations.
1252    ///
1253    /// REQUIRES: `input` is nonempty.
1254    /// REQUIRES: All elements of `input` share the same `target_name`.
1255    pub fn from_offers(mut input: Vec<T>) -> Self
1256    where
1257        T: OfferDeclCommon + Clone,
1258    {
1259        match input.len() {
1260            1 => {
1261                let input = input.remove(0);
1262                match input.source() {
1263                    OfferSource::Collection(_) => Self::Aggregate(vec![input]),
1264                    _ => Self::Single(input),
1265                }
1266            }
1267            0 => panic!("empty bundles are not allowed"),
1268            _ => Self::Aggregate(input),
1269        }
1270    }
1271
1272    /// Creates a `RouteBundle` from of a single expose routing declaration.
1273    pub fn from_expose(input: T) -> Self
1274    where
1275        T: ExposeDeclCommon + Clone,
1276    {
1277        Self::from_exposes(vec![input])
1278    }
1279
1280    /// Creates a `RouteBundle` from of a list of expose routing declarations.
1281    ///
1282    /// REQUIRES: `input` is nonempty.
1283    /// REQUIRES: All elements of `input` share the same `target_name`.
1284    pub fn from_exposes(mut input: Vec<T>) -> Self
1285    where
1286        T: ExposeDeclCommon + Clone,
1287    {
1288        match input.len() {
1289            1 => {
1290                let input = input.remove(0);
1291                match input.source() {
1292                    ExposeSource::Collection(_) => Self::Aggregate(vec![input]),
1293                    _ => Self::Single(input),
1294                }
1295            }
1296            0 => panic!("empty bundles are not allowed"),
1297            _ => Self::Aggregate(input),
1298        }
1299    }
1300}
1301
1302impl<T> RouteBundle<T>
1303where
1304    T: ExposeDeclCommon + Clone,
1305{
1306    pub fn availability(&self) -> &Availability {
1307        match self {
1308            Self::Single(e) => e.availability(),
1309            Self::Aggregate(v) => {
1310                assert!(
1311                    v.iter()
1312                        .zip(v.iter().skip(1))
1313                        .all(|(a, b)| a.availability() == b.availability()),
1314                    "CM validation should ensure all aggregated capabilities have the same availability"
1315                );
1316                v[0].availability()
1317            }
1318        }
1319    }
1320}
1321
1322/// Immutable iterator over a `RouteBundle`.
1323/// This `struct` is created by [`RouteBundle::iter`].
1324///
1325/// [`RouteBundle::iter`]: struct.RouteBundle.html#method.iter
1326pub struct RouteBundleIter<'a, T> {
1327    inner_single: Option<&'a T>,
1328    inner_aggregate: Option<slice::Iter<'a, T>>,
1329}
1330
1331impl<'a, T> Iterator for RouteBundleIter<'a, T> {
1332    type Item = &'a T;
1333
1334    fn next(&mut self) -> Option<Self::Item> {
1335        if let Some(item) = self.inner_single.take() {
1336            Some(item)
1337        } else if let Some(iter) = &mut self.inner_aggregate {
1338            iter.next()
1339        } else {
1340            None
1341        }
1342    }
1343
1344    fn size_hint(&self) -> (usize, Option<usize>) {
1345        if let Some(_) = self.inner_single {
1346            (1, Some(1))
1347        } else if let Some(iter) = &self.inner_aggregate {
1348            iter.size_hint()
1349        } else {
1350            (0, Some(0))
1351        }
1352    }
1353}
1354
1355impl<'a, T> ExactSizeIterator for RouteBundleIter<'a, T> {}
1356
1357#[allow(clippy::large_enum_variant)] // TODO(https://fxbug.dev/401087293)
1358enum ExposeSegment<C: ComponentInstanceInterface + 'static> {
1359    Done(ExposeResult<C>),
1360    Next(RouteBundle<ExposeDecl>, Arc<C>),
1361}
1362
1363impl Expose {
1364    /// Routes the capability starting from the `expose` declaration at `target` to a valid source
1365    /// (as defined by `sources`).
1366    async fn route<C, V>(
1367        mut expose_bundle: RouteBundle<ExposeDecl>,
1368        mut target: Arc<C>,
1369        sources: &Sources,
1370        visitor: &mut V,
1371        mapper: &mut dyn DebugRouteMapper,
1372    ) -> Result<ExposeResult<C>, RoutingError>
1373    where
1374        C: ComponentInstanceInterface + 'static,
1375        V: ExposeVisitor,
1376        V: CapabilityVisitor,
1377    {
1378        loop {
1379            let visit_expose = match &expose_bundle {
1380                RouteBundle::Single(expose) => Some(expose),
1381                RouteBundle::Aggregate(exposes) => {
1382                    // TODO(https://fxbug.dev/42124541): Visit routes in all aggregates.
1383                    if exposes.len() == 1 { Some(&exposes[0]) } else { None }
1384                }
1385            };
1386            if let Some(visit_expose) = visit_expose {
1387                mapper.add_expose(target.moniker().clone(), visit_expose.clone().into());
1388                ExposeVisitor::visit(visitor, &target.moniker().clone().into(), &visit_expose)?;
1389            }
1390
1391            // Make sure this isn't coming from a dictionary
1392            for e in expose_bundle.iter() {
1393                if !e.source_path().dirname.is_dot() {
1394                    return Err(RoutingError::DictionariesNotSupported {
1395                        moniker: target.moniker().clone(),
1396                        cap_type: CapabilityTypeName::from(e),
1397                    });
1398                }
1399            }
1400
1401            match expose_bundle {
1402                RouteBundle::Single(expose) => {
1403                    match Self::route_segment(expose, target, sources, visitor, mapper).await? {
1404                        ExposeSegment::Done(r) => return Ok(r),
1405                        ExposeSegment::Next(e, t) => {
1406                            expose_bundle = e;
1407                            target = t;
1408                        }
1409                    }
1410                }
1411                RouteBundle::Aggregate(_) => {
1412                    return Ok(ExposeResult::ExposeFromAnonymizedAggregate(expose_bundle, target));
1413                }
1414            }
1415        }
1416    }
1417
1418    async fn route_segment<C, V>(
1419        expose: ExposeDecl,
1420        target: Arc<C>,
1421        sources: &Sources,
1422        visitor: &mut V,
1423        mapper: &mut dyn DebugRouteMapper,
1424    ) -> Result<ExposeSegment<C>, RoutingError>
1425    where
1426        C: ComponentInstanceInterface + 'static,
1427        V: ExposeVisitor,
1428        V: CapabilityVisitor,
1429    {
1430        let res = match expose.source() {
1431            ExposeSource::Void => {
1432                ExposeSegment::Done(ExposeResult::Source(CapabilitySource::Void(VoidSource {
1433                    capability: InternalCapability::new(
1434                        (&expose).into(),
1435                        expose.source_name().clone(),
1436                    ),
1437                    moniker: target.moniker().clone(),
1438                })))
1439            }
1440            ExposeSource::Self_ => {
1441                let target_capabilities = target.lock_resolved_state().await?.capabilities();
1442                ExposeSegment::Done(ExposeResult::Source(CapabilitySource::Component(
1443                    ComponentSource {
1444                        capability: sources.find_component_source(
1445                            expose.source_name(),
1446                            target.moniker(),
1447                            &target_capabilities,
1448                            visitor,
1449                            mapper,
1450                        )?,
1451                        moniker: target.moniker().clone(),
1452                    },
1453                )))
1454            }
1455            ExposeSource::Framework => ExposeSegment::Done(ExposeResult::Source(
1456                CapabilitySource::Framework(FrameworkSource {
1457                    capability: sources.framework_source(
1458                        target.moniker(),
1459                        expose.source_name().clone(),
1460                        mapper,
1461                    )?,
1462                    moniker: target.moniker().clone(),
1463                }),
1464            )),
1465            ExposeSource::Capability(_) => {
1466                sources.capability_source(target.moniker())?;
1467                ExposeSegment::Done(ExposeResult::Source(CapabilitySource::Capability(
1468                    CapabilityToCapabilitySource {
1469                        source_capability: ComponentCapability::Expose(expose.into()),
1470                        moniker: target.moniker().clone(),
1471                    },
1472                )))
1473            }
1474            ExposeSource::Child(child) => {
1475                let child_component = {
1476                    let child_moniker = ChildName::new(child.clone().into(), None);
1477                    target.lock_resolved_state().await?.get_child(&child_moniker).ok_or_else(
1478                        || RoutingError::ExposeFromChildInstanceNotFound {
1479                            child_moniker,
1480                            moniker: target.moniker().clone(),
1481                            capability_id: expose.source_name().clone().into(),
1482                        },
1483                    )?
1484                };
1485                let child_exposes = child_component.lock_resolved_state().await?.exposes();
1486                let child_exposes = find_matching_exposes(
1487                    CapabilityTypeName::from(&expose),
1488                    expose.source_name(),
1489                    &child_exposes,
1490                )
1491                .ok_or_else(|| {
1492                    let child_moniker =
1493                        child_component.child_moniker().expect("ChildName should exist");
1494                    <ExposeDecl as ErrorNotFoundInChild>::error_not_found_in_child(
1495                        target.moniker().clone(),
1496                        child_moniker.into(),
1497                        expose.source_name().clone(),
1498                    )
1499                })?;
1500                ExposeSegment::Next(child_exposes, child_component)
1501            }
1502            ExposeSource::Collection(_) => {
1503                ExposeSegment::Done(ExposeResult::ExposeFromAnonymizedAggregate(
1504                    RouteBundle::from_expose(expose),
1505                    target,
1506                ))
1507            }
1508        };
1509        Ok(res)
1510    }
1511}
1512
1513fn target_matches_moniker(target: &OfferTarget, child_moniker: &BorrowedChildName) -> bool {
1514    match target {
1515        OfferTarget::Child(target_ref) => {
1516            &target_ref.name == child_moniker.name()
1517                && target_ref.collection.as_ref().map(Borrow::borrow) == child_moniker.collection()
1518        }
1519        OfferTarget::Collection(target_collection) => {
1520            Some(target_collection.borrow()) == child_moniker.collection()
1521        }
1522        OfferTarget::Capability(_) => false,
1523    }
1524}
1525
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}