routing/bedrock/
structured_dict.rs1use crate::DictExt;
6use cm_types::{BorrowedName, IterablePath, Name};
7use fidl_fuchsia_component_sandbox as fsandbox;
8use lazy_static::lazy_static;
9use sandbox::{Capability, Dict};
10use std::fmt;
11use std::marker::PhantomData;
12
13trait StructuredDict: Into<Dict> + Default + Clone + fmt::Debug {
20 fn from_dict(dict: Dict) -> Self;
27}
28
29#[derive(Clone, Debug, Default)]
38#[allow(private_bounds)]
39pub struct StructuredDictMap<T: StructuredDict> {
40 inner: Dict,
41 phantom: PhantomData<T>,
42}
43
44impl<T: StructuredDict> StructuredDict for StructuredDictMap<T> {
45 fn from_dict(dict: Dict) -> Self {
46 Self { inner: dict, phantom: Default::default() }
47 }
48}
49
50#[allow(private_bounds)]
51impl<T: StructuredDict> StructuredDictMap<T> {
52 pub fn insert(&self, key: Name, value: T) -> Result<(), fsandbox::CapabilityStoreError> {
53 let dict: Dict = value.into();
54 self.inner.insert(key, dict.into())
55 }
56
57 pub fn get(&self, key: &BorrowedName) -> Option<T> {
58 self.inner.get(key).expect("structured map entry must be cloneable").map(|cap| {
59 let Capability::Dictionary(dict) = cap else {
60 unreachable!("structured map entry must be a dict: {cap:?}");
61 };
62 T::from_dict(dict)
63 })
64 }
65
66 pub fn remove(&self, key: &Name) -> Option<T> {
67 self.inner.remove(&*key).map(|cap| {
68 let Capability::Dictionary(dict) = cap else {
69 unreachable!("structured map entry must be a dict: {cap:?}");
70 };
71 T::from_dict(dict)
72 })
73 }
74
75 pub fn append(&self, other: &Self) -> Result<(), ()> {
76 self.inner.append(&other.inner)
77 }
78
79 pub fn enumerate(&self) -> impl Iterator<Item = (Name, T)> {
80 self.inner.enumerate().map(|(key, capability_res)| match capability_res {
81 Ok(Capability::Dictionary(dict)) => (key, T::from_dict(dict)),
82 Ok(cap) => unreachable!("structured map entry must be a dict: {cap:?}"),
83 Err(_) => panic!("structured map entry must be cloneable"),
84 })
85 }
86}
87
88impl<T: StructuredDict> From<StructuredDictMap<T>> for Dict {
89 fn from(m: StructuredDictMap<T>) -> Self {
90 m.inner
91 }
92}
93
94lazy_static! {
96 static ref PARENT: Name = "parent".parse().unwrap();
98
99 static ref ENVIRONMENT: Name = "environment".parse().unwrap();
101
102 static ref DEBUG: Name = "debug".parse().unwrap();
104
105 static ref RUNNERS: Name = "runners".parse().unwrap();
107
108 static ref RESOLVERS: Name = "resolvers".parse().unwrap();
110
111 static ref FRAMEWORK: Name = "framework".parse().unwrap();
113}
114
115#[derive(Clone, Debug)]
118pub struct ComponentInput(Dict);
119
120impl Default for ComponentInput {
121 fn default() -> Self {
122 Self::new(ComponentEnvironment::new())
123 }
124}
125
126impl StructuredDict for ComponentInput {
127 fn from_dict(dict: Dict) -> Self {
128 Self(dict)
129 }
130}
131
132impl ComponentInput {
133 pub fn new(environment: ComponentEnvironment) -> Self {
134 let dict = Dict::new();
135 dict.insert(PARENT.clone(), Dict::new().into()).ok();
136 dict.insert(ENVIRONMENT.clone(), Dict::from(environment).into()).ok();
137 Self(dict)
138 }
139
140 pub fn shallow_copy(&self) -> Result<Self, ()> {
145 let dict = Dict::new();
149 dict.insert(PARENT.clone(), self.capabilities().shallow_copy()?.into()).ok();
150 dict.insert(ENVIRONMENT.clone(), Dict::from(self.environment()).shallow_copy()?.into())
151 .ok();
152 Ok(Self(dict))
153 }
154
155 pub fn capabilities(&self) -> Dict {
157 let cap = self.0.get(&*PARENT).expect("capabilities must be cloneable").unwrap();
158 let Capability::Dictionary(dict) = cap else {
159 unreachable!("parent entry must be a dict: {cap:?}");
160 };
161 dict
162 }
163
164 pub fn environment(&self) -> ComponentEnvironment {
166 let cap = self.0.get(&*ENVIRONMENT).expect("environment must be cloneable").unwrap();
167 let Capability::Dictionary(dict) = cap else {
168 unreachable!("environment entry must be a dict: {cap:?}");
169 };
170 ComponentEnvironment(dict)
171 }
172
173 pub fn insert_capability(
174 &self,
175 path: &impl IterablePath,
176 capability: Capability,
177 ) -> Result<(), fsandbox::CapabilityStoreError> {
178 self.capabilities().insert_capability(path, capability.into())
179 }
180}
181
182impl From<ComponentInput> for Dict {
183 fn from(e: ComponentInput) -> Self {
184 e.0
185 }
186}
187
188#[derive(Clone, Debug)]
191pub struct ComponentEnvironment(Dict);
192
193impl Default for ComponentEnvironment {
194 fn default() -> Self {
195 let dict = Dict::new();
196 dict.insert(DEBUG.clone(), Dict::new().into()).ok();
197 dict.insert(RUNNERS.clone(), Dict::new().into()).ok();
198 dict.insert(RESOLVERS.clone(), Dict::new().into()).ok();
199 Self(dict)
200 }
201}
202
203impl StructuredDict for ComponentEnvironment {
204 fn from_dict(dict: Dict) -> Self {
205 Self(dict)
206 }
207}
208
209impl ComponentEnvironment {
210 pub fn new() -> Self {
211 Self::default()
212 }
213
214 pub fn debug(&self) -> Dict {
216 let cap = self.0.get(&*DEBUG).expect("debug must be cloneable").unwrap();
217 let Capability::Dictionary(dict) = cap else {
218 unreachable!("debug entry must be a dict: {cap:?}");
219 };
220 dict
221 }
222
223 pub fn runners(&self) -> Dict {
225 let cap = self.0.get(&*RUNNERS).expect("runners must be cloneable").unwrap();
226 let Capability::Dictionary(dict) = cap else {
227 unreachable!("runners entry must be a dict: {cap:?}");
228 };
229 dict
230 }
231
232 pub fn resolvers(&self) -> Dict {
234 let cap = self.0.get(&*RESOLVERS).expect("resolvers must be cloneable").unwrap();
235 let Capability::Dictionary(dict) = cap else {
236 unreachable!("resolvers entry must be a dict: {cap:?}");
237 };
238 dict
239 }
240
241 pub fn shallow_copy(&self) -> Result<Self, ()> {
242 let dict = Dict::new();
246 dict.insert(DEBUG.clone(), self.debug().shallow_copy()?.into()).ok();
247 dict.insert(RUNNERS.clone(), self.runners().shallow_copy()?.into()).ok();
248 dict.insert(RESOLVERS.clone(), self.resolvers().shallow_copy()?.into()).ok();
249 Ok(Self(dict))
250 }
251}
252
253impl From<ComponentEnvironment> for Dict {
254 fn from(e: ComponentEnvironment) -> Self {
255 e.0
256 }
257}
258
259#[derive(Clone, Debug)]
263pub struct ComponentOutput(Dict);
264
265impl Default for ComponentOutput {
266 fn default() -> Self {
267 Self::new()
268 }
269}
270
271impl StructuredDict for ComponentOutput {
272 fn from_dict(dict: Dict) -> Self {
273 Self(dict)
274 }
275}
276
277impl ComponentOutput {
278 pub fn new() -> Self {
279 let dict = Dict::new();
280 dict.insert(PARENT.clone(), Dict::new().into()).ok();
281 dict.insert(FRAMEWORK.clone(), Dict::new().into()).ok();
282 Self(dict)
283 }
284
285 pub fn shallow_copy(&self) -> Result<Self, ()> {
290 let dict = Dict::new();
294 dict.insert(PARENT.clone(), self.capabilities().shallow_copy()?.into()).ok();
295 dict.insert(FRAMEWORK.clone(), self.framework().shallow_copy()?.into()).ok();
296 Ok(Self(dict))
297 }
298
299 pub fn capabilities(&self) -> Dict {
301 let cap = self.0.get(&*PARENT).expect("capabilities must be cloneable").unwrap();
302 let Capability::Dictionary(dict) = cap else {
303 unreachable!("parent entry must be a dict: {cap:?}");
304 };
305 dict
306 }
307
308 pub fn framework(&self) -> Dict {
310 let cap = self.0.get(&*FRAMEWORK).expect("capabilities must be cloneable").unwrap();
311 let Capability::Dictionary(dict) = cap else {
312 unreachable!("framework entry must be a dict: {cap:?}");
313 };
314 dict
315 }
316}
317
318impl From<ComponentOutput> for Dict {
319 fn from(e: ComponentOutput) -> Self {
320 e.0
321 }
322}
323
324#[cfg(test)]
325mod tests {
326 use super::*;
327 use assert_matches::assert_matches;
328 use sandbox::DictKey;
329
330 impl StructuredDict for Dict {
331 fn from_dict(dict: Dict) -> Self {
332 dict
333 }
334 }
335
336 #[fuchsia::test]
337 async fn structured_dict_map() {
338 let dict1 = {
339 let dict = Dict::new();
340 dict.insert("a".parse().unwrap(), Dict::new().into())
341 .expect("dict entry already exists");
342 dict
343 };
344 let dict2 = {
345 let dict = Dict::new();
346 dict.insert("b".parse().unwrap(), Dict::new().into())
347 .expect("dict entry already exists");
348 dict
349 };
350 let dict2_alt = {
351 let dict = Dict::new();
352 dict.insert("c".parse().unwrap(), Dict::new().into())
353 .expect("dict entry already exists");
354 dict
355 };
356 let name1 = Name::new("1").unwrap();
357 let name2 = Name::new("2").unwrap();
358
359 let map: StructuredDictMap<Dict> = Default::default();
360 assert_matches!(map.get(&name1), None);
361 assert!(map.insert(name1.clone(), dict1).is_ok());
362 let d = map.get(&name1).unwrap();
363 let key = DictKey::new("a").unwrap();
364 assert_matches!(d.get(&key), Ok(Some(_)));
365
366 assert!(map.insert(name2.clone(), dict2).is_ok());
367 let d = map.remove(&name2).unwrap();
368 assert_matches!(map.remove(&name2), None);
369 let key = DictKey::new("b").unwrap();
370 assert_matches!(d.get(&key), Ok(Some(_)));
371
372 assert!(map.insert(name2.clone(), dict2_alt).is_ok());
373 let d = map.get(&name2).unwrap();
374 let key = DictKey::new("c").unwrap();
375 assert_matches!(d.get(&key), Ok(Some(_)));
376 }
377}