routing/bedrock/
dict_ext.rs1use async_trait::async_trait;
6use capability_source::CapabilitySource;
7use cm_types::{IterablePath, RelativePath};
8use fidl_fuchsia_component_runtime::RouteRequest;
9use router_error::RouterError;
10use runtime_capabilities::{Capability, Dictionary, Routable, Router, WeakInstanceToken};
11use std::sync::Arc;
12
13#[async_trait]
14pub trait DictExt {
15 fn get_capability(&self, path: &impl IterablePath) -> Option<Capability>;
17
18 fn insert_capability(
21 &self,
22 path: &impl IterablePath,
23 capability: Capability,
24 ) -> Option<Capability>;
25
26 fn remove_capability(&self, path: &impl IterablePath) -> Option<Capability>;
28}
29
30#[async_trait]
31impl DictExt for Arc<Dictionary> {
32 fn get_capability(&self, path: &impl IterablePath) -> Option<Capability> {
33 let mut segments = path.iter_segments();
34 let Some(mut current_name) = segments.next() else {
35 return Some(Capability::Dictionary(self.clone()));
36 };
37 let mut current_dict = self.clone();
38 loop {
39 match segments.next() {
40 Some(next_name) => {
41 let sub_dict =
42 current_dict.get(current_name).and_then(|value| value.to_dictionary())?;
43 current_dict = sub_dict;
44
45 current_name = next_name;
46 }
47 None => return current_dict.get(current_name),
48 }
49 }
50 }
51
52 fn insert_capability(
53 &self,
54 path: &impl IterablePath,
55 capability: Capability,
56 ) -> Option<Capability> {
57 let mut segments = path.iter_segments();
58 let mut current_name = segments.next().expect("path must be non-empty");
59 let mut current_dict = self.clone();
60 loop {
61 match segments.next() {
62 Some(next_name) => {
63 let sub_dict = {
64 match current_dict.get(current_name) {
65 Some(Capability::Dictionary(dict)) => dict,
66 Some(Capability::DictionaryRouter(preexisting_router)) => {
67 let mut path = vec![next_name];
68 while let Some(name) = segments.next() {
69 path.push(name);
70 }
71 let path = RelativePath::from(path);
72 let new_router = Router::new(AdditiveDictionaryRouter {
73 preexisting_router,
74 path,
75 capability,
76 });
77
78 return current_dict.insert(current_name.into(), new_router.into());
80 }
81 None => {
82 let dict = Dictionary::new();
83 current_dict.insert(
84 current_name.into(),
85 Capability::Dictionary(dict.clone()),
86 );
87 dict
88 }
89 _ => return None,
90 }
91 };
92 current_dict = sub_dict;
93
94 current_name = next_name;
95 }
96 None => {
97 return current_dict.insert(current_name.into(), capability);
98 }
99 }
100 }
101 }
102
103 fn remove_capability(&self, path: &impl IterablePath) -> Option<Capability> {
104 let mut segments = path.iter_segments();
105 let mut current_name = segments.next().expect("path must be non-empty");
106 let mut current_dict = self.clone();
107 loop {
108 match segments.next() {
109 Some(next_name) => {
110 let sub_dict =
111 current_dict.get(current_name).and_then(|value| value.to_dictionary());
112 if sub_dict.is_none() {
113 return None;
115 }
116 current_dict = sub_dict.unwrap();
117 current_name = next_name;
118 }
119 None => {
120 return current_dict.remove(current_name);
121 }
122 }
123 }
124 }
125}
126
127struct AdditiveDictionaryRouter {
128 preexisting_router: Arc<Router<Dictionary>>,
129 path: RelativePath,
130 capability: Capability,
131}
132
133#[async_trait]
134impl Routable<Dictionary> for AdditiveDictionaryRouter {
135 async fn route(
136 &self,
137 request: RouteRequest,
138 target: Arc<WeakInstanceToken>,
139 ) -> Result<Option<Arc<Dictionary>>, RouterError> {
140 let dictionary = match self.preexisting_router.route(request, target).await {
141 Ok(Some(dictionary)) => dictionary.shallow_copy(),
142 other_response => return other_response,
143 };
144 let _ = dictionary.insert_capability(&self.path, self.capability.clone());
145 Ok(Some(dictionary))
146 }
147
148 async fn route_debug(
149 &self,
150 request: RouteRequest,
151 target: Arc<WeakInstanceToken>,
152 ) -> Result<CapabilitySource, RouterError> {
153 self.preexisting_router.route_debug(request, target).await
154 }
155}