Skip to content

Commit

Permalink
Allow skipping a callback when reforming
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
ctron committed Sep 8, 2022
1 parent 87e1d0e commit 7c57013
Showing 1 changed file with 66 additions and 1 deletion.
67 changes: 66 additions & 1 deletion packages/yew/src/callback.rs
Expand Up @@ -68,7 +68,7 @@ impl<IN> Default for Callback<IN> {

impl<IN: 'static, OUT: 'static> Callback<IN, OUT> {
/// 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<F, T>(&self, func: F) -> Callback<T, OUT>
where
F: Fn(T) -> IN + 'static,
Expand All @@ -82,4 +82,69 @@ impl<IN: 'static, OUT: 'static> Callback<IN, OUT> {
}
}

impl<IN: 'static> Callback<IN> {
/// 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<F, T>(&self, func: F) -> Callback<T>
where
F: Fn(T) -> Option<IN> + 'static,
{
let this = self.clone();
let func = move |input| {
if let Some(output) = func(input) {
this.emit(output);
}
};
Callback::from(func)
}
}

impl<IN, OUT> ImplicitClone for Callback<IN, OUT> {}

#[cfg(test)]
mod test {
use super::*;
use std::sync::Mutex;

/// emit the callback with the provided value
fn emit<T, I, R: 'static + Clone, F>(values: I, f: F) -> Vec<R>
where
I: IntoIterator<Item = T>,
F: FnOnce(Callback<R>) -> Callback<T>,
{
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]
);
}
}

0 comments on commit 7c57013

Please sign in to comment.