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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
use std::debug_assert_eq;
use std::cell::RefCell;
use std::cmp::Eq;
use std::collections::HashMap;
use std::error;
use std::hash::Hash;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;

use display_derive::Display;
use typemap::TypeMap;

//#region Persistent
/// A warpper represents managed data. This struct gives exclusive, mutable access to the value.
/// When user want to use some sort of data stored in the DB, it should always be warpped in this type.
/// When the value is dropped, it's stored to a persistent storage.
pub struct Persistent<'store, Key, Value>
where
    Key: Copy + Eq + Hash + 'static,
    Value: 'static,
{
    store: &'store Store,
    key: Key,

    // Can't use a reference to the store because that will lock the entire store.
    // Can't use Rc either because store will hold a Rc to the object as well and thus we can't mutate it.
    // Use Option here so we can swap out the value in Drop. It should never be None. (consider using unsafe for better performance?)
    value: Option<Value>,
}

impl<'store, Key, Value> Persistent<'store, Key, Value>
where
    Key: Copy + Eq + Hash + 'static,
    Value: 'static,
{
    pub fn get_key(&self) -> Key {
        self.key
    }
}

impl<'store, Key, Value> Drop for Persistent<'store, Key, Value>
where
    Key: Copy + Eq + Hash + 'static,
    Value: 'static,
{
    fn drop(&mut self) {
        let value = mem::replace(&mut self.value, None).expect("Internal Error: value should not be None");
        self.store.r#return(self.key, value);
    }
}

impl<'store, Key, Value> Deref for Persistent<'store, Key, Value>
where
    Key: Copy + Eq + Hash + 'static,
    Value: 'static,
{
    type Target = Value;

    fn deref(&self) -> &Self::Target {
        self.value.as_ref().expect("Internal Error: value should not be None.")
    }
}

impl<'store, Key, Value> DerefMut for Persistent<'store, Key, Value>
where
    Key: Copy + Eq + Hash + 'static,
    Value: 'static,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.value.as_mut().expect("Internal Error: value should not be None.")
    }
}
//#endregion


//#region PersistentRef
/// A warpper represents managed data. This struct gives shared, readonly access to the value.
/// When user want to use some sort of data stored in the DB, it should always be warpped in this type.
/// When the value is dropped, it's stored to a persistent storage.
// We could just use Rc here. It will mostly be the same except it doesn't come with key (which can be solved by returning a tuple).
// However, Rc is an implemenration detail and we don't want to leak it.
#[derive(Clone)]
pub struct PersistentRef<Key, Value>
where
    Key: Copy + Eq + Hash + 'static,
    Value: 'static,
{
    key: Key,

    // Can't use a reference to the store because that will lock the entire store.
    value: Rc<Value>,
}

impl<Key, Value> PersistentRef<Key, Value>
where
    Key: Copy + Eq + Hash + 'static,
    Value: 'static,
{
    pub fn get_key(&self) -> Key {
        self.key
    }
}

impl<Key, Value> Deref for PersistentRef<Key, Value>
where
    Key: Copy + Eq + Hash + 'static,
    Value: 'static,
{
    type Target = Value;

    fn deref(&self) -> &Self::Target {
        &*self.value
    }
}
//#endregion


//#region TypeKey
/// TypeKey
struct TypeKey<Key, Value>(PhantomData<(Key, Value)>);

impl<Key, Value> typemap::Key for TypeKey<Key, Value>
where
    Key: 'static,
    Value: 'static,
{
    type Value = HashMap<Key, State<Value>>;
}

//#endregion

//#region State
/// The state of an item
enum State<Item> {
    InStore(Rc<Item>),
    Locked,
}
//#endregion

//#region ...Error types
#[derive(Debug, Display)]
pub enum StoreError {
    #[display(fmt = "the specified (key, type) pair already exists in the store")]
    Existing,
}

impl error::Error for StoreError {}

#[derive(Debug, Display)]
pub enum LockError {
    #[display(fmt = "the specified (key, type) pair doesn't exist in the store")]
    NotFound,
    #[display(fmt = "the queried item is already locked")]
    Locked,
    #[display(fmt = "the queried item is currently borrowed")]
    Borrowed,
}

impl error::Error for LockError {}

#[derive(Debug, Display)]
pub enum BorrowError {
    #[display(fmt = "the specified type, key pair doesn't exist in the store")]
    NotFound,
    #[display(fmt = "the queried item is already locked")]
    Locked,
}

impl error::Error for BorrowError {}
//#endregion

//#region store
pub struct Store {
    map: RefCell<TypeMap>,
}

impl Store {
    pub fn new() -> Self {
        Self {
            map: RefCell::new(TypeMap::new()),
        }
    }

    /// start managing an item
    pub fn store<Key, Value>(&self, key: Key, value: Value) -> Result<(), StoreError>
    where
        Key: Copy + Eq + Hash + 'static,
        Value: 'static,
    {
        let mut map = self.map.borrow_mut();
        if !map.contains::<TypeKey<Key, Value>>() {
            map.insert::<TypeKey<Key, Value>>(HashMap::new());
        }

        let hash_map = map.get_mut::<TypeKey<Key, Value>>().unwrap();
        if hash_map.contains_key(&key) {
            Err(StoreError::Existing)?;
        }

        if hash_map.insert(key, State::InStore(Rc::new(value))).is_some() {
            panic!("Internal Error: item should not exist in store")
        };

        Ok(())
    }

    /// get a managed item from store
    pub fn lock<Key, Value>(&self, key: Key) -> Result<Persistent<Key, Value>, LockError>
        where
            Key: Copy + Eq + Hash + 'static,
            Value: 'static,
    {
        let mut map = self.map.borrow_mut();
        let hash_map = match map.get_mut::<TypeKey<Key, Value>>() {
            Some(hash_map) => hash_map,
            None => return Err(LockError::NotFound),
        };
        let value = match hash_map.get_mut(&key) {
            Some(value) => value,
            None => return Err(LockError::NotFound),
        };

        match value {
            State::InStore(value) => {
                if Rc::strong_count(value) != 1 {
                    return Err(LockError::Borrowed);
                }
            },
            State::Locked => return Err(LockError::Locked),
        }

        // Can't just take reference here because that will lock the entire store.
        // Can't use Rc either because the store will hold a reference to it thus prevent us from mutating the object.
        let value = match mem::replace(value, State::Locked) {
            State::InStore(value) => value,
            _ => panic!("Internal Error: value should exist in store"),
        };

        Ok(Persistent{store: self, key, value: Some(Rc::try_unwrap(value).ok().expect("Internal Error: value shouldn't be borrowed"))})
    }

    /// get a reference to a managed item from store
    pub fn borrow<Key, Value>(&self, key: Key) -> Result<PersistentRef<Key, Value>, BorrowError>
    where
        Key: Copy + Eq + Hash + 'static,
        Value: 'static,
    {
        let mut map = self.map.borrow_mut();
        let hash_map = match map.get_mut::<TypeKey<Key, Value>>() {
            Some(hash_map) => hash_map,
            None => return Err(BorrowError::NotFound),
        };
        let value = match hash_map.get_mut(&key) {
            Some(value) => value,
            None => return Err(BorrowError::NotFound),
        };

        let value = match value {
            State::InStore(value) => value.clone(),
            _ => return Err(BorrowError::Locked),
        };

        Ok(PersistentRef{key, value})
    }

    /// return an item to store.
    /// This method should only be called when Persistent<_, _> is dropped.
    /// Thus make it private
    /// @precondition: the value being returned must exist in the store in Locked state. Panic if not met in debug mode.
    fn r#return<Key, Value>(&self, key: Key, value: Value)
    where
        Key: Copy + Eq + Hash + 'static,
        Value: 'static,
    {
        let mut map = self.map.borrow_mut();
        let hash_map = map.get_mut::<TypeKey<Key, Value>>().expect("Internal Error: key should exist in store.");
        let retrived_mark = hash_map.get_mut(&key).expect("Internal Error: key should exist in store.");
        debug_assert_eq!(mem::discriminant(retrived_mark), mem::discriminant(&State::Locked));

        mem::replace(retrived_mark, State::InStore(Rc::new(value)));
    }
}

impl Default for Store {
    fn default() -> Self {
        Self::new()
    }
}
//#endregion