diff --git a/packages/yew/src/callback.rs b/packages/yew/src/callback.rs index 1ba61d9de74..c6db179d1cc 100644 --- a/packages/yew/src/callback.rs +++ b/packages/yew/src/callback.rs @@ -4,6 +4,9 @@ //! - [Counter](https://github.com/yewstack/yew/tree/master/examples/counter) //! - [Timer](https://github.com/yewstack/yew/tree/master/examples/timer) +use std::any; +use std::cell::RefCell; +use std::collections::HashMap; use std::fmt; use std::rc::Rc; @@ -33,6 +36,8 @@ macro_rules! generate_callback_impls { } } + impl Eq for $callback {} + impl fmt::Debug for $callback { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "$callback<_>") @@ -46,15 +51,31 @@ macro_rules! generate_callback_impls { } } - impl $callback { + impl $callback { /// Creates a "no-op" callback which can be used when it is not suitable to use an /// `Option<$callback>`. pub fn noop() -> Self { - Self::from(|_: $in_ty| ()) + thread_local! { + static NOOP: RefCell>> = RefCell::new(Default::default()); + } + + Self { + cb: NOOP.with(|noop| { + noop.borrow_mut() + .entry(any::TypeId::of::<$in_ty>()) + .or_insert_with(|| { + let func: Rc ()> = Rc::new(|_: $in_ty| ()); + Box::new(func) as Box + }) + .downcast_ref:: ()>>() + .unwrap() + .clone() + }), + } } } - impl Default for $callback { + impl Default for $callback { fn default() -> Self { Self::noop() } @@ -300,4 +321,9 @@ mod test { reformed.emit(&mut value).expect("is some"); assert_eq!(value, 45); } + + #[test] + fn test_noop_eq() { + assert_eq!(Callback::::noop(), Callback::::noop()); + } }