Add global tests and wrap global update functions in update call to flush effects
Co-authored-by: Antonio Scandurra <me@as-cii.com>
This commit is contained in:
parent
454f7a570c
commit
0a8d543f66
1 changed files with 124 additions and 49 deletions
|
@ -763,7 +763,7 @@ type GlobalActionCallback = dyn FnMut(&dyn AnyAction, &mut MutableAppContext);
|
||||||
type SubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext) -> bool>;
|
type SubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext) -> bool>;
|
||||||
type GlobalSubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext)>;
|
type GlobalSubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext)>;
|
||||||
type ObservationCallback = Box<dyn FnMut(&mut MutableAppContext) -> bool>;
|
type ObservationCallback = Box<dyn FnMut(&mut MutableAppContext) -> bool>;
|
||||||
type GlobalObservationCallback = Box<dyn FnMut(&mut MutableAppContext) -> bool>;
|
type GlobalObservationCallback = Box<dyn FnMut(&mut MutableAppContext)>;
|
||||||
type ReleaseObservationCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext)>;
|
type ReleaseObservationCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext)>;
|
||||||
|
|
||||||
pub struct MutableAppContext {
|
pub struct MutableAppContext {
|
||||||
|
@ -1206,7 +1206,7 @@ impl MutableAppContext {
|
||||||
pub fn observe_global<G, F>(&mut self, observe: F) -> Subscription
|
pub fn observe_global<G, F>(&mut self, observe: F) -> Subscription
|
||||||
where
|
where
|
||||||
G: Any,
|
G: Any,
|
||||||
F: 'static + FnMut(&mut MutableAppContext) -> bool,
|
F: 'static + FnMut(&mut MutableAppContext),
|
||||||
{
|
{
|
||||||
let type_id = TypeId::of::<G>();
|
let type_id = TypeId::of::<G>();
|
||||||
let id = post_inc(&mut self.next_subscription_id);
|
let id = post_inc(&mut self.next_subscription_id);
|
||||||
|
@ -1415,21 +1415,25 @@ impl MutableAppContext {
|
||||||
|
|
||||||
pub fn default_global<T: 'static + Default>(&mut self) -> &T {
|
pub fn default_global<T: 'static + Default>(&mut self) -> &T {
|
||||||
let type_id = TypeId::of::<T>();
|
let type_id = TypeId::of::<T>();
|
||||||
if !self.cx.globals.contains_key(&type_id) {
|
self.update(|this| {
|
||||||
self.notify_global(type_id);
|
if !this.globals.contains_key(&type_id) {
|
||||||
}
|
this.notify_global(type_id);
|
||||||
self.cx
|
}
|
||||||
.globals
|
|
||||||
.entry(type_id)
|
this.cx
|
||||||
.or_insert_with(|| Box::new(T::default()))
|
.globals
|
||||||
.downcast_ref()
|
.entry(type_id)
|
||||||
.unwrap()
|
.or_insert_with(|| Box::new(T::default()));
|
||||||
|
});
|
||||||
|
self.globals.get(&type_id).unwrap().downcast_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_global<T: 'static>(&mut self, state: T) {
|
pub fn set_global<T: 'static>(&mut self, state: T) {
|
||||||
let type_id = TypeId::of::<T>();
|
self.update(|this| {
|
||||||
self.cx.globals.insert(type_id, Box::new(state));
|
let type_id = TypeId::of::<T>();
|
||||||
self.notify_global(type_id);
|
this.cx.globals.insert(type_id, Box::new(state));
|
||||||
|
this.notify_global(type_id);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_default_global<T, F, U>(&mut self, update: F) -> U
|
pub fn update_default_global<T, F, U>(&mut self, update: F) -> U
|
||||||
|
@ -1437,16 +1441,18 @@ impl MutableAppContext {
|
||||||
T: 'static + Default,
|
T: 'static + Default,
|
||||||
F: FnOnce(&mut T, &mut MutableAppContext) -> U,
|
F: FnOnce(&mut T, &mut MutableAppContext) -> U,
|
||||||
{
|
{
|
||||||
let type_id = TypeId::of::<T>();
|
self.update(|this| {
|
||||||
let mut state = self
|
let type_id = TypeId::of::<T>();
|
||||||
.cx
|
let mut state = this
|
||||||
.globals
|
.cx
|
||||||
.remove(&type_id)
|
.globals
|
||||||
.unwrap_or_else(|| Box::new(T::default()));
|
.remove(&type_id)
|
||||||
let result = update(state.downcast_mut().unwrap(), self);
|
.unwrap_or_else(|| Box::new(T::default()));
|
||||||
self.cx.globals.insert(type_id, state);
|
let result = update(state.downcast_mut().unwrap(), this);
|
||||||
self.notify_global(type_id);
|
this.cx.globals.insert(type_id, state);
|
||||||
result
|
this.notify_global(type_id);
|
||||||
|
result
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_global<T, F, U>(&mut self, update: F) -> U
|
pub fn update_global<T, F, U>(&mut self, update: F) -> U
|
||||||
|
@ -1454,16 +1460,18 @@ impl MutableAppContext {
|
||||||
T: 'static,
|
T: 'static,
|
||||||
F: FnOnce(&mut T, &mut MutableAppContext) -> U,
|
F: FnOnce(&mut T, &mut MutableAppContext) -> U,
|
||||||
{
|
{
|
||||||
let type_id = TypeId::of::<T>();
|
self.update(|this| {
|
||||||
let mut state = self
|
let type_id = TypeId::of::<T>();
|
||||||
.cx
|
let mut state = this
|
||||||
.globals
|
.cx
|
||||||
.remove(&type_id)
|
.globals
|
||||||
.expect("no global has been added for this type");
|
.remove(&type_id)
|
||||||
let result = update(state.downcast_mut().unwrap(), self);
|
.expect("no global has been added for this type");
|
||||||
self.cx.globals.insert(type_id, state);
|
let result = update(state.downcast_mut().unwrap(), this);
|
||||||
self.notify_global(type_id);
|
this.cx.globals.insert(type_id, state);
|
||||||
result
|
this.notify_global(type_id);
|
||||||
|
result
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
|
pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
|
||||||
|
@ -2056,21 +2064,19 @@ impl MutableAppContext {
|
||||||
if self.cx.globals.contains_key(&observed_type_id) {
|
if self.cx.globals.contains_key(&observed_type_id) {
|
||||||
for (id, callback) in callbacks {
|
for (id, callback) in callbacks {
|
||||||
if let Some(mut callback) = callback {
|
if let Some(mut callback) = callback {
|
||||||
let alive = callback(self);
|
callback(self);
|
||||||
if alive {
|
match self
|
||||||
match self
|
.global_observations
|
||||||
.global_observations
|
.lock()
|
||||||
.lock()
|
.entry(observed_type_id)
|
||||||
.entry(observed_type_id)
|
.or_default()
|
||||||
.or_default()
|
.entry(id)
|
||||||
.entry(id)
|
{
|
||||||
{
|
collections::btree_map::Entry::Vacant(entry) => {
|
||||||
collections::btree_map::Entry::Vacant(entry) => {
|
entry.insert(Some(callback));
|
||||||
entry.insert(Some(callback));
|
}
|
||||||
}
|
collections::btree_map::Entry::Occupied(entry) => {
|
||||||
collections::btree_map::Entry::Occupied(entry) => {
|
entry.remove();
|
||||||
entry.remove();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5205,6 +5211,61 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[crate::test(self)]
|
||||||
|
fn test_global(cx: &mut MutableAppContext) {
|
||||||
|
type Global = usize;
|
||||||
|
|
||||||
|
let observation_count = Rc::new(RefCell::new(0));
|
||||||
|
let subscription = cx.observe_global::<Global, _>({
|
||||||
|
let observation_count = observation_count.clone();
|
||||||
|
move |_| {
|
||||||
|
*observation_count.borrow_mut() += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(!cx.has_global::<Global>());
|
||||||
|
assert_eq!(cx.default_global::<Global>(), &0);
|
||||||
|
assert_eq!(*observation_count.borrow(), 1);
|
||||||
|
assert!(cx.has_global::<Global>());
|
||||||
|
assert_eq!(
|
||||||
|
cx.update_global::<Global, _, _>(|global, _| {
|
||||||
|
*global = 1;
|
||||||
|
"Update Result"
|
||||||
|
}),
|
||||||
|
"Update Result"
|
||||||
|
);
|
||||||
|
assert_eq!(*observation_count.borrow(), 2);
|
||||||
|
assert_eq!(cx.global::<Global>(), &1);
|
||||||
|
|
||||||
|
drop(subscription);
|
||||||
|
cx.update_global::<Global, _, _>(|global, _| {
|
||||||
|
*global = 2;
|
||||||
|
});
|
||||||
|
assert_eq!(*observation_count.borrow(), 2);
|
||||||
|
|
||||||
|
type OtherGlobal = f32;
|
||||||
|
|
||||||
|
let observation_count = Rc::new(RefCell::new(0));
|
||||||
|
cx.observe_global::<OtherGlobal, _>({
|
||||||
|
let observation_count = observation_count.clone();
|
||||||
|
move |_| {
|
||||||
|
*observation_count.borrow_mut() += 1;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
cx.update_default_global::<OtherGlobal, _, _>(|global, _| {
|
||||||
|
assert_eq!(global, &0.0);
|
||||||
|
*global = 2.0;
|
||||||
|
"Default update result"
|
||||||
|
}),
|
||||||
|
"Default update result"
|
||||||
|
);
|
||||||
|
assert_eq!(cx.global::<OtherGlobal>(), &2.0);
|
||||||
|
assert_eq!(*observation_count.borrow(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
#[crate::test(self)]
|
#[crate::test(self)]
|
||||||
fn test_dropping_subscribers(cx: &mut MutableAppContext) {
|
fn test_dropping_subscribers(cx: &mut MutableAppContext) {
|
||||||
struct View;
|
struct View;
|
||||||
|
@ -5556,6 +5617,20 @@ mod tests {
|
||||||
assert_eq!(*observation_count.borrow(), 1);
|
assert_eq!(*observation_count.borrow(), 1);
|
||||||
|
|
||||||
// Global Observation
|
// Global Observation
|
||||||
|
let observation_count = Rc::new(RefCell::new(0));
|
||||||
|
let subscription = Rc::new(RefCell::new(None));
|
||||||
|
*subscription.borrow_mut() = Some(cx.observe_global::<(), _>({
|
||||||
|
let observation_count = observation_count.clone();
|
||||||
|
let subscription = subscription.clone();
|
||||||
|
move |_| {
|
||||||
|
subscription.borrow_mut().take();
|
||||||
|
*observation_count.borrow_mut() += 1;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
cx.default_global::<()>();
|
||||||
|
cx.set_global(());
|
||||||
|
assert_eq!(*observation_count.borrow(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[crate::test(self)]
|
#[crate::test(self)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue