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 Dictionary {
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 Dictionary {
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 Dictionary {
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 Dictionary {
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: &Dictionary) -> 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) -> Option<Capability>
171 where
172 Key: Borrow<Q> + Ord,
173 Q: Ord,
174 {
175 self.lock().entries.get(key)
176 }
177
178 pub fn get_or_insert(&self, key: &Key, default: impl FnOnce() -> Capability) -> Capability {
181 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
182 match entries.get(key) {
183 Some(v) => v,
184 None => {
185 let v = (default)();
186 entries.insert(key.clone(), v.clone(), update_notifiers).unwrap();
187 v
188 }
189 }
190 }
191
192 pub fn remove(&self, key: &BorrowedKey) -> Option<Capability> {
195 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
196 entries.remove(key, update_notifiers)
197 }
198
199 pub fn enumerate(&self) -> impl Iterator<Item = (Key, Capability)> + use<> {
201 self.lock()
202 .entries
203 .iter()
204 .map(|(k, v)| (k.clone(), v.clone()))
205 .collect::<Vec<_>>()
206 .into_iter()
207 }
208
209 pub fn snapshot_keys_as_strings(&self) -> Vec<String> {
211 let guard = self.lock();
212 match &guard.entries {
213 HybridMap::Vec(vec) => vec.iter().map(|(k, _)| k.to_string()).collect(),
214 HybridMap::Map(map) => map.keys().map(|k| k.to_string()).collect(),
215 }
216 }
217
218 pub fn is_empty(&self) -> bool {
220 self.lock().entries.is_empty()
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) -> 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) => Some(vec[index].1.clone()),
303 Err(_) => None,
304 },
305 Self::Map(map) => match map.get(key) {
306 Some(capability) => Some(capability.clone()),
307 None => 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) {
341 Entry::Occupied(mut occupied) => {
342 update_notifiers.update(EntryUpdate::Remove(occupied.key()));
343 update_notifiers.update(EntryUpdate::Add(occupied.key(), &capability));
344 occupied.insert(capability);
345 Err(fsandbox::CapabilityStoreError::ItemAlreadyExists)
346 }
347 Entry::Vacant(vacant) => {
348 update_notifiers.update(EntryUpdate::Add(vacant.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 for (k, _) in other.iter() {
395 let contains_key = match self {
396 Self::Vec(vec) => matches!(Self::sorted_vec_index_of(vec, k), Ok(_)),
397 Self::Map(map) => map.contains_key(k),
398 };
399 if contains_key {
400 return Err(());
401 }
402 }
403
404 if self.len() + other.len() >= HYBRID_SWITCH_INSERTION_LEN {
405 self.switch_to_map();
407 } else if let Self::Vec(vec) = self {
408 vec.reserve(other.len());
411 }
412 for (k, v) in other.iter() {
413 self.insert(k.clone(), v.clone(), update_notifiers)
414 .expect("append: insert should have succeeded");
415 }
416 Ok(())
417 }
418
419 pub fn shallow_copy(&self) -> Result<Self, ()> {
420 match self {
421 Self::Vec(vec) => {
422 let mut new_vec = Vec::with_capacity(vec.len());
423 for (key, value) in vec.iter() {
424 new_vec.push((key.clone(), value.clone()));
425 }
426 Ok(HybridMap::Vec(new_vec))
427 }
428 Self::Map(map) => {
429 let mut new_map = BTreeMap::new();
430 for (key, value) in map.iter() {
431 new_map.insert(key.clone(), value.clone());
432 }
433 Ok(HybridMap::Map(new_map))
434 }
435 }
436 }
437
438 pub fn len(&self) -> usize {
439 match self {
440 Self::Map(map) => map.len(),
441 Self::Vec(vec) => vec.len(),
442 }
443 }
444
445 pub fn is_empty(&self) -> bool {
446 match self {
447 Self::Map(map) => map.is_empty(),
448 Self::Vec(vec) => vec.is_empty(),
449 }
450 }
451
452 pub fn iter(&self) -> impl Iterator<Item = (&Key, &Capability)> {
453 match self {
454 Self::Vec(vec) => itertools::Either::Left(vec.iter().map(|kv| (&kv.0, &kv.1))),
455 Self::Map(map) => itertools::Either::Right(map.iter()),
456 }
457 }
458
459 pub fn into_iter(self) -> impl Iterator<Item = (Key, Capability)> {
460 match self {
461 Self::Vec(vec) => itertools::Either::Left(vec.into_iter()),
462 Self::Map(map) => itertools::Either::Right(map.into_iter()),
463 }
464 }
465
466 fn switch_to_map(&mut self) {
467 match self {
468 Self::Map(_) => {}
469 Self::Vec(vec) => {
470 let vec = std::mem::replace(vec, Vec::new());
471 let map = BTreeMap::from_iter(vec.into_iter());
472 *self = Self::Map(map);
473 }
474 }
475 }
476
477 fn switch_to_vec(&mut self) {
478 match self {
479 Self::Vec(_) => {}
480 Self::Map(map) => {
481 let map = std::mem::replace(map, Default::default());
482 let vec = Vec::from_iter(map.into_iter());
483 *self = Self::Vec(vec);
484 }
485 }
486 }
487
488 #[inline]
489 fn sorted_vec_index_of<Q: ?Sized>(vec: &Vec<(Key, Capability)>, key: &Q) -> Result<usize, usize>
490 where
491 Key: Borrow<Q> + Ord,
492 Q: Ord,
493 {
494 vec.binary_search_by(|probe| probe.0.borrow().cmp(&key))
495 }
496}
497
498#[derive(Default)]
499pub(crate) struct UpdateNotifiers(Vec<UpdateNotifierFn>);
500
501impl UpdateNotifiers {
502 fn update<'a>(&'a mut self, update: EntryUpdate<'a>) {
503 self.0.retain_mut(|notifier_fn| match (notifier_fn)(update) {
504 UpdateNotifierRetention::Retain => true,
505 UpdateNotifierRetention::Drop_ => false,
506 });
507 }
508}
509
510