1use crate::{CapabilityBound, WeakInstanceToken};
6use async_trait::async_trait;
7use capability_source::CapabilitySource;
8use cm_rust::{Availability, CapabilityTypeName};
9use cm_types::Name;
10use fidl_fuchsia_component_runtime::RouteRequest;
11use router_error::RouterError;
12use std::fmt;
13use std::sync::Arc;
14
15#[async_trait]
18pub trait Routable<T>: Send + Sync
19where
20 T: CapabilityBound,
21{
22 async fn route(
23 &self,
24 request: RouteRequest,
25 target: Arc<WeakInstanceToken>,
27 ) -> Result<Option<Arc<T>>, RouterError>;
28
29 async fn route_debug(
32 &self,
33 request: RouteRequest,
34 target: Arc<WeakInstanceToken>,
36 ) -> Result<CapabilitySource, RouterError>;
37
38 fn error_info(&self) -> Option<RouterErrorInfo> {
40 None
41 }
42}
43
44#[derive(Clone, Debug, PartialEq, Eq)]
46pub struct RouterErrorInfo {
47 pub capability_type: CapabilityTypeName,
48 pub name: Name,
55 pub availability: Availability,
56}
57
58pub struct Router<T: CapabilityBound> {
66 routable: Box<dyn Routable<T>>,
67}
68
69impl CapabilityBound for Router<crate::Connector> {
70 fn debug_typename() -> &'static str {
71 "ConnectorRouter"
72 }
73
74 #[cfg(target_os = "fuchsia")]
75 fn try_into_directory_entry(
76 self: Arc<Self>,
77 scope: vfs::execution_scope::ExecutionScope,
78 token: Arc<crate::WeakInstanceToken>,
79 ) -> Result<Arc<dyn vfs::directory::entry::DirectoryEntry>, crate::ConversionError> {
80 Ok(self.into_directory_entry(fidl_fuchsia_io::DirentType::Service, scope, token))
81 }
82}
83impl CapabilityBound for Router<crate::Data> {
84 fn debug_typename() -> &'static str {
85 "DataRouter"
86 }
87
88 #[cfg(target_os = "fuchsia")]
89 fn try_into_directory_entry(
90 self: Arc<Self>,
91 scope: vfs::execution_scope::ExecutionScope,
92 token: Arc<crate::WeakInstanceToken>,
93 ) -> Result<Arc<dyn vfs::directory::entry::DirectoryEntry>, crate::ConversionError> {
94 Ok(self.into_directory_entry(fidl_fuchsia_io::DirentType::Service, scope, token))
95 }
96}
97impl CapabilityBound for Router<crate::Dictionary> {
98 fn debug_typename() -> &'static str {
99 "DictionaryRouter"
100 }
101
102 #[cfg(target_os = "fuchsia")]
103 fn try_into_directory_entry(
104 self: Arc<Self>,
105 scope: vfs::execution_scope::ExecutionScope,
106 token: Arc<crate::WeakInstanceToken>,
107 ) -> Result<Arc<dyn vfs::directory::entry::DirectoryEntry>, crate::ConversionError> {
108 Ok(self.into_directory_entry(fidl_fuchsia_io::DirentType::Service, scope, token))
109 }
110}
111
112impl CapabilityBound for Router<crate::DirConnector> {
113 fn debug_typename() -> &'static str {
114 "DirConnectorRouter"
115 }
116
117 #[cfg(target_os = "fuchsia")]
118 fn try_into_directory_entry(
119 self: Arc<Self>,
120 scope: vfs::execution_scope::ExecutionScope,
121 token: Arc<crate::WeakInstanceToken>,
122 ) -> Result<Arc<dyn vfs::directory::entry::DirectoryEntry>, crate::ConversionError> {
123 Ok(self.into_directory_entry(fidl_fuchsia_io::DirentType::Service, scope, token))
124 }
125}
126
127impl<T: CapabilityBound> fmt::Debug for Router<T> {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 f.debug_struct("Router").field("routable", &"[some routable object]").finish()
131 }
132}
133
134#[async_trait]
135impl<T: CapabilityBound> Routable<T> for Router<T> {
136 async fn route(
137 &self,
138 request: RouteRequest,
139 target: Arc<WeakInstanceToken>,
140 ) -> Result<Option<Arc<T>>, RouterError> {
141 Router::route(self, request, target).await
142 }
143
144 async fn route_debug(
145 &self,
146 request: RouteRequest,
147 target: Arc<WeakInstanceToken>,
148 ) -> Result<CapabilitySource, RouterError> {
149 Router::route_debug(self, request, target).await
150 }
151
152 fn error_info(&self) -> Option<RouterErrorInfo> {
153 self.routable.error_info()
154 }
155}
156
157impl<T: CapabilityBound> Router<T> {
158 pub fn new(routable: impl Routable<T> + 'static) -> Arc<Self> {
160 Arc::new(Self { routable: Box::new(routable) })
161 }
162
163 pub fn new_error(error: impl Into<RouterError>) -> Arc<Self> {
165 let v: RouterError = error.into();
166 Self::new(ErrRouter { v })
167 }
168
169 pub fn new_debug(source: CapabilitySource) -> Arc<Self> {
171 Self::new(DebugRouter { source })
172 }
173
174 pub async fn route(
176 &self,
177 request: RouteRequest,
178 target: Arc<WeakInstanceToken>,
179 ) -> Result<Option<Arc<T>>, RouterError> {
180 self.routable.route(request, target).await
181 }
182
183 pub async fn route_debug(
185 &self,
186 request: RouteRequest,
187 target: Arc<WeakInstanceToken>,
188 ) -> Result<CapabilitySource, RouterError> {
189 self.routable.route_debug(request, target).await
190 }
191
192 pub fn error_info(&self) -> Option<RouterErrorInfo> {
194 self.routable.error_info()
195 }
196}
197
198impl<T: CapabilityBound> Router<T> {
199 pub fn new_ok(c: impl Into<Arc<T>>) -> Arc<Self> {
202 let v: Arc<T> = c.into();
203 Self::new(OkRouter { v })
204 }
205}
206
207#[derive(Clone)]
208struct OkRouter<T: CapabilityBound> {
209 v: Arc<T>,
210}
211
212#[async_trait]
213impl<T: CapabilityBound> Routable<T> for OkRouter<T> {
214 async fn route(
215 &self,
216 _request: RouteRequest,
217 _target: Arc<WeakInstanceToken>,
218 ) -> Result<Option<Arc<T>>, RouterError> {
219 Ok(Some(self.v.clone()))
220 }
221
222 async fn route_debug(
223 &self,
224 _request: RouteRequest,
225 _target: Arc<WeakInstanceToken>,
226 ) -> Result<CapabilitySource, RouterError> {
227 panic!("OkRouter does not handle debug routes");
228 }
229}
230
231#[derive(Clone)]
232struct DebugRouter {
233 source: CapabilitySource,
234}
235
236#[async_trait]
237impl<T: CapabilityBound> Routable<T> for DebugRouter {
238 async fn route(
239 &self,
240 _request: RouteRequest,
241 _target: Arc<WeakInstanceToken>,
242 ) -> Result<Option<Arc<T>>, RouterError> {
243 panic!("DebugRouter does not handle non-debug routes");
244 }
245
246 async fn route_debug(
247 &self,
248 _request: RouteRequest,
249 _target: Arc<WeakInstanceToken>,
250 ) -> Result<CapabilitySource, RouterError> {
251 Ok(self.source.clone())
252 }
253}
254
255#[derive(Clone)]
256struct ErrRouter {
257 v: RouterError,
258}
259
260#[async_trait]
261impl<T: CapabilityBound> Routable<T> for ErrRouter {
262 async fn route(
263 &self,
264 _request: RouteRequest,
265 _target: Arc<WeakInstanceToken>,
266 ) -> Result<Option<Arc<T>>, RouterError> {
267 Err(self.v.clone())
268 }
269
270 async fn route_debug(
271 &self,
272 _request: RouteRequest,
273 _target: Arc<WeakInstanceToken>,
274 ) -> Result<CapabilitySource, RouterError> {
275 Err(self.v.clone())
276 }
277}