1use crate::{Capability, CapabilityBound};
6use derivative::Derivative;
7use fidl_fuchsia_component_sandbox as fsandbox;
8use fuchsia_sync::{Mutex, MutexGuard};
9use std::borrow::Borrow;
10use std::collections::BTreeMap;
11use std::collections::btree_map::Entry;
12use std::sync::Arc;
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()
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 fn insert(
154 &self,
155 key: Key,
156 capability: Capability,
157 ) -> Result<(), fsandbox::CapabilityStoreError> {
158 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
159 entries.insert(key, capability, update_notifiers)
160 }
161
162 pub fn append(&self, other: &Dict) -> Result<(), ()> {
163 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
164 let other = other.lock();
165 entries.append(&other.entries, update_notifiers)
166 }
167
168 pub fn get<Q: ?Sized>(&self, key: &Q) -> Result<Option<Capability>, ()>
173 where
174 Key: Borrow<Q> + Ord,
175 Q: Ord,
176 {
177 self.lock().entries.get(key)
178 }
179
180 pub fn get_or_insert(
185 &self,
186 key: &Key,
187 default: impl FnOnce() -> Capability,
188 ) -> Result<Capability, ()> {
189 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
190 match entries.get(key)? {
191 Some(v) => Ok(v),
192 None => {
193 let v = (default)();
194 entries.insert(key.clone(), v.try_clone()?, update_notifiers).unwrap();
195 Ok(v)
196 }
197 }
198 }
199
200 pub fn remove(&self, key: &BorrowedKey) -> Option<Capability> {
203 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
204 entries.remove(key, update_notifiers)
205 }
206
207 pub fn enumerate(&self) -> impl Iterator<Item = (Key, Result<Capability, ()>)> + use<> {
211 self.lock()
212 .entries
213 .iter()
214 .map(|(k, v)| (k.clone(), v.try_clone()))
215 .collect::<Vec<_>>()
216 .into_iter()
217 }
218
219 pub fn keys(&self) -> impl Iterator<Item = Key> + use<> {
221 self.lock().entries.iter().map(|(k, _)| k.clone()).collect::<Vec<_>>().into_iter()
222 }
223
224 pub fn drain(&self) -> impl Iterator<Item = (Key, Capability)> + use<> {
226 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
227 let entries = std::mem::replace(entries, HybridMap::default());
228 for (key, _) in entries.iter() {
229 update_notifiers.update(EntryUpdate::Remove(&key))
230 }
231 entries.into_iter()
232 }
233
234 pub fn shallow_copy(&self) -> Result<Self, ()> {
241 let copy = Self::new();
242 {
243 let DictInner { entries, .. } = &*self.lock();
244 let mut copy = copy.lock();
245 copy.entries = entries.shallow_copy()?;
246 }
247 Ok(copy)
248 }
249
250 #[allow(dead_code)]
253 pub(crate) fn not_found(&self, entry: &str) {
254 if let Some(not_found_handler) = &self.lock().not_found {
255 not_found_handler(entry);
256 }
257 }
258}
259
260impl DictInner {
261 #[cfg(target_os = "fuchsia")]
262 pub(crate) fn tasks(&mut self) -> &mut fasync::TaskGroup {
263 self.task_group.get_or_insert_with(|| fasync::TaskGroup::new())
264 }
265}
266
267pub(crate) const HYBRID_SWITCH_INSERTION_LEN: usize = 11;
268pub(crate) const HYBRID_SWITCH_REMOVAL_LEN: usize = 5;
269
270#[derive(Debug)]
284pub(crate) enum HybridMap {
285 Vec(Vec<(Key, Capability)>),
286 Map(BTreeMap<Key, Capability>),
287}
288
289impl Default for HybridMap {
290 fn default() -> Self {
291 Self::Vec(Vec::default())
292 }
293}
294
295impl HybridMap {
296 pub fn get<Q: ?Sized>(&self, key: &Q) -> Result<Option<Capability>, ()>
297 where
298 Key: Borrow<Q> + Ord,
299 Q: Ord,
300 {
301 match self {
302 Self::Vec(vec) => match Self::sorted_vec_index_of(vec, key) {
303 Ok(index) => Ok(Some(vec[index].1.try_clone()?)),
304 Err(_) => Ok(None),
305 },
306 Self::Map(map) => match map.get(key) {
307 Some(capability) => Ok(Some(capability.try_clone()?)),
308 None => Ok(None),
309 },
310 }
311 }
312
313 pub fn insert(
314 &mut self,
315 key: Key,
316 capability: Capability,
317 update_notifiers: &mut UpdateNotifiers,
318 ) -> Result<(), fsandbox::CapabilityStoreError> {
319 match self {
320 Self::Vec(vec) => match Self::sorted_vec_index_of(vec, &key) {
321 Ok(index) => {
322 update_notifiers.update(EntryUpdate::Remove(&key));
323 update_notifiers.update(EntryUpdate::Add(&key, &capability));
324 vec[index].1 = capability;
325 Err(fsandbox::CapabilityStoreError::ItemAlreadyExists)
326 }
327 Err(index) => {
328 update_notifiers.update(EntryUpdate::Add(&key, &capability));
329 if vec.len() + 1 >= HYBRID_SWITCH_INSERTION_LEN {
330 self.switch_to_map();
331 let Self::Map(map) = self else { unreachable!() };
332 map.insert(key, capability);
333 Ok(())
334 } else {
335 vec.reserve_exact(1);
336 vec.insert(index, (key, capability));
337 Ok(())
338 }
339 }
340 },
341 Self::Map(map) => match map.entry(key.clone()) {
342 Entry::Occupied(mut occupied) => {
343 update_notifiers.update(EntryUpdate::Remove(&key));
344 update_notifiers.update(EntryUpdate::Add(&key, &capability));
345 occupied.insert(capability);
346 Err(fsandbox::CapabilityStoreError::ItemAlreadyExists)
347 }
348 Entry::Vacant(vacant) => {
349 update_notifiers.update(EntryUpdate::Add(&key, &capability));
350 vacant.insert(capability);
351 Ok(())
352 }
353 },
354 }
355 }
356
357 pub fn remove(
358 &mut self,
359 key: &BorrowedKey,
360 update_notifiers: &mut UpdateNotifiers,
361 ) -> Option<Capability> {
362 let result = match self {
363 Self::Vec(vec) => match Self::sorted_vec_index_of(vec, key) {
364 Ok(index) => {
365 update_notifiers.update(EntryUpdate::Remove(key));
366 Some(vec.remove(index).1)
367 }
368 Err(_) => None,
369 },
370 Self::Map(map) => {
371 let result = map.remove(key);
372 if result.is_some() {
373 update_notifiers.update(EntryUpdate::Remove(key));
374 if self.len() <= HYBRID_SWITCH_REMOVAL_LEN {
375 self.switch_to_vec();
376 }
377 }
378 result
379 }
380 };
381 result
382 }
383
384 pub fn append(
385 &mut self,
386 other: &Self,
387 update_notifiers: &mut UpdateNotifiers,
388 ) -> Result<(), ()> {
389 if other.is_empty() {
390 return Ok(());
392 }
393
394 let to_insert: Result<Vec<_>, _> =
396 other.iter().map(|(k, v)| v.try_clone().map(|v| (k.clone(), v))).collect();
397 let to_insert = to_insert?;
398 for (k, _) in &to_insert {
399 let contains_key = match self {
400 Self::Vec(vec) => matches!(Self::sorted_vec_index_of(vec, k), Ok(_)),
401 Self::Map(map) => map.contains_key(k),
402 };
403 if contains_key {
404 return Err(());
405 }
406 }
407
408 if self.len() + other.len() >= HYBRID_SWITCH_INSERTION_LEN {
409 self.switch_to_map();
411 } else if let Self::Vec(vec) = self {
412 vec.reserve(other.len());
415 }
416 for (k, v) in to_insert {
417 self.insert(k, v, update_notifiers).expect("append: insert should have succeeded");
418 }
419 Ok(())
420 }
421
422 pub fn shallow_copy(&self) -> Result<Self, ()> {
423 match self {
424 Self::Vec(vec) => {
425 let mut new_vec = Vec::with_capacity(vec.len());
426 for (key, value) in vec.iter() {
427 new_vec.push((key.clone(), value.try_clone()?));
428 }
429 Ok(HybridMap::Vec(new_vec))
430 }
431 Self::Map(map) => {
432 let mut new_map = BTreeMap::new();
433 for (key, value) in map.iter() {
434 new_map.insert(key.clone(), value.try_clone()?);
435 }
436 Ok(HybridMap::Map(new_map))
437 }
438 }
439 }
440
441 pub fn len(&self) -> usize {
442 match self {
443 Self::Map(map) => map.len(),
444 Self::Vec(vec) => vec.len(),
445 }
446 }
447
448 pub fn is_empty(&self) -> bool {
449 match self {
450 Self::Map(map) => map.is_empty(),
451 Self::Vec(vec) => vec.is_empty(),
452 }
453 }
454
455 pub fn iter(&self) -> impl Iterator<Item = (&Key, &Capability)> {
456 match self {
457 Self::Vec(vec) => itertools::Either::Left(vec.iter().map(|kv| (&kv.0, &kv.1))),
458 Self::Map(map) => itertools::Either::Right(map.iter()),
459 }
460 }
461
462 pub fn into_iter(self) -> impl Iterator<Item = (Key, Capability)> {
463 match self {
464 Self::Vec(vec) => itertools::Either::Left(vec.into_iter()),
465 Self::Map(map) => itertools::Either::Right(map.into_iter()),
466 }
467 }
468
469 fn switch_to_map(&mut self) {
470 match self {
471 Self::Map(_) => {}
472 Self::Vec(vec) => {
473 let vec = std::mem::replace(vec, Vec::new());
474 let map = BTreeMap::from_iter(vec.into_iter());
475 *self = Self::Map(map);
476 }
477 }
478 }
479
480 fn switch_to_vec(&mut self) {
481 match self {
482 Self::Vec(_) => {}
483 Self::Map(map) => {
484 let map = std::mem::replace(map, Default::default());
485 let vec = Vec::from_iter(map.into_iter());
486 *self = Self::Vec(vec);
487 }
488 }
489 }
490
491 #[inline]
492 fn sorted_vec_index_of<Q: ?Sized>(vec: &Vec<(Key, Capability)>, key: &Q) -> Result<usize, usize>
493 where
494 Key: Borrow<Q> + Ord,
495 Q: Ord,
496 {
497 vec.binary_search_by(|probe| probe.0.borrow().cmp(&key))
498 }
499}
500
501#[derive(Default)]
502pub(crate) struct UpdateNotifiers(Vec<UpdateNotifierFn>);
503
504impl UpdateNotifiers {
505 fn update<'a>(&'a mut self, update: EntryUpdate<'a>) {
506 self.0.retain_mut(|notifier_fn| match (notifier_fn)(update) {
507 UpdateNotifierRetention::Retain => true,
508 UpdateNotifierRetention::Drop_ => false,
509 });
510 }
511}
512
513