1use crate::{Capability, CapabilityBound};
6use derivative::Derivative;
7use fuchsia_sync::{Mutex, MutexGuard};
8use std::borrow::Borrow;
9use std::collections::BTreeMap;
10use std::collections::btree_map::Entry;
11use std::sync::Arc;
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)]
21pub struct Dictionary {
22 inner: 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::Scope>,
44
45 #[derivative(Debug = "ignore")]
47 update_notifiers: UpdateNotifiers,
48}
49
50impl CapabilityBound for Dictionary {
51 fn debug_typename() -> &'static str {
52 "Dictionary"
53 }
54
55 #[cfg(target_os = "fuchsia")]
56 fn try_into_directory_entry(
57 self: Arc<Self>,
58 scope: vfs::execution_scope::ExecutionScope,
59 token: Arc<crate::WeakInstanceToken>,
60 ) -> Result<Arc<dyn vfs::directory::entry::DirectoryEntry>, crate::ConversionError> {
61 self.try_into_directory_entry_inner(scope, token)
62 }
63}
64
65impl Drop for DictInner {
66 fn drop(&mut self) {
67 let entries = std::mem::replace(&mut self.entries, HybridMap::default());
71 for (key, _) in entries.into_iter() {
72 self.update_notifiers.update(EntryUpdate::Remove(&key))
73 }
74 }
75}
76
77#[derive(Debug, Copy, Clone)]
79pub enum EntryUpdate<'a> {
80 Add(&'a BorrowedKey, &'a Capability),
81 Remove(&'a BorrowedKey),
82 Idle,
83}
84
85pub enum UpdateNotifierRetention {
88 Retain,
89 Drop_,
90}
91
92pub type UpdateNotifierFn =
97 Box<dyn for<'a> FnMut(EntryUpdate<'a>) -> UpdateNotifierRetention + Sync + Send>;
98
99impl Default for Dictionary {
100 fn default() -> Self {
101 Self {
102 inner: Mutex::new(DictInner {
103 entries: HybridMap::default(),
104 not_found: None,
105 #[cfg(target_os = "fuchsia")]
106 task_group: None,
107 update_notifiers: UpdateNotifiers::default(),
108 }),
109 }
110 }
111}
112
113impl Dictionary {
114 pub fn new() -> Arc<Self> {
116 Arc::new(Self::default())
117 }
118
119 pub fn new_with_not_found(not_found: impl Fn(&str) -> () + 'static + Send + Sync) -> Arc<Self> {
122 Arc::new(Self {
123 inner: Mutex::new(DictInner {
124 entries: HybridMap::default(),
125 not_found: Some(Box::new(not_found)),
126 #[cfg(target_os = "fuchsia")]
127 task_group: None,
128 update_notifiers: UpdateNotifiers::default(),
129 }),
130 })
131 }
132
133 pub(crate) fn lock(&self) -> MutexGuard<'_, DictInner> {
134 self.inner.lock()
135 }
136
137 pub fn register_update_notifier(&self, mut notifier_fn: UpdateNotifierFn) {
147 let mut guard = self.lock();
148 for (key, value) in guard.entries.iter() {
149 if let UpdateNotifierRetention::Drop_ = (notifier_fn)(EntryUpdate::Add(key, value)) {
150 return;
152 }
153 }
154 if let UpdateNotifierRetention::Retain = (notifier_fn)(EntryUpdate::Idle) {
155 guard.update_notifiers.0.push(notifier_fn);
156 }
157 }
158
159 pub fn insert(&self, key: Key, capability: Capability) -> Option<Capability> {
162 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
163 entries.insert(key, capability, update_notifiers)
164 }
165
166 pub fn append(&self, other: &Dictionary) -> Result<(), ()> {
167 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
168 let other = other.lock();
169 entries.append(&other.entries, update_notifiers)
170 }
171
172 pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<Capability>
175 where
176 Key: Borrow<Q> + Ord,
177 Q: Ord,
178 {
179 self.lock().entries.get(key)
180 }
181
182 pub fn get_or_insert(&self, key: &Key, default: impl FnOnce() -> Capability) -> Capability {
185 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
186 match entries.get(key) {
187 Some(v) => v,
188 None => {
189 let v = (default)();
190 entries.insert(key.clone(), v.clone(), update_notifiers);
191 v
192 }
193 }
194 }
195
196 pub fn remove(&self, key: &BorrowedKey) -> Option<Capability> {
199 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
200 entries.remove(key, update_notifiers)
201 }
202
203 pub fn enumerate(&self) -> impl Iterator<Item = (Key, Capability)> + use<> {
205 self.lock()
206 .entries
207 .iter()
208 .map(|(k, v)| (k.clone(), v.clone()))
209 .collect::<Vec<_>>()
210 .into_iter()
211 }
212
213 pub fn snapshot_keys_as_strings(&self) -> Vec<String> {
215 let guard = self.lock();
216 match &guard.entries {
217 HybridMap::Vec(vec) => vec.iter().map(|(k, _)| k.to_string()).collect(),
218 HybridMap::Map(map) => map.keys().map(|k| k.to_string()).collect(),
219 }
220 }
221
222 pub fn is_empty(&self) -> bool {
224 self.lock().entries.is_empty()
225 }
226
227 pub fn drain(&self) -> impl Iterator<Item = (Key, Capability)> + use<> {
229 let DictInner { entries, update_notifiers, .. } = &mut *self.lock();
230 let entries = std::mem::replace(entries, HybridMap::default());
231 for (key, _) in entries.iter() {
232 update_notifiers.update(EntryUpdate::Remove(&key))
233 }
234 entries.into_iter()
235 }
236
237 pub fn shallow_copy(&self) -> Arc<Self> {
242 let copy = Self::new();
243 {
244 let DictInner { entries, .. } = &*self.lock();
245 let mut copy = copy.lock();
246 copy.entries = entries.shallow_copy();
247 }
248 copy
249 }
250
251 #[allow(dead_code)]
254 pub(crate) fn not_found(&self, entry: &str) {
255 if let Some(not_found_handler) = &self.lock().not_found {
256 not_found_handler(entry);
257 }
258 }
259}
260
261impl DictInner {
262 #[cfg(target_os = "fuchsia")]
263 pub(crate) fn tasks(&mut self) -> &mut fasync::Scope {
264 self.task_group.get_or_insert_with(|| fasync::Scope::new())
265 }
266}
267
268pub(crate) const HYBRID_SWITCH_INSERTION_LEN: usize = 11;
269pub(crate) const HYBRID_SWITCH_REMOVAL_LEN: usize = 5;
270
271#[derive(Debug)]
285pub(crate) enum HybridMap {
286 Vec(Vec<(Key, Capability)>),
287 Map(BTreeMap<Key, Capability>),
288}
289
290impl Default for HybridMap {
291 fn default() -> Self {
292 Self::Vec(Vec::default())
293 }
294}
295
296impl HybridMap {
297 pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<Capability>
298 where
299 Key: Borrow<Q> + Ord,
300 Q: Ord,
301 {
302 match self {
303 Self::Vec(vec) => match Self::sorted_vec_index_of(vec, key) {
304 Ok(index) => Some(vec[index].1.clone()),
305 Err(_) => None,
306 },
307 Self::Map(map) => match map.get(key) {
308 Some(capability) => Some(capability.clone()),
309 None => None,
310 },
311 }
312 }
313
314 pub fn insert(
315 &mut self,
316 key: Key,
317 mut capability: Capability,
318 update_notifiers: &mut UpdateNotifiers,
319 ) -> Option<Capability> {
320 match self {
321 Self::Vec(vec) => match Self::sorted_vec_index_of(vec, &key) {
322 Ok(index) => {
323 update_notifiers.update(EntryUpdate::Remove(&key));
324 update_notifiers.update(EntryUpdate::Add(&key, &capability));
325 std::mem::swap(&mut capability, &mut vec[index].1);
326 Some(capability)
327 }
328 Err(index) => {
329 update_notifiers.update(EntryUpdate::Add(&key, &capability));
330 if vec.len() + 1 >= HYBRID_SWITCH_INSERTION_LEN {
331 self.switch_to_map();
332 let Self::Map(map) = self else { unreachable!() };
333 map.insert(key, capability);
334 None
335 } else {
336 vec.reserve_exact(1);
337 vec.insert(index, (key, capability));
338 None
339 }
340 }
341 },
342 Self::Map(map) => match map.entry(key) {
343 Entry::Occupied(mut occupied) => {
344 update_notifiers.update(EntryUpdate::Remove(occupied.key()));
345 update_notifiers.update(EntryUpdate::Add(occupied.key(), &capability));
346 Some(occupied.insert(capability))
347 }
348 Entry::Vacant(vacant) => {
349 update_notifiers.update(EntryUpdate::Add(vacant.key(), &capability));
350 vacant.insert(capability);
351 None
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 for (k, _) in other.iter() {
396 let contains_key = match self {
397 Self::Vec(vec) => matches!(Self::sorted_vec_index_of(vec, k), Ok(_)),
398 Self::Map(map) => map.contains_key(k),
399 };
400 if contains_key {
401 return Err(());
402 }
403 }
404
405 if self.len() + other.len() >= HYBRID_SWITCH_INSERTION_LEN {
406 self.switch_to_map();
408 } else if let Self::Vec(vec) = self {
409 vec.reserve(other.len());
412 }
413 for (k, v) in other.iter() {
414 self.insert(k.clone(), v.clone(), update_notifiers);
415 }
416 Ok(())
417 }
418
419 pub fn shallow_copy(&self) -> 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 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 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