1use std::cell::{Cell, RefCell};
99use std::collections::HashMap;
100use std::hash::Hash;
101use std::rc::Rc;
102
103type ScopeRef<K, V> = Rc<ScopeData<K, V>>;
106
107type Slot<K, V> = (ScopeRef<K, V>, usize);
110
111struct Entry<K, V> {
115 key: K,
118 value: V,
120 shadowed: Option<Slot<K, V>>,
125}
126
127struct ScopeData<K, V> {
131 entries: RefCell<Vec<Entry<K, V>>>,
134 parent: Option<ScopeRef<K, V>>,
136 depth: u32,
138 active: Cell<bool>,
140}
141
142impl<K, V> Drop for ScopeData<K, V> {
143 fn drop(&mut self) {
144 debug_assert!(!self.active.get(), "Cannot destroy an active scope");
148 }
149}
150
151pub struct ScopePtr<K, V>(Option<ScopeRef<K, V>>);
156
157impl<K, V> ScopePtr<K, V> {
158 fn new(scope: ScopeRef<K, V>) -> Self {
159 ScopePtr(Some(scope))
160 }
161
162 pub fn is_null(&self) -> bool {
164 self.0.is_none()
165 }
166
167 pub fn reset(&mut self) {
169 self.0 = None;
170 }
171
172 fn get(&self) -> Option<&ScopeRef<K, V>> {
173 self.0.as_ref()
174 }
175}
176
177impl<K, V> Clone for ScopePtr<K, V> {
178 fn clone(&self) -> Self {
179 ScopePtr(self.0.clone())
182 }
183}
184
185impl<K, V> Default for ScopePtr<K, V> {
186 fn default() -> Self {
187 ScopePtr(None)
189 }
190}
191
192impl<K, V> PartialEq for ScopePtr<K, V> {
193 fn eq(&self, other: &Self) -> bool {
195 match (&self.0, &other.0) {
196 (Some(a), Some(b)) => Rc::ptr_eq(a, b),
197 (None, None) => true,
198 _ => false,
199 }
200 }
201}
202
203pub struct Scope<'m, K: Eq + Hash + Copy, V: Clone> {
206 base: &'m PersistentScopedMap<K, V>,
207 scope: ScopeRef<K, V>,
208}
209
210impl<'m, K: Eq + Hash + Copy, V: Clone> Scope<'m, K, V> {
211 pub fn new(base: &'m PersistentScopedMap<K, V>) -> Self {
213 let parent = base.scope.borrow().clone();
214 let depth = parent.as_ref().map_or(0, |p| p.depth + 1);
215 let scope = Rc::new(ScopeData {
216 entries: RefCell::new(Vec::new()),
217 parent,
218 depth,
219 active: Cell::new(true),
220 });
221 *base.scope.borrow_mut() = Some(scope.clone());
222 Scope { base, scope }
223 }
224
225 pub fn depth(&self) -> u32 {
227 self.scope.depth
228 }
229
230 pub fn ptr(&self) -> ScopePtr<K, V> {
233 ScopePtr::new(self.scope.clone())
234 }
235}
236
237impl<'m, K: Eq + Hash + Copy, V: Clone> Drop for Scope<'m, K, V> {
238 fn drop(&mut self) {
239 self.base.pop_scope(&self.scope);
240 }
241}
242
243pub struct PersistentScopedMap<K, V> {
248 map: RefCell<HashMap<K, Slot<K, V>>>,
250 scope: RefCell<Option<ScopeRef<K, V>>>,
252}
253
254impl<K: Eq + Hash + Copy, V: Clone> Default for PersistentScopedMap<K, V> {
255 fn default() -> Self {
256 Self::new()
257 }
258}
259
260impl<K, V> Drop for PersistentScopedMap<K, V> {
261 fn drop(&mut self) {
262 debug_assert!(
263 self.scope.borrow().is_none(),
264 "Scopes remain when destructing PersistentScopedMap"
265 );
266 debug_assert!(
267 self.map.borrow().is_empty(),
268 "Elements remaining in map without scope!"
269 );
270 }
271}
272
273impl<K: Eq + Hash + Copy, V: Clone> PersistentScopedMap<K, V> {
274 pub fn new() -> Self {
275 PersistentScopedMap {
276 map: RefCell::new(HashMap::new()),
277 scope: RefCell::new(None),
278 }
279 }
280
281 pub fn current_scope(&self) -> ScopePtr<K, V> {
283 ScopePtr(self.scope.borrow().clone())
284 }
285
286 fn require_current(&self) -> ScopeRef<K, V> {
287 self.scope
288 .borrow()
289 .clone()
290 .expect("PersistentScopedMap has no current scope")
291 }
292
293 fn require_scope(ptr: &ScopePtr<K, V>) -> ScopeRef<K, V> {
294 ptr.get()
295 .cloned()
296 .expect("PersistentScopedMapScopePtr must not be null")
297 }
298
299 fn push_entry(&self, scope: &ScopeRef<K, V>, key: K, idx: usize) {
304 let prev = self.map.borrow_mut().insert(key, (scope.clone(), idx));
305 if let Some((ref prev_scope, _)) = prev {
306 debug_assert!(
307 prev_scope.depth < scope.depth,
308 "Can't insert values under existing names"
309 );
310 }
311 scope.entries.borrow_mut()[idx].shadowed = prev;
312 }
313
314 fn insert_new_node(
317 &self,
318 scope: &ScopeRef<K, V>,
319 key: K,
320 value: V,
321 ) -> usize {
322 let idx = {
323 let mut entries = scope.entries.borrow_mut();
324 entries.push(Entry {
325 key,
326 value,
327 shadowed: None,
328 });
329 entries.len() - 1
330 };
331 self.push_entry(scope, key, idx);
332 idx
333 }
334
335 fn pop_entry(&self, scope: &ScopeRef<K, V>, key: K, idx: usize) {
339 let mut map = self.map.borrow_mut();
340 let current = map
341 .get(&key)
342 .cloned()
343 .expect("Asked to pop an empty scope value");
344 debug_assert!(
345 Rc::ptr_eq(¤t.0, scope) && current.1 == idx,
346 "Unexpected innermost value for key"
347 );
348 let shadowed = scope.entries.borrow()[idx].shadowed.clone();
349 match shadowed {
350 Some(s) => {
351 map.insert(key, s);
352 }
353 None => {
354 map.remove(&key);
355 }
356 }
357 }
358
359 fn pop_scope(&self, scope: &ScopeRef<K, V>) {
362 debug_assert!(
363 scope.active.get(),
364 "Attempting to pop an inactive scope"
365 );
366 {
367 let current = self.scope.borrow();
368 debug_assert!(
369 matches!(current.as_ref(), Some(c) if Rc::ptr_eq(c, scope)),
370 "Attempting to pop not current scope"
371 );
372 }
373
374 let len = scope.entries.borrow().len();
375 for idx in 0..len {
376 let key = scope.entries.borrow()[idx].key;
377 self.pop_entry(scope, key, idx);
378 }
379 scope.active.set(false);
380 *self.scope.borrow_mut() = scope.parent.clone();
381 }
382
383 fn push_child_scope(&self, scope: &ScopeRef<K, V>) {
386 debug_assert!(
387 !scope.active.get(),
388 "Attempting to push an active scope"
389 );
390 {
391 let current = self.scope.borrow();
392 let is_child_of_current = match (&scope.parent, current.as_ref()) {
393 (Some(p), Some(c)) => Rc::ptr_eq(p, c),
394 (None, None) => true,
395 _ => false,
396 };
397 debug_assert!(
398 is_child_of_current,
399 "Attempting to push a scope that isn't a child of the \
400 current one"
401 );
402 }
403
404 let len = scope.entries.borrow().len();
405 for idx in 0..len {
406 let key = scope.entries.borrow()[idx].key;
407 self.push_entry(scope, key, idx);
408 }
409 scope.active.set(true);
410 *self.scope.borrow_mut() = Some(scope.clone());
411 }
412
413 fn try_emplace_into_scope_impl(
420 &self,
421 scope: &ScopeRef<K, V>,
422 key: K,
423 value: V,
424 ) -> (usize, bool) {
425 debug_assert!(
426 self.require_current().active.get(),
427 "Attempting to modify an inactive scope"
428 );
429 let existing = self.map.borrow().get(&key).cloned();
430 if let Some((ref existing_scope, existing_idx)) = existing {
431 if existing_scope.depth == scope.depth {
432 return (existing_idx, false);
434 }
435 }
436 let idx = self.insert_new_node(scope, key, value);
438 (idx, true)
439 }
440
441 pub fn try_emplace_into_scope(
447 &self,
448 scope: &ScopePtr<K, V>,
449 key: K,
450 value: V,
451 ) -> bool {
452 let scope_rc = Self::require_scope(scope);
453 self.try_emplace_into_scope_impl(&scope_rc, key, value).1
454 }
455
456 pub fn try_emplace(&self, key: K, value: V) -> bool {
459 let scope_rc = self.require_current();
460 self.try_emplace_into_scope_impl(&scope_rc, key, value).1
461 }
462
463 pub fn put_in_scope(&self, scope: &ScopePtr<K, V>, key: K, value: V) {
467 let scope_rc = Self::require_scope(scope);
468 let (idx, inserted) = self.try_emplace_into_scope_impl(
469 &scope_rc,
470 key,
471 value.clone(),
472 );
473 if !inserted {
474 scope_rc.entries.borrow_mut()[idx].value = value;
475 }
476 }
477
478 pub fn put(&self, key: K, value: V) {
480 let current = self.current_scope();
481 self.put_in_scope(¤t, key, value);
482 }
483
484 pub fn count(&self, key: &K) -> u32 {
486 u32::from(self.map.borrow().contains_key(key))
487 }
488
489 pub fn lookup(&self, key: &K) -> Option<V> {
491 self.find(key)
492 }
493
494 pub fn find(&self, key: &K) -> Option<V> {
496 let map = self.map.borrow();
497 let (scope, idx) = map.get(key)?;
498 let value = scope.entries.borrow()[*idx].value.clone();
499 Some(value)
500 }
501
502 pub fn find_with_depth(&self, key: &K) -> Option<(V, u32)> {
505 let map = self.map.borrow();
506 let (scope, idx) = map.get(key)?;
507 let value = scope.entries.borrow()[*idx].value.clone();
508 Some((value, scope.depth))
509 }
510
511 pub fn find_in_current_scope(&self, key: &K) -> Option<V> {
514 let map = self.map.borrow();
515 let (scope, idx) = map.get(key)?;
516 let current_depth = self.require_current().depth;
517 if scope.depth != current_depth {
519 return None;
520 }
521 let value = scope.entries.borrow()[*idx].value.clone();
522 Some(value)
523 }
524
525 pub fn activate_scope(&self, new_scope_ptr: &ScopePtr<K, V>) {
526 let new_scope = Self::require_scope(new_scope_ptr);
527 let mut activate_list: Vec<ScopeRef<K, V>> = Vec::new();
534 let mut active_parent = Some(new_scope);
535 while let Some(candidate) = active_parent {
536 if candidate.active.get() {
537 active_parent = Some(candidate);
538 break;
539 }
540 active_parent = candidate.parent.clone();
541 activate_list.push(candidate);
542 }
543
544 loop {
546 let current = self.scope.borrow().clone();
547 let reached = match (¤t, &active_parent) {
548 (Some(c), Some(a)) => Rc::ptr_eq(c, a),
549 (None, None) => true,
550 _ => false,
551 };
552 if reached {
553 break;
554 }
555 let current = current.expect("ran out of scopes to pop");
556 self.pop_scope(¤t);
557 }
558
559 for scope in activate_list.into_iter().rev() {
562 self.push_child_scope(&scope);
563 }
564 }
565
566 pub fn flatten(&self) -> HashMap<K, V> {
570 let map = self.map.borrow();
571 let mut result = HashMap::with_capacity(map.len());
572 for (key, (scope, idx)) in map.iter() {
573 result.insert(*key, scope.entries.borrow()[*idx].value.clone());
574 }
575 result
576 }
577
578 pub fn keys_by_scope(&self) -> Vec<Vec<K>> {
583 let current = self.require_current();
584 let size = (current.depth + 1) as usize;
585 let mut result: Vec<Vec<K>> = vec![Vec::new(); size];
586
587 for (key, (scope, _)) in self.map.borrow().iter() {
588 debug_assert!(scope.depth <= current.depth, "Node at bad depth");
589 result[size - scope.depth as usize - 1].push(*key);
590 }
591 result
592 }
593}
594
595#[cfg(test)]
596mod tests {
597 use super::*;
598
599 #[test]
602 fn smoke_test() {
603 let table: PersistentScopedMap<&str, &str> = PersistentScopedMap::new();
604 let scope = Scope::new(&table);
605 table.try_emplace("foo", "bar");
606 assert_eq!(table.lookup(&"foo"), Some("bar"));
607 drop(scope);
608 }
609
610 #[test]
611 fn nesting() {
612 let table: PersistentScopedMap<&str, &str> = PersistentScopedMap::new();
613 let outer = Scope::new(&table);
614 table.try_emplace("key", "outer");
615 assert_eq!(table.lookup(&"key"), Some("outer"));
616 {
617 let _inner = Scope::new(&table);
618 table.try_emplace("key", "inner");
619 assert_eq!(table.lookup(&"key"), Some("inner"));
620 }
621 assert_eq!(table.lookup(&"key"), Some("outer"));
622 drop(outer);
623 }
624
625 #[test]
626 fn overwrite() {
627 let table: PersistentScopedMap<&str, &str> = PersistentScopedMap::new();
628 let outer = Scope::new(&table);
629 table.put("key", "foo");
630 assert_eq!(table.lookup(&"key"), Some("foo"));
631 table.put("key", "outer");
632 assert_eq!(table.lookup(&"key"), Some("outer"));
633 {
634 let _inner = Scope::new(&table);
635 table.put("key", "foo");
636 assert_eq!(table.lookup(&"key"), Some("foo"));
637 table.put("key", "inner");
638 assert_eq!(table.lookup(&"key"), Some("inner"));
639 }
640 assert_eq!(table.lookup(&"key"), Some("outer"));
641 drop(outer);
642 }
643
644 #[test]
645 fn flatten_test() {
646 let table: PersistentScopedMap<&str, &str> = PersistentScopedMap::new();
647 let outer = Scope::new(&table);
648 table.try_emplace("out", "outer");
649 {
650 let _inner = Scope::new(&table);
651 table.try_emplace("in", "inner");
652 let map = table.flatten();
653 assert_eq!(map.len(), 2);
654 assert_eq!(map.get("out"), Some(&"outer"));
655 assert_eq!(map.get("in"), Some(&"inner"));
656 }
657 drop(outer);
658 }
659
660 #[test]
661 fn get_keys_by_scope() {
662 let table: PersistentScopedMap<&str, &str> = PersistentScopedMap::new();
663 let outer = Scope::new(&table);
664 table.try_emplace("out", "outer");
665 table.try_emplace("in", "trash");
666 {
667 let _inner = Scope::new(&table);
668 table.try_emplace("in", "inner");
669 let scopes = table.keys_by_scope();
670 assert_eq!(scopes.len(), 2);
671 assert_eq!(scopes[0].len(), 1);
672 assert_eq!(scopes[1].len(), 1);
673 assert_eq!(scopes[0][0], "in");
674 assert_eq!(scopes[1][0], "out");
675 }
676 drop(outer);
677 }
678
679 #[test]
680 fn put_test() {
681 let table: PersistentScopedMap<&str, &str> = PersistentScopedMap::new();
682 let outer = Scope::new(&table);
683 table.try_emplace("foo", "true");
684 {
685 let _inner = Scope::new(&table);
686 assert_eq!(table.lookup(&"foo"), Some("true"));
687 table.try_emplace("foo", "false");
688 assert_eq!(table.lookup(&"foo"), Some("false"));
689 table.try_emplace("foo", "true");
690 assert_eq!(table.lookup(&"foo"), Some("false"));
691 table.put("foo", "false");
692 assert_eq!(table.lookup(&"foo"), Some("false"));
693 }
694 assert_eq!(table.lookup(&"foo"), Some("true"));
695 drop(outer);
696 }
697
698 #[test]
699 fn find_in_current_scope() {
700 let table: PersistentScopedMap<&str, &str> = PersistentScopedMap::new();
701 let outer = Scope::new(&table);
702 table.try_emplace("foo", "true");
703 {
704 let _inner = Scope::new(&table);
705 table.try_emplace("bar", "true");
706 assert_eq!(table.find_in_current_scope(&"foo"), None);
707 assert_eq!(table.find_in_current_scope(&"bar"), Some("true"));
708 }
709 assert_eq!(table.find_in_current_scope(&"foo"), Some("true"));
710 drop(outer);
711 }
712
713 #[test]
714 fn activate() {
715 let mut ptr: ScopePtr<&str, &str>;
716 let table: PersistentScopedMap<&str, &str> = PersistentScopedMap::new();
717 {
718 let a = Scope::new(&table);
719 table.try_emplace("A", "a");
720 table.try_emplace("key", "keyA");
721 let b = Scope::new(&table);
722 table.try_emplace("B", "b");
723 table.try_emplace("key", "keyB");
724 {
725 let c = Scope::new(&table);
726 table.try_emplace("C", "c");
727 table.try_emplace("key", "keyC");
728 let d = Scope::new(&table);
729 table.try_emplace("D", "d");
730 table.try_emplace("key", "keyD");
731 ptr = d.ptr();
732
733 {
734 let map = table.flatten();
735 assert_eq!(map.len(), 5);
736 assert_eq!(map.get("A"), Some(&"a"));
737 assert_eq!(map.get("B"), Some(&"b"));
738 assert_eq!(map.get("C"), Some(&"c"));
739 assert_eq!(map.get("D"), Some(&"d"));
740 assert_eq!(map.get("key"), Some(&"keyD"));
741 }
742 drop(d);
743 drop(c);
744 }
745 {
746 let map = table.flatten();
747 assert_eq!(map.len(), 3);
748 assert_eq!(map.get("A"), Some(&"a"));
749 assert_eq!(map.get("B"), Some(&"b"));
750 assert_eq!(map.get("key"), Some(&"keyB"));
751 }
752 let e = Scope::new(&table);
753 table.try_emplace("E", "e");
754 table.try_emplace("key", "keyE");
755 let f = Scope::new(&table);
756 table.try_emplace("F", "f");
757 table.try_emplace("key", "keyF");
758 let g = Scope::new(&table);
759 table.try_emplace("G", "g");
760 table.try_emplace("key", "keyG");
761 {
767 let map = table.flatten();
768 assert_eq!(map.len(), 6);
769 assert_eq!(map.get("A"), Some(&"a"));
770 assert_eq!(map.get("B"), Some(&"b"));
771 assert_eq!(map.get("E"), Some(&"e"));
772 assert_eq!(map.get("F"), Some(&"f"));
773 assert_eq!(map.get("G"), Some(&"g"));
774 assert_eq!(map.get("key"), Some(&"keyG"));
775 }
776
777 table.activate_scope(&e.ptr());
778 {
779 let map = table.flatten();
780 assert_eq!(map.len(), 4);
781 assert_eq!(map.get("A"), Some(&"a"));
782 assert_eq!(map.get("B"), Some(&"b"));
783 assert_eq!(map.get("E"), Some(&"e"));
784 assert_eq!(map.get("key"), Some(&"keyE"));
785 }
786
787 table.activate_scope(&f.ptr());
788 {
789 let map = table.flatten();
790 assert_eq!(map.len(), 5);
791 assert_eq!(map.get("A"), Some(&"a"));
792 assert_eq!(map.get("B"), Some(&"b"));
793 assert_eq!(map.get("E"), Some(&"e"));
794 assert_eq!(map.get("F"), Some(&"f"));
795 assert_eq!(map.get("key"), Some(&"keyF"));
796 }
797 table.activate_scope(&g.ptr());
798 {
799 let map = table.flatten();
800 assert_eq!(map.len(), 6);
801 assert_eq!(map.get("A"), Some(&"a"));
802 assert_eq!(map.get("B"), Some(&"b"));
803 assert_eq!(map.get("E"), Some(&"e"));
804 assert_eq!(map.get("F"), Some(&"f"));
805 assert_eq!(map.get("G"), Some(&"g"));
806 assert_eq!(map.get("key"), Some(&"keyG"));
807 }
808
809 table.activate_scope(&ptr);
811 {
812 let map = table.flatten();
813 assert_eq!(map.len(), 5);
814 assert_eq!(map.get("A"), Some(&"a"));
815 assert_eq!(map.get("B"), Some(&"b"));
816 assert_eq!(map.get("C"), Some(&"c"));
817 assert_eq!(map.get("D"), Some(&"d"));
818 assert_eq!(map.get("key"), Some(&"keyD"));
819 }
820
821 table.activate_scope(&g.ptr());
822 {
823 let map = table.flatten();
824 assert_eq!(map.len(), 6);
825 assert_eq!(map.get("A"), Some(&"a"));
826 assert_eq!(map.get("B"), Some(&"b"));
827 assert_eq!(map.get("E"), Some(&"e"));
828 assert_eq!(map.get("F"), Some(&"f"));
829 assert_eq!(map.get("G"), Some(&"g"));
830 assert_eq!(map.get("key"), Some(&"keyG"));
831 }
832 drop(g);
833 drop(f);
834 drop(e);
835 drop(b);
836 drop(a);
837 }
838 ptr.reset();
841 }
842
843 #[test]
844 fn count_and_find() {
845 let table: PersistentScopedMap<&str, &str> = PersistentScopedMap::new();
846 let outer = Scope::new(&table);
847 assert_eq!(table.count(&"foo"), 0);
848 table.try_emplace("foo", "true");
849 assert_eq!(table.count(&"foo"), 1);
850 assert_eq!(table.find(&"foo"), Some("true"));
851 assert_eq!(table.find_with_depth(&"foo"), Some(("true", 0)));
852 {
853 let _inner = Scope::new(&table);
854 table.try_emplace("foo", "inner");
855 assert_eq!(table.find_with_depth(&"foo"), Some(("inner", 1)));
856 }
857 assert_eq!(table.find_with_depth(&"foo"), Some(("true", 0)));
858 drop(outer);
859 }
860
861 #[test]
866 fn drop_last_ptr_of_popped_scope_does_not_disturb_siblings() {
867 let table: PersistentScopedMap<&str, &str> = PersistentScopedMap::new();
868 let outer = Scope::new(&table);
869 table.try_emplace("A", "a");
870
871 let mut b_ptr: ScopePtr<&str, &str>;
872 {
873 let b = Scope::new(&table);
874 table.try_emplace("B", "b");
875 b_ptr = b.ptr();
876 }
879 assert_eq!(table.lookup(&"B"), None);
880
881 b_ptr.reset();
885
886 let c_ptr;
887 {
888 let c = Scope::new(&table);
890 table.try_emplace("C", "c");
891 c_ptr = c.ptr();
892 }
893
894 table.activate_scope(&c_ptr);
896 assert_eq!(table.lookup(&"A"), Some("a"));
897 assert_eq!(table.lookup(&"C"), Some("c"));
898 assert_eq!(table.lookup(&"B"), None);
899
900 table.activate_scope(&outer.ptr());
902 drop(outer);
903 }
904}