Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b809d3b

Browse files
committedNov 19, 2023
Add Ref/RefMut try_map method
1 parent 9a66e44 commit b809d3b

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed
 

‎library/core/src/cell.rs

+96
Original file line numberDiff line numberDiff line change
@@ -1518,6 +1518,47 @@ impl<'b, T: ?Sized> Ref<'b, T> {
15181518
}
15191519
}
15201520

1521+
/// Tries to makes a new `Ref` for a component of the borrowed data.
1522+
/// On failure, the original guard is returned alongside with the error
1523+
/// returned by the closure.
1524+
///
1525+
/// The `RefCell` is already immutably borrowed, so this cannot fail.
1526+
///
1527+
/// This is an associated function that needs to be used as
1528+
/// `Ref::try_map(...)`. A method would interfere with methods of the same
1529+
/// name on the contents of a `RefCell` used through `Deref`.
1530+
///
1531+
/// # Examples
1532+
///
1533+
/// ```
1534+
/// #![feature(refcell_try_map)]
1535+
/// use std::cell::{RefCell, Ref};
1536+
/// use std::str::{from_utf8, Utf8Error};
1537+
///
1538+
/// let c = RefCell::new(vec![0xF0, 0x9F, 0xA6 ,0x80]);
1539+
/// let b1: Ref<'_, Vec<u8>> = c.borrow();
1540+
/// let b2: Result<Ref<'_, str>, _> = Ref::try_map(b1, |v| from_utf8(v));
1541+
/// assert_eq!(&*b2.unwrap(), "🦀");
1542+
///
1543+
/// let c = RefCell::new(vec![0xF0, 0x9F, 0xA6]);
1544+
/// let b1: Ref<'_, Vec<u8>> = c.borrow();
1545+
/// let b2: Result<_, (Ref<'_, Vec<u8>>, Utf8Error)> = Ref::try_map(b1, |v| from_utf8(v));
1546+
/// let (b3, e) = b2.unwrap_err();
1547+
/// assert_eq!(*b3, vec![0xF0, 0x9F, 0xA6]);
1548+
/// assert_eq!(e.valid_up_to(), 0);
1549+
/// ```
1550+
#[unstable(feature = "refcell_try_map", issue = "none")]
1551+
#[inline]
1552+
pub fn try_map<U: ?Sized, E, F>(orig: Ref<'b, T>, f: F) -> Result<Ref<'b, U>, (Self, E)>
1553+
where
1554+
F: FnOnce(&T) -> Result<&U, E>,
1555+
{
1556+
match f(&*orig) {
1557+
Ok(value) => Ok(Ref { value: NonNull::from(value), borrow: orig.borrow }),
1558+
Err(e) => Err((orig, e)),
1559+
}
1560+
}
1561+
15211562
/// Splits a `Ref` into multiple `Ref`s for different components of the
15221563
/// borrowed data.
15231564
///
@@ -1678,6 +1719,61 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
16781719
}
16791720
}
16801721

1722+
/// Tries to makes a new `RefMut` for a component of the borrowed data.
1723+
/// On failure, the original guard is returned alongside with the error
1724+
/// returned by the closure.
1725+
///
1726+
/// The `RefCell` is already mutably borrowed, so this cannot fail.
1727+
///
1728+
/// This is an associated function that needs to be used as
1729+
/// `RefMut::try_map(...)`. A method would interfere with methods of the same
1730+
/// name on the contents of a `RefCell` used through `Deref`.
1731+
///
1732+
/// # Examples
1733+
///
1734+
/// ```
1735+
/// #![feature(refcell_try_map)]
1736+
/// use std::cell::{RefCell, RefMut};
1737+
/// use std::str::{from_utf8_mut, Utf8Error};
1738+
///
1739+
/// let c = RefCell::new(vec![0x68, 0x65, 0x6C, 0x6C, 0x6F]);
1740+
/// {
1741+
/// let b1: RefMut<'_, Vec<u8>> = c.borrow_mut();
1742+
/// let b2: Result<RefMut<'_, str>, _> = RefMut::try_map(b1, |v| from_utf8_mut(v));
1743+
/// let mut b2 = b2.unwrap();
1744+
/// assert_eq!(&*b2, "hello");
1745+
/// b2.make_ascii_uppercase();
1746+
/// }
1747+
/// assert_eq!(*c.borrow(), "HELLO".as_bytes());
1748+
///
1749+
/// let c = RefCell::new(vec![0xFF]);
1750+
/// let b1: RefMut<'_, Vec<u8>> = c.borrow_mut();
1751+
/// let b2: Result<_, (RefMut<'_, Vec<u8>>, Utf8Error)> = RefMut::try_map(b1, |v| from_utf8_mut(v));
1752+
/// let (b3, e) = b2.unwrap_err();
1753+
/// assert_eq!(*b3, vec![0xFF]);
1754+
/// assert_eq!(e.valid_up_to(), 0);
1755+
/// ```
1756+
#[unstable(feature = "refcell_try_map", issue = "none")]
1757+
#[inline]
1758+
pub fn try_map<U: ?Sized, E, F>(
1759+
mut orig: RefMut<'b, T>,
1760+
f: F,
1761+
) -> Result<RefMut<'b, U>, (Self, E)>
1762+
where
1763+
F: FnOnce(&mut T) -> Result<&mut U, E>,
1764+
{
1765+
// SAFETY: function holds onto an exclusive reference for the duration
1766+
// of its call through `orig`, and the pointer is only de-referenced
1767+
// inside of the function call never allowing the exclusive reference to
1768+
// escape.
1769+
match f(&mut *orig) {
1770+
Ok(value) => {
1771+
Ok(RefMut { value: NonNull::from(value), borrow: orig.borrow, marker: PhantomData })
1772+
}
1773+
Err(e) => Err((orig, e)),
1774+
}
1775+
}
1776+
16811777
/// Splits a `RefMut` into multiple `RefMut`s for different components of the
16821778
/// borrowed data.
16831779
///

0 commit comments

Comments
 (0)
Failed to load comments.