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
use std::{
    cmp::PartialEq,
    fmt,
    marker::PhantomData,
    ops::{Deref, DerefMut},
};
pub use crate::Resource;
pub struct RefMut<'a, R: 'a> {
    inner: rt_map::RefMut<'a, Box<dyn Resource>>,
    phantom: PhantomData<&'a R>,
}
impl<'a, R> fmt::Debug for RefMut<'a, R>
where
    R: Resource + fmt::Debug + 'a,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let inner: &R = self;
        f.debug_struct("RefMut").field("inner", inner).finish()
    }
}
impl<'a, R> PartialEq for RefMut<'a, R>
where
    R: Resource + PartialEq + 'a,
{
    fn eq(&self, other: &Self) -> bool {
        let r_self: &R = self;
        let r_other: &R = other;
        r_self == r_other
    }
}
impl<'a, R> RefMut<'a, R> {
    pub fn new(inner: rt_map::RefMut<'a, Box<dyn Resource>>) -> Self {
        Self {
            inner,
            phantom: PhantomData,
        }
    }
}
impl<'a, R> Deref for RefMut<'a, R>
where
    R: Resource,
{
    type Target = R;
    fn deref(&self) -> &R {
        self.inner
            .downcast_ref::<R>()
            .unwrap_or_else(|| panic!("Failed to downcast to {}", std::any::type_name::<R>()))
    }
}
impl<'a, R> DerefMut for RefMut<'a, R>
where
    R: Resource,
{
    fn deref_mut(&mut self) -> &mut R {
        self.inner
            .downcast_mut::<R>()
            .unwrap_or_else(|| panic!("Failed to downcast to {}", std::any::type_name::<R>()))
    }
}
#[cfg(test)]
mod tests {
    use std::{
        fmt::{self, Write},
        sync::atomic::AtomicUsize,
    };
    use rt_map::CellRefMut;
    use crate::Resource;
    use super::RefMut;
    #[test]
    fn debug_includes_inner_field() -> fmt::Result {
        let flag = AtomicUsize::new(0);
        let mut value: Box<dyn Resource> = Box::new(A(1));
        let ref_mut = RefMut::<A>::new(rt_map::RefMut::new(CellRefMut {
            flag: &flag,
            value: &mut value,
        }));
        let mut debug_string = String::with_capacity(64);
        write!(&mut debug_string, "{:?}", ref_mut)?;
        assert_eq!("RefMut { inner: A(1) }", debug_string.as_str());
        Ok(())
    }
    #[test]
    fn partial_eq_compares_value() -> fmt::Result {
        let flag = AtomicUsize::new(0);
        let mut value: Box<dyn Resource> = Box::new(A(1));
        let mut value_clone: Box<dyn Resource> = Box::new(A(1));
        let ref_mut = RefMut::<A>::new(rt_map::RefMut::new(CellRefMut {
            flag: &flag,
            value: &mut value,
        }));
        assert_eq!(
            RefMut::<A>::new(rt_map::RefMut::new(CellRefMut {
                flag: &flag,
                value: &mut value_clone,
            })),
            ref_mut
        );
        assert_ne!(
            RefMut::<A>::new(rt_map::RefMut::new(CellRefMut {
                flag: &flag,
                value: &mut (Box::new(A(2)) as Box<dyn Resource>),
            })),
            ref_mut
        );
        Ok(())
    }
    #[test]
    fn deref_mut_returns_value() -> fmt::Result {
        let flag = AtomicUsize::new(0);
        let mut value: Box<dyn Resource> = Box::new(A(1));
        let mut ref_mut = RefMut::<A>::new(rt_map::RefMut::new(CellRefMut {
            flag: &flag,
            value: &mut value,
        }));
        assert_eq!(
            RefMut::<A>::new(rt_map::RefMut::new(CellRefMut {
                flag: &flag,
                value: &mut (Box::new(A(1)) as Box<dyn Resource>),
            })),
            ref_mut
        );
        ref_mut.0 = 2;
        assert_eq!(
            RefMut::<A>::new(rt_map::RefMut::new(CellRefMut {
                flag: &flag,
                value: &mut (Box::new(A(2)) as Box<dyn Resource>),
            })),
            ref_mut
        );
        Ok(())
    }
    #[derive(Debug, Clone, PartialEq)]
    struct A(usize);
}