#[cfg(doc)]
use core::cell::RefCell;
use core::{
cell::{Ref, RefMut},
ops::{Deref, DerefMut},
};
use generic_array::{arr, typenum::U0, ArrayLength, GenericArray};
use crate::clone_arr::clone_arr;
pub struct NestedRefMut<'a, T, N>
where
T: ?Sized,
N: ArrayLength<Ref<'a, ()>>,
{
pub(crate) inner: RefMut<'a, T>,
pub(crate) outer: GenericArray<Ref<'a, ()>, N>,
}
impl<'a, T> NestedRefMut<'a, T, U0>
where
T: ?Sized,
{
#[must_use]
#[inline]
pub fn new(inner: RefMut<'a, T>) -> Self {
let outer = arr![Ref<'a, ()>;];
Self { inner, outer }
}
}
impl<'a, T, N> NestedRefMut<'a, T, N>
where
T: ?Sized,
N: ArrayLength<Ref<'a, ()>>,
{
#[inline]
pub fn map<U, F>(orig: Self, f: F) -> NestedRefMut<'a, U, N>
where
U: ?Sized,
F: FnOnce(&mut T) -> &mut U,
{
NestedRefMut {
inner: RefMut::map(orig.inner, f),
outer: orig.outer,
}
}
#[inline]
#[allow(clippy::missing_errors_doc)]
pub fn filter_map<U, F>(orig: Self, f: F) -> Result<NestedRefMut<'a, U, N>, Self>
where
U: ?Sized,
F: FnOnce(&mut T) -> Option<&mut U>,
{
let outer = orig.outer;
match RefMut::filter_map(orig.inner, f) {
Ok(inner) => Ok(NestedRefMut { inner, outer }),
Err(inner) => Err(NestedRefMut { inner, outer }),
}
}
#[inline]
pub fn map_split<U, V, F>(orig: Self, f: F) -> (NestedRefMut<'a, U, N>, NestedRefMut<'a, V, N>)
where
U: ?Sized,
V: ?Sized,
F: FnOnce(&mut T) -> (&mut U, &mut V),
{
let outer_a = clone_arr(&orig.outer);
let outer_b = orig.outer;
let (inner_a, inner_b) = RefMut::map_split(orig.inner, f);
(
NestedRefMut {
inner: inner_a,
outer: outer_a,
},
NestedRefMut {
inner: inner_b,
outer: outer_b,
},
)
}
}
impl<'a, T, N> Deref for NestedRefMut<'a, T, N>
where
T: ?Sized,
N: ArrayLength<Ref<'a, ()>>,
{
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<'a, T, N> DerefMut for NestedRefMut<'a, T, N>
where
T: ?Sized,
N: ArrayLength<Ref<'a, ()>>,
{
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
#[cfg(test)]
mod tests {
use core::cell::RefCell;
use crate::{NestedRef, NestedRefMut};
#[test]
fn simple() {
let rc = RefCell::new(0);
let mut nr = NestedRefMut::new(rc.borrow_mut());
assert_eq!(*nr, 0);
*nr = 1;
assert_eq!(*nr, 1);
}
#[test]
fn deep() {
let rc = RefCell::new(RefCell::new(RefCell::new(0)));
let nr = NestedRef::new(rc.borrow());
let nr = NestedRef::map_ref(nr, RefCell::borrow);
let mut nr = NestedRef::map_ref_mut(nr, RefCell::borrow_mut);
assert_eq!(*nr, 0);
*nr = 1;
assert_eq!(*nr, 1);
}
#[test]
fn map() {
let rc = RefCell::new((0, 0));
let nr = NestedRefMut::new(rc.borrow_mut());
let mut nr = NestedRefMut::map(nr, |x| &mut x.0);
assert_eq!(*nr, 0);
*nr = 1;
assert_eq!(*nr, 1);
}
#[test]
fn filter_map() {
let rc = RefCell::new(0);
let nr = NestedRefMut::new(rc.borrow_mut());
let nr = NestedRefMut::filter_map::<(), _>(nr, |_| None)
.map(|_| ())
.expect_err("This filter_map should fail");
let mut nr = NestedRefMut::filter_map(nr, |x| Some(x))
.map_err(|_| ())
.expect("This filter_map should succeed");
assert_eq!(*nr, 0);
*nr = 1;
assert_eq!(*nr, 1);
}
#[test]
fn map_split() {
let rc = RefCell::new((0, 0));
let nr = NestedRefMut::new(rc.borrow_mut());
let (mut nr, _nr2) = NestedRefMut::map_split(nr, |x| (&mut x.0, &mut x.1));
assert_eq!(*nr, 0);
*nr = 1;
assert_eq!(*nr, 1);
}
}