use crate::traits::*;
use crate::watcher::*;
use crate::releasable::*;
use crate::binding_context::*;
use std::sync::*;
struct BoundValue<Value> {
value: Value,
when_changed: Vec<ReleasableNotifiable>
}
impl<Value: Clone + PartialEq> BoundValue<Value> {
pub fn new(val: Value) -> BoundValue<Value> {
BoundValue {
value: val,
when_changed: vec![]
}
}
pub fn set_without_notifying(&mut self, new_value: Value) -> bool {
let changed = self.value != new_value;
self.value = new_value;
changed
}
pub fn get_notifiable_items(&self) -> Vec<ReleasableNotifiable> {
self.when_changed
.iter()
.map(|item| item.clone_for_inspection())
.collect()
}
pub fn filter_unused_notifications(&mut self) {
self.when_changed.retain(|releasable| releasable.is_in_use());
}
fn get(&self) -> Value {
self.value.clone()
}
fn get_mut(&mut self) -> &mut Value {
&mut self.value
}
fn when_changed(&mut self, what: Arc<dyn Notifiable>) -> ReleasableNotifiable {
let releasable = ReleasableNotifiable::new(what);
self.when_changed.push(releasable.clone_as_owned());
self.filter_unused_notifications();
releasable
}
}
impl<Value: Default + Clone + PartialEq> Default for BoundValue<Value> {
fn default() -> Self {
BoundValue::new(Value::default())
}
}
impl<Value: std::fmt::Debug> std::fmt::Debug for BoundValue<Value> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.value.fmt(f)
}
}
impl<Value: PartialEq> PartialEq for BoundValue<Value> {
fn eq(&self, other: &Self) -> bool {
self.value.eq(&other.value)
}
}
#[derive(Clone)]
pub struct Binding<Value> {
value: Arc<Mutex<BoundValue<Value>>>
}
impl<Value: Default + Clone + PartialEq> Default for Binding<Value> {
fn default() -> Self {
Binding::new(Value::default())
}
}
impl<Value: std::fmt::Debug> std::fmt::Debug for Binding<Value> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.value.fmt(f)
}
}
impl<Value: PartialEq> PartialEq for Binding<Value> {
fn eq(&self, other: &Self) -> bool {
self.value.lock().unwrap().eq(&other.value.lock().unwrap())
}
}
impl<Value: Clone+PartialEq> Binding<Value> {
pub fn new(value: Value) -> Binding<Value> {
Binding {
value: Arc::new(Mutex::new(BoundValue::new(value)))
}
}
}
impl<Value: 'static+Clone+PartialEq+Send> Changeable for Binding<Value> {
fn when_changed(&self, what: Arc<dyn Notifiable>) -> Box<dyn Releasable> {
Box::new(self.value.lock().unwrap().when_changed(what))
}
}
impl<TValue> Bound for Binding<TValue>
where
TValue: 'static + Clone + PartialEq + Send,
{
type Value = TValue;
fn get(&self) -> Self::Value {
BindingContext::add_dependency(self.clone());
self.value.lock().unwrap().get()
}
fn watch(&self, what: Arc<dyn Notifiable>) -> Arc<dyn Watcher<Self::Value>> {
let watch_binding = self.clone();
let (watcher, notifiable) = NotifyWatcher::new(move || watch_binding.get(), what);
self.value.lock().unwrap().when_changed.push(notifiable);
self.value.lock().unwrap().filter_unused_notifications();
Arc::new(watcher)
}
}
impl<Value> MutableBound for Binding<Value>
where
Value: 'static + Clone + PartialEq + Send
{
fn set(&self, new_value: Value) {
let notifications = {
let mut cell = self.value.lock().unwrap();
let changed = cell.set_without_notifying(new_value);
if changed {
cell.get_notifiable_items()
} else {
vec![]
}
};
let mut needs_filtering = false;
for to_notify in notifications {
needs_filtering = !to_notify.mark_as_changed() || needs_filtering;
}
if needs_filtering {
let mut cell = self.value.lock().unwrap();
cell.filter_unused_notifications();
}
}
}
impl<Value: 'static + Clone + PartialEq + Send> WithBound<Value> for Binding<Value> {
fn with_ref<F, T>(&self, f: F) -> T
where
F: FnOnce(&Value) -> T,
{
f(&self.value.lock().unwrap().value)
}
fn with_mut<F>(&self, f: F)
where
F: FnOnce(&mut Value) -> bool,
{
let notifications = {
let mut v = self.value.lock().unwrap();
let changed = f(v.get_mut());
if changed {
v.get_notifiable_items()
} else {
vec![]
}
};
let mut needs_filtering = false;
for to_notify in notifications {
needs_filtering = !to_notify.mark_as_changed() || needs_filtering;
}
if needs_filtering {
let mut cell = self.value.lock().unwrap();
cell.filter_unused_notifications();
}
}
}
impl<Value: 'static+Clone+PartialEq+Send> From<Value> for Binding<Value> {
#[inline]
fn from(val: Value) -> Binding<Value> {
Binding::new(val)
}
}
impl<'a, Value: 'static+Clone+PartialEq+Send> From<&'a Binding<Value>> for Binding<Value> {
#[inline]
fn from(val: &'a Binding<Value>) -> Binding<Value> {
Binding::clone(val)
}
}
impl<'a, Value: 'static+Clone+PartialEq+Send> From<&'a Value> for Binding<Value> {
#[inline]
fn from(val: &'a Value) -> Binding<Value> {
Binding::new(val.clone())
}
}