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 4ca6673
Showing 1 changed file with 61 additions and 1 deletion.
62 changes: 61 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 @@ -80,6 +80,66 @@ impl<IN: 'static, OUT: 'static> Callback<IN, OUT> {
};
Callback::from(func)
}

/// 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, OUT>
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::*;

/// emit the callback with the provided value
fn emit<I, T, F, R>(values: I, f: F) -> Vec<R>
where
I: IntoIterator<Item = T>,
F: FnOnce(Callback<R>) -> Callback<T>,
{
let mut result: Vec<T> = Vec::new();
for value in values {
f(Callback::from(|v| result.push(v))).emit(value);
}
result
}

#[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| !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 4ca6673

Please sign in to comment.