use std::{
any::Any,
fmt,
marker::PhantomData,
mem,
ops::{ControlFlow, Deref},
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
time::Instant,
};
mod args;
pub use args::*;
mod command;
pub use command::*;
mod events;
pub use events::*;
mod channel;
pub use channel::*;
use crate::{
handler::{AppHandler, AppHandlerArgs},
update::{EventUpdate, UpdateDeliveryList, UpdateSubscribers},
widget::WidgetId,
};
use parking_lot::Mutex;
use zng_app_context::AppLocal;
use zng_clone_move::clmv;
use zng_unique_id::{IdEntry, IdMap, IdSet};
#[macro_export]
macro_rules! event_macro {
($(
$(#[$attr:meta])*
$vis:vis static $EVENT:ident: $Args:path;
)+) => {
$(
$(#[$attr])*
$vis static $EVENT: $crate::event::Event<$Args> = {
$crate::event::app_local! {
static LOCAL: $crate::event::EventData = const { $crate::event::EventData::new(std::stringify!($EVENT)) };
}
$crate::event::Event::new(&LOCAL)
};
)+
}
}
#[doc(inline)]
pub use crate::event_macro as event;
#[doc(hidden)]
pub struct EventData {
name: &'static str,
widget_subs: IdMap<WidgetId, EventHandle>,
hooks: Vec<EventHook>,
}
impl EventData {
#[doc(hidden)]
pub const fn new(name: &'static str) -> Self {
EventData {
name,
widget_subs: IdMap::new(),
hooks: vec![],
}
}
}
pub struct Event<A: EventArgs> {
local: &'static AppLocal<EventData>,
_args: PhantomData<fn(A)>,
}
impl<A: EventArgs> fmt::Debug for Event<A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
write!(f, "Event({})", self.name())
} else {
write!(f, "{}", self.name())
}
}
}
impl<A: EventArgs> Event<A> {
#[doc(hidden)]
pub const fn new(local: &'static AppLocal<EventData>) -> Self {
Event { local, _args: PhantomData }
}
pub fn as_any(&self) -> AnyEvent {
AnyEvent { local: self.local }
}
pub fn subscribe(&self, widget_id: WidgetId) -> EventHandle {
self.as_any().subscribe(widget_id)
}
pub fn is_subscriber(&self, widget_id: WidgetId) -> bool {
self.as_any().is_subscriber(widget_id)
}
pub fn has_subscribers(&self) -> bool {
self.as_any().has_subscribers()
}
pub fn visit_subscribers<T>(&self, visit: impl FnMut(WidgetId) -> ControlFlow<T>) -> Option<T> {
self.as_any().visit_subscribers(visit)
}
pub fn name(&self) -> &'static str {
self.local.read().name
}
pub fn has(&self, update: &EventUpdate) -> bool {
*self == update.event
}
pub fn on<'a>(&self, update: &'a EventUpdate) -> Option<&'a A> {
if *self == update.event {
update.args.as_any().downcast_ref()
} else {
None
}
}
pub fn on_unhandled<'a>(&self, update: &'a EventUpdate) -> Option<&'a A> {
self.on(update).filter(|a| !a.propagation().is_stopped())
}
pub fn handle<R>(&self, update: &EventUpdate, handler: impl FnOnce(&A) -> R) -> Option<R> {
if let Some(args) = self.on(update) {
args.handle(handler)
} else {
None
}
}
pub fn new_update(&self, args: A) -> EventUpdate {
self.new_update_custom(args, UpdateDeliveryList::new(Box::new(self.as_any())))
}
pub fn new_update_custom(&self, args: A, mut delivery_list: UpdateDeliveryList) -> EventUpdate {
args.delivery_list(&mut delivery_list);
EventUpdate {
event: self.as_any(),
delivery_list,
args: Box::new(args),
pre_actions: Mutex::new(vec![]),
pos_actions: Mutex::new(vec![]),
}
}
pub fn notify(&self, args: A) {
let update = self.new_update(args);
EVENTS.notify(update);
}
pub fn on_pre_event<H>(&self, handler: H) -> EventHandle
where
H: AppHandler<A>,
{
self.on_event_impl(handler, true)
}
pub fn on_event(&self, handler: impl AppHandler<A>) -> EventHandle {
self.on_event_impl(handler, false)
}
fn on_event_impl(&self, handler: impl AppHandler<A>, is_preview: bool) -> EventHandle {
let handler = Arc::new(Mutex::new(handler));
let (inner_handle_owner, inner_handle) = zng_handle::Handle::new(());
self.as_any().hook(move |update| {
if inner_handle_owner.is_dropped() {
return false;
}
let handle = inner_handle.downgrade();
update.push_once_action(
Box::new(clmv!(handler, |update| {
let args = update.args().as_any().downcast_ref::<A>().unwrap();
if !args.propagation().is_stopped() {
handler.lock().event(
args,
&AppHandlerArgs {
handle: &handle,
is_preview,
},
);
}
})),
is_preview,
);
true
})
}
pub fn receiver(&self) -> EventReceiver<A>
where
A: Send,
{
let (sender, receiver) = flume::unbounded();
self.as_any()
.hook(move |update| sender.send(update.args().as_any().downcast_ref::<A>().unwrap().clone()).is_ok())
.perm();
EventReceiver { receiver, event: *self }
}
pub fn sender(&self) -> EventSender<A>
where
A: Send,
{
EVENTS_SV.write().sender(*self)
}
pub fn has_hooks(&self) -> bool {
self.as_any().has_hooks()
}
}
impl<A: EventArgs> Clone for Event<A> {
fn clone(&self) -> Self {
*self
}
}
impl<A: EventArgs> Copy for Event<A> {}
impl<A: EventArgs> PartialEq for Event<A> {
fn eq(&self, other: &Self) -> bool {
self.local == other.local
}
}
impl<A: EventArgs> Eq for Event<A> {}
#[derive(Clone, Copy)]
pub struct AnyEvent {
local: &'static AppLocal<EventData>,
}
impl fmt::Debug for AnyEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
write!(f, "AnyEvent({})", self.name())
} else {
write!(f, "{}", self.name())
}
}
}
impl AnyEvent {
pub fn name(&self) -> &'static str {
self.local.read().name
}
pub fn is<A: EventArgs>(&self, event: &Event<A>) -> bool {
self == event
}
pub fn has(&self, update: &EventUpdate) -> bool {
*self == update.event
}
pub fn hook(&self, hook: impl Fn(&mut EventUpdate) -> bool + Send + Sync + 'static) -> EventHandle {
self.hook_impl(Box::new(hook))
}
fn hook_impl(&self, hook: Box<dyn Fn(&mut EventUpdate) -> bool + Send + Sync>) -> EventHandle {
let (handle, hook) = EventHandle::new(hook);
self.local.write().hooks.push(hook);
handle
}
pub fn subscribe(&self, widget_id: WidgetId) -> EventHandle {
self.local
.write()
.widget_subs
.entry(widget_id)
.or_insert_with(EventHandle::new_none)
.clone()
}
pub fn is_subscriber(&self, widget_id: WidgetId) -> bool {
self.local.read().widget_subs.contains_key(&widget_id)
}
pub fn has_subscribers(&self) -> bool {
!self.local.read().widget_subs.is_empty()
}
pub fn visit_subscribers<T>(&self, mut visit: impl FnMut(WidgetId) -> ControlFlow<T>) -> Option<T> {
for sub in self.local.read().widget_subs.keys() {
match visit(*sub) {
ControlFlow::Continue(_) => continue,
ControlFlow::Break(r) => return Some(r),
}
}
None
}
pub fn has_hooks(&self) -> bool {
!self.local.read().hooks.is_empty()
}
pub(crate) fn on_update(&self, update: &mut EventUpdate) {
let mut hooks = mem::take(&mut self.local.write().hooks);
hooks.retain(|h| h.call(update));
let mut write = self.local.write();
hooks.append(&mut write.hooks);
write.hooks = hooks;
}
}
impl PartialEq for AnyEvent {
fn eq(&self, other: &Self) -> bool {
self.local == other.local
}
}
impl Eq for AnyEvent {}
impl std::hash::Hash for AnyEvent {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
std::hash::Hash::hash(self.local, state)
}
}
impl<A: EventArgs> PartialEq<AnyEvent> for Event<A> {
fn eq(&self, other: &AnyEvent) -> bool {
self.local == other.local
}
}
impl<A: EventArgs> PartialEq<Event<A>> for AnyEvent {
fn eq(&self, other: &Event<A>) -> bool {
self.local == other.local
}
}
impl UpdateSubscribers for AnyEvent {
fn contains(&self, widget_id: WidgetId) -> bool {
if let Some(mut write) = self.local.try_write() {
match write.widget_subs.entry(widget_id) {
IdEntry::Occupied(e) => {
let t = e.get().retain();
if !t {
let _ = e.remove();
}
t
}
IdEntry::Vacant(_) => false,
}
} else {
match self.local.read().widget_subs.get(&widget_id) {
Some(e) => e.retain(),
None => false,
}
}
}
fn to_set(&self) -> IdSet<WidgetId> {
self.local.read().widget_subs.keys().copied().collect()
}
}
#[must_use = "the event subscriptions or handlers are dropped if the handle is dropped"]
#[derive(Clone, Default)]
pub struct EventHandles(pub Vec<EventHandle>);
impl EventHandles {
pub const fn dummy() -> Self {
EventHandles(vec![])
}
pub fn is_dummy(&self) -> bool {
self.0.is_empty() || self.0.iter().all(EventHandle::is_dummy)
}
pub fn perm(self) {
for handle in self.0 {
handle.perm()
}
}
pub fn push(&mut self, other: EventHandle) -> &mut Self {
if !other.is_dummy() {
self.0.push(other);
}
self
}
pub fn clear(&mut self) {
self.0.clear();
}
}
impl FromIterator<EventHandle> for EventHandles {
fn from_iter<T: IntoIterator<Item = EventHandle>>(iter: T) -> Self {
EventHandles(iter.into_iter().filter(|h| !h.is_dummy()).collect())
}
}
impl<const N: usize> From<[EventHandle; N]> for EventHandles {
fn from(handles: [EventHandle; N]) -> Self {
handles.into_iter().filter(|h| !h.is_dummy()).collect()
}
}
impl Extend<EventHandle> for EventHandles {
fn extend<T: IntoIterator<Item = EventHandle>>(&mut self, iter: T) {
for handle in iter {
self.push(handle);
}
}
}
impl IntoIterator for EventHandles {
type Item = EventHandle;
type IntoIter = std::vec::IntoIter<EventHandle>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
struct EventHandleData {
perm: AtomicBool,
hook: Option<Box<dyn Fn(&mut EventUpdate) -> bool + Send + Sync>>,
}
#[derive(Clone)]
#[must_use = "the event subscription or handler is dropped if the handle is dropped"]
pub struct EventHandle(Option<Arc<EventHandleData>>);
impl PartialEq for EventHandle {
fn eq(&self, other: &Self) -> bool {
match (&self.0, &other.0) {
(None, None) => true,
(None, Some(_)) | (Some(_), None) => false,
(Some(a), Some(b)) => Arc::ptr_eq(a, b),
}
}
}
impl Eq for EventHandle {}
impl std::hash::Hash for EventHandle {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let i = match &self.0 {
Some(rc) => Arc::as_ptr(rc) as usize,
None => 0,
};
state.write_usize(i);
}
}
impl fmt::Debug for EventHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let i = match &self.0 {
Some(rc) => Arc::as_ptr(rc) as usize,
None => 0,
};
f.debug_tuple("EventHandle").field(&i).finish()
}
}
impl Default for EventHandle {
fn default() -> Self {
Self::dummy()
}
}
impl EventHandle {
fn new(hook: Box<dyn Fn(&mut EventUpdate) -> bool + Send + Sync>) -> (Self, EventHook) {
let rc = Arc::new(EventHandleData {
perm: AtomicBool::new(false),
hook: Some(hook),
});
(Self(Some(rc.clone())), EventHook(rc))
}
fn new_none() -> Self {
Self(Some(Arc::new(EventHandleData {
perm: AtomicBool::new(false),
hook: None,
})))
}
pub fn dummy() -> Self {
EventHandle(None)
}
pub fn is_dummy(&self) -> bool {
self.0.is_none()
}
pub fn perm(self) {
if let Some(rc) = self.0 {
rc.perm.store(true, Ordering::Relaxed);
}
}
pub fn with(self, other: Self) -> EventHandles {
[self, other].into()
}
fn retain(&self) -> bool {
let rc = self.0.as_ref().unwrap();
Arc::strong_count(rc) > 1 || rc.perm.load(Ordering::Relaxed)
}
}
struct EventHook(Arc<EventHandleData>);
impl EventHook {
fn call(&self, update: &mut EventUpdate) -> bool {
(Arc::strong_count(&self.0) > 1 || self.0.perm.load(Ordering::Relaxed)) && (self.0.hook.as_ref().unwrap())(update)
}
}