Files
bone_cake
lobby
rask_engine
rask_server
rask_wasm
rask_wasm_graphics
rask_wasm_logic
rask_wasm_processor
rask_wasm_shared
wasm_sync
  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
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use crate::mem;
use std::fmt::Debug;

pub trait Element: Clone + Sized + Default + Debug {}
type Flag = u8;

impl<T: Clone + Sized + Default + Debug> Element for T {}

#[repr(C)]
#[derive(Debug, Default)]
pub struct DoubleBuffer<T: Element> {
    pub(self) reading_at: Flag,
    pub(self) provided: Flag,
    buffer: [T; 2],
}

#[derive(Debug)]
pub struct ReaderBufferView<'a, T: Element> {
    ptr: &'a mut DoubleBuffer<T>,
    read_pos: u8,
}

#[derive(Debug)]
pub struct WriterBufferView<'a, T: Element> {
    ptr: &'a mut DoubleBuffer<T>,
    write_pos: u8,
}

impl<T: Element> DoubleBuffer<T> {
    pub fn new() -> Self {
        DoubleBuffer {
            reading_at: 0,
            provided: 0,
            buffer: [T::default(), T::default()],
        }
    }

    pub fn borrow_reader(&mut self) -> Option<ReaderBufferView<T>> {
        match (self.get_reading_at(), self.get_provided()) {
            (0, 0) => None,
            (0, p) => {
                let mut x = p;
                self.set_reading_at(x);
                while x != p {
                    x = p;
                    self.set_reading_at(x);
                }
                Some(ReaderBufferView {
                    ptr: self,
                    read_pos: x - 1,
                })
            }
            (c, p) => panic!("invalid state ({},{}) for consumer reached", c, p),
        }
    }

    pub fn borrow_writer(&mut self) -> WriterBufferView<T> {
        let write_pos = match (self.get_reading_at(), self.get_provided()) {
            (0, 0) => 0,
            (0, y) => 2 - y,
            (y, x) => {
                if x == y {
                    2 - y
                } else {
                    self.set_provided(y);
                    y - 1
                }
            }
        };
        WriterBufferView {
            ptr: self,
            write_pos,
        }
    }

    pub extern "C" fn set_reading_at(&mut self, reading_at: Flag) {
        unsafe { mem::atomic_write_u8(&mut self.reading_at, reading_at) }
    }

    pub extern "C" fn get_reading_at(&self) -> Flag {
        unsafe { mem::atomic_read_u8(&self.reading_at) }
    }

    pub extern "C" fn set_provided(&mut self, provided: Flag) {
        unsafe { mem::atomic_write_u8(&mut self.provided, provided) }
    }

    pub extern "C" fn get_provided(&self) -> Flag {
        unsafe { mem::atomic_read_u8(&self.provided) }
    }
}

impl<'a, T: Element> ReaderBufferView<'a, T> {
    pub fn get(&self) -> &T {
        &self.ptr.buffer[self.read_pos as usize]
    }
}

impl<'a, T: Element> WriterBufferView<'a, T> {
    pub fn get(&self) -> &T {
        &self.ptr.buffer[self.write_pos as usize]
    }

    pub fn set(&mut self, data: T) {
        self.ptr.buffer[self.write_pos as usize] = data;
    }
}

impl<'a, T: Element> std::ops::Drop for ReaderBufferView<'a, T> {
    fn drop(&mut self) {
        self.ptr.set_reading_at(0);
    }
}

impl<'a, T: Element> std::ops::Drop for WriterBufferView<'a, T> {
    fn drop(&mut self) {
        self.ptr.set_provided(self.write_pos + 1);
    }
}