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)]
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 mut capability: Capability,
316 update_notifiers: &mut UpdateNotifiers,
317 ) -> Option<Capability> {
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 std::mem::swap(&mut capability, &mut vec[index].1);
324 Some(capability)
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 None
333 } else {
334 vec.reserve_exact(1);
335 vec.insert(index, (key, capability));
336 None
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 Some(occupied.insert(capability))
345 }
346 Entry::Vacant(vacant) => {
347 update_notifiers.update(EntryUpdate::Add(vacant.key(), &capability));
348 vacant.insert(capability);
349 None
350 }
351 },
352 }
353 }
354
355 pub fn remove(
356 &mut self,
357 key: &BorrowedKey,
358 update_notifiers: &mut UpdateNotifiers,
359 ) -> Option<Capability> {
360 let result = match self {
361 Self::Vec(vec) => match Self::sorted_vec_index_of(vec, key) {
362 Ok(index) => {
363 update_notifiers.update(EntryUpdate::Remove(key));
364 Some(vec.remove(index).1)
365 }
366 Err(_) => None,
367 },
368 Self::Map(map) => {
369 let result = map.remove(key);
370 if result.is_some() {
371 update_notifiers.update(EntryUpdate::Remove(key));
372 if self.len() <= HYBRID_SWITCH_REMOVAL_LEN {
373 self.switch_to_vec();
374 }
375 }
376 result
377 }
378 };
379 result
380 }
381
382 pub fn append(
383 &mut self,
384 other: &Self,
385 update_notifiers: &mut UpdateNotifiers,
386 ) -> Result<(), ()> {
387 if other.is_empty() {
388 return Ok(());
390 }
391
392 for (k, _) in other.iter() {
394 let contains_key = match self {
395 Self::Vec(vec) => matches!(Self::sorted_vec_index_of(vec, k), Ok(_)),
396 Self::Map(map) => map.contains_key(k),
397 };
398 if contains_key {
399 return Err(());
400 }
401 }
402
403 if self.len() + other.len() >= HYBRID_SWITCH_INSERTION_LEN {
404 self.switch_to_map();
406 } else if let Self::Vec(vec) = self {
407 vec.reserve(other.len());
410 }
411 for (k, v) in other.iter() {
412 self.insert(k.clone(), v.clone(), update_notifiers);
413 }
414 Ok(())
415 }
416
417 pub fn shallow_copy(&self) -> Self {
418 match self {
419 Self::Vec(vec) => {
420 let mut new_vec = Vec::with_capacity(vec.len());
421 for (key, value) in vec.iter() {
422 new_vec.push((key.clone(), value.clone()));
423 }
424 HybridMap::Vec(new_vec)
425 }
426 Self::Map(map) => {
427 let mut new_map = BTreeMap::new();
428 for (key, value) in map.iter() {
429 new_map.insert(key.clone(), value.clone());
430 }
431 HybridMap::Map(new_map)
432 }
433 }
434 }
435
436 pub fn len(&self) -> usize {
437 match self {
438 Self::Map(map) => map.len(),
439 Self::Vec(vec) => vec.len(),
440 }
441 }
442
443 pub fn is_empty(&self) -> bool {
444 match self {
445 Self::Map(map) => map.is_empty(),
446 Self::Vec(vec) => vec.is_empty(),
447 }
448 }
449
450 pub fn iter(&self) -> impl Iterator<Item = (&Key, &Capability)> {
451 match self {
452 Self::Vec(vec) => itertools::Either::Left(vec.iter().map(|kv| (&kv.0, &kv.1))),
453 Self::Map(map) => itertools::Either::Right(map.iter()),
454 }
455 }
456
457 pub fn into_iter(self) -> impl Iterator<Item = (Key, Capability)> {
458 match self {
459 Self::Vec(vec) => itertools::Either::Left(vec.into_iter()),
460 Self::Map(map) => itertools::Either::Right(map.into_iter()),
461 }
462 }
463
464 fn switch_to_map(&mut self) {
465 match self {
466 Self::Map(_) => {}
467 Self::Vec(vec) => {
468 let vec = std::mem::replace(vec, Vec::new());
469 let map = BTreeMap::from_iter(vec.into_iter());
470 *self = Self::Map(map);
471 }
472 }
473 }
474
475 fn switch_to_vec(&mut self) {
476 match self {
477 Self::Vec(_) => {}
478 Self::Map(map) => {
479 let map = std::mem::replace(map, Default::default());
480 let vec = Vec::from_iter(map.into_iter());
481 *self = Self::Vec(vec);
482 }
483 }
484 }
485
486 #[inline]
487 fn sorted_vec_index_of<Q: ?Sized>(vec: &Vec<(Key, Capability)>, key: &Q) -> Result<usize, usize>
488 where
489 Key: Borrow<Q> + Ord,
490 Q: Ord,
491 {
492 vec.binary_search_by(|probe| probe.0.borrow().cmp(&key))
493 }
494}
495
496#[derive(Default)]
497pub(crate) struct UpdateNotifiers(Vec<UpdateNotifierFn>);
498
499impl UpdateNotifiers {
500 fn update<'a>(&'a mut self, update: EntryUpdate<'a>) {
501 self.0.retain_mut(|notifier_fn| match (notifier_fn)(update) {
502 UpdateNotifierRetention::Retain => true,
503 UpdateNotifierRetention::Drop_ => false,
504 });
505 }
506}
507
508