use std::{sync::*, ops::*}; #[derive(PartialEq, Eq, Debug)] enum Status { Same, Changed, } impl Default for Status { fn default() -> Self { Status::Same } } pub struct DoubleBuffer { read_buffer: Arc>, write_buffer: T, } impl DoubleBuffer { pub fn new() -> Self where T: Default { Self { read_buffer: Arc::default(), write_buffer: T::default(), } } pub fn split(self) -> (DoubleBufferRead, DoubleBufferWrite) { ( DoubleBufferRead { read_buffer: Arc::clone(&self.read_buffer), }, DoubleBufferWrite { read_buffer: self.read_buffer, write_buffer: self.write_buffer, } ) } } pub struct DoubleBufferRead { read_buffer: Arc>, } pub struct DoubleBufferReadGuard<'a, T> { guard: MutexGuard<'a, (T, Status)>, } impl<'a, T> Deref for DoubleBufferReadGuard<'a, T> { type Target = T; fn deref(&self) -> &T { &self.guard.0 } } impl<'a, T> DerefMut for DoubleBufferReadGuard<'a, T> { fn deref_mut(&mut self) -> &mut T { &mut self.guard.0 } } impl DoubleBufferRead { pub fn if_changed(&self) -> Option> { match self.read_buffer.lock() { Ok(mut guard) => { if guard.1 == Status::Changed { // mark buffer as same guard.1 = Status::Same; // return guard Some(DoubleBufferReadGuard { guard }) } else { None } }, Err(PoisonError { .. }) => None, } } } pub struct DoubleBufferWrite { read_buffer: Arc>, write_buffer: T, } impl DoubleBufferWrite { pub fn swap(buffer: &mut Self) { match buffer.read_buffer.lock() { Ok(mut guard) => { // mark buffer as changed guard.1 = Status::Changed; // swap the buffers std::mem::swap(&mut guard.0, &mut buffer.write_buffer); }, Err(PoisonError { .. }) => {}, } } } impl Deref for DoubleBufferWrite { type Target = T; fn deref(&self) -> &T { &self.write_buffer } } impl DerefMut for DoubleBufferWrite { fn deref_mut(&mut self) -> &mut T { &mut self.write_buffer } }