use std::any::Any;
type PropertyCallback<T> = Box<dyn FnMut(&T)>;
pub struct Property<T: Any>
{
value: Option<T>,
subscriptions: Vec<PropertyCallback<T>>,
}
impl<T: Any> Property<T>
{
pub fn new(value: T) -> Self
{
Self {
value: Some(value),
subscriptions: Vec::new(),
}
}
pub fn empty() -> Self {
Self {
value: None,
subscriptions: Vec::new(),
}
}
pub fn get(&self) -> Option<&T> {
self.value.as_ref()
}
pub fn assign(&mut self, value: T)
{
self.value = Some(value);
for callback in self.subscriptions.iter_mut() {
callback(self.value.as_ref().unwrap());
}
}
pub fn subscribe(&mut self, callback: Box<dyn FnMut(&T)>) {
self.subscriptions.push(callback);
}
}
#[cfg(test)]
mod tests {
use std::sync::{Arc, Mutex};
use super::*;
#[test]
fn test_empty_property_i32() {
let prop = Property::<i32>::empty();
assert_eq!(prop.get(), None);
}
#[test]
fn test_new_property_i32() {
let prop = Property::new(42);
assert_eq!(prop.get(), Some(42).as_ref());
}
#[test]
fn test_assign_property_i32() {
let mut prop = Property::new(42);
assert_eq!(prop.get(), Some(42).as_ref());
prop.assign(99);
assert_eq!(prop.get(), Some(99).as_ref());
prop.assign(11);
assert_eq!(prop.get(), Some(11).as_ref());
}
#[test]
fn test_subscribe_property_i32() {
let mut prop = Property::new(42);
let count = Arc::new(Mutex::new(0));
let count_clone = Arc::clone(&count);
prop.subscribe(Box::new(move |val| {
assert_eq!(*val, 11);
let mut count = count_clone.lock().unwrap();
*count += 1;
}));
prop.assign(11);
prop.assign(11);
assert_eq!(*count.lock().unwrap(), 2);
}
#[derive(Copy, Clone, PartialEq, Debug)]
struct MyInt(i32);
#[test]
fn test_empty_property_newtype() {
let prop = Property::<MyInt>::empty();
assert_eq!(prop.get(), None);
}
#[test]
fn test_new_property_newtype() {
let prop = Property::new(MyInt(42));
assert_eq!(prop.get(), Some(MyInt(42)).as_ref());
}
#[test]
fn test_assign_property_newtype() {
let mut prop = Property::new(MyInt(42));
assert_eq!(prop.get(), Some(MyInt(42)).as_ref());
prop.assign(MyInt(99));
assert_eq!(prop.get(), Some(MyInt(99)).as_ref());
prop.assign(MyInt(11));
assert_eq!(prop.get(), Some(MyInt(11)).as_ref());
}
#[test]
fn test_subscribe_property_newtype() {
let mut prop = Property::new(MyInt(42));
let count = Arc::new(Mutex::new(0));
let count_clone = Arc::clone(&count);
prop.subscribe(Box::new(move |val| {
assert_eq!(*val, MyInt(11));
let mut count = count_clone.lock().unwrap();
*count += 1;
}));
prop.assign(MyInt(11));
prop.assign(MyInt(11));
prop.assign(MyInt(11));
assert_eq!(*count.lock().unwrap(), 3);
}
}