@@ -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