1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use super::{
	Signal,
	Slot,
	SlotImpl,
};

/// Property represents a storage which may receive new values via it's slot
/// and may notify about value change via it's signal.
///
/// It's important that [Property::try_update] method have to be called to
/// initiate slot data processing.
pub struct Property<T: 'static + Clone> {
	value: T,
	slot: SlotImpl<T>,
	signal: Signal<T>,
}

impl<T: 'static + Clone> Property<T> {
	/// Creates new property instance.
	pub fn new(value: T) -> Property<T> {
		return Property {
			value,
			slot: SlotImpl::new(),
			signal: Signal::new(),
		};
	}

	/// Signal will be emited at least every time inner value will be changed
	///
	/// It's possible that signal may be emited with the same value.
	pub fn signal(&mut self) -> &mut Signal<T> {
		return &mut self.signal;
	}

	/// The slot allows value change to be scheduled.
	///
	/// The value will not be changed without (Property::try_update) call.
	/// Only after that the value will be update and signal will be emited.
	pub fn slot(&self) -> &dyn Slot<T> {
		return &self.slot;
	}

	/// Sets new value. Signal will be emited to inform about value change.
	pub fn set(
		&mut self,
		new_value: T,
	) {
		Property::update_value(&mut self.value, &mut self.signal, new_value);
	}

	/// Allow access to property's value via immutable ref
	pub fn as_ref(&self) -> &T {
		return &self.value;
	}

	/// Allow function to be change inner value. Signal will be rased to inform
	/// about value change even if value is the same.
	pub fn for_mut(
		&mut self,
		f: &dyn Fn(&mut T),
	) {
		f(&mut self.value);
		if self.signal.has_connections() {
			self.signal.emit(self.value.clone());
		}
	}

	/// Initiates inner value update from slot's data. Signal will be emited for
	/// every incoming slot data.
	///
	/// return true if there was at least one update from slot, otherwise return false
	pub fn try_update(&mut self) -> bool {
		let mut result = false;

		for v in self.slot.data_iter() {
			result = true;
			Property::update_value(&mut self.value, &mut self.signal, v);
		}

		return result;
	}

	fn update_value(
		holder: &mut T,
		signal: &mut Signal<T>,
		new_value: T,
	) {
		*holder = new_value;
		signal.emit(holder.clone());
	}
}

impl<T: 'static + Clone + Default> Default for Property<T> {
	fn default() -> Self {
		return Self::new(T::default());
	}
}