1use crate::{Capability, CapabilityBound};
6use derivative::Derivative;
7use fidl_fuchsia_component_sandbox as fsandbox;
8use futures::channel::oneshot;
9use std::borrow::Borrow;
10use std::collections::BTreeMap;
11use std::collections::btree_map::Entry;
12use std::sync::{Arc, Mutex, MutexGuard};
13
14#[cfg(target_os = "fuchsia")]
15use fuchsia_async as fasync;
16
17pub type Key = cm_types::Name;
18pub type BorrowedKey = cm_types::BorrowedName;
19
20#[derive(Debug, Clone)]
22pub struct Dict {
23 inner: Arc<Mutex<DictInner>>,
24}
25
26#[derive(Derivative)]
27#[derivative(Debug)]
28pub(crate) struct DictInner {
29 pub(crate) entries: HybridMap,
31
32 #[derivative(Debug = "ignore")]
35 #[allow(dead_code)]
37 pub(crate) not_found: Option<Box<dyn Fn(&str) -> () + 'static + Send + Sync>>,
38
39 #[cfg(target_os = "fuchsia")]
43 #[derivative(Debug = "ignore")]
44 task_group: Option<fasync::TaskGroup>,
45
46 #[derivative(Debug = "ignore")]
48 update_notifiers: UpdateNotifiers,
49}
50
51impl CapabilityBound for Dict {
52 fn debug_typename() -> &'static str {
53 "Dictionary"
54 }
55}
56
57impl Drop for DictInner {
58 fn drop(&mut self) {
59 let entries = std::mem::replace(&mut self.entries, HybridMap::default());
63 for (key, _) in entries.into_iter() {
64 self.update_notifiers.update(EntryUpdate::Remove(&key))
65 }
66 }
67}
68
69#[derive(Debug, Copy, Clone)]
71pub enum EntryUpdate<'a> {
72 Add(&'a BorrowedKey, &'a Capability),
73 Remove(&'a BorrowedKey),
74 Idle,
75}
76
77pub enum UpdateNotifierRetention {
80 Retain,
81 Drop_,
82}
83
84pub type UpdateNotifierFn =
89 Box<dyn for<'a> FnMut(EntryUpdate<'a>) -> UpdateNotifierRetention + Sync + Send>;
90
91impl Default for Dict {
92 fn default() -> Self {
93 Self {
94 inner: Arc::new(Mutex::new(DictInner {
95 entries: HybridMap::default(),
96 not_found: None,
97 #[cfg(target_os = "fuchsia")]
98 task_group: None,
99 update_notifiers: UpdateNotifiers::default(),
100 })),
101 }
102 }
103}
104
105impl Dict {
106 pub fn new() -> Self {
108 Self::default()
109 }
110
111 pub fn new_with_not_found(not_found: impl Fn(&str) -> () + 'static + Send + Sync) -> Self {
114 Self {
115 inner: Arc::new(Mutex::new(DictInner {
116 entries: HybridMap::default(),
117 not_found: Some(Box::new(not_found)),
118 #[cfg(target_os = "fuchsia")]
119 task_group: None,
120 update_notifiers: UpdateNotifiers::default(),
121 })),
122 }
123 }
124
125 pub(crate) fn lock(&self) -> MutexGuard<'_, DictInner> {
126 self.inner.lock().unwrap()
127 }
128
129 pub fn register_update_notifier(&self, mut notifier_fn: UpdateNotifierFn) {
139 let mut guard = self.lock();
140 for (key, value) in guard.entries.iter() {
141 if let UpdateNotifierRetention::Drop_ = (notifier_fn)(EntryUpdate::Add(key, value)) {
142 return;
144 }
145 }
146 if let UpdateNotifierRetention::Retain = (notifier_fn)(EntryUpdate::Idle) {
147 guard.update_notifiers.0.push(notifier_fn);
148 }
149 }
150
151 pub async fn follow_updates_from(&self, other_dict: Dict) -> Option<Key> {
158 let self_clone = self.clone();
159 let (sender, receiver) = oneshot::channel();
160 let mut sender = Some(sender);
161 other_dict.register_update_notifier(Box::new(move |entry_update| {
162 match entry_update {
163 EntryUpdate::Add(key, capability) => {
164 if let Some(_preexisting_value) = self_clone.get(key).ok().flatten() {
165 if let Some(sender) = sender.take() {
168 let _ = sender.send(Some(key.into()));
169 } else {
170 log::warn!("unable to add {key} to dictionary because the dictionary already contains an item with the same name");
171 }
172 } else {
173 let _ = self_clone.insert(key.into(), capability.try_clone().unwrap());
174 }
175 }
176 EntryUpdate::Remove(key) => {
177 let _ = self_clone.remove(key);
178 }
179 EntryUpdate::Idle => {
180 if let Some(sender) = sender.take() {
181 let _ = sender.send(None);
182 }
183 }
184 }
185 UpdateNotifierRetention::Retain
186 }));
187
188 receiver.await.expect("sender was dropped unexpectedly")
189 }
190
191 pub fn insert(
194 &self,
195 key: Key,
196 capability: Capability,
197 ) -> Result<(), fsandbox::CapabilityStoreError> {
198 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
199 entries.insert(key, capability, update_notifiers)
200 }
201
202 pub fn append(&self, other: &Dict) -> Result<(), ()> {
203 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
204 let other = other.lock();
205 entries.append(&other.entries, update_notifiers)
206 }
207
208 pub fn get<Q: ?Sized>(&self, key: &Q) -> Result<Option<Capability>, ()>
213 where
214 Key: Borrow<Q> + Ord,
215 Q: Ord,
216 {
217 self.lock().entries.get(key)
218 }
219
220 pub fn get_or_insert(
225 &self,
226 key: &Key,
227 default: impl FnOnce() -> Capability,
228 ) -> Result<Capability, ()> {
229 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
230 match entries.get(key)? {
231 Some(v) => Ok(v),
232 None => {
233 let v = (default)();
234 entries.insert(key.clone(), v.try_clone()?, update_notifiers).unwrap();
235 Ok(v)
236 }
237 }
238 }
239
240 pub fn remove(&self, key: &BorrowedKey) -> Option<Capability> {
243 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
244 entries.remove(key, update_notifiers)
245 }
246
247 pub fn enumerate(&self) -> impl Iterator<Item = (Key, Result<Capability, ()>)> + use<> {
251 self.lock()
252 .entries
253 .iter()
254 .map(|(k, v)| (k.clone(), v.try_clone()))
255 .collect::<Vec<_>>()
256 .into_iter()
257 }
258
259 pub fn keys(&self) -> impl Iterator<Item = Key> + use<> {
261 self.lock().entries.iter().map(|(k, _)| k.clone()).collect::<Vec<_>>().into_iter()
262 }
263
264 pub fn drain(&self) -> impl Iterator<Item = (Key, Capability)> + use<> {
266 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
267 let entries = std::mem::replace(entries, HybridMap::default());
268 for (key, _) in entries.iter() {
269 update_notifiers.update(EntryUpdate::Remove(&key))
270 }
271 entries.into_iter()
272 }
273
274 pub fn shallow_copy(&self) -> Result<Self, ()> {
281 let copy = Self::new();
282 {
283 let DictInner { entries, .. } = &*self.lock();
284 let mut copy = copy.lock();
285 copy.entries = entries.shallow_copy()?;
286 }
287 Ok(copy)
288 }
289
290 #[allow(dead_code)]
293 pub(crate) fn not_found(&self, entry: &str) {
294 if let Some(not_found_handler) = &self.lock().not_found {
295 not_found_handler(entry);
296 }
297 }
298}
299
300impl DictInner {
301 #[cfg(target_os = "fuchsia")]
302 pub(crate) fn tasks(&mut self) -> &mut fasync::TaskGroup {
303 self.task_group.get_or_insert_with(|| fasync::TaskGroup::new())
304 }
305}
306
307pub(crate) const HYBRID_SWITCH_INSERTION_LEN: usize = 11;
308pub(crate) const HYBRID_SWITCH_REMOVAL_LEN: usize = 5;
309
310#[derive(Debug)]
324pub(crate) enum HybridMap {
325 Vec(Vec<(Key, Capability)>),
326 Map(BTreeMap<Key, Capability>),
327}
328
329impl Default for HybridMap {
330 fn default() -> Self {
331 Self::Vec(Vec::default())
332 }
333}
334
335impl HybridMap {
336 pub fn get<Q: ?Sized>(&self, key: &Q) -> Result<Option<Capability>, ()>
337 where
338 Key: Borrow<Q> + Ord,
339 Q: Ord,
340 {
341 match self {
342 Self::Vec(vec) => match Self::sorted_vec_index_of(vec, key) {
343 Ok(index) => Ok(Some(vec[index].1.try_clone()?)),
344 Err(_) => Ok(None),
345 },
346 Self::Map(map) => match map.get(key) {
347 Some(capability) => Ok(Some(capability.try_clone()?)),
348 None => Ok(None),
349 },
350 }
351 }
352
353 pub fn insert(
354 &mut self,
355 key: Key,
356 capability: Capability,
357 update_notifiers: &mut UpdateNotifiers,
358 ) -> Result<(), fsandbox::CapabilityStoreError> {
359 match self {
360 Self::Vec(vec) => match Self::sorted_vec_index_of(vec, &key) {
361 Ok(index) => {
362 update_notifiers.update(EntryUpdate::Remove(&key));
363 update_notifiers.update(EntryUpdate::Add(&key, &capability));
364 vec[index].1 = capability;
365 Err(fsandbox::CapabilityStoreError::ItemAlreadyExists)
366 }
367 Err(index) => {
368 update_notifiers.update(EntryUpdate::Add(&key, &capability));
369 if vec.len() + 1 >= HYBRID_SWITCH_INSERTION_LEN {
370 self.switch_to_map();
371 let Self::Map(map) = self else { unreachable!() };
372 map.insert(key, capability);
373 Ok(())
374 } else {
375 vec.reserve_exact(1);
376 vec.insert(index, (key, capability));
377 Ok(())
378 }
379 }
380 },
381 Self::Map(map) => match map.entry(key.clone()) {
382 Entry::Occupied(mut occupied) => {
383 update_notifiers.update(EntryUpdate::Remove(&key));
384 update_notifiers.update(EntryUpdate::Add(&key, &capability));
385 occupied.insert(capability);
386 Err(fsandbox::CapabilityStoreError::ItemAlreadyExists)
387 }
388 Entry::Vacant(vacant) => {
389 update_notifiers.update(EntryUpdate::Add(&key, &capability));
390 vacant.insert(capability);
391 Ok(())
392 }
393 },
394 }
395 }
396
397 pub fn remove(
398 &mut self,
399 key: &BorrowedKey,
400 update_notifiers: &mut UpdateNotifiers,
401 ) -> Option<Capability> {
402 let result = match self {
403 Self::Vec(vec) => match Self::sorted_vec_index_of(vec, key) {
404 Ok(index) => {
405 update_notifiers.update(EntryUpdate::Remove(key));
406 Some(vec.remove(index).1)
407 }
408 Err(_) => None,
409 },
410 Self::Map(map) => {
411 let result = map.remove(key);
412 if result.is_some() {
413 update_notifiers.update(EntryUpdate::Remove(key));
414 if self.len() <= HYBRID_SWITCH_REMOVAL_LEN {
415 self.switch_to_vec();
416 }
417 }
418 result
419 }
420 };
421 result
422 }
423
424 pub fn append(
425 &mut self,
426 other: &Self,
427 update_notifiers: &mut UpdateNotifiers,
428 ) -> Result<(), ()> {
429 if other.is_empty() {
430 return Ok(());
432 }
433
434 let to_insert: Result<Vec<_>, _> =
436 other.iter().map(|(k, v)| v.try_clone().map(|v| (k.clone(), v))).collect();
437 let to_insert = to_insert?;
438 for (k, _) in &to_insert {
439 let contains_key = match self {
440 Self::Vec(vec) => matches!(Self::sorted_vec_index_of(vec, k), Ok(_)),
441 Self::Map(map) => map.contains_key(k),
442 };
443 if contains_key {
444 return Err(());
445 }
446 }
447
448 if self.len() + other.len() >= HYBRID_SWITCH_INSERTION_LEN {
449 self.switch_to_map();
451 } else if let Self::Vec(vec) = self {
452 vec.reserve(other.len());
455 }
456 for (k, v) in to_insert {
457 self.insert(k, v, update_notifiers).expect("append: insert should have succeeded");
458 }
459 Ok(())
460 }
461
462 pub fn shallow_copy(&self) -> Result<Self, ()> {
463 match self {
464 Self::Vec(vec) => {
465 let mut new_vec = Vec::with_capacity(vec.len());
466 for (key, value) in vec.iter() {
467 new_vec.push((key.clone(), value.try_clone()?));
468 }
469 Ok(HybridMap::Vec(new_vec))
470 }
471 Self::Map(map) => {
472 let mut new_map = BTreeMap::new();
473 for (key, value) in map.iter() {
474 new_map.insert(key.clone(), value.try_clone()?);
475 }
476 Ok(HybridMap::Map(new_map))
477 }
478 }
479 }
480
481 pub fn len(&self) -> usize {
482 match self {
483 Self::Map(map) => map.len(),
484 Self::Vec(vec) => vec.len(),
485 }
486 }
487
488 pub fn is_empty(&self) -> bool {
489 match self {
490 Self::Map(map) => map.is_empty(),
491 Self::Vec(vec) => vec.is_empty(),
492 }
493 }
494
495 pub fn iter(&self) -> impl Iterator<Item = (&Key, &Capability)> {
496 match self {
497 Self::Vec(vec) => itertools::Either::Left(vec.iter().map(|kv| (&kv.0, &kv.1))),
498 Self::Map(map) => itertools::Either::Right(map.iter()),
499 }
500 }
501
502 pub fn into_iter(self) -> impl Iterator<Item = (Key, Capability)> {
503 match self {
504 Self::Vec(vec) => itertools::Either::Left(vec.into_iter()),
505 Self::Map(map) => itertools::Either::Right(map.into_iter()),
506 }
507 }
508
509 fn switch_to_map(&mut self) {
510 match self {
511 Self::Map(_) => {}
512 Self::Vec(vec) => {
513 let vec = std::mem::replace(vec, Vec::new());
514 let map = BTreeMap::from_iter(vec.into_iter());
515 *self = Self::Map(map);
516 }
517 }
518 }
519
520 fn switch_to_vec(&mut self) {
521 match self {
522 Self::Vec(_) => {}
523 Self::Map(map) => {
524 let map = std::mem::replace(map, Default::default());
525 let vec = Vec::from_iter(map.into_iter());
526 *self = Self::Vec(vec);
527 }
528 }
529 }
530
531 #[inline]
532 fn sorted_vec_index_of<Q: ?Sized>(vec: &Vec<(Key, Capability)>, key: &Q) -> Result<usize, usize>
533 where
534 Key: Borrow<Q> + Ord,
535 Q: Ord,
536 {
537 vec.binary_search_by(|probe| probe.0.borrow().cmp(&key))
538 }
539}
540
541#[derive(Default)]
542pub(crate) struct UpdateNotifiers(Vec<UpdateNotifierFn>);
543
544impl UpdateNotifiers {
545 fn update<'a>(&'a mut self, update: EntryUpdate<'a>) {
546 self.0.retain_mut(|notifier_fn| match (notifier_fn)(update) {
547 UpdateNotifierRetention::Retain => true,
548 UpdateNotifierRetention::Drop_ => false,
549 });
550 }
551}
552
553