#![forbid(unsafe_code)]
use std::{cell::RefCell, collections::HashMap, fmt::Debug, hash::Hash, rc::Rc};
use crate::{create_isomorphic_effect, create_signal, ReadSignal, Scope, WriteSignal};
pub fn create_selector<T>(
cx: Scope,
source: impl Fn() -> T + Clone + 'static,
) -> impl Fn(T) -> bool + Clone
where
T: PartialEq + Eq + Debug + Clone + Hash + 'static,
{
create_selector_with_fn(cx, source, |a, b| a == b)
}
pub fn create_selector_with_fn<T>(
cx: Scope,
source: impl Fn() -> T + Clone + 'static,
f: impl Fn(&T, &T) -> bool + Clone + 'static,
) -> impl Fn(T) -> bool + Clone
where
T: PartialEq + Eq + Debug + Clone + Hash + 'static,
{
#[allow(clippy::type_complexity)]
let subs: Rc<RefCell<HashMap<T, (ReadSignal<bool>, WriteSignal<bool>)>>> =
Rc::new(RefCell::new(HashMap::new()));
let v = Rc::new(RefCell::new(None));
create_isomorphic_effect(cx, {
let subs = Rc::clone(&subs);
let f = f.clone();
let v = Rc::clone(&v);
move |prev: Option<T>| {
let next_value = source();
*v.borrow_mut() = Some(next_value.clone());
if prev.as_ref() != Some(&next_value) {
let subs = { subs.borrow().clone() };
for (key, signal) in subs.into_iter() {
if f(&key, &next_value) || (prev.is_some() && f(&key, prev.as_ref().unwrap())) {
signal.1.update(|n| *n = true);
}
}
}
next_value
}
});
move |key| {
let mut subs = subs.borrow_mut();
let (read, _) = subs
.entry(key.clone())
.or_insert_with(|| create_signal(cx, false));
_ = read.try_with(|n| *n);
f(&key, v.borrow().as_ref().unwrap())
}
}