use core::fmt::Debug;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::ops::{Deref, Sub};
use std::rc::{Rc, Weak};
pub use super::cutoff::Cutoff;
pub use super::incr::{Incr, WeakIncr};
pub use super::internal_observer::{ObserverError, SubscriptionToken};
pub use super::kind::expert::public as expert;
pub use super::node_update::NodeUpdate;
#[doc(inline)]
pub use super::Value;
use super::internal_observer::{ErasedObserver, InternalObserver};
use super::node::NodeId;
use super::node_update::OnUpdateHandler;
use super::scope;
use super::state::State;
use super::var::{ErasedVariable, Var as InternalVar};
#[derive(Clone)]
pub struct Observer<T: Value> {
internal: Rc<InternalObserver<T>>,
sentinel: Rc<()>,
}
impl<T: Value> PartialEq for Observer<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.internal, &other.internal)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Update<T> {
Initialised(T),
Changed(T),
Invalidated,
}
impl<T> Update<T> {
#[inline]
pub fn value(self) -> Option<T> {
match self {
Self::Initialised(t) => Some(t),
Self::Changed(t) => Some(t),
_ => None,
}
}
}
impl<T> Update<&T> {
#[inline]
pub fn cloned(&self) -> Update<T>
where
T: Clone,
{
match *self {
Self::Initialised(t) => Update::Initialised(t.clone()),
Self::Changed(t) => Update::Changed(t.clone()),
Self::Invalidated => Update::Invalidated,
}
}
}
impl<T: Value> Observer<T> {
#[inline]
pub(crate) fn new(internal: Rc<InternalObserver<T>>) -> Self {
Self {
internal,
sentinel: Rc::new(()),
}
}
#[inline]
pub fn try_get_value(&self) -> Result<T, ObserverError> {
self.internal.try_get_value()
}
#[inline]
pub fn value(&self) -> T {
self.internal.try_get_value().unwrap()
}
pub fn subscribe(&self, on_update: impl FnMut(Update<&T>) + 'static) -> SubscriptionToken {
self.try_subscribe(on_update).unwrap()
}
pub fn try_subscribe(
&self,
mut on_update: impl FnMut(Update<&T>) + 'static,
) -> Result<SubscriptionToken, ObserverError> {
let handler_fn = Box::new(move |node_update: NodeUpdate<&T>| {
let update = match node_update {
NodeUpdate::Necessary(t) => Update::Initialised(t),
NodeUpdate::Changed(t) => Update::Changed(t),
NodeUpdate::Invalidated => Update::Invalidated,
NodeUpdate::Unnecessary => {
panic!("Incremental bug -- Observer subscription got NodeUpdate::Unnecessary")
}
};
on_update(update)
});
let state = self
.internal
.incr_state()
.ok_or(ObserverError::ObservingInvalid)?;
let now = state.stabilisation_num.get();
let handler = OnUpdateHandler::new(now, handler_fn);
let token = self.internal.subscribe(handler)?;
let node = self.internal.observing_erased();
let state = node.state();
node.handle_after_stabilisation(&state);
Ok(token)
}
#[inline]
pub fn state(&self) -> WeakState {
self.internal
.incr_state()
.map_or_else(|| WeakState { inner: Weak::new() }, |s| s.public_weak())
}
#[inline]
pub fn unsubscribe(&self, token: SubscriptionToken) -> Result<(), ObserverError> {
self.internal.unsubscribe(token)
}
pub fn save_dot_to_file(&self, named: &str) {
let node = self.internal.observing_erased();
super::node::save_dot_to_file(&mut core::iter::once(node), named).unwrap();
}
pub fn save_dot_to_string(&self) -> String {
let node = self.internal.observing_erased();
let mut buf = String::new();
super::node::save_dot(&mut buf, &mut core::iter::once(node)).unwrap();
buf
}
pub fn disallow_future_use(&self) {
let Some(state) = self.internal.incr_state() else {
return;
};
self.internal.disallow_future_use(&state);
}
}
impl<T: Value> Drop for Observer<T> {
fn drop(&mut self) {
if Rc::strong_count(&self.sentinel) <= 1 {
if let Some(state) = self.internal.incr_state() {
self.internal.disallow_future_use(&state);
} else {
self.internal
.state
.set(super::internal_observer::ObserverState::Disallowed);
}
}
}
}
#[derive(Clone)]
pub struct Var<T: Value> {
internal: Rc<InternalVar<T>>,
sentinel: Rc<()>,
watch: Incr<T>,
}
impl<T: Value> fmt::Debug for Var<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut tuple = f.debug_tuple("Var");
let internal = self.internal.value.borrow();
tuple.field(&self.id()).field(&*internal).finish()
}
}
impl<T: Value> PartialEq for Var<T> {
fn eq(&self, other: &Self) -> bool {
self.id() == other.id()
}
}
impl<T: Value> Deref for Var<T> {
type Target = Incr<T>;
fn deref(&self) -> &Self::Target {
&self.watch
}
}
impl<T: Value> Var<T> {
pub(crate) fn new(internal: Rc<InternalVar<T>>) -> Self {
Self {
watch: internal.watch(),
internal,
sentinel: Rc::new(()),
}
}
#[inline]
pub fn set(&self, value: T) {
self.internal.set(value)
}
#[inline]
pub fn was_changed_during_stabilisation(&self) -> bool {
self.internal.was_changed_during_stabilisation()
}
#[inline]
pub fn update(&self, f: impl FnOnce(T) -> T)
where
T: Default,
{
self.internal.update(f)
}
#[inline]
pub fn replace_with(&self, f: impl FnOnce(&mut T) -> T) -> T {
self.internal.replace_with(|mutable| f(mutable))
}
#[inline]
pub fn replace(&self, value: T) -> T {
self.internal.replace_with(|_| value)
}
#[inline]
pub fn modify(&self, f: impl FnOnce(&mut T)) {
self.internal.modify(f);
}
#[inline]
pub fn get(&self) -> T {
self.internal.get()
}
#[inline]
pub fn watch(&self) -> Incr<T> {
self.watch.clone()
}
#[inline]
pub fn id(&self) -> NodeId {
self.internal.node_id.get()
}
}
impl<T: Value> Drop for Var<T> {
fn drop(&mut self) {
tracing::trace!("dropping public::Var with id {:?}", self.id());
if Rc::strong_count(&self.sentinel) <= 1 {
if let Some(state) = self.internal.state.upgrade() {
let mut dead_vars = state.dead_vars.borrow_mut();
dead_vars.push(self.internal.erased());
} else {
self.internal.break_rc_cycle();
}
}
}
}
#[derive(Debug, Clone)]
pub struct IncrState {
pub(crate) inner: Rc<State>,
}
impl Default for IncrState {
fn default() -> Self {
Self::new()
}
}
impl PartialEq for IncrState {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.ptr_eq(other)
}
}
impl IncrState {
pub fn new() -> Self {
let inner = State::new();
Self { inner }
}
pub fn new_with_height(max_height: usize) -> Self {
let inner = State::new_with_height(max_height);
Self { inner }
}
#[inline]
pub fn ptr_eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.inner, &other.inner)
}
#[inline]
pub fn weak(&self) -> WeakState {
WeakState {
inner: Rc::downgrade(&self.inner),
}
}
pub fn add_weak_map<S: WeakMap + 'static>(&self, weak_map: Rc<RefCell<S>>) {
self.inner.add_weak_map(weak_map)
}
pub fn weak_memoize_fn<I: Hash + Eq + Clone + 'static, T: Value>(
&self,
mut f: impl FnMut(I) -> Incr<T> + Clone,
) -> impl FnMut(I) -> Incr<T> + Clone {
let storage: WeakHashMap<I, T> = WeakHashMap::default();
let storage: Rc<RefCell<WeakHashMap<I, T>>> = Rc::new(RefCell::new(storage));
self.add_weak_map(storage.clone());
let weak_state = self.weak();
let creation_scope = self.current_scope();
move |i| {
let storage_ = storage.borrow();
if storage_.contains_key(&i) {
let occ = storage_.get(&i).unwrap();
let incr = occ.upgrade();
if let Some(found_strong) = incr {
return found_strong;
}
}
drop(storage_);
let val = weak_state
.upgrade()
.unwrap()
.within_scope(creation_scope.clone(), || f(i.clone()));
let mut storage_ = storage.borrow_mut();
storage_.insert(i, val.weak());
val
}
}
#[inline]
pub fn is_stable(&self) -> bool {
self.inner.is_stable()
}
pub fn stabilise(&self) {
self.inner.stabilise();
}
#[inline]
pub fn is_stabilising(&self) -> bool {
self.inner.is_stabilising()
}
pub fn stabilise_debug(&self, dot_file_prefix: &str) {
self.inner.stabilise_debug(Some(dot_file_prefix));
}
#[inline]
pub fn constant<T: Value>(&self, value: T) -> Incr<T> {
self.inner.constant(value)
}
pub fn fold<F, T: Value, R: Value>(&self, vec: Vec<Incr<T>>, init: R, f: F) -> Incr<R>
where
F: FnMut(R, &T) -> R + 'static,
{
self.inner.fold(vec, init, f)
}
pub fn var<T: Value>(&self, value: T) -> Var<T> {
self.inner.var_in_scope(value, scope::Scope::Top)
}
pub fn var_current_scope<T: Value>(&self, value: T) -> Var<T> {
self.inner.var_in_scope(value, self.inner.current_scope())
}
pub fn unsubscribe(&self, token: SubscriptionToken) {
self.inner.unsubscribe(token)
}
pub fn set_max_height_allowed(&self, new_max_height: usize) {
self.inner.set_max_height_allowed(new_max_height)
}
pub fn within_scope<R>(&self, scope: Scope, f: impl FnOnce() -> R) -> R {
self.inner.within_scope(scope.0, f)
}
#[inline]
pub fn current_scope(&self) -> Scope {
Scope(self.inner.current_scope())
}
pub fn save_dot_to_file(&self, named: &str) {
self.inner.save_dot_to_file(named)
}
pub fn stats(&self) -> Stats {
Stats {
created: self.inner.num_nodes_created.get(),
changed: self.inner.num_nodes_changed.get(),
recomputed: self.inner.num_nodes_recomputed.get(),
invalidated: self.inner.num_nodes_invalidated.get(),
became_necessary: self.inner.num_nodes_became_necessary.get(),
became_unnecessary: self.inner.num_nodes_became_unnecessary.get(),
necessary: self.inner.num_nodes_became_necessary.get()
- self.inner.num_nodes_became_unnecessary.get(),
}
}
}
#[derive(Debug, Clone)]
pub struct WeakState {
pub(crate) inner: Weak<State>,
}
impl PartialEq for WeakState {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.ptr_eq(other)
}
}
impl WeakState {
#[inline]
pub fn ptr_eq(&self, other: &Self) -> bool {
self.inner.ptr_eq(&other.inner)
}
#[inline]
pub fn strong_count(&self) -> usize {
self.inner.strong_count()
}
#[inline]
pub fn weak_count(&self) -> usize {
self.inner.weak_count()
}
pub(crate) fn upgrade_inner(&self) -> Option<Rc<State>> {
self.inner.upgrade()
}
#[inline]
pub fn upgrade(&self) -> Option<IncrState> {
Some(IncrState {
inner: self.upgrade_inner()?,
})
}
#[doc(hidden)]
pub fn print_heap(&self) {
let inner = self.upgrade_inner().unwrap();
println!("{:?}", inner.recompute_heap);
}
#[inline]
pub fn constant<T: Value>(&self, value: T) -> Incr<T> {
self.upgrade().unwrap().constant(value)
}
pub fn fold<F, T: Value, R: Value>(&self, vec: Vec<Incr<T>>, init: R, f: F) -> Incr<R>
where
F: FnMut(R, &T) -> R + 'static,
{
self.inner.upgrade().unwrap().fold(vec, init, f)
}
pub fn var<T: Value>(&self, value: T) -> Var<T> {
self.inner
.upgrade()
.unwrap()
.var_in_scope(value, scope::Scope::Top)
}
pub fn var_current_scope<T: Value>(&self, value: T) -> Var<T> {
let inner = self.inner.upgrade().unwrap();
inner.var_in_scope(value, inner.current_scope())
}
pub fn within_scope<R>(&self, scope: Scope, f: impl FnOnce() -> R) -> R {
self.inner.upgrade().unwrap().within_scope(scope.0, f)
}
#[inline]
pub fn current_scope(&self) -> Scope {
Scope(self.inner.upgrade().unwrap().current_scope())
}
pub fn save_dot_to_file(&self, named: &str) {
self.inner.upgrade().unwrap().save_dot_to_file(named)
}
pub fn save_dot_to_string(&self) -> String {
self.inner.upgrade().unwrap().save_dot_to_string()
}
pub fn unsubscribe(&self, token: SubscriptionToken) {
self.inner.upgrade().unwrap().unsubscribe(token)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Stats {
pub created: usize,
pub changed: usize,
pub recomputed: usize,
pub invalidated: usize,
pub became_necessary: usize,
pub became_unnecessary: usize,
pub necessary: usize,
}
#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct StatsDiff {
pub created: isize,
pub changed: isize,
pub recomputed: isize,
pub invalidated: isize,
pub became_necessary: isize,
pub became_unnecessary: isize,
pub necessary: isize,
}
impl Debug for StatsDiff {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut f = f.debug_struct("StatsDiff");
let mut field = |name: &str, x: isize| {
if x != 0 {
f.field(name, &x);
}
};
field("created", self.created);
field("changed", self.changed);
field("recomputed", self.recomputed);
field("invalidated", self.invalidated);
field("became_necessary", self.became_necessary);
field("became_unnecessary", self.became_unnecessary);
field("necessary", self.necessary);
f.finish()
}
}
impl Stats {
pub fn diff(&self, other: Self) -> StatsDiff {
StatsDiff {
created: self.created as isize - other.created as isize,
changed: self.changed as isize - other.changed as isize,
recomputed: self.recomputed as isize - other.recomputed as isize,
invalidated: self.invalidated as isize - other.invalidated as isize,
became_necessary: self.became_necessary as isize - other.became_necessary as isize,
became_unnecessary: self.became_unnecessary as isize
- other.became_unnecessary as isize,
necessary: self.necessary as isize - other.necessary as isize,
}
}
}
impl Sub for Stats {
type Output = StatsDiff;
fn sub(self, rhs: Self) -> Self::Output {
self.diff(rhs)
}
}
pub trait IntoIncr<T> {
fn into_incr(self) -> Incr<T>;
}
impl<T: Value> AsRef<Incr<T>> for Var<T> {
#[inline]
fn as_ref(&self) -> &Incr<T> {
self.deref()
}
}
impl<T: Value> AsRef<Incr<T>> for Incr<T> {
#[inline]
fn as_ref(&self) -> &Incr<T> {
&self
}
}
impl<T> IntoIncr<T> for Incr<T> {
#[inline]
fn into_incr(self) -> Incr<T> {
self
}
}
impl<T> IntoIncr<T> for &Incr<T> {
#[inline]
fn into_incr(self) -> Incr<T> {
self.clone()
}
}
impl<T: Value> IntoIncr<T> for Var<T> {
#[inline]
fn into_incr(self) -> Incr<T> {
self.watch()
}
}
impl<T: Value> IntoIncr<T> for &Var<T> {
#[inline]
fn into_incr(self) -> Incr<T> {
self.watch()
}
}
#[allow(clippy::len_without_is_empty)]
pub trait WeakMap {
fn len(&self) -> usize;
fn capacity(&self) -> usize;
fn garbage_collect(&mut self);
}
pub type WeakHashMap<K, V> = HashMap<K, WeakIncr<V>>;
impl<K: Hash, V> WeakMap for WeakHashMap<K, V> {
fn garbage_collect(&mut self) {
self.retain(|_k, v| v.strong_count() != 0);
}
fn len(&self) -> usize {
HashMap::len(self)
}
fn capacity(&self) -> usize {
HashMap::capacity(self)
}
}
#[cfg(feature = "slotmap")]
pub type WeakSlotMap<K, V> = slotmap::HopSlotMap<K, WeakIncr<V>>;
#[cfg(feature = "slotmap")]
impl<K: slotmap::Key, V> WeakMap for WeakSlotMap<K, V> {
fn garbage_collect(&mut self) {
self.retain(|_k, v| v.strong_count() != 0);
}
fn len(&self) -> usize {
slotmap::HopSlotMap::len(self)
}
fn capacity(&self) -> usize {
slotmap::HopSlotMap::capacity(self)
}
}
#[derive(Clone)]
pub struct Scope(scope::Scope);
impl Debug for Scope {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl Scope {
pub const fn top() -> Self {
Scope(scope::Scope::Top)
}
}