routing/bedrock/
lazy_get.rs1use crate::bedrock::dict_ext::request_with_dictionary_replacement;
6use crate::{DictExt, RoutingError};
7use async_trait::async_trait;
8use capability_source::CapabilitySource;
9use cm_types::IterablePath;
10use fidl_fuchsia_component_runtime::RouteRequest;
11use moniker::ExtendedMoniker;
12use router_error::RouterError;
13use runtime_capabilities::{CapabilityBound, Dictionary, Routable, Router, WeakInstanceToken};
14use std::fmt::Debug;
15
16pub trait LazyGet<T: CapabilityBound>: Routable<Dictionary> {
18 fn lazy_get<P>(self, path: P, not_found_error: RoutingError) -> Router<T>
22 where
23 P: IterablePath + Debug + 'static;
24}
25
26impl<R: Routable<Dictionary> + 'static, T: CapabilityBound> LazyGet<T> for R {
27 fn lazy_get<P>(self, path: P, not_found_error: RoutingError) -> Router<T>
28 where
29 P: IterablePath + Debug + 'static,
30 {
31 #[derive(Debug)]
32 struct ScopedDictRouter<P: IterablePath + Debug + 'static> {
33 router: Router<Dictionary>,
34 path: P,
35 not_found_error: RoutingError,
36 }
37
38 #[async_trait]
39 impl<P: IterablePath + Debug + 'static, T: CapabilityBound> Routable<T> for ScopedDictRouter<P> {
40 async fn route(
41 &self,
42 request: RouteRequest,
43 target: WeakInstanceToken,
44 ) -> Result<Option<T>, RouterError> {
45 let get_init_request = || request_with_dictionary_replacement(&request);
46
47 let init_request = (get_init_request)()?;
48 match self.router.route(init_request, target.clone()).await? {
49 Some(dict) => {
50 let moniker: ExtendedMoniker = self.not_found_error.clone().into();
51 match dict.get_with_request(&moniker, &self.path, request, target).await {
52 Err(router_error)
53 if let Ok(RoutingError::BedrockNotPresentInDictionary {
54 ..
55 }) = router_error.clone().try_into() =>
56 {
57 Err(self.not_found_error.clone().into())
58 }
59 Err(e) => Err(e),
60 Ok(None) => Ok(None),
61 Ok(Some(cap)) => {
62 let actual_type_name = cap.debug_typename();
63 let cap = T::try_from(cap).map_err(|_| {
64 RoutingError::BedrockWrongCapabilityType {
65 expected: T::debug_typename().into(),
66 actual: actual_type_name.into(),
67 moniker,
68 }
69 })?;
70 Ok(Some(cap))
71 }
72 }
73 }
74 None => Ok(None),
75 }
76 }
77
78 async fn route_debug(
79 &self,
80 request: RouteRequest,
81 target: WeakInstanceToken,
82 ) -> Result<CapabilitySource, RouterError> {
83 let get_init_request = || request_with_dictionary_replacement(&request);
84
85 let init_request = (get_init_request)()?;
89 match self.router.route(init_request, target.clone()).await? {
90 Some(dict) => {
91 let moniker: ExtendedMoniker = self.not_found_error.clone().into();
92 match dict
93 .get_with_request_debug(&moniker, &self.path, request, target)
94 .await
95 {
96 Err(router_error)
97 if let Ok(RoutingError::BedrockNotPresentInDictionary {
98 ..
99 }) = router_error.clone().try_into() =>
100 {
101 Err(self.not_found_error.clone().into())
102 }
103 other_result => other_result,
104 }
105 }
106 None => {
107 let init_request = (get_init_request)()?;
112 self.router.route_debug(init_request, target).await
113 }
114 }
115 }
116 }
117
118 Router::<T>::new(ScopedDictRouter {
119 router: Router::<Dictionary>::new(self),
120 path,
121 not_found_error: not_found_error.into(),
122 })
123 }
124}