Skip to content

Commit

Permalink
Add GcCellRef::filter_map
Browse files Browse the repository at this point in the history
Fixes #176.

Signed-off-by: Anders Kaseorg <[email protected]>
  • Loading branch information
andersk committed Jul 17, 2024
1 parent 8a5cfdd commit 2224e16
Showing 1 changed file with 43 additions and 0 deletions.
43 changes: 43 additions & 0 deletions gc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,49 @@ impl<'a, T: ?Sized> GcCellRef<'a, T> {
ret
}

/// Makes a new `GcCellRef` for an optional component of the borrowed data.
/// The original guard is returned as an `Err(..)` if the closure returns
/// `None`.
///
/// The `GcCell` is already immutably borrowed, so this cannot fail.
///
/// This is an associated function that needs to be used as
/// `GcCellRef::filter_map(...)`. A method would interfere with methods of
/// the same name on the contents of a `GcCellRef` used through `Deref`.
///
/// # Examples
///
/// ```
/// use gc::{GcCell, GcCellRef};
///
/// let c = GcCell::new(vec![1, 2, 3]);
/// let b1: GcCellRef<Vec<u32>> = c.borrow();
/// let b2: Result<GcCellRef<u32>, _> = GcCellRef::filter_map(b1, |v| v.get(1));
/// assert_eq!(*b2.unwrap(), 2);
/// ```
#[inline]
pub fn filter_map<U, F>(orig: Self, f: F) -> Result<GcCellRef<'a, U>, Self>
where
U: ?Sized,
F: FnOnce(&T) -> Option<&U>,
{
match f(orig.value) {
None => Err(orig),
Some(value) => {
let ret = GcCellRef {
flags: orig.flags,
value,
};

// We have to tell the compiler not to call the destructor of GcCellRef,
// because it will update the borrow flags.
std::mem::forget(orig);

Ok(ret)
}
}
}

/// Splits a `GcCellRef` into multiple `GcCellRef`s for different components of the borrowed data.
///
/// The `GcCell` is already immutably borrowed, so this cannot fail.
Expand Down

0 comments on commit 2224e16

Please sign in to comment.