use nami::{Computed, SignalExt, signal::IntoComputed, zip::zip};
use crate::Environment;
#[derive(Debug, Clone)]
pub struct Disabled(Computed<bool>);
impl Disabled {
#[must_use]
pub fn new(disabled: impl IntoComputed<bool>) -> Self {
Self(disabled.into_computed())
}
#[must_use]
pub const fn signal(&self) -> &Computed<bool> {
&self.0
}
#[must_use]
pub fn resolve(env: &Environment, local: impl IntoComputed<bool>) -> Computed<bool> {
let local = local.into_computed();
match env.get::<Self>() {
Some(inherited) => zip(inherited.0.clone(), local)
.map(|(inherited, local)| inherited || local)
.into_computed(),
None => local,
}
}
pub fn install(env: &mut Environment, disabled: impl IntoComputed<bool>) {
let merged = Self::resolve(env, disabled);
env.insert(Self(merged));
}
}
#[cfg(test)]
mod tests {
use super::Disabled;
use crate::Environment;
use nami::{Signal, binding};
#[test]
fn resolve_without_scope_returns_local_signal() {
let env = Environment::new();
let local = binding(false);
let resolved = Disabled::resolve(&env, local.clone());
assert!(!resolved.get());
local.set(true);
assert!(resolved.get());
}
#[test]
fn nested_scopes_or_combine_reactively() {
let mut env = Environment::new();
let outer = binding(false);
Disabled::install(&mut env, outer.clone());
let inner = binding(false);
Disabled::install(&mut env, inner.clone());
let resolved = env
.get::<Disabled>()
.expect("installed disabled scope must be present")
.signal()
.clone();
assert!(!resolved.get());
outer.set(true);
assert!(resolved.get(), "outer scope must disable the subtree");
outer.set(false);
inner.set(true);
assert!(resolved.get(), "inner scope must disable the subtree");
inner.set(false);
assert!(!resolved.get());
}
}