1use crate::{CapabilityBound, WeakInstanceToken};
6use async_trait::async_trait;
7use capability_source::CapabilitySource;
8use fidl_fuchsia_component_runtime::RouteRequest;
9use router_error::RouterError;
10use std::fmt;
11use std::sync::Arc;
12
13#[async_trait]
16pub trait Routable<T>: Send + Sync
17where
18 T: CapabilityBound,
19{
20 async fn route(
21 &self,
22 request: RouteRequest,
23 target: Arc<WeakInstanceToken>,
25 ) -> Result<Option<Arc<T>>, RouterError>;
26
27 async fn route_debug(
30 &self,
31 request: RouteRequest,
32 target: Arc<WeakInstanceToken>,
34 ) -> Result<CapabilitySource, RouterError>;
35}
36
37pub struct Router<T: CapabilityBound> {
45 routable: Box<dyn Routable<T>>,
46}
47
48impl CapabilityBound for Router<crate::Connector> {
49 fn debug_typename() -> &'static str {
50 "ConnectorRouter"
51 }
52
53 #[cfg(target_os = "fuchsia")]
54 fn try_into_directory_entry(
55 self: Arc<Self>,
56 scope: vfs::execution_scope::ExecutionScope,
57 token: Arc<crate::WeakInstanceToken>,
58 ) -> Result<Arc<dyn vfs::directory::entry::DirectoryEntry>, crate::ConversionError> {
59 Ok(self.into_directory_entry(fidl_fuchsia_io::DirentType::Service, scope, token))
60 }
61}
62impl CapabilityBound for Router<crate::Data> {
63 fn debug_typename() -> &'static str {
64 "DataRouter"
65 }
66
67 #[cfg(target_os = "fuchsia")]
68 fn try_into_directory_entry(
69 self: Arc<Self>,
70 scope: vfs::execution_scope::ExecutionScope,
71 token: Arc<crate::WeakInstanceToken>,
72 ) -> Result<Arc<dyn vfs::directory::entry::DirectoryEntry>, crate::ConversionError> {
73 Ok(self.into_directory_entry(fidl_fuchsia_io::DirentType::Service, scope, token))
74 }
75}
76impl CapabilityBound for Router<crate::Dictionary> {
77 fn debug_typename() -> &'static str {
78 "DictionaryRouter"
79 }
80
81 #[cfg(target_os = "fuchsia")]
82 fn try_into_directory_entry(
83 self: Arc<Self>,
84 scope: vfs::execution_scope::ExecutionScope,
85 token: Arc<crate::WeakInstanceToken>,
86 ) -> Result<Arc<dyn vfs::directory::entry::DirectoryEntry>, crate::ConversionError> {
87 Ok(self.into_directory_entry(fidl_fuchsia_io::DirentType::Service, scope, token))
88 }
89}
90
91impl CapabilityBound for Router<crate::DirConnector> {
92 fn debug_typename() -> &'static str {
93 "DirConnectorRouter"
94 }
95
96 #[cfg(target_os = "fuchsia")]
97 fn try_into_directory_entry(
98 self: Arc<Self>,
99 scope: vfs::execution_scope::ExecutionScope,
100 token: Arc<crate::WeakInstanceToken>,
101 ) -> Result<Arc<dyn vfs::directory::entry::DirectoryEntry>, crate::ConversionError> {
102 Ok(self.into_directory_entry(fidl_fuchsia_io::DirentType::Service, scope, token))
103 }
104}
105
106impl<T: CapabilityBound> fmt::Debug for Router<T> {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 f.debug_struct("Router").field("routable", &"[some routable object]").finish()
110 }
111}
112
113#[async_trait]
114impl<T: CapabilityBound> Routable<T> for Router<T> {
115 async fn route(
116 &self,
117 request: RouteRequest,
118 target: Arc<WeakInstanceToken>,
119 ) -> Result<Option<Arc<T>>, RouterError> {
120 Router::route(self, request, target).await
121 }
122
123 async fn route_debug(
124 &self,
125 request: RouteRequest,
126 target: Arc<WeakInstanceToken>,
127 ) -> Result<CapabilitySource, RouterError> {
128 Router::route_debug(self, request, target).await
129 }
130}
131
132impl<T: CapabilityBound> Router<T> {
133 pub fn new(routable: impl Routable<T> + 'static) -> Arc<Self> {
135 Arc::new(Self { routable: Box::new(routable) })
136 }
137
138 pub fn new_error(error: impl Into<RouterError>) -> Arc<Self> {
140 let v: RouterError = error.into();
141 Self::new(ErrRouter { v })
142 }
143
144 pub fn new_debug(source: CapabilitySource) -> Arc<Self> {
146 Self::new(DebugRouter { source })
147 }
148
149 pub async fn route(
151 &self,
152 request: RouteRequest,
153 target: Arc<WeakInstanceToken>,
154 ) -> Result<Option<Arc<T>>, RouterError> {
155 self.routable.route(request, target).await
156 }
157
158 pub async fn route_debug(
160 &self,
161 request: RouteRequest,
162 target: Arc<WeakInstanceToken>,
163 ) -> Result<CapabilitySource, RouterError> {
164 self.routable.route_debug(request, target).await
165 }
166}
167
168impl<T: CapabilityBound> Router<T> {
169 pub fn new_ok(c: impl Into<Arc<T>>) -> Arc<Self> {
172 let v: Arc<T> = c.into();
173 Self::new(OkRouter { v })
174 }
175}
176
177#[derive(Clone)]
178struct OkRouter<T: CapabilityBound> {
179 v: Arc<T>,
180}
181
182#[async_trait]
183impl<T: CapabilityBound> Routable<T> for OkRouter<T> {
184 async fn route(
185 &self,
186 _request: RouteRequest,
187 _target: Arc<WeakInstanceToken>,
188 ) -> Result<Option<Arc<T>>, RouterError> {
189 Ok(Some(self.v.clone()))
190 }
191
192 async fn route_debug(
193 &self,
194 _request: RouteRequest,
195 _target: Arc<WeakInstanceToken>,
196 ) -> Result<CapabilitySource, RouterError> {
197 panic!("OkRouter does not handle debug routes");
198 }
199}
200
201#[derive(Clone)]
202struct DebugRouter {
203 source: CapabilitySource,
204}
205
206#[async_trait]
207impl<T: CapabilityBound> Routable<T> for DebugRouter {
208 async fn route(
209 &self,
210 _request: RouteRequest,
211 _target: Arc<WeakInstanceToken>,
212 ) -> Result<Option<Arc<T>>, RouterError> {
213 panic!("DebugRouter does not handle non-debug routes");
214 }
215
216 async fn route_debug(
217 &self,
218 _request: RouteRequest,
219 _target: Arc<WeakInstanceToken>,
220 ) -> Result<CapabilitySource, RouterError> {
221 Ok(self.source.clone())
222 }
223}
224
225#[derive(Clone)]
226struct ErrRouter {
227 v: RouterError,
228}
229
230#[async_trait]
231impl<T: CapabilityBound> Routable<T> for ErrRouter {
232 async fn route(
233 &self,
234 _request: RouteRequest,
235 _target: Arc<WeakInstanceToken>,
236 ) -> Result<Option<Arc<T>>, RouterError> {
237 Err(self.v.clone())
238 }
239
240 async fn route_debug(
241 &self,
242 _request: RouteRequest,
243 _target: Arc<WeakInstanceToken>,
244 ) -> Result<CapabilitySource, RouterError> {
245 Err(self.v.clone())
246 }
247}