Skip to content

Commit 72e87ee

Browse files
committed
Add GcCellRefMut::filter_map
Signed-off-by: Anders Kaseorg <[email protected]>
1 parent d50f6c0 commit 72e87ee

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed

gc/src/lib.rs

+49
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,55 @@ impl<'a, T: Trace + ?Sized, U: ?Sized> GcCellRefMut<'a, T, U> {
946946
value: f(value),
947947
}
948948
}
949+
950+
/// Makes a new `GcCellRefMut` for an optional component of the borrowed
951+
/// data. The original guard is returned as an `Err(..)` if the closure
952+
/// returns `None`.
953+
///
954+
/// The `GcCellRefMut` is already mutably borrowed, so this cannot fail.
955+
///
956+
/// This is an associated function that needs to be used as
957+
/// `GcCellRefMut::filter_map(...)`. A method would interfere with methods
958+
/// of the same name on the contents of a `GcCell` used through `Deref`.
959+
///
960+
/// # Examples
961+
///
962+
/// ```
963+
/// use gc::{GcCell, GcCellRefMut};
964+
///
965+
/// let c = GcCell::new(vec![1, 2, 3]);
966+
///
967+
/// {
968+
/// let b1: GcCellRefMut<Vec<u32>> = c.borrow_mut();
969+
/// let mut b2: Result<GcCellRefMut<Vec<u32>, u32>, _> = GcCellRefMut::filter_map(b1, |v| v.get_mut(1));
970+
///
971+
/// if let Ok(mut b2) = b2 {
972+
/// *b2 += 2;
973+
/// }
974+
/// }
975+
///
976+
/// assert_eq!(*c.borrow(), vec![1, 4, 3]);
977+
/// ```
978+
#[inline]
979+
pub fn filter_map<V, F>(orig: Self, f: F) -> Result<GcCellRefMut<'a, T, V>, Self>
980+
where
981+
V: ?Sized,
982+
F: FnOnce(&mut U) -> Option<&mut V>,
983+
{
984+
let gc_cell = orig.gc_cell;
985+
986+
// Use MaybeUninit to avoid calling the destructor of
987+
// GcCellRefMut (which would update the borrow flags) and to
988+
// avoid duplicating the mutable reference orig.value (which
989+
// would be UB).
990+
let orig = mem::MaybeUninit::new(orig);
991+
let value = unsafe { ptr::addr_of!((*orig.as_ptr()).value).read() };
992+
993+
match f(value) {
994+
None => Err(unsafe { orig.assume_init() }),
995+
Some(value) => Ok(GcCellRefMut { gc_cell, value }),
996+
}
997+
}
949998
}
950999

9511000
impl<'a, T: Trace + ?Sized, U: ?Sized> Deref for GcCellRefMut<'a, T, U> {

0 commit comments

Comments
 (0)