1use crate::{Capability, CapabilityBound};
6use derivative::Derivative;
7use fidl_fuchsia_component_sandbox as fsandbox;
8use std::borrow::Borrow;
9use std::collections::BTreeMap;
10use std::collections::btree_map::Entry;
11use std::sync::{Arc, Mutex, MutexGuard};
12
13#[cfg(target_os = "fuchsia")]
14use fuchsia_async as fasync;
15
16pub type Key = cm_types::Name;
17pub type BorrowedKey = cm_types::BorrowedName;
18
19#[derive(Debug, Clone)]
21pub struct Dict {
22 inner: Arc<Mutex<DictInner>>,
23}
24
25#[derive(Derivative)]
26#[derivative(Debug)]
27pub(crate) struct DictInner {
28 pub(crate) entries: HybridMap,
30
31 #[derivative(Debug = "ignore")]
34 #[allow(dead_code)]
36 pub(crate) not_found: Option<Box<dyn Fn(&str) -> () + 'static + Send + Sync>>,
37
38 #[cfg(target_os = "fuchsia")]
42 #[derivative(Debug = "ignore")]
43 task_group: Option<fasync::TaskGroup>,
44
45 #[derivative(Debug = "ignore")]
47 update_notifiers: UpdateNotifiers,
48}
49
50impl CapabilityBound for Dict {
51 fn debug_typename() -> &'static str {
52 "Dictionary"
53 }
54}
55
56impl Drop for DictInner {
57 fn drop(&mut self) {
58 let entries = std::mem::replace(&mut self.entries, HybridMap::default());
62 for (key, _) in entries.into_iter() {
63 self.update_notifiers.update(EntryUpdate::Remove(&key))
64 }
65 }
66}
67
68#[derive(Debug, Copy, Clone)]
70pub enum EntryUpdate<'a> {
71 Add(&'a BorrowedKey, &'a Capability),
72 Remove(&'a BorrowedKey),
73 Idle,
74}
75
76pub enum UpdateNotifierRetention {
79 Retain,
80 Drop_,
81}
82
83pub type UpdateNotifierFn =
88 Box<dyn for<'a> FnMut(EntryUpdate<'a>) -> UpdateNotifierRetention + Sync + Send>;
89
90impl Default for Dict {
91 fn default() -> Self {
92 Self {
93 inner: Arc::new(Mutex::new(DictInner {
94 entries: HybridMap::default(),
95 not_found: None,
96 #[cfg(target_os = "fuchsia")]
97 task_group: None,
98 update_notifiers: UpdateNotifiers::default(),
99 })),
100 }
101 }
102}
103
104impl Dict {
105 pub fn new() -> Self {
107 Self::default()
108 }
109
110 pub fn new_with_not_found(not_found: impl Fn(&str) -> () + 'static + Send + Sync) -> Self {
113 Self {
114 inner: Arc::new(Mutex::new(DictInner {
115 entries: HybridMap::default(),
116 not_found: Some(Box::new(not_found)),
117 #[cfg(target_os = "fuchsia")]
118 task_group: None,
119 update_notifiers: UpdateNotifiers::default(),
120 })),
121 }
122 }
123
124 pub(crate) fn lock(&self) -> MutexGuard<'_, DictInner> {
125 self.inner.lock().unwrap()
126 }
127
128 pub fn register_update_notifier(&self, mut notifier_fn: UpdateNotifierFn) {
138 let mut guard = self.lock();
139 for (key, value) in guard.entries.iter() {
140 if let UpdateNotifierRetention::Drop_ = (notifier_fn)(EntryUpdate::Add(key, value)) {
141 return;
143 }
144 }
145 if let UpdateNotifierRetention::Retain = (notifier_fn)(EntryUpdate::Idle) {
146 guard.update_notifiers.0.push(notifier_fn);
147 }
148 }
149
150 pub fn insert(
153 &self,
154 key: Key,
155 capability: Capability,
156 ) -> Result<(), fsandbox::CapabilityStoreError> {
157 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
158 entries.insert(key, capability, update_notifiers)
159 }
160
161 pub fn append(&self, other: &Dict) -> Result<(), ()> {
162 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
163 let other = other.lock();
164 entries.append(&other.entries, update_notifiers)
165 }
166
167 pub fn get<Q: ?Sized>(&self, key: &Q) -> Result<Option<Capability>, ()>
172 where
173 Key: Borrow<Q> + Ord,
174 Q: Ord,
175 {
176 self.lock().entries.get(key)
177 }
178
179 pub fn get_or_insert(
184 &self,
185 key: &Key,
186 default: impl FnOnce() -> Capability,
187 ) -> Result<Capability, ()> {
188 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
189 match entries.get(key)? {
190 Some(v) => Ok(v),
191 None => {
192 let v = (default)();
193 entries.insert(key.clone(), v.try_clone()?, update_notifiers).unwrap();
194 Ok(v)
195 }
196 }
197 }
198
199 pub fn remove(&self, key: &BorrowedKey) -> Option<Capability> {
202 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
203 entries.remove(key, update_notifiers)
204 }
205
206 pub fn enumerate(&self) -> impl Iterator<Item = (Key, Result<Capability, ()>)> + use<> {
210 self.lock()
211 .entries
212 .iter()
213 .map(|(k, v)| (k.clone(), v.try_clone()))
214 .collect::<Vec<_>>()
215 .into_iter()
216 }
217
218 pub fn keys(&self) -> impl Iterator<Item = Key> + use<> {
220 self.lock().entries.iter().map(|(k, _)| k.clone()).collect::<Vec<_>>().into_iter()
221 }
222
223 pub fn drain(&self) -> impl Iterator<Item = (Key, Capability)> + use<> {
225 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
226 let entries = std::mem::replace(entries, HybridMap::default());
227 for (key, _) in entries.iter() {
228 update_notifiers.update(EntryUpdate::Remove(&key))
229 }
230 entries.into_iter()
231 }
232
233 pub fn shallow_copy(&self) -> Result<Self, ()> {
240 let copy = Self::new();
241 {
242 let DictInner { entries, .. } = &*self.lock();
243 let mut copy = copy.lock();
244 copy.entries = entries.shallow_copy()?;
245 }
246 Ok(copy)
247 }
248
249 #[allow(dead_code)]
252 pub(crate) fn not_found(&self, entry: &str) {
253 if let Some(not_found_handler) = &self.lock().not_found {
254 not_found_handler(entry);
255 }
256 }
257}
258
259impl DictInner {
260 #[cfg(target_os = "fuchsia")]
261 pub(crate) fn tasks(&mut self) -> &mut fasync::TaskGroup {
262 self.task_group.get_or_insert_with(|| fasync::TaskGroup::new())
263 }
264}
265
266pub(crate) const HYBRID_SWITCH_INSERTION_LEN: usize = 11;
267pub(crate) const HYBRID_SWITCH_REMOVAL_LEN: usize = 5;
268
269#[derive(Debug)]
283pub(crate) enum HybridMap {
284 Vec(Vec<(Key, Capability)>),
285 Map(BTreeMap<Key, Capability>),
286}
287
288impl Default for HybridMap {
289 fn default() -> Self {
290 Self::Vec(Vec::default())
291 }
292}
293
294impl HybridMap {
295 pub fn get<Q: ?Sized>(&self, key: &Q) -> Result<Option<Capability>, ()>
296 where
297 Key: Borrow<Q> + Ord,
298 Q: Ord,
299 {
300 match self {
301 Self::Vec(vec) => match Self::sorted_vec_index_of(vec, key) {
302 Ok(index) => Ok(Some(vec[index].1.try_clone()?)),
303 Err(_) => Ok(None),
304 },
305 Self::Map(map) => match map.get(key) {
306 Some(capability) => Ok(Some(capability.try_clone()?)),
307 None => Ok(None),
308 },
309 }
310 }
311
312 pub fn insert(
313 &mut self,
314 key: Key,
315 capability: Capability,
316 update_notifiers: &mut UpdateNotifiers,
317 ) -> Result<(), fsandbox::CapabilityStoreError> {
318 match self {
319 Self::Vec(vec) => match Self::sorted_vec_index_of(vec, &key) {
320 Ok(index) => {
321 update_notifiers.update(EntryUpdate::Remove(&key));
322 update_notifiers.update(EntryUpdate::Add(&key, &capability));
323 vec[index].1 = capability;
324 Err(fsandbox::CapabilityStoreError::ItemAlreadyExists)
325 }
326 Err(index) => {
327 update_notifiers.update(EntryUpdate::Add(&key, &capability));
328 if vec.len() + 1 >= HYBRID_SWITCH_INSERTION_LEN {
329 self.switch_to_map();
330 let Self::Map(map) = self else { unreachable!() };
331 map.insert(key, capability);
332 Ok(())
333 } else {
334 vec.reserve_exact(1);
335 vec.insert(index, (key, capability));
336 Ok(())
337 }
338 }
339 },
340 Self::Map(map) => match map.entry(key.clone()) {
341 Entry::Occupied(mut occupied) => {
342 update_notifiers.update(EntryUpdate::Remove(&key));
343 update_notifiers.update(EntryUpdate::Add(&key, &capability));
344 occupied.insert(capability);
345 Err(fsandbox::CapabilityStoreError::ItemAlreadyExists)
346 }
347 Entry::Vacant(vacant) => {
348 update_notifiers.update(EntryUpdate::Add(&key, &capability));
349 vacant.insert(capability);
350 Ok(())
351 }
352 },
353 }
354 }
355
356 pub fn remove(
357 &mut self,
358 key: &BorrowedKey,
359 update_notifiers: &mut UpdateNotifiers,
360 ) -> Option<Capability> {
361 let result = match self {
362 Self::Vec(vec) => match Self::sorted_vec_index_of(vec, key) {
363 Ok(index) => {
364 update_notifiers.update(EntryUpdate::Remove(key));
365 Some(vec.remove(index).1)
366 }
367 Err(_) => None,
368 },
369 Self::Map(map) => {
370 let result = map.remove(key);
371 if result.is_some() {
372 update_notifiers.update(EntryUpdate::Remove(key));
373 if self.len() <= HYBRID_SWITCH_REMOVAL_LEN {
374 self.switch_to_vec();
375 }
376 }
377 result
378 }
379 };
380 result
381 }
382
383 pub fn append(
384 &mut self,
385 other: &Self,
386 update_notifiers: &mut UpdateNotifiers,
387 ) -> Result<(), ()> {
388 if other.is_empty() {
389 return Ok(());
391 }
392
393 let to_insert: Result<Vec<_>, _> =
395 other.iter().map(|(k, v)| v.try_clone().map(|v| (k.clone(), v))).collect();
396 let to_insert = to_insert?;
397 for (k, _) in &to_insert {
398 let contains_key = match self {
399 Self::Vec(vec) => matches!(Self::sorted_vec_index_of(vec, k), Ok(_)),
400 Self::Map(map) => map.contains_key(k),
401 };
402 if contains_key {
403 return Err(());
404 }
405 }
406
407 if self.len() + other.len() >= HYBRID_SWITCH_INSERTION_LEN {
408 self.switch_to_map();
410 } else if let Self::Vec(vec) = self {
411 vec.reserve(other.len());
414 }
415 for (k, v) in to_insert {
416 self.insert(k, v, update_notifiers).expect("append: insert should have succeeded");
417 }
418 Ok(())
419 }
420
421 pub fn shallow_copy(&self) -> Result<Self, ()> {
422 match self {
423 Self::Vec(vec) => {
424 let mut new_vec = Vec::with_capacity(vec.len());
425 for (key, value) in vec.iter() {
426 new_vec.push((key.clone(), value.try_clone()?));
427 }
428 Ok(HybridMap::Vec(new_vec))
429 }
430 Self::Map(map) => {
431 let mut new_map = BTreeMap::new();
432 for (key, value) in map.iter() {
433 new_map.insert(key.clone(), value.try_clone()?);
434 }
435 Ok(HybridMap::Map(new_map))
436 }
437 }
438 }
439
440 pub fn len(&self) -> usize {
441 match self {
442 Self::Map(map) => map.len(),
443 Self::Vec(vec) => vec.len(),
444 }
445 }
446
447 pub fn is_empty(&self) -> bool {
448 match self {
449 Self::Map(map) => map.is_empty(),
450 Self::Vec(vec) => vec.is_empty(),
451 }
452 }
453
454 pub fn iter(&self) -> impl Iterator<Item = (&Key, &Capability)> {
455 match self {
456 Self::Vec(vec) => itertools::Either::Left(vec.iter().map(|kv| (&kv.0, &kv.1))),
457 Self::Map(map) => itertools::Either::Right(map.iter()),
458 }
459 }
460
461 pub fn into_iter(self) -> impl Iterator<Item = (Key, Capability)> {
462 match self {
463 Self::Vec(vec) => itertools::Either::Left(vec.into_iter()),
464 Self::Map(map) => itertools::Either::Right(map.into_iter()),
465 }
466 }
467
468 fn switch_to_map(&mut self) {
469 match self {
470 Self::Map(_) => {}
471 Self::Vec(vec) => {
472 let vec = std::mem::replace(vec, Vec::new());
473 let map = BTreeMap::from_iter(vec.into_iter());
474 *self = Self::Map(map);
475 }
476 }
477 }
478
479 fn switch_to_vec(&mut self) {
480 match self {
481 Self::Vec(_) => {}
482 Self::Map(map) => {
483 let map = std::mem::replace(map, Default::default());
484 let vec = Vec::from_iter(map.into_iter());
485 *self = Self::Vec(vec);
486 }
487 }
488 }
489
490 #[inline]
491 fn sorted_vec_index_of<Q: ?Sized>(vec: &Vec<(Key, Capability)>, key: &Q) -> Result<usize, usize>
492 where
493 Key: Borrow<Q> + Ord,
494 Q: Ord,
495 {
496 vec.binary_search_by(|probe| probe.0.borrow().cmp(&key))
497 }
498}
499
500#[derive(Default)]
501pub(crate) struct UpdateNotifiers(Vec<UpdateNotifierFn>);
502
503impl UpdateNotifiers {
504 fn update<'a>(&'a mut self, update: EntryUpdate<'a>) {
505 self.0.retain_mut(|notifier_fn| match (notifier_fn)(update) {
506 UpdateNotifierRetention::Retain => true,
507 UpdateNotifierRetention::Drop_ => false,
508 });
509 }
510}
511
512