nested_ref/
shared.rs

1//! Shared reference to data contained in one or more nested [`RefCell`]s
2
3#[cfg(doc)]
4use core::cell::RefCell;
5use core::{
6    cell::{Ref, RefMut},
7    ops::{Add, Deref},
8    ptr::addr_of,
9};
10
11use generic_array::{
12    arr,
13    sequence::Lengthen,
14    typenum::{Add1, B1, U0},
15    ArrayLength, GenericArray,
16};
17
18use crate::{clone_arr::clone_arr, NestedRefMut};
19
20/// Shared reference to data contained in one or more nested [`RefCell`]s.
21///
22/// This has the same interface as [`Ref`], with the additional methods
23/// [`map_ref`](NestedRef::map_ref) and [`map_ref_mut`](NestedRef::map_ref_mut) that form references
24/// into nested [`RefCell`]s.
25///
26/// # Examples
27///
28/// ```
29/// # use std::cell::{Cell, RefCell};
30/// # use nested_ref::NestedRef;
31/// // Create a `RefCell` two levels deep and a `NestedRef` into it
32/// let rc = RefCell::new(RefCell::new(Cell::new(0)));
33/// let nr = NestedRef::new(rc.borrow());
34/// let nr = NestedRef::map_ref(nr, RefCell::borrow);
35/// assert_eq!(nr.get(), 0);
36///
37/// // Mutate through `NestedRef`
38/// nr.set(1);
39/// assert_eq!(nr.get(), 1);
40///
41/// // Mutate through independent `Ref`
42/// rc.borrow().borrow().set(2);
43/// assert_eq!(nr.get(), 2);
44/// ```
45pub struct NestedRef<'a, T, N>
46where
47    T: ?Sized,
48    N: ArrayLength<Ref<'a, ()>>,
49{
50    /// Reference into the innermost [`RefCell`]
51    inner: Ref<'a, T>,
52    /// Type-erased references into the other [`RefCell`]s, from outermost to innermost
53    // We store a `&()` in each array entry. It would be better to store the internal `BorrowRef`
54    // directly, but that's not exposed.
55    outer: GenericArray<Ref<'a, ()>, N>,
56}
57
58impl<'a, T> NestedRef<'a, T, U0>
59where
60    T: ?Sized,
61{
62    /// Creates a new reference inside a single [`RefCell`]
63    #[must_use]
64    #[inline]
65    pub fn new(inner: Ref<'a, T>) -> Self {
66        // Start with an empty array of outer `Ref`s
67        let outer = arr![Ref<'a, ()>;];
68        Self { inner, outer }
69    }
70}
71
72impl<'a, T, N> NestedRef<'a, T, N>
73where
74    T: ?Sized,
75    N: ArrayLength<Ref<'a, ()>>,
76{
77    /// Clones the reference, like [`Ref::clone`].
78    ///
79    /// This is an associated function, because a method would interfere with methods of the same
80    /// name on the contents of the [`RefCell`].
81    #[must_use]
82    #[inline]
83    #[allow(clippy::should_implement_trait)]
84    pub fn clone(orig: &Self) -> Self {
85        // Just clone all contained `Ref`s
86        Self {
87            inner: Ref::clone(&orig.inner),
88            outer: clone_arr(&orig.outer),
89        }
90    }
91
92    /// Creates a reference to a component of the borrowed data, like [`Ref::map`].
93    ///
94    /// This is an associated function, because a method would interfere with methods of the same
95    /// name on the contents of the [`RefCell`].
96    #[inline]
97    pub fn map<U, F>(orig: Self, f: F) -> NestedRef<'a, U, N>
98    where
99        U: ?Sized,
100        F: FnOnce(&T) -> &U,
101    {
102        // Outer `Ref` is type-erased, so just map the inner `Ref`
103        NestedRef {
104            inner: Ref::map(orig.inner, f),
105            outer: orig.outer,
106        }
107    }
108
109    /// Creates a reference to an optional component of the borrowed data, like [`Ref::filter_map`].
110    /// The original reference is returned inside an `Err` if the closure returns `None`.
111    ///
112    /// This is an associated function, because a method would interfere with methods of the same
113    /// name on the contents of the [`RefCell`].
114    #[inline]
115    #[allow(clippy::missing_errors_doc)]
116    pub fn filter_map<U, F>(orig: Self, f: F) -> Result<NestedRef<'a, U, N>, Self>
117    where
118        U: ?Sized,
119        F: FnOnce(&T) -> Option<&U>,
120    {
121        // Outer `Ref`s remain the same
122        let outer = orig.outer;
123        // Delegate to inner `Ref` and put the result back together
124        match Ref::filter_map(orig.inner, f) {
125            Ok(inner) => Ok(NestedRef { inner, outer }),
126            Err(inner) => Err(NestedRef { inner, outer }),
127        }
128    }
129
130    /// Splits a reference into multiple references for different components of the borrowed data,
131    /// like [`Ref::map_split`].
132    ///
133    /// This is an associated function, because a method would interfere with methods of the same
134    /// name on the contents of the [`RefCell`].
135    #[inline]
136    pub fn map_split<U, V, F>(orig: Self, f: F) -> (NestedRef<'a, U, N>, NestedRef<'a, V, N>)
137    where
138        U: ?Sized,
139        V: ?Sized,
140        F: FnOnce(&T) -> (&U, &V),
141    {
142        // We need the outer `Ref`s two times
143        let outer_a = clone_arr(&orig.outer);
144        let outer_b = orig.outer;
145        // Delegate to inner `Ref` and put the results back together
146        let (inner_a, inner_b) = Ref::map_split(orig.inner, f);
147        (
148            NestedRef {
149                inner: inner_a,
150                outer: outer_a,
151            },
152            NestedRef {
153                inner: inner_b,
154                outer: outer_b,
155            },
156        )
157    }
158}
159
160impl<'a, T, N> NestedRef<'a, T, N>
161where
162    T: ?Sized,
163    N: ArrayLength<Ref<'a, ()>> + Add<B1>,
164    <N as Add<B1>>::Output: ArrayLength<Ref<'a, ()>>,
165    GenericArray<Ref<'a, ()>, N>:
166        Lengthen<Ref<'a, ()>, Longer = GenericArray<Ref<'a, ()>, Add1<N>>>,
167{
168    /// Creates a shared reference to a component of the borrowed data that is contained in a nested
169    /// [`RefCell`].
170    ///
171    /// This is an associated function, because a method would interfere with methods of the same
172    /// name on the contents of the [`RefCell`].
173    ///
174    /// # Examples
175    ///
176    /// ```
177    /// # use std::cell::RefCell;
178    /// # use nested_ref::NestedRef;
179    /// let c = RefCell::new(('a', RefCell::new(2)));
180    /// let b1 = NestedRef::new(c.borrow());
181    /// let b2 = NestedRef::map_ref(b1, |t| t.1.borrow());
182    /// assert_eq!(*b2, 2);
183    /// ```
184    #[inline]
185    pub fn map_ref<U, F>(orig: Self, f: F) -> NestedRef<'a, U, Add1<N>>
186    where
187        U: ?Sized,
188        F: FnOnce(&T) -> Ref<'_, U>,
189    {
190        // Safety: The array of outer references is kept alive as long as the returned object
191        let (t, outer) = unsafe { orig.nest() };
192        // Apply mapping function to obtain new inner `Ref`
193        let inner = f(t);
194        // Bundle all `Ref`s together
195        NestedRef { inner, outer }
196    }
197
198    /// Creates an exclusive reference to a component of the borrowed data that is contained in a
199    /// nested [`RefCell`].
200    ///
201    /// This is an associated function, because a method would interfere with methods of the same
202    /// name on the contents of the [`RefCell`].
203    ///
204    /// # Examples
205    ///
206    /// ```
207    /// # use std::cell::RefCell;
208    /// # use nested_ref::NestedRef;
209    /// let c = RefCell::new(('a', RefCell::new(2)));
210    /// let b1 = NestedRef::new(c.borrow());
211    /// let mut b2 = NestedRef::map_ref_mut(b1, |t| t.1.borrow_mut());
212    /// assert_eq!(*b2, 2);
213    /// *b2 = 3;
214    /// ```
215    #[inline]
216    pub fn map_ref_mut<U, F>(orig: Self, f: F) -> NestedRefMut<'a, U, Add1<N>>
217    where
218        U: ?Sized,
219        F: FnOnce(&T) -> RefMut<'_, U>,
220    {
221        // Safety: The array of outer references is kept alive as long as the returned object
222        let (t, outer) = unsafe { orig.nest() };
223        // Apply mapping function to obtain new inner `RefMut`
224        let inner = f(t);
225        // Bundle all `Ref`s together
226        NestedRefMut { inner, outer }
227    }
228
229    /// Increases the nesting level by appending the innermost reference to the outer references.
230    /// Returns the innermost reference as a plain reference, along with the new array of outer
231    /// references.
232    ///
233    /// # Safety
234    ///
235    /// The returned array must be kept alive as long as the returned reference.
236    #[must_use]
237    #[inline]
238    unsafe fn nest(self) -> (&'a T, GenericArray<Ref<'a, ()>, Add1<N>>) {
239        // Get a reference to the `T` that is independent of the inner `Ref`
240        let t = addr_of!(*self.inner);
241        // Safety: The inner `Ref` is kept alive as long as this reference, as guaranteed by the
242        // caller
243        let t: &'a T = unsafe { &*t };
244        // Type-erase old inner `Ref` and append it to the outer `Ref`s
245        let new = Ref::map(self.inner, |_| &());
246        let outer = self.outer.append(new);
247        // Return plain reference and array of outer references
248        (t, outer)
249    }
250}
251
252impl<'a, T, N> Deref for NestedRef<'a, T, N>
253where
254    T: ?Sized,
255    N: ArrayLength<Ref<'a, ()>>,
256{
257    type Target = T;
258
259    #[inline]
260    fn deref(&self) -> &Self::Target {
261        &self.inner
262    }
263}
264
265#[cfg(test)]
266mod tests {
267    use core::cell::{Cell, RefCell};
268
269    use crate::NestedRef;
270
271    /// Tests a `NestedRef` that's one level deep
272    #[test]
273    fn simple() {
274        // Create `RefCell` and `NestedRef` into it
275        let rc = RefCell::new(Cell::new(0));
276        let nr = NestedRef::new(rc.borrow());
277        assert_eq!(nr.get(), 0);
278        assert_eq!(rc.borrow().get(), 0);
279        // Mutate through `NestedRef`
280        nr.set(1);
281        assert_eq!(nr.get(), 1);
282        assert_eq!(rc.borrow().get(), 1);
283        // Mutate through independent `Ref`
284        rc.borrow().set(2);
285        assert_eq!(nr.get(), 2);
286        assert_eq!(rc.borrow().get(), 2);
287    }
288
289    /// Tests a `NestedRef` that's three levels deep
290    #[test]
291    fn deep() {
292        // Create `RefCell` and `NestedRef` into it
293        let rc = RefCell::new(RefCell::new(RefCell::new(Cell::new(0))));
294        let nr = NestedRef::new(rc.borrow());
295        let nr = NestedRef::map_ref(nr, RefCell::borrow);
296        let nr = NestedRef::map_ref(nr, RefCell::borrow);
297        assert_eq!(nr.get(), 0);
298        assert_eq!(rc.borrow().borrow().borrow().get(), 0);
299        // Mutate through `NestedRef`
300        nr.set(1);
301        assert_eq!(nr.get(), 1);
302        assert_eq!(rc.borrow().borrow().borrow().get(), 1);
303        // Mutate through independent `Ref`
304        rc.borrow().borrow().borrow().set(2);
305        assert_eq!(nr.get(), 2);
306        assert_eq!(rc.borrow().borrow().borrow().get(), 2);
307    }
308
309    /// Tests the `NestedRef::clone` method
310    #[test]
311    fn clone() {
312        // Create `RefCell` and `NestedRef` into it
313        let rc = RefCell::new(Cell::new(0));
314        let nr = NestedRef::new(rc.borrow());
315        assert_eq!(nr.get(), 0);
316        assert_eq!(NestedRef::clone(&nr).get(), 0);
317        // Mutate through `NestedRef`
318        nr.set(1);
319        assert_eq!(nr.get(), 1);
320        assert_eq!(NestedRef::clone(&nr).get(), 1);
321        // Mutate through clone
322        NestedRef::clone(&nr).set(2);
323        assert_eq!(nr.get(), 2);
324        assert_eq!(NestedRef::clone(&nr).get(), 2);
325    }
326
327    /// Tests the `NestedRef::map` method
328    #[test]
329    fn map() {
330        // Create `RefCell` and `NestedRef` into it
331        let rc = RefCell::new((Cell::new(0), Cell::new(0)));
332        let nr = NestedRef::new(rc.borrow());
333        let nr = NestedRef::map(nr, |x| &x.0);
334        assert_eq!(nr.get(), 0);
335        assert_eq!(rc.borrow().0.get(), 0);
336        // Mutate through `NestedRef`
337        nr.set(1);
338        assert_eq!(nr.get(), 1);
339        assert_eq!(rc.borrow().0.get(), 1);
340        // Mutate through independent `Ref`
341        rc.borrow().0.set(2);
342        assert_eq!(nr.get(), 2);
343        assert_eq!(rc.borrow().0.get(), 2);
344    }
345
346    /// Tests the `NestedRef::filter_map` method
347    #[test]
348    fn filter_map() {
349        // Create `RefCell` and `NestedRef` into it
350        let rc = RefCell::new(Cell::new(0));
351        let nr = NestedRef::new(rc.borrow());
352        let nr = NestedRef::filter_map::<(), _>(nr, |_| None)
353            .map(|_| ())
354            .expect_err("This filter_map should fail");
355        let nr = NestedRef::filter_map(nr, |x| Some(x))
356            .map_err(|_| ())
357            .expect("This filter_map should succeed");
358        assert_eq!(nr.get(), 0);
359        assert_eq!(rc.borrow().get(), 0);
360        // Mutate through `NestedRef`
361        nr.set(1);
362        assert_eq!(nr.get(), 1);
363        assert_eq!(rc.borrow().get(), 1);
364        // Mutate through independent `Ref`
365        rc.borrow().set(2);
366        assert_eq!(nr.get(), 2);
367        assert_eq!(rc.borrow().get(), 2);
368    }
369
370    /// Tests the `NestedRef::map_split` method
371    #[test]
372    fn map_split() {
373        // Create `RefCell` and `NestedRef` into it
374        let rc = RefCell::new((Cell::new(0), Cell::new(0)));
375        let nr = NestedRef::new(rc.borrow());
376        let (nr, _nr2) = NestedRef::map_split(nr, |x| (&x.0, &x.1));
377        assert_eq!(nr.get(), 0);
378        assert_eq!(rc.borrow().0.get(), 0);
379        // Mutate through `NestedRef`
380        nr.set(1);
381        assert_eq!(nr.get(), 1);
382        assert_eq!(rc.borrow().0.get(), 1);
383        // Mutate through independent `Ref`
384        rc.borrow().0.set(2);
385        assert_eq!(nr.get(), 2);
386        assert_eq!(rc.borrow().0.get(), 2);
387    }
388}