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
use super::{BlackBox, Unit};
use crate::impl_unit;
use std::any::{Any, TypeId};
use std::cell::{Ref, RefCell, RefMut};

use super::*;

pub struct RefCellUnit<T> {
    pub(crate) inner: RefCell<T>,
}

impl<T> RefCellUnit<T> {
    pub fn new(data: T) -> Self {
        Self {
            inner: RefCell::new(data),
        }
    }
}

// Any changes made to RefCell/Mutex/RwLock units are done first on this one, and then
// Must be copied onto the other ones.
impl<'a, T: 'static> Unit<'a> for RefCellUnit<StorageUnit<T>> {
    type Borrowed = Ref<'a, dyn Any>;
    type MutBorrowed = RefMut<'a, dyn Any>;

    fn insert_any(&self, new: Box<dyn Any>) -> Option<(Box<dyn Any>, ErrorDesc)> {
        let newtype = new.type_id();
        if let Ok(mut x) = self.inner.try_borrow_mut() {
            if new.is::<T>() {
                x.insert(*new.downcast::<T>().unwrap_or_else(|_| {
                    panic!(
                        "Tried to insert an object with type {:?} into a storage of type {:?}",
                        newtype,
                        TypeId::of::<T>()
                    )
                }));
                None
            } else if new.is::<Vec<T>>() {
                x.insert_many(*new.downcast::<Vec<T>>().unwrap());
                None
            } else {
                Some((new, ErrorDesc::NoMatchingType))
            }
        } else {
            Some((new, ErrorDesc::BorrowedIncompatibly))
        }
    }

    fn waiting_insert(&self, _new: Box<dyn Any>) -> Option<(Box<dyn Any>, ErrorDesc)> {
        unreachable!()
    }

    fn storage(&'a self) -> DynamicResult<Ref<'a, dyn Any>> {
        self.inner
            .try_borrow()
            .ok()
            .map(|x| Ref::map::<dyn Any, _>(x, |z| &*z))
            .ok_or(ErrorDesc::BorrowedIncompatibly)
    }
    fn storage_mut(&'a self) -> DynamicResult<RefMut<'a, dyn Any>> {
        self.inner
            .try_borrow_mut()
            .ok()
            .map(|x| RefMut::map::<dyn Any, _>(x, |z| &mut *z))
            .ok_or(ErrorDesc::BorrowedIncompatibly)
    }

    fn waiting_storage(&'a self) -> Ref<'a, dyn Any> {
        unreachable!()
    }
    fn waiting_storage_mut(&'a self) -> RefMut<'a, dyn Any> {
        unreachable!()
    }

    fn id(&self) -> TypeId {
        TypeId::of::<T>()
    }
}

type RefCellBlackBox =
    BlackBox<dyn for<'a> Unit<'a, Borrowed = Ref<'a, dyn Any>, MutBorrowed = RefMut<'a, dyn Any>>>;

///
/// The newtype for storage with interior mutability based on
/// [`RefCell`]s, only allowing for it exist on one thread.
///
/// # Note
/// Please refer to the [`make_storage`](../macro.make_storage.html)
/// macro to create storages using a shorthand.
///
/// [`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html
///
#[repr(transparent)]
pub struct DynamicStorage {
    black_box: RefCellBlackBox,
}

impl DynamicStorage {
    pub fn new() -> Self {
        Self {
            black_box: RefCellBlackBox::new(),
        }
    }
}

impl Default for DynamicStorage {
    fn default() -> Self {
        Self::new()
    }
}

impl_unit!(DynamicStorage, dyn Any, ('static), RefCellUnit(dyn for<'u> Unit<'u, Borrowed=Ref<'u, dyn Any>, MutBorrowed=RefMut<'u, dyn Any>>), RefMut, Ref, black_box, add_unmut);