use crate::{
context::Context,
observable::{CoreObservable, ObservableType},
observer::Observer,
};
#[derive(Clone)]
pub struct FilterMap<S, F> {
pub source: S,
pub func: F,
}
impl<S, F, Out> ObservableType for FilterMap<S, F>
where
S: ObservableType,
F: for<'a> FnMut(S::Item<'a>) -> Option<Out>,
{
type Item<'a>
= Out
where
Self: 'a;
type Err = S::Err;
}
pub struct FilterMapObserver<O, F> {
observer: O,
func: F,
}
impl<O, F, Item, Out, Err> Observer<Item, Err> for FilterMapObserver<O, F>
where
O: Observer<Out, Err>,
F: FnMut(Item) -> Option<Out>,
{
fn next(&mut self, v: Item) {
if let Some(mapped) = (self.func)(v) {
self.observer.next(mapped);
}
}
fn error(self, e: Err) { self.observer.error(e); }
fn complete(self) { self.observer.complete(); }
fn is_closed(&self) -> bool { self.observer.is_closed() }
}
impl<S, F, C, Out> CoreObservable<C> for FilterMap<S, F>
where
C: Context,
S: CoreObservable<C::With<FilterMapObserver<C::Inner, F>>>,
F: for<'a> FnMut(S::Item<'a>) -> Option<Out>,
{
type Unsub = S::Unsub;
fn subscribe(self, context: C) -> Self::Unsub {
let FilterMap { source, func } = self;
let wrapped = context.transform(|observer| FilterMapObserver { observer, func });
source.subscribe(wrapped)
}
}
#[cfg(test)]
mod tests {
use std::{cell::RefCell, rc::Rc};
use crate::prelude::*;
#[rxrust_macro::test]
fn test_filter_map_parse_strings() {
let result = Rc::new(RefCell::new(Vec::<i32>::new()));
let result_clone = result.clone();
Local::from_iter(vec!["1", "2", "invalid", "3", "not_a_number"])
.filter_map(|s| s.parse::<i32>().ok())
.subscribe(move |v| {
result_clone.borrow_mut().push(v);
});
assert_eq!(*result.borrow(), vec![1, 2, 3]);
}
#[rxrust_macro::test]
fn test_filter_map_some_none() {
let result = Rc::new(RefCell::new(Vec::<i32>::new()));
let result_clone = result.clone();
Local::from_iter(vec![1, 2, 3, 4, 5])
.filter_map(|x| if x % 2 == 0 { Some(x * 2) } else { None })
.subscribe(move |v| {
result_clone.borrow_mut().push(v);
});
assert_eq!(*result.borrow(), vec![4, 8]); }
#[rxrust_macro::test]
fn test_filter_map_all_none() {
let result = Rc::new(RefCell::new(Vec::<i32>::new()));
let result_clone = result.clone();
Local::from_iter(vec![1, 2, 3])
.filter_map(|_| None)
.subscribe(move |v| {
result_clone.borrow_mut().push(v);
});
assert_eq!(*result.borrow(), Vec::<i32>::new());
}
#[rxrust_macro::test]
fn test_filter_map_all_some() {
let result = Rc::new(RefCell::new(Vec::<i32>::new()));
let result_clone = result.clone();
Local::from_iter(vec![1, 2, 3])
.filter_map(|x| Some(x * 10))
.subscribe(move |v| {
result_clone.borrow_mut().push(v);
});
assert_eq!(*result.borrow(), vec![10, 20, 30]);
}
#[rxrust_macro::test]
fn test_filter_map_empty_source() {
let result = Rc::new(RefCell::new(Vec::<i32>::new()));
let result_clone = result.clone();
Local::from_iter(vec![] as Vec<i32>)
.filter_map(|x| Some(x * 2))
.subscribe(move |v| {
result_clone.borrow_mut().push(v);
});
assert_eq!(*result.borrow(), Vec::<i32>::new());
}
#[rxrust_macro::test]
fn test_filter_map_chaining_with_map() {
let result = Rc::new(RefCell::new(Vec::<i32>::new()));
let result_clone = result.clone();
Local::from_iter(vec!["1", "2", "invalid", "3"])
.filter_map(|s| s.parse::<i32>().ok())
.map(|x| x * 10)
.subscribe(move |v| {
result_clone.borrow_mut().push(v);
});
assert_eq!(*result.borrow(), vec![10, 20, 30]);
}
#[rxrust_macro::test]
fn test_filter_map_type_transformation() {
let result = Rc::new(RefCell::new(Vec::<usize>::new()));
let result_clone = result.clone();
Local::from_iter(vec!["hello", "world", "", "rust"])
.filter_map(|s| if s.len() > 3 { Some(s.len()) } else { None })
.subscribe(move |v| {
result_clone.borrow_mut().push(v);
});
assert_eq!(*result.borrow(), vec![5, 5, 4]); }
}