use {
alloc::{
boxed::Box,
rc::{Rc, Weak},
vec::Vec,
},
core::any::Any,
};
use crate::{
sync::SyncContext, RawWatchArg, Watch, WatchArg, WatchSet, WatcherHolder,
};
pub(crate) struct FrameInfo<'ctx, O: ?Sized> {
pub(crate) id: u8,
pub(crate) post_set: Weak<WatchSet<'ctx, O>>,
pub(crate) sync_context: Weak<SyncContext<'ctx, O>>,
}
impl<'ctx, O: ?Sized> Clone for FrameInfo<'ctx, O> {
fn clone(&self) -> Self {
Self {
id: self.id,
post_set: Weak::clone(&self.post_set),
sync_context: Weak::clone(&self.sync_context),
}
}
}
pub struct WatchContext<'ctx, O: ?Sized = DefaultOwner> {
next_frame: Rc<WatchSet<'ctx, O>>,
sync_context: Rc<SyncContext<'ctx, O>>,
pub(crate) frame_info: FrameInfo<'ctx, O>,
frame_limit: Option<usize>,
pub(crate) next_debug_name: &'static str,
pub(crate) owner: O,
}
impl<'ctx, O> WatchContext<'ctx, O> {
pub fn from_owner(owner: O) -> Self {
let frame_limit = if cfg!(debug_assertions) {
Some(1024)
} else {
None
};
let next_frame = Rc::default();
let sync_context = Rc::new(SyncContext::new());
let frame_info = FrameInfo {
id: 0,
post_set: Rc::downgrade(&next_frame),
sync_context: Rc::downgrade(&sync_context),
};
let next_debug_name = "<unknown>";
WatchContext {
next_frame,
sync_context,
frame_info,
frame_limit,
next_debug_name,
owner,
}
}
}
impl<'ctx, O: Default> WatchContext<'ctx, O> {
pub fn new() -> Self {
Self::from_owner(O::default())
}
}
impl<'ctx, O: ?Sized> WatchContext<'ctx, O> {
fn dbg_name(&mut self) -> &'static str {
core::mem::replace(&mut self.next_debug_name, "<unknown>")
}
pub fn add_watch<F>(&mut self, func: F)
where
F: 'ctx + Fn(&mut O, WatchArg<'_, 'ctx, O>),
{
let dbg_name = self.dbg_name();
self.add_watch_raw(dbg_name, move |mut raw_arg| {
let (owner, arg) = raw_arg.as_owner_and_arg();
func(owner, arg);
});
}
pub fn add_watch_might_add_watcher<F, T>(&mut self, func: F)
where
F: 'ctx + Fn(&mut O, WatchArg<'_, 'ctx, O>) -> Option<T>,
T: 'ctx + WatcherHolder<'ctx, O>,
T::Content: crate::Watcher<'ctx, O>,
{
let debug_name = self.dbg_name();
self.add_watch_raw(debug_name, move |mut raw_arg| {
let (owner, arg) = raw_arg.as_owner_and_arg();
if let Some(watcher) = func(owner, arg) {
raw_arg.context().add_watcher(&watcher);
}
});
}
pub fn add_watch_raw<F>(&mut self, debug_name: &'static str, f: F)
where
F: 'ctx + Fn(RawWatchArg<'_, 'ctx, O>),
{
Watch::spawn_raw(self, debug_name, f)
}
pub fn add_watcher<T>(&mut self, holder: &T)
where
T: 'ctx + ?Sized + WatcherHolder<'ctx, O>,
T::Content: crate::Watcher<'ctx, O>,
{
crate::watcher::init_watcher(self, holder);
}
pub fn owner(&mut self) -> &mut O {
&mut self.owner
}
pub fn update(&mut self) {
self.sync_context.check_for_updates();
if let Some(mut frame_limit) = self.frame_limit {
while !self.next_frame.empty() {
if frame_limit == 0 {
let current_watch_names = self.next_frame.debug_names();
panic!(
"Updating a WatchContext exceeded it's \
limit for iteration. This usually means there is a \
recursive watch. You may be interested in \
Watched::set_if_neq to resolve recursive watches. \
If the number of iterations was intentional, you \
can try increasing the limit with \
WatchContext::set_frame_limit. The following types \
might be involved in the recursive watch:\n {}",
current_watch_names,
);
}
self.next_frame.take().execute(self);
self.frame_info.id = self.frame_info.id.wrapping_add(1);
frame_limit -= 1;
}
} else {
while !self.next_frame.empty() {
self.next_frame.take().execute(self);
self.frame_info.id = self.frame_info.id.wrapping_add(1);
}
}
}
pub fn set_frame_limit(&mut self, value: Option<usize>) {
self.frame_limit = value;
}
}
impl<'ctx, O: Default> Default for WatchContext<'ctx, O> {
fn default() -> Self {
Self::new()
}
}
#[derive(Default)]
pub struct DefaultOwner {
owners: Vec<Box<dyn Any>>,
}
impl DefaultOwner {
pub fn add_owner<T: Any>(&mut self, owner: T) {
self.owners.push(Box::new(owner));
}
pub fn get_owner<T: Any>(&mut self) -> impl Iterator<Item = &mut T> {
self.owners
.iter_mut()
.filter_map(|boxed| boxed.downcast_mut::<T>())
}
}