use std::rc::Rc;
pub trait Listener {
fn kind(&self) -> ListenerKind;
fn handle(&self, event: web_sys::Event);
fn passive(&self) -> bool;
}
impl std::fmt::Debug for dyn Listener {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Listener {{ kind: {}, passive: {:?} }}",
self.kind().as_ref(),
self.passive(),
)
}
}
macro_rules! gen_listener_kinds {
($($kind:ident)*) => {
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
#[allow(non_camel_case_types)]
#[allow(missing_docs)]
pub enum ListenerKind {
$( $kind, )*
other(std::borrow::Cow<'static, str>),
}
impl ListenerKind {
pub fn type_name(&self) -> std::borrow::Cow<'static, str> {
match self {
Self::other(type_name) => type_name.clone(),
$( Self::$kind => stringify!($kind)[2..].into(), )*
}
}
}
impl AsRef<str> for ListenerKind {
fn as_ref(&self) -> &str {
match self {
$( Self::$kind => stringify!($kind), )*
Self::other(type_name) => type_name.as_ref(),
}
}
}
};
}
gen_listener_kinds! {
onabort
onauxclick
onblur
oncancel
oncanplay
oncanplaythrough
onchange
onclick
onclose
oncontextmenu
oncuechange
ondblclick
ondrag
ondragend
ondragenter
ondragexit
ondragleave
ondragover
ondragstart
ondrop
ondurationchange
onemptied
onended
onerror
onfocus
onfocusin
onfocusout
onformdata
oninput
oninvalid
onkeydown
onkeypress
onkeyup
onload
onloadeddata
onloadedmetadata
onloadstart
onmousedown
onmouseenter
onmouseleave
onmousemove
onmouseout
onmouseover
onmouseup
onpause
onplay
onplaying
onprogress
onratechange
onreset
onresize
onscroll
onsecuritypolicyviolation
onseeked
onseeking
onselect
onslotchange
onstalled
onsubmit
onsuspend
ontimeupdate
ontoggle
onvolumechange
onwaiting
onwheel
oncopy
oncut
onpaste
onanimationcancel
onanimationend
onanimationiteration
onanimationstart
ongotpointercapture
onloadend
onlostpointercapture
onpointercancel
onpointerdown
onpointerenter
onpointerleave
onpointerlockchange
onpointerlockerror
onpointermove
onpointerout
onpointerover
onpointerup
onselectionchange
onselectstart
onshow
ontouchcancel
ontouchend
ontouchmove
ontouchstart
ontransitioncancel
ontransitionend
ontransitionrun
ontransitionstart
}
#[derive(Debug)]
pub enum Listeners {
None,
Pending(Box<[Option<Rc<dyn Listener>>]>),
}
impl PartialEq for Listeners {
fn eq(&self, rhs: &Self) -> bool {
use Listeners::*;
match (self, rhs) {
(None, None) => true,
(Pending(lhs), Pending(rhs)) => {
if lhs.len() != rhs.len() {
false
} else {
use std::option::Option::None;
lhs.iter()
.zip(rhs.iter())
.all(|(lhs, rhs)| match (lhs, rhs) {
(Some(lhs), Some(rhs)) =>
{
#[allow(clippy::vtable_address_comparisons)]
Rc::ptr_eq(lhs, rhs)
}
(None, None) => true,
_ => false,
})
}
}
(None, Pending(pending)) | (Pending(pending), None) => pending.len() == 0,
}
}
}
impl Clone for Listeners {
fn clone(&self) -> Self {
match self {
Self::None => Self::None,
Self::Pending(v) => Self::Pending(v.clone()),
}
}
}
impl Default for Listeners {
fn default() -> Self {
Self::None
}
}