mvutils/
state.rs

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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use std::ops::{Deref, DerefMut};
use std::sync::{Arc};
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use crate::unsafe_utils::DangerousCell;

pub struct State<T> {
    inner: Arc<(DangerousCell<u64>, RwLock<T>)>,
    local_version: DangerousCell<u64>,
}

impl<T> State<T> {
    pub fn new(value: T) -> Self {
        Self {
            inner: Arc::new((DangerousCell::new(0), RwLock::new(value))),
            local_version: DangerousCell::new(0),
        }
    }

    pub fn read(&self) -> RwLockReadGuard<T> {
        self.inner.1.read()
    }

    pub fn write(&self) -> StateWriteGuard<T> {
        StateWriteGuard {
            inner: self.inner.1.write(),
            ptr: self.inner.0.get_mut(),
        }
    }

    pub fn get_version(&self) -> u64 {
        self.inner.0.get_val()
    }

    pub fn get_local_version(&self) -> u64 {
        self.local_version.get_val()
    }

    pub fn is_outdated(&self) -> bool {
        self.inner.0.get_val() != self.local_version.get_val()
    }

    pub fn update(&self) {
        self.local_version.replace(self.inner.0.get_val());
    }

    pub fn force_outdated(&self) {
        if self.inner.0.get_val() == 0 {
            self.local_version.replace(u64::MAX);
        } else {
            self.local_version.replace(0);
        }
    }
}

unsafe impl<T> Send for State<T> {}
unsafe impl<T> Sync for State<T> {}

impl<T> Clone for State<T> {
    fn clone(&self) -> Self {
        State {
            inner: self.inner.clone(),
            local_version: DangerousCell::new(self.local_version.get_val()),
        }
    }
}

impl<T> PartialEq for State<T> {
    fn eq(&self, other: &Self) -> bool {
        Arc::ptr_eq(&self.inner, &other.inner)
    }
}

impl<T> Eq for State<T> {}

impl<T> PartialOrd for State<T> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl<T> Ord for State<T> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.local_version.get_val().cmp(&other.local_version.get_val())
    }
}

pub struct StateWriteGuard<'a, T: ?Sized + 'a> {
    inner: RwLockWriteGuard<'a, T>,
    ptr: &'a mut u64,
}

impl<'a, T: ?Sized + 'a> Deref for StateWriteGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<'a, T: ?Sized + 'a> DerefMut for StateWriteGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

impl<'a, T: ?Sized + 'a> Drop for StateWriteGuard<'a, T> {
    fn drop(&mut self) {
        *self.ptr += 1;
    }
}

#[macro_export]
macro_rules! when {
    ([$($dependency:expr),+$(,)?] => $code:block) => {
        if $($dependency.is_outdated())||+ $code
    };
    ([$($dependency:expr),+$(,)?] => $code:block else $otherwise:block) => {
        if $($dependency.is_outdated())||+ $code
        else $otherwise
    };
    ([] => $code:block) => {};
    ([] => $code:block else $otherwise:block) => { $otherwise };
}

#[macro_export]
macro_rules! update {
    ([$($dependency:expr),+$(,)?]) => {
        $(
            $dependency.update();
        )+
    };
    ([]) => {};
}