1use std::any::TypeId;
4use std::cell::Cell;
5use std::fmt::{self, Debug};
6use std::hash::{Hash, Hasher};
7use std::rc::Rc;
8
9use crate::app::{App, Handle, HandleId};
10
11#[derive(Clone)]
20pub struct Listener {
21 callback: Rc<dyn Fn(&mut App)>,
22 identity: ListenerIdentity,
23}
24
25#[derive(Clone, Copy)]
29enum ListenerIdentity {
30 Closure,
31 HandleMethod(HandleId, TypeId),
32}
33
34impl Listener {
35 pub fn new(callback: impl Fn(&mut App) + 'static) -> Listener {
37 Listener {
38 callback: Rc::new(callback),
39 identity: ListenerIdentity::Closure,
40 }
41 }
42
43 pub fn handle_method<T: 'static, F>(this: Handle<T>, f: F) -> Listener
51 where
52 F: Fn(Handle<T>, &mut App) + 'static,
53 {
54 const {
55 assert!(
56 std::mem::size_of::<F>() == 0,
57 "pass the function by name: a fn pointer or capturing closure \
58 has no canonical identity to match on removal"
59 )
60 };
61 Listener {
62 callback: Rc::new(move |app: &mut App| f(this, app)),
63 identity: ListenerIdentity::HandleMethod(this.id(), TypeId::of::<F>()),
64 }
65 }
66
67 pub fn call(&self, app: &mut App) {
69 (self.callback)(app);
70 }
71}
72
73impl PartialEq for Listener {
74 fn eq(&self, other: &Listener) -> bool {
75 match (self.identity, other.identity) {
76 (ListenerIdentity::Closure, ListenerIdentity::Closure) => {
77 Rc::ptr_eq(&self.callback, &other.callback)
78 }
79 (
80 ListenerIdentity::HandleMethod(handle, function),
81 ListenerIdentity::HandleMethod(other_handle, other_function),
82 ) => handle == other_handle && function == other_function,
83 _ => false,
84 }
85 }
86}
87
88impl Eq for Listener {}
89
90impl Hash for Listener {
91 fn hash<H: Hasher>(&self, state: &mut H) {
92 match self.identity {
93 ListenerIdentity::Closure => (Rc::as_ptr(&self.callback) as *const ()).hash(state),
94 ListenerIdentity::HandleMethod(handle, function) => {
95 handle.hash(state);
96 function.hash(state);
97 }
98 }
99 }
100}
101
102impl Debug for Listener {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 f.write_str("Listener")
105 }
106}
107
108pub trait Listenable {
133 fn add_listener(&self, app: &mut App, listener: Listener);
135
136 fn remove_listener(&self, app: &mut App, listener: &Listener);
139}
140
141pub struct MergingListenable {
151 children: Vec<Option<Rc<dyn Listenable>>>,
152}
153
154impl MergingListenable {
155 pub fn new(children: Vec<Option<Rc<dyn Listenable>>>) -> MergingListenable {
157 MergingListenable { children }
158 }
159}
160
161impl Listenable for MergingListenable {
162 fn add_listener(&self, app: &mut App, listener: Listener) {
163 for child in self.children.iter().flatten() {
164 child.add_listener(app, listener.clone());
165 }
166 }
167
168 fn remove_listener(&self, app: &mut App, listener: &Listener) {
169 for child in self.children.iter().flatten() {
170 child.remove_listener(app, listener);
171 }
172 }
173}
174
175impl Debug for MergingListenable {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 write!(f, "Listenable::merge([{} children])", self.children.len())
178 }
179}
180
181pub trait ValueListenable<T>: Listenable {
188 fn value<'a>(&'a self, app: &'a App) -> &'a T;
193}
194
195#[derive(Debug, Default)]
197pub struct ChangeNotifierData {
198 count: usize,
199 listeners: Vec<Option<Listener>>,
203 notification_call_stack_depth: Rc<Cell<usize>>,
205 reentrantly_removed_listeners: usize,
206 #[cfg(debug_assertions)]
207 debug_disposed: bool,
208}
209
210impl ChangeNotifierData {
211 pub fn new() -> ChangeNotifierData {
213 ChangeNotifierData::default()
214 }
215
216 pub fn debug_assert_not_disposed(notifier: &ChangeNotifierData) -> bool {
233 #[cfg(debug_assertions)]
234 assert!(
235 !notifier.debug_disposed,
236 "A ChangeNotifier was used after being disposed.\n\
237 Once you have called dispose() on a ChangeNotifier, it can no longer be used."
238 );
239 let _ = notifier;
240 true
241 }
242
243 pub fn has_listeners(&self) -> bool {
266 self.count > 0
267 }
268
269 pub fn add_listener(&mut self, listener: Listener) {
297 debug_assert!(ChangeNotifierData::debug_assert_not_disposed(self));
298
299 if self.count == self.listeners.len() {
300 if self.count == 0 {
301 self.listeners = vec![None; 1];
302 } else {
303 let mut new_listeners = vec![None; self.listeners.len() * 2];
304 new_listeners[..self.count].clone_from_slice(&self.listeners[..self.count]);
305 self.listeners = new_listeners;
306 }
307 }
308 self.listeners[self.count] = Some(listener);
309 self.count += 1;
310 }
311
312 fn remove_at(&mut self, index: usize) {
313 self.count -= 1;
319 if self.count * 2 <= self.listeners.len() {
320 let mut new_listeners = vec![None; self.count];
321
322 new_listeners[..index].clone_from_slice(&self.listeners[..index]);
324
325 new_listeners[index..self.count]
327 .clone_from_slice(&self.listeners[index + 1..self.count + 1]);
328
329 self.listeners = new_listeners;
330 } else {
331 for i in index..self.count {
335 let moved = self.listeners[i + 1].clone();
336 self.listeners[i] = moved;
337 }
338 self.listeners[self.count] = None;
339 }
340 }
341
342 pub fn remove_listener(&mut self, listener: &Listener) {
365 for i in 0..self.count {
371 if self.listeners[i].as_ref() == Some(listener) {
372 if self.notification_call_stack_depth.get() > 0 {
373 self.listeners[i] = None;
378 self.reentrantly_removed_listeners += 1;
379 } else {
380 self.remove_at(i);
383 }
384 break;
385 }
386 }
387 }
388
389 pub fn dispose(&mut self) {
403 debug_assert!(ChangeNotifierData::debug_assert_not_disposed(self));
404 debug_assert!(
405 self.notification_call_stack_depth.get() == 0,
406 "The \"dispose()\" method on {self:?} was called during the call to \
407 \"notify_listeners()\". This is likely to cause errors since it modifies \
408 the list of listeners while the list is being used."
409 );
410 #[cfg(debug_assertions)]
411 {
412 self.debug_disposed = true;
413 }
414 self.listeners = Vec::new();
415 self.count = 0;
416 self.reentrantly_removed_listeners = 0;
423 }
424
425 pub(crate) fn notify_listeners<T: 'static>(
428 app: &mut App,
429 owner: Handle<T>,
430 field: fn(&mut T) -> &mut ChangeNotifierData,
431 ) {
432 let (notification, end) = {
433 let notifier = field(app.get_mut(owner));
434 debug_assert!(ChangeNotifierData::debug_assert_not_disposed(notifier));
435 if notifier.count == 0 {
436 return;
437 }
438
439 let notification =
450 Notification::begin(Rc::clone(¬ifier.notification_call_stack_depth));
451 (notification, notifier.count)
452 };
453
454 for i in 0..end {
455 let listener = field(app.get_mut(owner)).listeners[i].clone();
456 if let Some(listener) = listener {
457 listener.call(app);
458 }
459 }
460
461 drop(notification);
462
463 let notifier = field(app.get_mut(owner));
464 if notifier.notification_call_stack_depth.get() == 0
465 && notifier.reentrantly_removed_listeners > 0
466 {
467 notifier.compact_reentrantly_removed_listeners();
468 }
469 }
470
471 fn compact_reentrantly_removed_listeners(&mut self) {
472 let new_length = self.count - self.reentrantly_removed_listeners;
474 if new_length * 2 <= self.listeners.len() {
475 let mut new_listeners = vec![None; new_length];
478
479 let mut new_index = 0;
480 for listener in &self.listeners[..self.count] {
481 if listener.is_some() {
482 new_listeners[new_index] = listener.clone();
483 new_index += 1;
484 }
485 }
486
487 self.listeners = new_listeners;
488 } else {
489 for i in 0..new_length {
491 if self.listeners[i].is_none() {
492 let mut swap_index = i + 1;
494 while self.listeners[swap_index].is_none() {
495 swap_index += 1;
496 }
497 self.listeners.swap(i, swap_index);
498 }
499 }
500 }
501
502 self.reentrantly_removed_listeners = 0;
503 self.count = new_length;
504 }
505}
506
507struct Notification {
510 depth: Rc<Cell<usize>>,
511}
512
513impl Notification {
514 fn begin(depth: Rc<Cell<usize>>) -> Notification {
515 depth.set(depth.get() + 1);
516 Notification { depth }
517 }
518}
519
520impl Drop for Notification {
521 fn drop(&mut self) {
522 self.depth.set(self.depth.get() - 1);
523 }
524}
525
526pub trait ListenableObject: Sized + 'static {
534 fn add_listener(self: Handle<Self>, app: &mut App, listener: Listener);
536
537 fn remove_listener(self: Handle<Self>, app: &mut App, listener: &Listener);
540}
541
542impl<T: ChangeNotifier> ListenableObject for T {
543 fn add_listener(self: Handle<Self>, app: &mut App, listener: Listener) {
544 ChangeNotifier::will_add_listener(self, app);
545 app.get_mut(self)
546 .change_notifier_data_mut()
547 .add_listener(listener);
548 }
549
550 fn remove_listener(self: Handle<Self>, app: &mut App, listener: &Listener) {
551 if !app.contains(self) {
554 return;
555 }
556 app.get_mut(self)
557 .change_notifier_data_mut()
558 .remove_listener(listener);
559 ChangeNotifier::did_remove_listener(self, app);
560 }
561}
562
563impl<T: ListenableObject> Listenable for Handle<T> {
564 fn add_listener(&self, app: &mut App, listener: Listener) {
565 T::add_listener(*self, app, listener);
566 }
567
568 fn remove_listener(&self, app: &mut App, listener: &Listener) {
569 T::remove_listener(*self, app, listener);
570 }
571}
572
573pub trait ChangeNotifier: Sized + 'static {
587 fn change_notifier_data(&self) -> &ChangeNotifierData;
588
589 fn change_notifier_data_mut(&mut self) -> &mut ChangeNotifierData;
590
591 fn will_add_listener(self: Handle<Self>, app: &mut App) {
594 let _ = app;
595 }
596
597 fn did_remove_listener(self: Handle<Self>, app: &mut App) {
600 let _ = app;
601 }
602}
603
604impl ChangeNotifier for ChangeNotifierData {
605 fn change_notifier_data(&self) -> &ChangeNotifierData {
606 self
607 }
608
609 fn change_notifier_data_mut(&mut self) -> &mut ChangeNotifierData {
610 self
611 }
612}
613
614impl<T: ChangeNotifier> Handle<T> {
615 pub fn notify_listeners(self, app: &mut App) {
629 ChangeNotifierData::notify_listeners(app, self, T::change_notifier_data_mut);
630 }
631}
632
633#[derive(Debug, Default)]
650pub struct ValueNotifier<T> {
651 change_notifier: ChangeNotifierData,
652 value: T,
653}
654
655impl<T> ValueNotifier<T> {
656 pub fn new(value: T) -> ValueNotifier<T> {
658 ValueNotifier {
659 change_notifier: ChangeNotifierData::new(),
660 value,
661 }
662 }
663
664 pub fn value(&self) -> &T {
667 &self.value
668 }
669
670 pub fn dispose(&mut self) {
672 self.change_notifier.dispose();
673 }
674}
675
676impl<T: 'static> ChangeNotifier for ValueNotifier<T> {
677 fn change_notifier_data(&self) -> &ChangeNotifierData {
678 &self.change_notifier
679 }
680
681 fn change_notifier_data_mut(&mut self) -> &mut ChangeNotifierData {
682 &mut self.change_notifier
683 }
684}
685
686impl<T: PartialEq + 'static> Handle<ValueNotifier<T>> {
687 pub fn set_value(self, app: &mut App, new_value: T) {
692 if app.get(self).value == new_value {
693 return;
694 }
695 app.get_mut(self).value = new_value;
696 self.notify_listeners(app);
697 }
698}
699
700impl<T: 'static> ValueListenable<T> for Handle<ValueNotifier<T>> {
701 fn value<'a>(&'a self, app: &'a App) -> &'a T {
702 app.get(*self).value()
703 }
704}
705
706#[cfg(test)]
707mod tests {
708 use std::cell::RefCell;
709 use std::panic::{AssertUnwindSafe, catch_unwind};
710
711 use super::*;
712 use crate::app_cell::AppCell;
713
714 type Log = Rc<RefCell<Vec<String>>>;
715
716 fn fired(log: &Log) -> Vec<String> {
717 log.borrow().clone()
718 }
719
720 #[derive(Default)]
721 struct TestNotifier {
722 change_notifier: ChangeNotifierData,
723 }
724
725 impl ChangeNotifier for TestNotifier {
726 fn change_notifier_data(&self) -> &ChangeNotifierData {
727 &self.change_notifier
728 }
729
730 fn change_notifier_data_mut(&mut self) -> &mut ChangeNotifierData {
731 &mut self.change_notifier
732 }
733 }
734
735 fn recording(log: &Log, name: &'static str) -> Listener {
736 let log = Rc::clone(log);
737 Listener::new(move |_app| log.borrow_mut().push(name.to_string()))
738 }
739
740 fn add(app: &mut App, host: Handle<TestNotifier>, listener: Listener) {
741 host.add_listener(app, listener);
742 }
743
744 fn remove(app: &mut App, host: Handle<TestNotifier>, listener: &Listener) {
745 host.remove_listener(app, listener);
746 }
747
748 fn notify(app: &mut App, host: Handle<TestNotifier>) {
749 host.notify_listeners(app);
750 }
751
752 fn silence_panic_hook() -> Box<dyn Fn(&std::panic::PanicHookInfo<'_>) + Send + Sync + 'static> {
753 let hook = std::panic::take_hook();
754 std::panic::set_hook(Box::new(|_| {}));
755 hook
756 }
757
758 #[test]
760 fn listeners_are_called_in_the_order_they_were_added() {
761 let cell = AppCell::new();
762 let mut app = cell.borrow_mut();
763 let log = Log::default();
764 let host = app.create(TestNotifier::default());
765
766 let listener = recording(&log, "listener");
767 add(&mut app, host, listener.clone());
768 add(&mut app, host, listener.clone());
769 notify(&mut app, host);
770 assert_eq!(fired(&log), ["listener", "listener"]);
771 log.borrow_mut().clear();
772
773 remove(&mut app, host, &listener);
774 notify(&mut app, host);
775 assert_eq!(fired(&log), ["listener"]);
776 log.borrow_mut().clear();
777
778 remove(&mut app, host, &listener);
779 notify(&mut app, host);
780 assert_eq!(fired(&log), Vec::<String>::new());
781 log.borrow_mut().clear();
782
783 remove(&mut app, host, &listener);
784 notify(&mut app, host);
785 assert_eq!(fired(&log), Vec::<String>::new());
786 log.borrow_mut().clear();
787
788 add(&mut app, host, listener.clone());
789 notify(&mut app, host);
790 assert_eq!(fired(&log), ["listener"]);
791 log.borrow_mut().clear();
792
793 let listener1 = recording(&log, "listener1");
794 add(&mut app, host, listener1.clone());
795 notify(&mut app, host);
796 assert_eq!(fired(&log), ["listener", "listener1"]);
797 log.borrow_mut().clear();
798
799 let listener2 = recording(&log, "listener2");
800 add(&mut app, host, listener2.clone());
801 notify(&mut app, host);
802 assert_eq!(fired(&log), ["listener", "listener1", "listener2"]);
803 log.borrow_mut().clear();
804
805 remove(&mut app, host, &listener1);
806 notify(&mut app, host);
807 assert_eq!(fired(&log), ["listener", "listener2"]);
808 log.borrow_mut().clear();
809
810 add(&mut app, host, listener1.clone());
811 notify(&mut app, host);
812 assert_eq!(fired(&log), ["listener", "listener2", "listener1"]);
813 }
814
815 #[test]
817 fn a_listener_mutates_the_notifier_dispatching_to_it() {
818 let cell = AppCell::new();
819 let mut app = cell.borrow_mut();
820 let log = Log::default();
821 let host = app.create(TestNotifier::default());
822
823 let listener1 = recording(&log, "listener1");
824 let listener3 = recording(&log, "listener3");
825 let listener4 = recording(&log, "listener4");
826 let listener2 = {
827 let log = Rc::clone(&log);
828 let (one, three, four) = (listener1.clone(), listener3.clone(), listener4.clone());
829 Listener::new(move |app: &mut App| {
830 log.borrow_mut().push("listener2".to_string());
831 let notifier = &mut app.get_mut(host).change_notifier;
832 notifier.remove_listener(&one);
833 notifier.remove_listener(&three);
834 notifier.add_listener(four.clone());
835 })
836 };
837
838 add(&mut app, host, listener1);
839 add(&mut app, host, listener2);
840 add(&mut app, host, listener3);
841
842 notify(&mut app, host);
843 assert_eq!(fired(&log), ["listener1", "listener2"]);
844
845 log.borrow_mut().clear();
846 notify(&mut app, host);
847 assert_eq!(fired(&log), ["listener2", "listener4"]);
848
849 log.borrow_mut().clear();
850 notify(&mut app, host);
851 assert_eq!(fired(&log), ["listener2", "listener4", "listener4"]);
852 }
853
854 #[test]
856 fn a_listener_added_and_removed_immediately_during_notify_is_not_called() {
857 let cell = AppCell::new();
858 let mut app = cell.borrow_mut();
859 let log = Log::default();
860 let host = app.create(TestNotifier::default());
861
862 let listener2 = recording(&log, "listener2");
863 let listener3 = recording(&log, "listener3");
864 let listener1 = {
865 let log = Rc::clone(&log);
866 let two = listener2.clone();
867 let three = listener3.clone();
868 Listener::new(move |app: &mut App| {
869 log.borrow_mut().push("listener1".to_string());
870 let notifier = &mut app.get_mut(host).change_notifier;
871 notifier.add_listener(two.clone());
872 notifier.remove_listener(&two);
873 notifier.add_listener(three.clone());
874 })
875 };
876
877 add(&mut app, host, listener1);
878 notify(&mut app, host);
879 assert_eq!(fired(&log), ["listener1"]);
880 }
881
882 #[test]
884 fn a_self_removing_listener_in_the_middle_still_notifies_all() {
885 let cell = AppCell::new();
886 let mut app = cell.borrow_mut();
887 let log = Log::default();
888 let host = app.create(TestNotifier::default());
889
890 let listener1 = recording(&log, "listener1");
891 let self_removing_slot: Rc<RefCell<Option<Listener>>> = Rc::new(RefCell::new(None));
892 let self_removing = {
893 let log = Rc::clone(&log);
894 let slot = Rc::clone(&self_removing_slot);
895 Listener::new(move |app: &mut App| {
896 log.borrow_mut().push("selfRemovingListener".to_string());
897 let me = slot.borrow().clone().unwrap();
898 app.get_mut(host).change_notifier.remove_listener(&me);
899 })
900 };
901 *self_removing_slot.borrow_mut() = Some(self_removing.clone());
902
903 add(&mut app, host, listener1.clone());
904 add(&mut app, host, self_removing);
905 add(&mut app, host, listener1);
906
907 notify(&mut app, host);
908 assert_eq!(
909 fired(&log),
910 ["listener1", "selfRemovingListener", "listener1"]
911 );
912 }
913
914 #[test]
916 fn the_first_listener_removing_itself_still_notifies_the_rest() {
917 let cell = AppCell::new();
918 let mut app = cell.borrow_mut();
919 let log = Log::default();
920 let host = app.create(TestNotifier::default());
921
922 let self_removing_slot: Rc<RefCell<Option<Listener>>> = Rc::new(RefCell::new(None));
923 let self_removing = {
924 let log = Rc::clone(&log);
925 let slot = Rc::clone(&self_removing_slot);
926 Listener::new(move |app: &mut App| {
927 log.borrow_mut().push("selfRemovingListener".to_string());
928 let me = slot.borrow().clone().unwrap();
929 app.get_mut(host).change_notifier.remove_listener(&me);
930 })
931 };
932 *self_removing_slot.borrow_mut() = Some(self_removing.clone());
933 let listener1 = recording(&log, "listener1");
934
935 add(&mut app, host, self_removing);
936 add(&mut app, host, listener1);
937
938 notify(&mut app, host);
939 assert_eq!(fired(&log), ["selfRemovingListener", "listener1"]);
940 }
941
942 #[test]
943 fn only_a_handle_to_the_same_closure_compares_equal() {
944 let log = Log::default();
945 let listener = recording(&log, "a");
946
947 assert_eq!(listener, listener.clone());
948 assert_ne!(listener, recording(&log, "a"));
949 }
950
951 #[test]
952 fn a_rebuilt_handle_method_listener_matches_like_a_dart_tear_off() {
953 struct Host;
954 fn hook(_this: Handle<Host>, _app: &mut App) {}
955 fn other_hook(_this: Handle<Host>, _app: &mut App) {}
956
957 let cell = AppCell::new();
958 let mut app = cell.borrow_mut();
959 let a = app.create(Host);
960 let b = app.create(Host);
961
962 assert_eq!(
963 Listener::handle_method(a, hook),
964 Listener::handle_method(a, hook)
965 );
966 assert_ne!(
967 Listener::handle_method(a, hook),
968 Listener::handle_method(b, hook)
969 );
970 assert_ne!(
971 Listener::handle_method(a, hook),
972 Listener::handle_method(a, other_hook)
973 );
974 assert_ne!(Listener::handle_method(a, hook), Listener::new(|_app| {}));
975 }
976
977 #[test]
978 fn a_handle_method_listener_calls_the_function_with_its_handle() {
979 struct Host;
980 thread_local! {
981 static CALLED_WITH: Cell<Option<HandleId>> = const { Cell::new(None) };
982 }
983 fn hook(this: Handle<Host>, _app: &mut App) {
984 CALLED_WITH.with(|called| called.set(Some(this.id())));
985 }
986
987 let cell = AppCell::new();
988 let mut app = cell.borrow_mut();
989 let host = app.create(Host);
990 Listener::handle_method(host, hook).call(&mut app);
991 assert_eq!(CALLED_WITH.with(Cell::get), Some(host.id()));
992 }
993
994 #[test]
997 fn removing_keeps_order_across_both_shrink_branches() {
998 for first in 0..8 {
999 let cell = AppCell::new();
1000 let mut app = cell.borrow_mut();
1001 let log = Log::default();
1002 let host = app.create(TestNotifier::default());
1003
1004 let names = ["0", "1", "2", "3", "4", "5", "6", "7"];
1005 let listeners: Vec<Listener> = names.iter().map(|name| recording(&log, name)).collect();
1006 for listener in &listeners {
1007 add(&mut app, host, listener.clone());
1008 }
1009
1010 let mut survivors: Vec<String> = names.iter().map(|n| n.to_string()).collect();
1011 let mut saw_realloc = false;
1012
1013 for step in 0..8 {
1014 let index = (first + step) % 8;
1015 remove(&mut app, host, &listeners[index]);
1016 survivors.retain(|s| s != names[index]);
1017 saw_realloc |= app.get(host).change_notifier.listeners.len() < 8;
1018
1019 log.borrow_mut().clear();
1020 notify(&mut app, host);
1021 assert_eq!(fired(&log), survivors, "after removing {index}");
1022 assert_eq!(app.get(host).change_notifier.count, survivors.len());
1023 }
1024
1025 assert!(saw_realloc, "the shrink branch never ran");
1026 }
1027 }
1028
1029 #[test]
1031 fn dispose_drops_every_listener_but_leaves_removal_callable() {
1032 let cell = AppCell::new();
1033 let mut app = cell.borrow_mut();
1034 let log = Log::default();
1035 let host = app.create(TestNotifier::default());
1036
1037 let listener = recording(&log, "a");
1038 add(&mut app, host, listener.clone());
1039 app.get_mut(host).change_notifier.dispose();
1040
1041 assert!(!app.get(host).change_notifier.has_listeners());
1042 app.get_mut(host).change_notifier.remove_listener(&listener);
1043 assert_eq!(fired(&log), Vec::<String>::new());
1044 }
1045
1046 #[test]
1047 #[cfg(debug_assertions)]
1048 #[should_panic(expected = "was used after being disposed")]
1049 fn adding_a_listener_after_dispose_panics_in_debug() {
1050 let mut notifier = ChangeNotifierData::new();
1051 notifier.dispose();
1052 notifier.add_listener(recording(&Log::default(), "a"));
1053 }
1054
1055 #[test]
1056 #[cfg(debug_assertions)]
1057 #[should_panic(expected = "was used after being disposed")]
1058 fn notifying_after_dispose_panics_in_debug() {
1059 let cell = AppCell::new();
1060 let mut app = cell.borrow_mut();
1061 let host = app.create(TestNotifier::default());
1062 app.get_mut(host).change_notifier.dispose();
1063 notify(&mut app, host);
1064 }
1065
1066 #[test]
1067 #[cfg(debug_assertions)]
1068 #[should_panic(expected = "was used after being disposed")]
1069 fn disposing_twice_panics_in_debug() {
1070 let mut notifier = ChangeNotifierData::new();
1071 notifier.dispose();
1072 notifier.dispose();
1073 }
1074
1075 #[test]
1077 fn has_listeners_is_false_after_dispose() {
1078 let cell = AppCell::new();
1079 let mut app = cell.borrow_mut();
1080 let counter = app.create(ValueNotifier::new(0i32));
1081 counter.add_listener(&mut app, recording(&Log::default(), "a"));
1082 assert!(app.get(counter).change_notifier.has_listeners());
1083 app.get_mut(counter).dispose();
1084 assert!(!app.get(counter).change_notifier.has_listeners());
1085 }
1086
1087 #[test]
1089 fn value_notifier_notifies_only_when_the_value_differs() {
1090 let cell = AppCell::new();
1091 let mut app = cell.borrow_mut();
1092 let log = Log::default();
1093 let notifier = app.create(ValueNotifier::new(2.0));
1094
1095 notifier.add_listener(&mut app, {
1096 let log = Rc::clone(&log);
1097 Listener::new(move |app: &mut App| {
1098 log.borrow_mut().push(app.get(notifier).value().to_string());
1099 })
1100 });
1101
1102 notifier.set_value(&mut app, 3.0);
1103 assert_eq!(fired(&log), ["3"]);
1104 log.borrow_mut().clear();
1105
1106 notifier.set_value(&mut app, 3.0);
1107 assert_eq!(fired(&log), Vec::<String>::new());
1108 }
1109
1110 #[test]
1112 fn has_listeners() {
1113 let cell = AppCell::new();
1114 let mut app = cell.borrow_mut();
1115 let notifier = app.create(ValueNotifier::new(true));
1116 assert!(!app.get(notifier).change_notifier.has_listeners());
1117
1118 let test1 = recording(&Log::default(), "test1");
1119 let test2 = recording(&Log::default(), "test2");
1120
1121 notifier.add_listener(&mut app, test1.clone());
1122 assert!(app.get(notifier).change_notifier.has_listeners());
1123 notifier.add_listener(&mut app, test1.clone());
1124 assert!(app.get(notifier).change_notifier.has_listeners());
1125 notifier.remove_listener(&mut app, &test1);
1126 assert!(app.get(notifier).change_notifier.has_listeners());
1127 notifier.remove_listener(&mut app, &test1);
1128 assert!(!app.get(notifier).change_notifier.has_listeners());
1129 notifier.add_listener(&mut app, test1.clone());
1130 assert!(app.get(notifier).change_notifier.has_listeners());
1131 notifier.add_listener(&mut app, test2.clone());
1132 assert!(app.get(notifier).change_notifier.has_listeners());
1133 notifier.remove_listener(&mut app, &test1);
1134 assert!(app.get(notifier).change_notifier.has_listeners());
1135 notifier.remove_listener(&mut app, &test2);
1136 assert!(!app.get(notifier).change_notifier.has_listeners());
1137 }
1138
1139 #[test]
1141 fn debug_assert_not_disposed_returns_true_while_live() {
1142 let notifier = ChangeNotifierData::new();
1143 assert!(ChangeNotifierData::debug_assert_not_disposed(¬ifier));
1144 }
1145
1146 #[test]
1147 #[cfg(debug_assertions)]
1148 #[should_panic(expected = "was used after being disposed")]
1149 fn debug_assert_not_disposed_panics_after_dispose() {
1150 let mut notifier = ChangeNotifierData::new();
1151 notifier.dispose();
1152 ChangeNotifierData::debug_assert_not_disposed(¬ifier);
1153 }
1154
1155 #[test]
1157 fn a_listener_assigns_through_its_owners_setter_and_the_dispatch_recurses() {
1158 let cell = AppCell::new();
1159 let mut app = cell.borrow_mut();
1160 let log = Log::default();
1161 let counter = app.create(ValueNotifier::new(0i32));
1162
1163 let listener1 = {
1164 let log = Rc::clone(&log);
1165 Listener::new(move |app: &mut App| {
1166 log.borrow_mut().push("listener1".to_string());
1167 if *app.get(counter).value() < 0 {
1168 counter.set_value(app, 0);
1169 }
1170 })
1171 };
1172 counter.add_listener(&mut app, listener1);
1173
1174 counter.notify_listeners(&mut app);
1175 assert_eq!(fired(&log), ["listener1"]);
1176
1177 log.borrow_mut().clear();
1178 counter.set_value(&mut app, 3);
1179 assert_eq!(fired(&log), ["listener1"]);
1180
1181 log.borrow_mut().clear();
1182 counter.set_value(&mut app, -2);
1183 assert_eq!(fired(&log), ["listener1", "listener1"]);
1184 assert_eq!(*app.get(counter).value(), 0);
1185 }
1186
1187 #[test]
1189 fn removing_listeners_while_notifying_on_a_list_which_will_not_resize() {
1190 let cell = AppCell::new();
1191 let mut app = cell.borrow_mut();
1192 let log = Log::default();
1193 let host = app.create(TestNotifier::default());
1194
1195 let names = [
1196 "listener0",
1197 "listener1",
1198 "listener2",
1199 "listener3",
1200 "listener4",
1201 "listener5",
1202 "listener6",
1203 "listener7",
1204 "listener8",
1205 "listener9",
1206 "listener10",
1207 "listener11",
1208 ];
1209 let listeners: Vec<Listener> = names.iter().map(|name| recording(&log, name)).collect();
1210
1211 let auto_remove = {
1212 let to_remove = [
1213 listeners[1].clone(),
1214 listeners[3].clone(),
1215 listeners[4].clone(),
1216 ];
1217 let auto_remove_slot: Rc<RefCell<Option<Listener>>> = Rc::new(RefCell::new(None));
1218 let slot = Rc::clone(&auto_remove_slot);
1219 let listener = Listener::new(move |app: &mut App| {
1220 let notifier = &mut app.get_mut(host).change_notifier;
1221 notifier.remove_listener(&to_remove[0]);
1222 notifier.remove_listener(&to_remove[1]);
1223 notifier.remove_listener(&to_remove[2]);
1224 let me = slot.borrow().clone().unwrap();
1225 notifier.remove_listener(&me);
1226 });
1227 *auto_remove_slot.borrow_mut() = Some(listener.clone());
1228 listener
1229 };
1230
1231 add(&mut app, host, auto_remove);
1232 for listener in &listeners {
1233 add(&mut app, host, listener.clone());
1234 }
1235
1236 let remaining = [
1237 "listener0",
1238 "listener2",
1239 "listener5",
1240 "listener6",
1241 "listener7",
1242 "listener8",
1243 "listener9",
1244 "listener10",
1245 "listener11",
1246 ];
1247
1248 notify(&mut app, host);
1249 assert_eq!(fired(&log), remaining);
1250
1251 log.borrow_mut().clear();
1252 notify(&mut app, host);
1253 assert_eq!(fired(&log), remaining);
1254
1255 for i in [0, 2, 5, 6, 7, 8, 9, 10, 11] {
1256 remove(&mut app, host, &listeners[i]);
1257 }
1258 log.borrow_mut().clear();
1259 notify(&mut app, host);
1260 assert_eq!(fired(&log), Vec::<String>::new());
1261 }
1262
1263 #[test]
1265 #[cfg(debug_assertions)]
1266 fn dispose_during_notify_panics_and_does_not_finish_the_callback() {
1267 let cell = AppCell::new();
1268 let mut app = cell.borrow_mut();
1269 let host = app.create(TestNotifier::default());
1270 let finished = Rc::new(Cell::new(false));
1271 let finished_flag = Rc::clone(&finished);
1272 add(
1273 &mut app,
1274 host,
1275 Listener::new(move |app: &mut App| {
1276 app.get_mut(host).change_notifier.dispose();
1277 finished_flag.set(true);
1278 }),
1279 );
1280
1281 let hook = silence_panic_hook();
1282 let panicked = catch_unwind(AssertUnwindSafe(|| {
1283 notify(&mut app, host);
1284 }))
1285 .is_err();
1286 std::panic::set_hook(hook);
1287
1288 assert!(panicked);
1289 assert!(!finished.get());
1290 app.get_mut(host).change_notifier.dispose();
1291 }
1292
1293 #[test]
1294 fn a_bare_change_notifier_handle_can_notify() {
1295 let cell = AppCell::new();
1296 let mut app = cell.borrow_mut();
1297 let log = Log::default();
1298 let on_undo = app.create(ChangeNotifierData::new());
1299
1300 on_undo.add_listener(&mut app, recording(&log, "undo"));
1301 on_undo.notify_listeners(&mut app);
1302
1303 assert_eq!(fired(&log), ["undo"]);
1304 }
1305
1306 #[test]
1307 fn a_panicking_listener_leaves_the_notifier_usable() {
1308 let cell = AppCell::new();
1309 let mut app = cell.borrow_mut();
1310 let log = Log::default();
1311 let host = app.create(TestNotifier::default());
1312
1313 let l0 = recording(&log, "l0");
1314 let l2 = recording(&log, "l2");
1315 let l3 = Listener::new(|_app: &mut App| panic!("bad listener"));
1316 let l1 = {
1317 let log = Rc::clone(&log);
1318 let (zero, two) = (l0.clone(), l2.clone());
1319 Listener::new(move |app: &mut App| {
1320 log.borrow_mut().push("l1".to_string());
1321 let notifier = &mut app.get_mut(host).change_notifier;
1322 notifier.remove_listener(&zero);
1323 notifier.remove_listener(&two);
1324 })
1325 };
1326
1327 add(&mut app, host, l0);
1328 add(&mut app, host, l1);
1329 add(&mut app, host, l2);
1330 add(&mut app, host, l3.clone());
1331
1332 let hook = silence_panic_hook();
1333 let panicked = catch_unwind(AssertUnwindSafe(|| {
1334 notify(&mut app, host);
1335 }))
1336 .is_err();
1337 std::panic::set_hook(hook);
1338
1339 assert!(panicked);
1340 assert_eq!(fired(&log), ["l0", "l1"]);
1341 assert_eq!(
1342 app.get(host)
1343 .change_notifier
1344 .notification_call_stack_depth
1345 .get(),
1346 0
1347 );
1348 assert_eq!(app.get(host).change_notifier.count, 4);
1349
1350 app.get_mut(host).change_notifier.remove_listener(&l3);
1351 assert_eq!(app.get(host).change_notifier.count, 3);
1352 assert_eq!(
1353 app.get(host).change_notifier.reentrantly_removed_listeners,
1354 2
1355 );
1356
1357 log.borrow_mut().clear();
1358 notify(&mut app, host);
1359 assert_eq!(fired(&log), ["l1"]);
1360 assert_eq!(app.get(host).change_notifier.count, 1);
1361 assert_eq!(
1362 app.get(host).change_notifier.reentrantly_removed_listeners,
1363 0
1364 );
1365
1366 log.borrow_mut().clear();
1367 notify(&mut app, host);
1368 assert_eq!(fired(&log), ["l1"]);
1369 }
1370
1371 #[test]
1372 fn a_panic_inside_a_nested_dispatch_still_pairs_the_depth_guards() {
1373 let cell = AppCell::new();
1374 let mut app = cell.borrow_mut();
1375 let log = Log::default();
1376 let host = app.create(TestNotifier::default());
1377 let inner_host = app.create(TestNotifier::default());
1378
1379 let doomed = recording(&log, "doomed");
1380 add(
1381 &mut app,
1382 inner_host,
1383 Listener::new(|_app: &mut App| panic!("inner listener")),
1384 );
1385
1386 let outer = {
1387 let log = Rc::clone(&log);
1388 let doomed = doomed.clone();
1389 Listener::new(move |app: &mut App| {
1390 log.borrow_mut().push("outer".to_string());
1391 app.get_mut(host).change_notifier.remove_listener(&doomed);
1392 notify(app, inner_host);
1393 })
1394 };
1395
1396 add(&mut app, host, outer);
1397 add(&mut app, host, doomed);
1398
1399 let hook = silence_panic_hook();
1400 let panicked = catch_unwind(AssertUnwindSafe(|| {
1401 notify(&mut app, host);
1402 }))
1403 .is_err();
1404 std::panic::set_hook(hook);
1405
1406 assert!(panicked);
1407 assert_eq!(
1408 app.get(host)
1409 .change_notifier
1410 .notification_call_stack_depth
1411 .get(),
1412 0
1413 );
1414 assert_eq!(
1415 app.get(inner_host)
1416 .change_notifier
1417 .notification_call_stack_depth
1418 .get(),
1419 0
1420 );
1421
1422 let survivor = app.get(host).change_notifier.listeners[0].clone().unwrap();
1423 remove(&mut app, host, &survivor);
1424 log.borrow_mut().clear();
1425 notify(&mut app, host);
1426 assert_eq!(
1427 app.get(host).change_notifier.reentrantly_removed_listeners,
1428 0
1429 );
1430 assert!(!app.get(host).change_notifier.has_listeners());
1431 }
1432
1433 #[test]
1434 fn dispose_clears_the_compaction_owed_by_a_panicked_dispatch() {
1435 let cell = AppCell::new();
1436 let mut app = cell.borrow_mut();
1437 let log = Log::default();
1438 let host = app.create(TestNotifier::default());
1439
1440 let doomed = recording(&log, "doomed");
1441 let saboteur = {
1442 let doomed = doomed.clone();
1443 Listener::new(move |app: &mut App| {
1444 app.get_mut(host).change_notifier.remove_listener(&doomed);
1445 panic!("bad listener");
1446 })
1447 };
1448 add(&mut app, host, saboteur);
1449 add(&mut app, host, doomed);
1450
1451 let hook = silence_panic_hook();
1452 let _ = catch_unwind(AssertUnwindSafe(|| {
1453 notify(&mut app, host);
1454 }));
1455 std::panic::set_hook(hook);
1456
1457 assert_eq!(
1458 app.get(host).change_notifier.reentrantly_removed_listeners,
1459 1
1460 );
1461
1462 app.get_mut(host).change_notifier.dispose();
1463 assert_eq!(
1464 app.get(host).change_notifier.reentrantly_removed_listeners,
1465 0
1466 );
1467 assert_eq!(app.get(host).change_notifier.count, 0);
1468 }
1469
1470 #[test]
1471 #[cfg(not(debug_assertions))]
1472 fn a_disposed_notifier_reused_in_release_does_not_underflow() {
1473 let cell = AppCell::new();
1474 let mut app = cell.borrow_mut();
1475 let log = Log::default();
1476 let host = app.create(TestNotifier::default());
1477
1478 let doomed = recording(&log, "doomed");
1479 let saboteur = {
1480 let doomed = doomed.clone();
1481 Listener::new(move |app: &mut App| {
1482 app.get_mut(host).change_notifier.remove_listener(&doomed);
1483 panic!("bad listener");
1484 })
1485 };
1486 add(&mut app, host, saboteur);
1487 add(&mut app, host, doomed);
1488
1489 let hook = silence_panic_hook();
1490 let _ = catch_unwind(AssertUnwindSafe(|| {
1491 notify(&mut app, host);
1492 }));
1493 std::panic::set_hook(hook);
1494
1495 app.get_mut(host).change_notifier.dispose();
1496 add(&mut app, host, recording(&log, "after"));
1497
1498 log.borrow_mut().clear();
1499 notify(&mut app, host);
1500 assert_eq!(fired(&log), ["after"]);
1501 assert_eq!(app.get(host).change_notifier.count, 1);
1502 }
1503}