use std::ops::
{
Deref,
DerefMut,
Index,
IndexMut
};
pub struct DoubleBuffered<T: Clone>
{
rbuf: T,
wbuf: T,
}
impl<T: Clone> DoubleBuffered<T>
{
pub fn new(value: T) -> Self
{
Self
{
rbuf: value.clone(),
wbuf: value.clone(),
}
}
pub fn construct_with<F: Fn() -> T>(constructor: F) -> Self
{
Self
{
rbuf: constructor(),
wbuf: constructor(),
}
}
pub fn read(&self) -> &T
{
&self.rbuf
}
pub fn write(&mut self) -> &mut T
{
&mut self.wbuf
}
pub fn update(&mut self)
{
self.rbuf = self.wbuf.clone();
}
pub fn upsert(&mut self, value: T)
{
*self.write() = value;
self.update();
}
pub fn unbuffer_read(self) -> T
{
self.rbuf
}
pub fn unbuffer_write(self) -> T
{
self.wbuf
}
}
impl<T: Clone> Deref for DoubleBuffered<T>
{
type Target = T;
fn deref(&self) -> &T
{
self.read()
}
}
impl<T: Clone> DerefMut for DoubleBuffered<T>
{
fn deref_mut(&mut self) -> &mut T
{
self.write()
}
}
impl<T: Default + Clone> Default for DoubleBuffered<T>
{
fn default() -> Self
{
Self::construct_with(T::default)
}
}
impl<I, T: Index<I> + Clone> Index<I> for DoubleBuffered<T>
{
type Output = <T as Index<I>>::Output;
fn index(&self, index: I) -> &Self::Output
{
&self.rbuf[index]
}
}
impl<I, T: IndexMut<I> + Clone> IndexMut<I> for DoubleBuffered<T>
{
fn index_mut(&mut self, index: I) -> &mut Self::Output
{
&mut self.wbuf[index]
}
}
#[cfg(test)]
mod tests
{
use super::*;
#[test]
fn basic_int()
{
let mut db = DoubleBuffered::<i32>::default();
*db.write() = 3;
assert!(*db.read() == 0);
db.update();
assert!(*db.read() == 3);
*db.write() = 4;
assert!(*db.read() == 3);
db.update();
assert!(*db.read() == 4);
}
#[test]
fn basic_string()
{
let mut db = DoubleBuffered::construct_with(String::new);
assert!(*db.read() == String::new());
*db.write() = "hello, world".to_string();
db.update();
assert!(*db.read() == String::from("hello, world"));
}
#[test]
fn basic_int_using_deref()
{
let mut db = DoubleBuffered::<i32>::default();
*db = 3;
assert!(*db == 0);
db.update();
assert!(*db == 3);
*db = 4;
assert!(*db == 3);
db.update();
assert!(*db == 4);
}
#[test]
fn vec_i32()
{
let mut db = DoubleBuffered::<Vec<i32>>::default();
db.push(0);
db.update();
assert!(db[0] == 0);
db[0] = 1;
assert!(db[0] == 0);
db.update();
assert!(db[0] == 1);
}
}