From 32593838fa2c59bc8a0c24997eaef1cd381a17d8 Mon Sep 17 00:00:00 2001 From: Jens Reimann Date: Thu, 8 Sep 2022 13:42:43 +0200 Subject: [PATCH] Allow skipping a callback when reforming This adds a method to the callback, similar to Rust's filter_map, which allows to reform a callback, but also suppress the emit in case the reform function returns `None`. --- packages/yew/src/callback.rs | 68 +++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/packages/yew/src/callback.rs b/packages/yew/src/callback.rs index 84aff3ab3e3..55fc5287bc4 100644 --- a/packages/yew/src/callback.rs +++ b/packages/yew/src/callback.rs @@ -68,7 +68,7 @@ impl Default for Callback { impl Callback { /// Creates a new callback from another callback and a function - /// That when emited will call that function and will emit the original callback + /// That when emitted will call that function and will emit the original callback pub fn reform(&self, func: F) -> Callback where F: Fn(T) -> IN + 'static, @@ -82,4 +82,70 @@ impl Callback { } } +impl Callback { + /// Creates a new callback from another callback and a function + /// That when emitted will call that function and will emit the original callback if it is + /// not `None`. + pub fn filter_reform(&self, func: F) -> Callback + where + F: Fn(T) -> Option + 'static, + { + let this = self.clone(); + let func = move |input| { + if let Some(output) = func(input) { + this.emit(output); + } + }; + Callback::from(func) + } +} + impl ImplicitClone for Callback {} + +#[cfg(test)] +mod test { + use std::sync::Mutex; + + use super::*; + + /// emit the callback with the provided value + fn emit(values: I, f: F) -> Vec + where + I: IntoIterator, + F: FnOnce(Callback) -> Callback, + { + let result = Rc::new(Mutex::new(Vec::new())); + let cb_result = result.clone(); + let cb = f(Callback::from(move |v| cb_result.lock().unwrap().push(v))); + for value in values { + cb.emit(value); + } + let x = result.lock().unwrap().clone(); + x + } + + #[test] + fn test_callback() { + assert_eq!(*emit([true, false], |cb| cb), vec![true, false]); + } + + #[test] + fn test_reform() { + assert_eq!( + *emit([true, false], |cb| cb.reform(|v: bool| !v)), + vec![false, true] + ); + } + + #[test] + fn test_filter_reform() { + assert_eq!( + *emit([1, 2, 3], |cb| cb.filter_reform(|v| match v { + 1 => Some(true), + 2 => Some(false), + _ => None, + })), + vec![true, false] + ); + } +}