1use std::cell::{Ref, RefMut};
28
29pub struct NestedRef<'a, Inner, Outer>
31where
32 Inner: 'static,
33{
34 inner: Ref<'a, Inner>,
37 _outer: Box<Ref<'a, Outer>>,
39}
40impl<'a, Inner, Outer> NestedRef<'a, Inner, Outer>
41where
42 Inner: 'static,
43{
44 #[inline]
45 pub fn map(outer: Ref<'a, Outer>, borrow_fn: impl FnOnce(&Outer) -> Ref<Inner>) -> Self {
46 Self::filter_map(outer, |outer| Some(borrow_fn(outer))).unwrap()
47 }
48
49 #[inline]
50 pub fn filter_map(
51 outer: Ref<'a, Outer>,
52 borrow_fn: impl FnOnce(&Outer) -> Option<Ref<Inner>>,
53 ) -> Option<Self> {
54 let boxed_outer = Box::new(outer);
55 let inner: Ref<Inner> = borrow_fn(&boxed_outer)?;
56 let inner: Ref<'a, Inner> = unsafe { std::mem::transmute(inner) };
62 Some(Self {
63 inner,
64 _outer: boxed_outer,
65 })
66 }
67}
68impl<Inner, Outer> std::ops::Deref for NestedRef<'_, Inner, Outer>
69where
70 Inner: 'static,
71{
72 type Target = Inner;
73
74 fn deref(&self) -> &Self::Target {
75 self.inner.deref()
76 }
77}
78
79pub struct NestedRefMut<'a, Inner, Outer>
82where
83 Inner: 'static,
84{
85 inner: RefMut<'a, Inner>,
88 _outer: Box<Ref<'a, Outer>>,
90}
91impl<'a, Inner, Outer> NestedRefMut<'a, Inner, Outer>
92where
93 Inner: 'static,
94{
95 #[inline]
96 pub fn map(outer: Ref<'a, Outer>, borrow_fn: impl FnOnce(&Outer) -> RefMut<Inner>) -> Self {
97 Self::filter_map(outer, |outer| Some(borrow_fn(outer))).unwrap()
98 }
99
100 #[inline]
101 pub fn filter_map(
102 outer: Ref<'a, Outer>,
103 borrow_fn: impl FnOnce(&Outer) -> Option<RefMut<Inner>>,
104 ) -> Option<Self> {
105 let outer = Box::new(outer);
106 let inner: RefMut<Inner> = borrow_fn(&outer)?;
107 let inner: RefMut<'a, Inner> = unsafe { std::mem::transmute(inner) };
113 Some(Self {
114 inner,
115 _outer: outer,
116 })
117 }
118}
119impl<Inner, Outer> std::ops::Deref for NestedRefMut<'_, Inner, Outer>
120where
121 Inner: 'static,
122{
123 type Target = Inner;
124
125 fn deref(&self) -> &Self::Target {
126 self.inner.deref()
127 }
128}
129impl<Inner, Outer> std::ops::DerefMut for NestedRefMut<'_, Inner, Outer>
130where
131 Inner: 'static,
132{
133 fn deref_mut(&mut self) -> &mut Self::Target {
134 self.inner.deref_mut()
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use std::cell::RefCell;
141
142 use super::*;
143
144 struct TestOuter {
145 x: RefCell<i32>,
146 }
147
148 #[test]
149 fn nestedref_map() {
150 let outer = RefCell::new(TestOuter {
151 x: RefCell::new(42),
152 });
153 let nested = NestedRef::map(outer.borrow(), |inner| inner.x.borrow());
154 assert_eq!(*nested, 42);
155 }
156
157 #[test]
158 fn nestedref_filter_map_some() {
159 let outer = RefCell::new(TestOuter {
160 x: RefCell::new(42),
161 });
162 let nested = NestedRef::filter_map(outer.borrow(), |inner| Some(inner.x.borrow()));
163 let nested = nested.unwrap();
164 assert_eq!(*nested, 42);
165 }
166
167 #[test]
168 fn nestedref_filter_map_none() {
169 let outer = RefCell::new(TestOuter {
170 x: RefCell::new(42),
171 });
172 let nested = NestedRef::<i32, TestOuter>::filter_map(outer.borrow(), |_inner| None);
173 assert!(nested.is_none());
174 }
175
176 #[test]
177 fn nestedref_is_movable() {
178 let outer = RefCell::new(TestOuter {
179 x: RefCell::new(42),
180 });
181 let nested = NestedRef::map(outer.borrow(), |inner| inner.x.borrow());
182 assert_eq!(*nested, 42);
183 let boxed_nested = Box::new(nested);
184 assert_eq!(**boxed_nested, 42);
185 }
186
187 #[test]
188 fn nestedrefmut_map() {
189 let outer = RefCell::new(TestOuter {
190 x: RefCell::new(42),
191 });
192 {
193 let mut nested = NestedRefMut::map(outer.borrow(), |inner| inner.x.borrow_mut());
194 assert_eq!(*nested, 42);
195 *nested += 1;
196 assert_eq!(*nested, 43);
197 assert!(outer.borrow().x.try_borrow().is_err());
198 }
199 assert_eq!(*outer.borrow().x.borrow(), 43);
200 }
201
202 #[test]
203 fn nestedrefmut_filter_map_some() {
204 let outer = RefCell::new(TestOuter {
205 x: RefCell::new(42),
206 });
207 {
208 let nested =
209 NestedRefMut::filter_map(outer.borrow(), |inner| Some(inner.x.borrow_mut()));
210 let mut nested = nested.unwrap();
211 assert_eq!(*nested, 42);
212 *nested += 1;
213 assert_eq!(*nested, 43);
214 assert!(outer.borrow().x.try_borrow().is_err());
215 }
216 assert_eq!(*outer.borrow().x.borrow(), 43);
217 }
218
219 #[test]
220 fn nestedrefmut_filter_map_none() {
221 let outer = RefCell::new(TestOuter {
222 x: RefCell::new(42),
223 });
224 let nested = NestedRefMut::<i32, TestOuter>::filter_map(outer.borrow(), |_inner| None);
225 assert!(nested.is_none());
226 }
227
228 #[test]
229 fn nestedrefmut_is_movable() {
230 let outer = RefCell::new(TestOuter {
231 x: RefCell::new(42),
232 });
233 {
234 let nested = NestedRefMut::map(outer.borrow(), |inner| inner.x.borrow_mut());
235 assert_eq!(*nested, 42);
236 let mut nested = Box::new(nested);
237 assert_eq!(**nested, 42);
238 **nested += 1;
239 assert_eq!(**nested, 43);
240 }
241 assert_eq!(*outer.borrow().x.borrow(), 43);
242 }
243}