1use std::fmt::{self, Debug};
4use std::rc::Rc;
5
6use indexmap::{IndexMap, IndexSet};
7pub use inset_embedder::{RestorationData, RestorationMap, RestorationUpdate};
8use inset_foundation::{App, ChangeNotifier, ChangeNotifierData, Handle};
9use inset_scheduler::{FrameCallback, SchedulerBinding};
10
11#[derive(Default)]
91pub struct RestorationManager {
92 change_notifier: ChangeNotifierData,
93 root_bucket: Option<Handle<RestorationBucket>>,
95 pending_root_bucket: bool,
98 root_bucket_is_valid: bool,
99 is_replacing: bool,
100 debug_doing_update: bool,
101 serialization_scheduled: bool,
102 buckets_needing_serialization: IndexSet<Handle<RestorationBucket>>,
103}
104
105impl ChangeNotifier for RestorationManager {
106 fn change_notifier_data(&self) -> &ChangeNotifierData {
107 &self.change_notifier
108 }
109
110 fn change_notifier_data_mut(&mut self) -> &mut ChangeNotifierData {
111 &mut self.change_notifier
112 }
113}
114
115impl RestorationManager {
116 pub fn instance(app: &mut App) -> Handle<RestorationManager> {
120 app.singleton::<RestorationManager>()
121 }
122
123 pub fn root_bucket(self: Handle<Self>, app: &mut App) -> Option<Handle<RestorationBucket>> {
145 if app.get(self).root_bucket_is_valid {
146 return app.get(self).root_bucket;
147 }
148 if !app.get(self).pending_root_bucket {
149 app.get_mut(self).pending_root_bucket = true;
150 self.get_root_bucket_from_engine(app);
151 }
152 app.get(self).root_bucket
153 }
154
155 pub fn is_replacing(self: Handle<Self>, app: &App) -> bool {
164 app.get(self).is_replacing
165 }
166
167 fn get_root_bucket_from_engine(self: Handle<Self>, app: &mut App) {
168 let config = app
169 .platform()
170 .restoration()
171 .and_then(|restoration| restoration.get());
172 if !app.get(self).pending_root_bucket {
173 return;
177 }
178 debug_assert!(app.get(self).root_bucket.is_none());
179 self.parse_and_handle_restoration_update_from_engine(app, config);
180 }
181
182 fn parse_and_handle_restoration_update_from_engine(
183 self: Handle<Self>,
184 app: &mut App,
185 update: Option<RestorationUpdate>,
186 ) {
187 let (enabled, data) = match update {
188 Some(update) => (update.enabled, update.data),
189 None => (false, None),
190 };
191 self.handle_restoration_update_from_engine(app, enabled, data);
192 }
193
194 pub fn handle_restoration_update_from_engine(
209 self: Handle<Self>,
210 app: &mut App,
211 enabled: bool,
212 data: Option<RestorationMap>,
213 ) {
214 debug_assert!(enabled || data.is_none());
215
216 let is_replacing = app.get(self).root_bucket_is_valid && enabled;
217 app.get_mut(self).is_replacing = is_replacing;
218 if is_replacing {
219 SchedulerBinding::add_post_frame_callback(
220 app,
221 FrameCallback::new(move |app, _| app.get_mut(self).is_replacing = false),
222 None,
223 );
224 }
225
226 let old_root = app.get(self).root_bucket;
227 let new_root = enabled.then(|| RestorationBucket::root(app, self, data));
228 let this = app.get_mut(self);
229 this.root_bucket = new_root;
230 this.root_bucket_is_valid = true;
231 this.pending_root_bucket = false;
232
233 if new_root != old_root {
234 self.notify_listeners(app);
235 if let Some(old_root) = old_root {
236 old_root.dispose(app);
237 }
238 }
239 }
240
241 pub fn send_to_engine(self: Handle<Self>, app: &mut App, encoded_data: RestorationMap) {
246 if let Some(restoration) = app.platform().restoration() {
247 restoration.put(encoded_data);
248 }
249 }
250
251 pub fn schedule_serialization_for(
259 self: Handle<Self>,
260 app: &mut App,
261 bucket: Handle<RestorationBucket>,
262 ) {
263 debug_assert!(app.get(bucket).manager == Some(self));
264 debug_assert!(!app.get(self).debug_doing_update);
265 app.get_mut(self)
266 .buckets_needing_serialization
267 .insert(bucket);
268 if !app.get(self).serialization_scheduled {
269 app.get_mut(self).serialization_scheduled = true;
270 SchedulerBinding::add_post_frame_callback(
271 app,
272 FrameCallback::new(move |app, _| self.do_serialization(app)),
273 None,
274 );
275 }
276 }
277
278 pub fn unschedule_serialization_for(
286 self: Handle<Self>,
287 app: &mut App,
288 bucket: Handle<RestorationBucket>,
289 ) {
290 debug_assert!(app.get(bucket).manager == Some(self));
291 debug_assert!(!app.get(self).debug_doing_update);
292 app.get_mut(self)
293 .buckets_needing_serialization
294 .shift_remove(&bucket);
295 }
296
297 fn do_serialization(self: Handle<Self>, app: &mut App) {
298 if !app.get(self).serialization_scheduled {
299 return;
300 }
301 if cfg!(debug_assertions) {
302 app.get_mut(self).debug_doing_update = true;
303 }
304 app.get_mut(self).serialization_scheduled = false;
305
306 let buckets = std::mem::take(&mut app.get_mut(self).buckets_needing_serialization);
307 for bucket in buckets {
308 bucket.finalize(app);
309 }
310 let root = app
311 .get(self)
312 .root_bucket
313 .expect("a bucket that scheduled serialization is in the root bucket's hierarchy");
314 let data = root.with_raw_data(app, |data| data.clone());
315 self.send_to_engine(app, data);
316
317 if cfg!(debug_assertions) {
318 app.get_mut(self).debug_doing_update = false;
319 }
320 }
321
322 pub fn flush_data(self: Handle<Self>, app: &mut App) {
340 debug_assert!(!app.get(self).debug_doing_update);
341 if SchedulerBinding::has_scheduled_frame(app) {
342 return;
343 }
344 self.do_serialization(app);
345 debug_assert!(!app.get(self).serialization_scheduled);
346 }
347
348 pub fn dispose(self: Handle<Self>, app: &mut App) {
350 if let Some(root_bucket) = app.get(self).root_bucket {
351 root_bucket.dispose(app);
352 }
353 app.get_mut(self).change_notifier.dispose();
354 }
355}
356
357const CHILDREN_MAP_KEY: &str = "c";
358const VALUES_MAP_KEY: &str = "v";
359
360fn data_key(restoration_id: &str) -> RestorationData {
362 RestorationData::String(restoration_id.to_string())
363}
364
365fn sub_map<'a>(data: &'a mut RestorationMap, key: &str) -> &'a mut RestorationMap {
367 data.entry(data_key(key))
368 .or_insert_with(|| RestorationData::Map(RestorationMap::new()))
369 .as_map_mut()
370 .expect("the values and children entries of raw data are maps")
371}
372
373enum RawData {
379 Own(RestorationMap),
380 InParent,
381}
382
383pub struct RestorationBucket {
450 manager: Option<Handle<RestorationManager>>,
451 parent: Option<Handle<RestorationBucket>>,
452 raw_data: RawData,
453 restoration_id: String,
454 claimed_children: IndexMap<String, Handle<RestorationBucket>>,
457 children_to_add: IndexMap<String, Vec<Handle<RestorationBucket>>>,
460 needs_serialization: bool,
461 debug_owner: Option<Rc<dyn Debug>>,
462}
463
464impl Debug for RestorationBucket {
465 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
466 write!(
467 f,
468 "RestorationBucket(restorationId: {}, owner: {})",
469 self.restoration_id,
470 owner_description(self)
471 )
472 }
473}
474
475fn owner_description(bucket: &RestorationBucket) -> String {
477 match &bucket.debug_owner {
478 Some(owner) => format!("{owner:?}"),
479 None => "None".to_string(),
480 }
481}
482
483impl RestorationBucket {
484 pub fn empty(
492 app: &mut App,
493 restoration_id: &str,
494 debug_owner: Option<Rc<dyn Debug>>,
495 ) -> Handle<RestorationBucket> {
496 let bucket = RestorationBucket::new(restoration_id, RestorationMap::new(), debug_owner);
497 app.create(bucket)
498 }
499
500 pub fn root(
523 app: &mut App,
524 manager: Handle<RestorationManager>,
525 raw_data: Option<RestorationMap>,
526 ) -> Handle<RestorationBucket> {
527 let debug_owner: Option<Rc<dyn Debug>> =
528 cfg!(debug_assertions).then(|| Rc::new(manager) as Rc<dyn Debug>);
529 let mut bucket = RestorationBucket::new("root", raw_data.unwrap_or_default(), debug_owner);
530 bucket.manager = Some(manager);
531 app.create(bucket)
532 }
533
534 pub fn child(
545 app: &mut App,
546 restoration_id: &str,
547 parent: Handle<RestorationBucket>,
548 debug_owner: Option<Rc<dyn Debug>>,
549 ) -> Handle<RestorationBucket> {
550 debug_assert!(parent.with_raw_children(app, |children| {
551 children.contains_key(&data_key(restoration_id))
552 }));
553 let mut bucket = RestorationBucket::new(restoration_id, RestorationMap::new(), debug_owner);
554 bucket.raw_data = RawData::InParent;
555 bucket.manager = app.get(parent).manager;
556 bucket.parent = Some(parent);
557 app.create(bucket)
558 }
559
560 fn new(
561 restoration_id: &str,
562 raw_data: RestorationMap,
563 debug_owner: Option<Rc<dyn Debug>>,
564 ) -> RestorationBucket {
565 RestorationBucket {
566 manager: None,
567 parent: None,
568 raw_data: RawData::Own(raw_data),
569 restoration_id: restoration_id.to_string(),
570 claimed_children: IndexMap::new(),
571 children_to_add: IndexMap::new(),
572 needs_serialization: false,
573 debug_owner: cfg!(debug_assertions).then_some(debug_owner).flatten(),
574 }
575 }
576
577 pub fn debug_owner(self: Handle<Self>, app: &App) -> Option<Rc<dyn Debug>> {
583 debug_assert!(self.debug_assert_not_disposed(app));
584 app.get(self).debug_owner.clone()
585 }
586
587 pub fn is_replacing(self: Handle<Self>, app: &App) -> bool {
597 app.get(self)
598 .manager
599 .is_some_and(|manager| manager.is_replacing(app))
600 }
601
602 pub fn restoration_id(self: Handle<Self>, app: &App) -> &str {
606 debug_assert!(self.debug_assert_not_disposed(app));
607 &app.get(self).restoration_id
608 }
609
610 fn with_raw_data<R>(
612 self: Handle<Self>,
613 app: &mut App,
614 action: impl FnOnce(&mut RestorationMap) -> R,
615 ) -> R {
616 let mut ancestry = Vec::new();
617 let mut owner = self;
618 while matches!(app.get(owner).raw_data, RawData::InParent) {
619 ancestry.push(data_key(&app.get(owner).restoration_id));
620 owner = app
621 .get(owner)
622 .parent
623 .expect("a bucket whose map lives in its parent has one");
624 }
625 let mut map = match &mut app.get_mut(owner).raw_data {
626 RawData::Own(map) => map,
627 RawData::InParent => unreachable!("the walk ends at the bucket that owns the map"),
628 };
629 for restoration_id in ancestry.iter().rev() {
630 map = map
631 .get_mut(&data_key(CHILDREN_MAP_KEY))
632 .and_then(RestorationData::as_map_mut)
633 .and_then(|children| children.get_mut(restoration_id))
634 .and_then(RestorationData::as_map_mut)
635 .expect("a stored bucket's map is under its parent's children");
636 }
637 action(map)
638 }
639
640 fn with_raw_children<R>(
642 self: Handle<Self>,
643 app: &mut App,
644 action: impl FnOnce(&mut RestorationMap) -> R,
645 ) -> R {
646 self.with_raw_data(app, |data| action(sub_map(data, CHILDREN_MAP_KEY)))
647 }
648
649 fn with_raw_values<R>(
651 self: Handle<Self>,
652 app: &mut App,
653 action: impl FnOnce(&mut RestorationMap) -> R,
654 ) -> R {
655 self.with_raw_data(app, |data| action(sub_map(data, VALUES_MAP_KEY)))
656 }
657
658 pub fn read(
672 self: Handle<Self>,
673 app: &mut App,
674 restoration_id: &str,
675 ) -> Option<RestorationData> {
676 debug_assert!(self.debug_assert_not_disposed(app));
677 self.with_raw_values(app, |values| values.get(&data_key(restoration_id)).cloned())
678 }
679
680 pub fn write(
696 self: Handle<Self>,
697 app: &mut App,
698 restoration_id: &str,
699 value: impl Into<RestorationData>,
700 ) {
701 debug_assert!(self.debug_assert_not_disposed(app));
702 let value = value.into();
703 let key = data_key(restoration_id);
704 let written = self.with_raw_values(app, |values| {
705 if values.get(&key) != Some(&value) || !values.contains_key(&key) {
706 values.insert(key, value);
707 return true;
708 }
709 false
710 });
711 if written {
712 self.mark_needs_serialization(app);
713 }
714 }
715
716 pub fn remove(
729 self: Handle<Self>,
730 app: &mut App,
731 restoration_id: &str,
732 ) -> Option<RestorationData> {
733 debug_assert!(self.debug_assert_not_disposed(app));
734 let key = data_key(restoration_id);
735 let (result, needs_update) = self.with_raw_data(app, |data| {
736 let values = sub_map(data, VALUES_MAP_KEY);
737 let needs_update = values.contains_key(&key);
738 let result = values.shift_remove(&key);
739 let emptied = values.is_empty();
740 if emptied {
741 data.shift_remove(&data_key(VALUES_MAP_KEY));
742 }
743 (result, needs_update)
744 });
745 if needs_update {
746 self.mark_needs_serialization(app);
747 }
748 result
749 }
750
751 pub fn contains(self: Handle<Self>, app: &mut App, restoration_id: &str) -> bool {
760 debug_assert!(self.debug_assert_not_disposed(app));
761 self.with_raw_values(app, |values| values.contains_key(&data_key(restoration_id)))
762 }
763
764 pub fn claim_child(
789 self: Handle<Self>,
790 app: &mut App,
791 restoration_id: &str,
792 debug_owner: Option<Rc<dyn Debug>>,
793 ) -> Handle<RestorationBucket> {
794 debug_assert!(self.debug_assert_not_disposed(app));
795 let claimed = app.get(self).claimed_children.contains_key(restoration_id);
810 let stored = self.with_raw_children(app, |children| {
811 children.contains_key(&data_key(restoration_id))
812 });
813 if claimed || !stored {
814 let child = RestorationBucket::empty(app, restoration_id, debug_owner);
815 self.adopt_child(app, child);
816 return child;
817 }
818
819 let child = RestorationBucket::child(app, restoration_id, self, debug_owner);
821 app.get_mut(self)
822 .claimed_children
823 .insert(restoration_id.to_string(), child);
824 child
825 }
826
827 pub fn adopt_child(self: Handle<Self>, app: &mut App, child: Handle<RestorationBucket>) {
841 debug_assert!(self.debug_assert_not_disposed(app));
842 if app.get(child).parent != Some(self) {
843 if let Some(old_parent) = app.get(child).parent {
844 old_parent.remove_child_data(app, child);
845 }
846 app.get_mut(child).parent = Some(self);
847 self.add_child_data(app, child);
848 if app.get(child).manager != app.get(self).manager {
849 self.recursively_update_manager(app, child);
850 }
851 }
852 debug_assert!(app.get(child).parent == Some(self));
853 debug_assert!(app.get(child).manager == app.get(self).manager);
854 }
855
856 fn drop_child(self: Handle<Self>, app: &mut App, child: Handle<RestorationBucket>) {
857 debug_assert!(app.get(child).parent == Some(self));
858 self.remove_child_data(app, child);
859 app.get_mut(child).parent = None;
860 if app.get(child).manager.is_some() {
861 child.update_manager(app, None);
862 child.visit_children(app, |app, grandchild| {
863 self.recursively_update_manager(app, grandchild);
864 });
865 }
866 }
867
868 fn mark_needs_serialization(self: Handle<Self>, app: &mut App) {
869 if !app.get(self).needs_serialization {
870 app.get_mut(self).needs_serialization = true;
871 if let Some(manager) = app.get(self).manager {
872 manager.schedule_serialization_for(app, self);
873 }
874 }
875 }
876
877 pub fn finalize(self: Handle<Self>, app: &mut App) {
880 debug_assert!(self.debug_assert_not_disposed(app));
881 debug_assert!(app.get(self).needs_serialization);
882 app.get_mut(self).needs_serialization = false;
883 debug_assert!(self.debug_assert_integrity(app));
884 }
885
886 fn recursively_update_manager(self: Handle<Self>, app: &mut App, bucket: Handle<Self>) {
887 bucket.update_manager(app, app.get(self).manager);
888 bucket.visit_children(app, |app, child| {
889 self.recursively_update_manager(app, child)
890 });
891 }
892
893 fn update_manager(
894 self: Handle<Self>,
895 app: &mut App,
896 new_manager: Option<Handle<RestorationManager>>,
897 ) {
898 if app.get(self).manager == new_manager {
899 return;
900 }
901 if app.get(self).needs_serialization
902 && let Some(manager) = app.get(self).manager
903 {
904 manager.unschedule_serialization_for(app, self);
905 }
906 app.get_mut(self).manager = new_manager;
907 if app.get(self).needs_serialization && app.get(self).manager.is_some() {
908 app.get_mut(self).needs_serialization = false;
909 self.mark_needs_serialization(app);
910 }
911 }
912
913 fn debug_assert_integrity(self: Handle<Self>, app: &App) -> bool {
914 if !cfg!(debug_assertions) {
915 return true;
916 }
917 let this = app.get(self);
918 if this.children_to_add.is_empty() {
919 return true;
920 }
921 let mut error = vec![
922 "Multiple owners claimed child RestorationBuckets with the same IDs.".to_string(),
923 format!("The following IDs were claimed multiple times from the parent {this:?}:"),
924 ];
925 for (restoration_id, buckets) in &this.children_to_add {
926 debug_assert!(!buckets.is_empty());
927 error.push(format!(" * \"{restoration_id}\" was claimed by:"));
928 for bucket in buckets {
929 error.push(format!(" * {}", owner_description(app.get(*bucket))));
930 }
931 let owner = this
932 .claimed_children
933 .get(restoration_id)
934 .expect("a pending child implies a current owner of the same ID");
935 error.push(format!(
936 " * {} (current owner)",
937 owner_description(app.get(*owner))
938 ));
939 }
940 panic!("{}", error.join("\n"));
941 }
942
943 fn remove_child_data(self: Handle<Self>, app: &mut App, child: Handle<RestorationBucket>) {
944 debug_assert!(app.get(child).parent == Some(self));
945 let child_id = app.get(child).restoration_id.clone();
946 if app.get_mut(self).claimed_children.shift_remove(&child_id) == Some(child) {
947 child.reclaim_raw_data(app);
948 let pending_child = app
949 .get_mut(self)
950 .children_to_add
951 .get_mut(&child_id)
952 .and_then(Vec::pop);
953 if let Some(to_add) = pending_child {
954 self.finalize_add_child_data(app, to_add);
955 if app.get(self).children_to_add[&child_id].is_empty() {
956 app.get_mut(self).children_to_add.shift_remove(&child_id);
957 }
958 }
959 let no_children = self.with_raw_children(app, |children| children.is_empty());
960 if no_children {
961 self.with_raw_data(app, |data| data.shift_remove(&data_key(CHILDREN_MAP_KEY)));
962 }
963 self.mark_needs_serialization(app);
964 return;
965 }
966 let Some(pending) = app.get_mut(self).children_to_add.get_mut(&child_id) else {
967 return;
968 };
969 if let Some(index) = pending.iter().position(|bucket| *bucket == child) {
970 pending.remove(index);
971 }
972 if pending.is_empty() {
973 app.get_mut(self).children_to_add.shift_remove(&child_id);
974 }
975 }
976
977 fn add_child_data(self: Handle<Self>, app: &mut App, child: Handle<RestorationBucket>) {
978 debug_assert!(app.get(child).parent == Some(self));
979 let child_id = app.get(child).restoration_id.clone();
980 if app.get(self).claimed_children.contains_key(&child_id) {
981 app.get_mut(self)
985 .children_to_add
986 .entry(child_id)
987 .or_default()
988 .push(child);
989 self.mark_needs_serialization(app);
990 return;
991 }
992 self.finalize_add_child_data(app, child);
993 self.mark_needs_serialization(app);
994 }
995
996 fn finalize_add_child_data(
997 self: Handle<Self>,
998 app: &mut App,
999 child: Handle<RestorationBucket>,
1000 ) {
1001 let child_id = app.get(child).restoration_id.clone();
1002 debug_assert!(!app.get(self).claimed_children.contains_key(&child_id));
1003 debug_assert!(
1004 self.with_raw_children(app, |children| !children.contains_key(&data_key(&child_id)))
1005 );
1006 app.get_mut(self)
1007 .claimed_children
1008 .insert(child_id.clone(), child);
1009 let data = match std::mem::replace(&mut app.get_mut(child).raw_data, RawData::InParent) {
1010 RawData::Own(data) => data,
1011 RawData::InParent => unreachable!("a bucket being stored owns its map"),
1012 };
1013 self.with_raw_children(app, |children| {
1014 children.insert(data_key(&child_id), RestorationData::Map(data));
1015 });
1016 }
1017
1018 fn reclaim_raw_data(self: Handle<Self>, app: &mut App) {
1021 if matches!(app.get(self).raw_data, RawData::Own(_)) {
1022 return;
1023 }
1024 let parent = app
1025 .get(self)
1026 .parent
1027 .expect("a bucket whose map lives in its parent has one");
1028 let key = data_key(&app.get(self).restoration_id);
1029 let data = parent
1030 .with_raw_children(app, |children| children.shift_remove(&key))
1031 .and_then(RestorationData::into_map)
1032 .expect("a stored bucket's map is under its parent's children");
1033 app.get_mut(self).raw_data = RawData::Own(data);
1034 }
1035
1036 fn visit_children(
1037 self: Handle<Self>,
1038 app: &mut App,
1039 visitor: impl Fn(&mut App, Handle<RestorationBucket>),
1040 ) {
1041 let this = app.get(self);
1042 let children: Vec<Handle<RestorationBucket>> = this
1043 .claimed_children
1044 .values()
1045 .copied()
1046 .chain(this.children_to_add.values().flatten().copied())
1047 .collect();
1048 for child in children {
1049 visitor(app, child);
1050 }
1051 }
1052
1053 pub fn rename(self: Handle<Self>, app: &mut App, new_restoration_id: &str) {
1066 debug_assert!(self.debug_assert_not_disposed(app));
1067 if new_restoration_id == app.get(self).restoration_id {
1068 return;
1069 }
1070 if let Some(parent) = app.get(self).parent {
1071 parent.remove_child_data(app, self);
1072 }
1073 app.get_mut(self).restoration_id = new_restoration_id.to_string();
1074 if let Some(parent) = app.get(self).parent {
1075 parent.add_child_data(app, self);
1076 }
1077 }
1078
1079 pub fn dispose(self: Handle<Self>, app: &mut App) {
1092 debug_assert!(self.debug_assert_not_disposed(app));
1093 self.visit_children(app, |app, child| self.drop_child(app, child));
1094 app.get_mut(self).claimed_children.clear();
1095 app.get_mut(self).children_to_add.clear();
1096 if let Some(parent) = app.get(self).parent {
1097 parent.remove_child_data(app, self);
1098 }
1099 app.get_mut(self).parent = None;
1100 self.update_manager(app, None);
1101 app.destroy(self);
1102 }
1103
1104 fn debug_assert_not_disposed(self: Handle<Self>, app: &App) -> bool {
1105 assert!(
1106 app.contains(self),
1107 "A RestorationBucket was used after being disposed.\n\
1108 Once you have called dispose() on a RestorationBucket, it can no longer be used."
1109 );
1110 true
1111 }
1112}
1113
1114#[cfg(test)]
1115mod tests {
1116 use inset_foundation::AppCell;
1117 use std::cell::{Cell, RefCell};
1118 use std::panic::{AssertUnwindSafe, catch_unwind};
1119 use std::time::Duration;
1120
1121 use inset_embedder::Restoration;
1122 use inset_foundation::{ListenableObject, Listener};
1123 use inset_scheduler::FrameTarget;
1124 use inset_test::{IMPLICIT_VIEW_ID, TestPlatform};
1125
1126 use super::*;
1127
1128 #[derive(Default)]
1131 struct RecordingRestoration {
1132 stored: RefCell<Option<RestorationUpdate>>,
1133 puts: RefCell<Vec<RestorationMap>>,
1134 gets: Cell<usize>,
1135 }
1136
1137 impl Restoration for RecordingRestoration {
1138 fn get(&self) -> Option<RestorationUpdate> {
1139 self.gets.set(self.gets.get() + 1);
1140 self.stored.borrow().clone()
1141 }
1142
1143 fn put(&self, data: RestorationMap) {
1144 self.puts.borrow_mut().push(data);
1145 }
1146 }
1147
1148 struct Fixture {
1149 cell: Rc<AppCell>,
1150 restoration: Rc<RecordingRestoration>,
1151 manager: Handle<RestorationManager>,
1152 }
1153
1154 impl Fixture {
1155 fn new() -> Fixture {
1156 let restoration = Rc::new(RecordingRestoration::default());
1157 let platform = TestPlatform::new()
1159 .with_restoration(restoration.clone())
1160 .with_views(&[IMPLICIT_VIEW_ID]);
1161 let cell = AppCell::with_platform(Rc::new(platform));
1162 let mut app = cell.borrow_mut();
1163 let manager = RestorationManager::instance(&mut app);
1164 drop(app);
1165 Fixture {
1166 cell,
1167 restoration,
1168 manager,
1169 }
1170 }
1171
1172 fn restored(data: RestorationMap) -> (Fixture, Handle<RestorationBucket>) {
1174 let mut fixture = Fixture::new();
1175 fixture.push_from_host(true, Some(data));
1176 let root = fixture
1177 .manager
1178 .root_bucket(&mut fixture.cell.borrow_mut())
1179 .expect("restoration is enabled");
1180 (fixture, root)
1181 }
1182
1183 fn push_from_host(&mut self, enabled: bool, data: Option<RestorationMap>) {
1185 self.manager.handle_restoration_update_from_engine(
1186 &mut self.cell.borrow_mut(),
1187 enabled,
1188 data,
1189 );
1190 }
1191
1192 fn serialize(&mut self) -> Vec<RestorationMap> {
1194 self.manager.flush_data(&mut self.cell.borrow_mut());
1195 self.restoration.puts.borrow_mut().drain(..).collect()
1196 }
1197
1198 fn serialized(&mut self) -> Option<RestorationMap> {
1200 let mut puts = self.serialize();
1201 assert!(puts.len() <= 1, "one serialization sends one message");
1202 puts.pop()
1203 }
1204
1205 fn pump(&mut self) {
1206 let views = [IMPLICIT_VIEW_ID];
1207 SchedulerBinding::handle_begin_frame(
1208 &mut self.cell.borrow_mut(),
1209 &views,
1210 Some(Duration::ZERO),
1211 );
1212 self.cell.borrow_mut().drain_microtasks();
1213 SchedulerBinding::handle_draw_frame(&mut self.cell.borrow_mut(), &views);
1214 self.cell.borrow_mut().drain_microtasks();
1215 }
1216 }
1217
1218 fn map<const N: usize>(entries: [(&str, RestorationData); N]) -> RestorationMap {
1219 entries
1220 .into_iter()
1221 .map(|(key, value)| (RestorationData::from(key), value))
1222 .collect()
1223 }
1224
1225 fn raw_data_set() -> RestorationMap {
1227 map([
1228 (
1229 "v",
1230 map([("value1", 10i64.into()), ("value2", "Hello".into())]).into(),
1231 ),
1232 (
1233 "c",
1234 map([(
1235 "child1",
1236 map([("v", map([("foo", 22i64.into())]).into())]).into(),
1237 )])
1238 .into(),
1239 ),
1240 ])
1241 }
1242
1243 fn other_raw_data_set() -> RestorationMap {
1245 map([
1246 ("v", map([("foo", 33i64.into())]).into()),
1247 (
1248 "c",
1249 map([(
1250 "childFoo",
1251 map([("v", map([("bar", "Hello".into())]).into())]).into(),
1252 )])
1253 .into(),
1254 ),
1255 ])
1256 }
1257
1258 fn at<'a>(data: &'a RestorationMap, path: &[&str]) -> Option<&'a RestorationData> {
1260 let (last, parents) = path.split_last()?;
1261 let mut map = data;
1262 for key in parents {
1263 map = map.get(&RestorationData::from(*key))?.as_map()?;
1264 }
1265 map.get(&RestorationData::from(*last))
1266 }
1267
1268 fn owner(name: &'static str) -> Option<Rc<dyn Debug>> {
1269 Some(Rc::new(name))
1270 }
1271
1272 fn panic_message(error: &Box<dyn std::any::Any + Send>) -> String {
1273 error
1274 .downcast_ref::<String>()
1275 .cloned()
1276 .or_else(|| error.downcast_ref::<&str>().map(|text| text.to_string()))
1277 .unwrap_or_default()
1278 }
1279
1280 #[test]
1281 fn the_root_bucket_comes_from_the_host_and_is_asked_for_once() {
1282 let fixture = Fixture::new();
1283 *fixture.restoration.stored.borrow_mut() = Some(RestorationUpdate {
1284 enabled: true,
1285 data: Some(raw_data_set()),
1286 });
1287
1288 let root = fixture
1289 .manager
1290 .root_bucket(&mut fixture.cell.borrow_mut())
1291 .expect("the host enabled restoration");
1292 assert_eq!(fixture.restoration.gets.get(), 1);
1293 assert_eq!(root.restoration_id(&fixture.cell.borrow()), "root");
1294 assert_eq!(
1295 root.read(&mut fixture.cell.borrow_mut(), "value1"),
1296 Some(10i64.into())
1297 );
1298 assert_eq!(
1299 root.read(&mut fixture.cell.borrow_mut(), "value2"),
1300 Some("Hello".into())
1301 );
1302
1303 let child = root.claim_child(&mut fixture.cell.borrow_mut(), "child1", None);
1304 assert_eq!(
1305 child.read(&mut fixture.cell.borrow_mut(), "foo"),
1306 Some(22i64.into())
1307 );
1308
1309 assert_eq!(
1310 fixture.manager.root_bucket(&mut fixture.cell.borrow_mut()),
1311 Some(root)
1312 );
1313 assert_eq!(
1314 fixture.restoration.gets.get(),
1315 1,
1316 "the host is asked once, then the answer is kept"
1317 );
1318 }
1319
1320 #[test]
1321 fn data_received_before_the_first_access_is_used_without_asking_the_host() {
1322 let mut fixture = Fixture::new();
1323 fixture.push_from_host(true, Some(raw_data_set()));
1324
1325 let root = fixture.manager.root_bucket(&mut fixture.cell.borrow_mut());
1326 assert!(root.is_some());
1327 assert_eq!(fixture.restoration.gets.get(), 0);
1328 }
1329
1330 #[test]
1331 fn new_data_replaces_the_root_bucket_and_notifies_listeners() {
1332 let (mut fixture, root) = Fixture::restored(raw_data_set());
1333 let child = root.claim_child(&mut fixture.cell.borrow_mut(), "child1", None);
1334 assert_eq!(
1335 child.read(&mut fixture.cell.borrow_mut(), "foo"),
1336 Some(22i64.into())
1337 );
1338
1339 let notifications = Rc::new(Cell::new(0));
1340 let counter = Rc::clone(¬ifications);
1341 fixture.manager.add_listener(
1342 &mut fixture.cell.borrow_mut(),
1343 Listener::new(move |_app| counter.set(counter.get() + 1)),
1344 );
1345
1346 fixture.push_from_host(true, Some(other_raw_data_set()));
1347 assert_eq!(notifications.get(), 1);
1348
1349 let new_root = fixture
1350 .manager
1351 .root_bucket(&mut fixture.cell.borrow_mut())
1352 .expect("restoration is still enabled");
1353 assert_ne!(new_root, root);
1354 assert!(
1355 !fixture.cell.borrow().contains(root),
1356 "the old root was disposed"
1357 );
1358
1359 child.dispose(&mut fixture.cell.borrow_mut());
1360
1361 assert_eq!(
1362 new_root.read(&mut fixture.cell.borrow_mut(), "foo"),
1363 Some(33i64.into())
1364 );
1365 assert_eq!(
1366 new_root.read(&mut fixture.cell.borrow_mut(), "value1"),
1367 None
1368 );
1369 let new_child = new_root.claim_child(&mut fixture.cell.borrow_mut(), "childFoo", None);
1370 assert_eq!(
1371 new_child.read(&mut fixture.cell.borrow_mut(), "bar"),
1372 Some("Hello".into())
1373 );
1374 }
1375
1376 #[test]
1377 fn there_is_no_root_bucket_while_restoration_is_disabled() {
1378 let mut fixture = Fixture::new();
1379 *fixture.restoration.stored.borrow_mut() = Some(RestorationUpdate {
1380 enabled: false,
1381 data: None,
1382 });
1383 let notifications = Rc::new(Cell::new(0));
1384 let counter = Rc::clone(¬ifications);
1385 fixture.manager.add_listener(
1386 &mut fixture.cell.borrow_mut(),
1387 Listener::new(move |_app| counter.set(counter.get() + 1)),
1388 );
1389
1390 assert_eq!(
1391 fixture.manager.root_bucket(&mut fixture.cell.borrow_mut()),
1392 None
1393 );
1394 assert_eq!(notifications.get(), 0);
1395
1396 fixture.push_from_host(true, Some(raw_data_set()));
1397 assert_eq!(notifications.get(), 1);
1398 assert!(
1399 fixture
1400 .manager
1401 .root_bucket(&mut fixture.cell.borrow_mut())
1402 .is_some()
1403 );
1404
1405 fixture.push_from_host(false, None);
1406 assert_eq!(notifications.get(), 2);
1407 assert_eq!(
1408 fixture.manager.root_bucket(&mut fixture.cell.borrow_mut()),
1409 None
1410 );
1411 }
1412
1413 #[test]
1414 fn a_host_that_stores_nothing_leaves_restoration_off() {
1415 let fixture = Fixture::new();
1416 assert_eq!(
1417 fixture.manager.root_bucket(&mut fixture.cell.borrow_mut()),
1418 None
1419 );
1420 assert_eq!(fixture.restoration.gets.get(), 1);
1421 }
1422
1423 #[test]
1424 fn is_replacing_is_true_until_the_end_of_the_next_frame() {
1425 let (mut fixture, root) = Fixture::restored(raw_data_set());
1426 assert!(!fixture.manager.is_replacing(&fixture.cell.borrow()));
1427 assert!(!root.is_replacing(&fixture.cell.borrow()));
1428
1429 fixture.push_from_host(true, None);
1430 let new_root = fixture
1431 .manager
1432 .root_bucket(&mut fixture.cell.borrow_mut())
1433 .expect("restoration is enabled");
1434 assert_ne!(new_root, root);
1435 assert!(fixture.manager.is_replacing(&fixture.cell.borrow()));
1436 assert!(new_root.is_replacing(&fixture.cell.borrow()));
1437
1438 fixture.pump();
1439 assert!(!fixture.manager.is_replacing(&fixture.cell.borrow()));
1440 assert!(!new_root.is_replacing(&fixture.cell.borrow()));
1441
1442 fixture.push_from_host(false, None);
1443 assert!(!fixture.manager.is_replacing(&fixture.cell.borrow()));
1444 }
1445
1446 #[test]
1447 fn scheduled_serialization_reaches_the_host_at_the_end_of_the_frame() {
1448 let (mut fixture, root) = Fixture::restored(raw_data_set());
1449 root.write(&mut fixture.cell.borrow_mut(), "value1", 22i64);
1450 assert!(fixture.restoration.puts.borrow().is_empty());
1451
1452 fixture.pump();
1453
1454 let puts = fixture
1455 .restoration
1456 .puts
1457 .borrow_mut()
1458 .drain(..)
1459 .collect::<Vec<_>>();
1460 assert_eq!(puts.len(), 1);
1461 assert_eq!(at(&puts[0], &["v", "value1"]), Some(&22i64.into()));
1462 }
1463
1464 #[test]
1465 fn flush_data_waits_for_a_scheduled_frame_and_otherwise_sends_at_once() {
1466 let (mut fixture, root) = Fixture::restored(raw_data_set());
1467 SchedulerBinding::schedule_frame(&mut fixture.cell.borrow_mut(), FrameTarget::EveryView);
1468 root.write(&mut fixture.cell.borrow_mut(), "foo", 1i64);
1469
1470 fixture.manager.flush_data(&mut fixture.cell.borrow_mut());
1471 assert!(
1472 fixture.restoration.puts.borrow().is_empty(),
1473 "the scheduled frame will flush it"
1474 );
1475
1476 fixture.pump();
1477 assert_eq!(fixture.restoration.puts.borrow_mut().drain(..).count(), 1);
1478
1479 root.write(&mut fixture.cell.borrow_mut(), "foo", 2i64);
1480 let data = fixture
1481 .serialized()
1482 .expect("a write schedules serialization");
1483 assert_eq!(at(&data, &["v", "foo"]), Some(&2i64.into()));
1484 }
1485
1486 #[test]
1487 fn nothing_is_sent_when_no_bucket_asked_for_serialization() {
1488 let (mut fixture, _root) = Fixture::restored(raw_data_set());
1489 assert!(fixture.serialized().is_none());
1490 }
1491
1492 #[test]
1493 fn root_bucket_values() {
1494 let (mut fixture, root) = Fixture::restored(raw_data_set());
1495 assert_eq!(
1496 root.debug_owner(&fixture.cell.borrow()).is_some(),
1497 cfg!(debug_assertions)
1498 );
1499 assert_eq!(
1500 root.read(&mut fixture.cell.borrow_mut(), "value1"),
1501 Some(10i64.into())
1502 );
1503 assert_eq!(
1504 root.read(&mut fixture.cell.borrow_mut(), "value2"),
1505 Some("Hello".into())
1506 );
1507 assert_eq!(root.read(&mut fixture.cell.borrow_mut(), "value3"), None);
1508 assert!(fixture.serialized().is_none());
1509
1510 root.write(&mut fixture.cell.borrow_mut(), "value1", 22i64);
1511 assert_eq!(
1512 root.read(&mut fixture.cell.borrow_mut(), "value1"),
1513 Some(22i64.into())
1514 );
1515 let data = fixture
1516 .serialized()
1517 .expect("a write schedules serialization");
1518 assert_eq!(at(&data, &["v", "value1"]), Some(&22i64.into()));
1519
1520 root.write(&mut fixture.cell.borrow_mut(), "value3", true);
1521 assert_eq!(
1522 root.read(&mut fixture.cell.borrow_mut(), "value3"),
1523 Some(true.into())
1524 );
1525 let data = fixture
1526 .serialized()
1527 .expect("a write schedules serialization");
1528 assert_eq!(at(&data, &["v", "value3"]), Some(&true.into()));
1529
1530 assert_eq!(
1531 root.remove(&mut fixture.cell.borrow_mut(), "value1"),
1532 Some(22i64.into())
1533 );
1534 assert_eq!(root.read(&mut fixture.cell.borrow_mut(), "value1"), None);
1535 let data = fixture
1536 .serialized()
1537 .expect("a removal schedules serialization");
1538 assert_eq!(at(&data, &["v", "value1"]), None);
1539
1540 assert_eq!(root.remove(&mut fixture.cell.borrow_mut(), "value4"), None);
1541 assert!(
1542 fixture.serialized().is_none(),
1543 "removing what is not there changes nothing"
1544 );
1545
1546 root.write(&mut fixture.cell.borrow_mut(), "value4", None::<i64>);
1547 assert_eq!(
1548 root.read(&mut fixture.cell.borrow_mut(), "value4"),
1549 Some(RestorationData::Null)
1550 );
1551 assert!(root.contains(&mut fixture.cell.borrow_mut(), "value4"));
1552 let data = fixture
1553 .serialized()
1554 .expect("a write schedules serialization");
1555 assert_eq!(at(&data, &["v", "value4"]), Some(&RestorationData::Null));
1556 }
1557
1558 #[test]
1559 fn child_bucket_values() {
1560 let (mut fixture, root) = Fixture::restored(raw_data_set());
1561 let child = RestorationBucket::child(
1562 &mut fixture.cell.borrow_mut(),
1563 "child1",
1564 root,
1565 owner("owner"),
1566 );
1567
1568 assert_eq!(child.restoration_id(&fixture.cell.borrow()), "child1");
1569 assert_eq!(
1570 child.read(&mut fixture.cell.borrow_mut(), "foo"),
1571 Some(22i64.into())
1572 );
1573 assert_eq!(child.read(&mut fixture.cell.borrow_mut(), "bar"), None);
1574 assert!(fixture.serialized().is_none());
1575
1576 child.write(&mut fixture.cell.borrow_mut(), "foo", 44i64);
1577 assert_eq!(
1578 child.read(&mut fixture.cell.borrow_mut(), "foo"),
1579 Some(44i64.into())
1580 );
1581 let data = fixture
1582 .serialized()
1583 .expect("a write schedules serialization");
1584 assert_eq!(at(&data, &["c", "child1", "v", "foo"]), Some(&44i64.into()));
1585
1586 assert_eq!(
1587 child.remove(&mut fixture.cell.borrow_mut(), "foo"),
1588 Some(44i64.into())
1589 );
1590 let data = fixture
1591 .serialized()
1592 .expect("a removal schedules serialization");
1593 assert_eq!(at(&data, &["c", "child1", "v", "foo"]), None);
1594 }
1595
1596 #[test]
1597 fn claiming_a_child_with_existing_data_keeps_that_data() {
1598 let (mut fixture, root) = Fixture::restored(raw_data_set());
1599 let child = root.claim_child(&mut fixture.cell.borrow_mut(), "child1", owner("owner"));
1600 assert!(
1601 fixture.serialized().is_none(),
1602 "claiming stored data changes nothing"
1603 );
1604 assert_eq!(child.restoration_id(&fixture.cell.borrow()), "child1");
1605 assert_eq!(
1606 child.read(&mut fixture.cell.borrow_mut(), "foo"),
1607 Some(22i64.into())
1608 );
1609
1610 child.write(&mut fixture.cell.borrow_mut(), "bar", 44i64);
1611 let data = fixture
1612 .serialized()
1613 .expect("a write schedules serialization");
1614 assert_eq!(at(&data, &["c", "child1", "v", "bar"]), Some(&44i64.into()));
1615 }
1616
1617 #[test]
1618 fn claiming_a_child_with_no_existing_data_gives_an_empty_bucket() {
1619 let (mut fixture, root) = Fixture::restored(raw_data_set());
1620 let child = root.claim_child(&mut fixture.cell.borrow_mut(), "child2", owner("owner"));
1621 assert_eq!(child.restoration_id(&fixture.cell.borrow()), "child2");
1622
1623 child.write(&mut fixture.cell.borrow_mut(), "foo", 55i64);
1624 assert_eq!(
1625 child.read(&mut fixture.cell.borrow_mut(), "foo"),
1626 Some(55i64.into())
1627 );
1628 let data = fixture
1629 .serialized()
1630 .expect("a new child schedules serialization");
1631 assert_eq!(at(&data, &["c", "child2", "v", "foo"]), Some(&55i64.into()));
1632 }
1633
1634 #[cfg(debug_assertions)]
1635 #[test]
1636 fn claiming_a_claimed_child_reports_the_duplicate_ids_at_finalization() {
1637 let (mut fixture, root) = Fixture::restored(raw_data_set());
1638 let _first = root.claim_child(
1639 &mut fixture.cell.borrow_mut(),
1640 "child1",
1641 owner("FirstClaim"),
1642 );
1643 let second = root.claim_child(
1644 &mut fixture.cell.borrow_mut(),
1645 "child1",
1646 owner("SecondClaim"),
1647 );
1648 assert_eq!(second.read(&mut fixture.cell.borrow_mut(), "foo"), None);
1649
1650 let error = catch_unwind(AssertUnwindSafe(|| fixture.serialized())).unwrap_err();
1651 let message = panic_message(&error);
1652 assert!(
1653 message.contains("Multiple owners claimed child RestorationBuckets with the same IDs."),
1654 "{message}"
1655 );
1656 assert!(
1657 message.contains(" * \"child1\" was claimed by:"),
1658 "{message}"
1659 );
1660 assert!(message.contains("\"SecondClaim\""), "{message}");
1661 assert!(
1662 message.contains("\"FirstClaim\" (current owner)"),
1663 "{message}"
1664 );
1665 }
1666
1667 #[test]
1668 fn claiming_a_claimed_child_is_fine_once_the_first_owner_gives_it_up() {
1669 let (mut fixture, root) = Fixture::restored(raw_data_set());
1670 let first = root.claim_child(
1671 &mut fixture.cell.borrow_mut(),
1672 "child1",
1673 owner("FirstClaim"),
1674 );
1675 let second = root.claim_child(
1676 &mut fixture.cell.borrow_mut(),
1677 "child1",
1678 owner("SecondClaim"),
1679 );
1680 second.write(&mut fixture.cell.borrow_mut(), "bar", 55i64);
1681
1682 first.dispose(&mut fixture.cell.borrow_mut());
1683
1684 let data = fixture
1685 .serialized()
1686 .expect("the shuffle schedules serialization");
1687 assert_eq!(at(&data, &["c", "child1", "v", "foo"]), None);
1688 assert_eq!(at(&data, &["c", "child1", "v", "bar"]), Some(&55i64.into()));
1689 }
1690
1691 #[test]
1692 fn unclaiming_and_claiming_the_same_id_gives_a_fresh_bucket() {
1693 let (fixture, root) = Fixture::restored(raw_data_set());
1694 let first = root.claim_child(
1695 &mut fixture.cell.borrow_mut(),
1696 "child1",
1697 owner("FirstClaim"),
1698 );
1699 assert_eq!(
1700 first.read(&mut fixture.cell.borrow_mut(), "foo"),
1701 Some(22i64.into())
1702 );
1703 first.dispose(&mut fixture.cell.borrow_mut());
1704
1705 let second = root.claim_child(
1706 &mut fixture.cell.borrow_mut(),
1707 "child1",
1708 owner("SecondClaim"),
1709 );
1710 assert_eq!(second.read(&mut fixture.cell.borrow_mut(), "foo"), None);
1711 }
1712
1713 #[test]
1714 fn the_raw_data_drops_the_values_and_children_maps_when_they_empty_out() {
1715 let (mut fixture, root) = Fixture::restored(raw_data_set());
1716 let child = root.claim_child(&mut fixture.cell.borrow_mut(), "child1", owner("owner"));
1717 child.dispose(&mut fixture.cell.borrow_mut());
1718 let data = fixture
1719 .serialized()
1720 .expect("dropping a child schedules serialization");
1721 assert_eq!(at(&data, &["c"]), None);
1722
1723 assert_eq!(
1724 root.remove(&mut fixture.cell.borrow_mut(), "value1"),
1725 Some(10i64.into())
1726 );
1727 assert_eq!(
1728 root.remove(&mut fixture.cell.borrow_mut(), "value2"),
1729 Some("Hello".into())
1730 );
1731 let data = fixture
1732 .serialized()
1733 .expect("a removal schedules serialization");
1734 assert_eq!(at(&data, &["v"]), None);
1735 }
1736
1737 #[test]
1738 fn dispose_deletes_the_data_of_the_whole_subtree() {
1739 let (mut fixture, root) = Fixture::restored(raw_data_set());
1740 let child1 = root.claim_child(&mut fixture.cell.borrow_mut(), "child1", owner("owner1"));
1741 child1.claim_child(
1742 &mut fixture.cell.borrow_mut(),
1743 "child1OfChild1",
1744 owner("owner1.1"),
1745 );
1746 let child2 = root.claim_child(&mut fixture.cell.borrow_mut(), "child2", owner("owner2"));
1747 child2.write(&mut fixture.cell.borrow_mut(), "foo", 1i64);
1748
1749 let data = fixture
1750 .serialized()
1751 .expect("new children schedule serialization");
1752 assert!(at(&data, &["c", "child1"]).is_some());
1753 assert!(at(&data, &["c", "child2"]).is_some());
1754
1755 child1.dispose(&mut fixture.cell.borrow_mut());
1756 let data = fixture
1757 .serialized()
1758 .expect("dropping a child schedules serialization");
1759 assert_eq!(at(&data, &["c", "child1"]), None);
1760
1761 child2.dispose(&mut fixture.cell.borrow_mut());
1762 let data = fixture
1763 .serialized()
1764 .expect("dropping a child schedules serialization");
1765 assert_eq!(at(&data, &["c"]), None);
1766 }
1767
1768 #[test]
1769 fn rename_to_the_same_id_changes_nothing() {
1770 let (mut fixture, root) = Fixture::restored(raw_data_set());
1771 let child = root.claim_child(&mut fixture.cell.borrow_mut(), "child1", owner("owner1"));
1772
1773 child.rename(&mut fixture.cell.borrow_mut(), "child1");
1774 assert_eq!(child.restoration_id(&fixture.cell.borrow()), "child1");
1775 assert!(fixture.serialized().is_none());
1776 }
1777
1778 #[test]
1779 fn rename_to_an_unused_id_moves_the_data() {
1780 let (mut fixture, root) = Fixture::restored(raw_data_set());
1781 let child = root.claim_child(&mut fixture.cell.borrow_mut(), "child1", owner("owner1"));
1782
1783 child.rename(&mut fixture.cell.borrow_mut(), "new-name");
1784 assert_eq!(child.restoration_id(&fixture.cell.borrow()), "new-name");
1785
1786 let data = fixture
1787 .serialized()
1788 .expect("a rename schedules serialization");
1789 assert_eq!(at(&data, &["c", "child1"]), None);
1790 assert_eq!(
1791 at(&data, &["c", "new-name", "v", "foo"]),
1792 Some(&22i64.into())
1793 );
1794 }
1795
1796 #[cfg(debug_assertions)]
1797 #[test]
1798 fn rename_onto_a_used_id_reports_the_duplicate_unless_it_is_given_up() {
1799 let (mut fixture, root) = Fixture::restored(raw_data_set());
1800 let _child1 = root.claim_child(&mut fixture.cell.borrow_mut(), "child1", owner("owner1"));
1801 let child2 = root.claim_child(&mut fixture.cell.borrow_mut(), "child2", owner("owner2"));
1802 child2.rename(&mut fixture.cell.borrow_mut(), "child1");
1803
1804 let error = catch_unwind(AssertUnwindSafe(|| fixture.serialized())).unwrap_err();
1805 assert!(
1806 panic_message(&error)
1807 .contains("Multiple owners claimed child RestorationBuckets with the same IDs."),
1808 );
1809 }
1810
1811 #[test]
1812 fn rename_onto_a_given_up_id_takes_it_over() {
1813 let (mut fixture, root) = Fixture::restored(raw_data_set());
1814 let child1 = root.claim_child(&mut fixture.cell.borrow_mut(), "child1", owner("owner1"));
1815 let child2 = root.claim_child(&mut fixture.cell.borrow_mut(), "child2", owner("owner2"));
1816 child2.write(&mut fixture.cell.borrow_mut(), "bar", 7i64);
1817 fixture.serialize();
1818
1819 child2.rename(&mut fixture.cell.borrow_mut(), "child1");
1820 child1.dispose(&mut fixture.cell.borrow_mut());
1821
1822 let data = fixture
1823 .serialized()
1824 .expect("the shuffle schedules serialization");
1825 assert_eq!(at(&data, &["c", "child1", "v", "bar"]), Some(&7i64.into()));
1826 assert_eq!(at(&data, &["c", "child2"]), None);
1827 }
1828
1829 #[test]
1830 fn renaming_a_child_that_is_still_waiting_for_its_id() {
1831 let (mut fixture, root) = Fixture::restored(raw_data_set());
1832 let child1 = root.claim_child(&mut fixture.cell.borrow_mut(), "child1", owner("owner1"));
1833 let child2 = root.claim_child(&mut fixture.cell.borrow_mut(), "child1", owner("owner2"));
1834
1835 child2.rename(&mut fixture.cell.borrow_mut(), "foo");
1836
1837 let data = fixture
1838 .serialized()
1839 .expect("the shuffle schedules serialization");
1840 assert_eq!(child1.restoration_id(&fixture.cell.borrow()), "child1");
1841 assert_eq!(child2.restoration_id(&fixture.cell.borrow()), "foo");
1842 assert_eq!(at(&data, &["c", "child1", "v", "foo"]), Some(&22i64.into()));
1843 assert_eq!(
1844 at(&data, &["c", "foo"]),
1845 Some(&RestorationMap::new().into())
1846 );
1847 }
1848
1849 #[test]
1850 fn adopting_a_child_of_this_bucket_changes_nothing() {
1851 let (mut fixture, root) = Fixture::restored(raw_data_set());
1852 let child = root.claim_child(&mut fixture.cell.borrow_mut(), "child1", owner("owner1"));
1853
1854 root.adopt_child(&mut fixture.cell.borrow_mut(), child);
1855 assert!(fixture.serialized().is_none());
1856 }
1857
1858 #[test]
1859 fn adopting_a_fresh_child_puts_it_in_the_hierarchy() {
1860 let (mut fixture, root) = Fixture::restored(raw_data_set());
1861 let child = RestorationBucket::empty(
1862 &mut fixture.cell.borrow_mut(),
1863 "fresh-child",
1864 owner("owner1"),
1865 );
1866 assert!(!child.is_replacing(&fixture.cell.borrow()));
1867
1868 root.adopt_child(&mut fixture.cell.borrow_mut(), child);
1869 child.write(&mut fixture.cell.borrow_mut(), "value", 22i64);
1870
1871 let data = fixture
1872 .serialized()
1873 .expect("an adoption schedules serialization");
1874 assert_eq!(
1875 at(&data, &["c", "fresh-child", "v", "value"]),
1876 Some(&22i64.into())
1877 );
1878 }
1879
1880 #[test]
1881 fn adopting_a_child_that_already_had_a_parent_moves_its_data() {
1882 let (mut fixture, root) = Fixture::restored(raw_data_set());
1883 let child = root.claim_child(&mut fixture.cell.borrow_mut(), "child1", owner("owner1"));
1884 let child_of_child = child.claim_child(
1885 &mut fixture.cell.borrow_mut(),
1886 "childOfChild",
1887 owner("owner2"),
1888 );
1889 child_of_child.write(&mut fixture.cell.borrow_mut(), "foo", "bar");
1890 let data = fixture
1891 .serialized()
1892 .expect("a write schedules serialization");
1893 assert_eq!(
1894 at(&data, &["c", "child1", "c", "childOfChild", "v", "foo"]),
1895 Some(&"bar".into())
1896 );
1897
1898 root.adopt_child(&mut fixture.cell.borrow_mut(), child_of_child);
1899
1900 let data = fixture
1901 .serialized()
1902 .expect("an adoption schedules serialization");
1903 assert_eq!(at(&data, &["c", "child1", "c"]), None);
1904 assert_eq!(
1905 at(&data, &["c", "childOfChild", "v", "foo"]),
1906 Some(&"bar".into())
1907 );
1908 }
1909
1910 #[cfg(debug_assertions)]
1911 #[test]
1912 fn adopting_onto_a_used_id_reports_the_duplicate_unless_it_is_given_up() {
1913 let (mut fixture, root) = Fixture::restored(raw_data_set());
1914 let child = root.claim_child(&mut fixture.cell.borrow_mut(), "child1", owner("owner1"));
1915 let child_of_child =
1916 child.claim_child(&mut fixture.cell.borrow_mut(), "child1", owner("owner2"));
1917 child_of_child.write(&mut fixture.cell.borrow_mut(), "foo", "bar");
1918
1919 root.adopt_child(&mut fixture.cell.borrow_mut(), child_of_child);
1920
1921 let error = catch_unwind(AssertUnwindSafe(|| fixture.serialized())).unwrap_err();
1922 assert!(
1923 panic_message(&error)
1924 .contains("Multiple owners claimed child RestorationBuckets with the same IDs."),
1925 );
1926 }
1927
1928 #[test]
1929 fn adopting_onto_a_given_up_id_takes_it_over() {
1930 let (mut fixture, root) = Fixture::restored(raw_data_set());
1931 let child = root.claim_child(&mut fixture.cell.borrow_mut(), "child1", owner("owner1"));
1932 let child_of_child =
1933 child.claim_child(&mut fixture.cell.borrow_mut(), "child1", owner("owner2"));
1934 child_of_child.write(&mut fixture.cell.borrow_mut(), "foo", "bar");
1935 fixture.serialize();
1936
1937 root.adopt_child(&mut fixture.cell.borrow_mut(), child_of_child);
1938 child.dispose(&mut fixture.cell.borrow_mut());
1939
1940 let data = fixture
1941 .serialized()
1942 .expect("the shuffle schedules serialization");
1943 assert_eq!(at(&data, &["c", "child1", "v", "foo"]), Some(&"bar".into()));
1944 }
1945
1946 #[test]
1947 fn a_child_of_a_parentless_bucket_joins_the_manager_when_it_is_adopted() {
1948 let (mut fixture, root) = Fixture::restored(raw_data_set());
1949 let detached =
1950 RestorationBucket::empty(&mut fixture.cell.borrow_mut(), "detached", owner("owner1"));
1951 let child = detached.claim_child(&mut fixture.cell.borrow_mut(), "leaf", owner("owner2"));
1952 child.write(&mut fixture.cell.borrow_mut(), "foo", 3i64);
1953 assert!(
1954 fixture.serialized().is_none(),
1955 "a bucket outside the hierarchy has no manager to schedule with"
1956 );
1957
1958 root.adopt_child(&mut fixture.cell.borrow_mut(), detached);
1959
1960 let data = fixture
1961 .serialized()
1962 .expect("an adoption schedules serialization");
1963 assert_eq!(
1964 at(&data, &["c", "detached", "c", "leaf", "v", "foo"]),
1965 Some(&3i64.into())
1966 );
1967 }
1968
1969 #[cfg(debug_assertions)]
1970 #[test]
1971 fn a_bucket_cannot_be_used_after_it_is_disposed() {
1972 let cell = AppCell::new();
1973 let mut app = cell.borrow_mut();
1974 let bucket = RestorationBucket::empty(&mut app, "foo", None);
1975 bucket.dispose(&mut app);
1976
1977 let error = catch_unwind(AssertUnwindSafe(|| bucket.read(&mut app, "foo"))).unwrap_err();
1978 assert!(
1979 panic_message(&error).contains("A RestorationBucket was used after being disposed."),
1980 );
1981 }
1982
1983 #[test]
1984 fn disposing_the_manager_disposes_the_root_bucket() {
1985 let (fixture, root) = Fixture::restored(raw_data_set());
1986 fixture.manager.dispose(&mut fixture.cell.borrow_mut());
1987 assert!(!fixture.cell.borrow().contains(root));
1988 }
1989
1990 #[test]
1991 fn a_bucket_reports_the_owner_it_was_claimed_with() {
1992 let (fixture, root) = Fixture::restored(raw_data_set());
1993 let child = root.claim_child(&mut fixture.cell.borrow_mut(), "child1", owner("owner1"));
1994 let described = format!("{:?}", fixture.cell.borrow().get(child));
1995 if cfg!(debug_assertions) {
1996 assert_eq!(
1997 described,
1998 "RestorationBucket(restorationId: child1, owner: \"owner1\")"
1999 );
2000 } else {
2001 assert_eq!(
2002 described,
2003 "RestorationBucket(restorationId: child1, owner: None)"
2004 );
2005 }
2006 }
2007}