Skip to content

Commit f6bdffd

Browse files
committed
Add Ref/RefMut try_map method
1 parent 855e0fe commit f6bdffd

File tree

1 file changed

+93
-0
lines changed

1 file changed

+93
-0
lines changed

library/core/src/cell.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,6 +1573,47 @@ impl<'b, T: ?Sized> Ref<'b, T> {
15731573
}
15741574
}
15751575

1576+
/// Tries to makes a new `Ref` for a component of the borrowed data.
1577+
/// On failure, the original guard is returned alongside with the error
1578+
/// returned by the closure.
1579+
///
1580+
/// The `RefCell` is already immutably borrowed, so this cannot fail.
1581+
///
1582+
/// This is an associated function that needs to be used as
1583+
/// `Ref::try_map(...)`. A method would interfere with methods of the same
1584+
/// name on the contents of a `RefCell` used through `Deref`.
1585+
///
1586+
/// # Examples
1587+
///
1588+
/// ```
1589+
/// #![feature(refcell_try_map)]
1590+
/// use std::cell::{RefCell, Ref};
1591+
/// use std::str::{from_utf8, Utf8Error};
1592+
///
1593+
/// let c = RefCell::new(vec![0xF0, 0x9F, 0xA6 ,0x80]);
1594+
/// let b1: Ref<'_, Vec<u8>> = c.borrow();
1595+
/// let b2: Result<Ref<'_, str>, _> = Ref::try_map(b1, |v| from_utf8(v));
1596+
/// assert_eq!(&*b2.unwrap(), "🦀");
1597+
///
1598+
/// let c = RefCell::new(vec![0xF0, 0x9F, 0xA6]);
1599+
/// let b1: Ref<'_, Vec<u8>> = c.borrow();
1600+
/// let b2: Result<_, (Ref<'_, Vec<u8>>, Utf8Error)> = Ref::try_map(b1, |v| from_utf8(v));
1601+
/// let (b3, e) = b2.unwrap_err();
1602+
/// assert_eq!(*b3, vec![0xF0, 0x9F, 0xA6]);
1603+
/// assert_eq!(e.valid_up_to(), 0);
1604+
/// ```
1605+
#[unstable(feature = "refcell_try_map", issue = "143801")]
1606+
#[inline]
1607+
pub fn try_map<U: ?Sized, E>(
1608+
orig: Ref<'b, T>,
1609+
f: impl FnOnce(&T) -> Result<&U, E>,
1610+
) -> Result<Ref<'b, U>, (Self, E)> {
1611+
match f(&*orig) {
1612+
Ok(value) => Ok(Ref { value: NonNull::from(value), borrow: orig.borrow }),
1613+
Err(e) => Err((orig, e)),
1614+
}
1615+
}
1616+
15761617
/// Splits a `Ref` into multiple `Ref`s for different components of the
15771618
/// borrowed data.
15781619
///
@@ -1734,6 +1775,58 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
17341775
}
17351776
}
17361777

1778+
/// Tries to makes a new `RefMut` for a component of the borrowed data.
1779+
/// On failure, the original guard is returned alongside with the error
1780+
/// returned by the closure.
1781+
///
1782+
/// The `RefCell` is already mutably borrowed, so this cannot fail.
1783+
///
1784+
/// This is an associated function that needs to be used as
1785+
/// `RefMut::try_map(...)`. A method would interfere with methods of the same
1786+
/// name on the contents of a `RefCell` used through `Deref`.
1787+
///
1788+
/// # Examples
1789+
///
1790+
/// ```
1791+
/// #![feature(refcell_try_map)]
1792+
/// use std::cell::{RefCell, RefMut};
1793+
/// use std::str::{from_utf8_mut, Utf8Error};
1794+
///
1795+
/// let c = RefCell::new(vec![0x68, 0x65, 0x6C, 0x6C, 0x6F]);
1796+
/// {
1797+
/// let b1: RefMut<'_, Vec<u8>> = c.borrow_mut();
1798+
/// let b2: Result<RefMut<'_, str>, _> = RefMut::try_map(b1, |v| from_utf8_mut(v));
1799+
/// let mut b2 = b2.unwrap();
1800+
/// assert_eq!(&*b2, "hello");
1801+
/// b2.make_ascii_uppercase();
1802+
/// }
1803+
/// assert_eq!(*c.borrow(), "HELLO".as_bytes());
1804+
///
1805+
/// let c = RefCell::new(vec![0xFF]);
1806+
/// let b1: RefMut<'_, Vec<u8>> = c.borrow_mut();
1807+
/// let b2: Result<_, (RefMut<'_, Vec<u8>>, Utf8Error)> = RefMut::try_map(b1, |v| from_utf8_mut(v));
1808+
/// let (b3, e) = b2.unwrap_err();
1809+
/// assert_eq!(*b3, vec![0xFF]);
1810+
/// assert_eq!(e.valid_up_to(), 0);
1811+
/// ```
1812+
#[unstable(feature = "refcell_try_map", issue = "143801")]
1813+
#[inline]
1814+
pub fn try_map<U: ?Sized, E>(
1815+
mut orig: RefMut<'b, T>,
1816+
f: impl FnOnce(&mut T) -> Result<&mut U, E>,
1817+
) -> Result<RefMut<'b, U>, (Self, E)> {
1818+
// SAFETY: function holds onto an exclusive reference for the duration
1819+
// of its call through `orig`, and the pointer is only de-referenced
1820+
// inside of the function call never allowing the exclusive reference to
1821+
// escape.
1822+
match f(&mut *orig) {
1823+
Ok(value) => {
1824+
Ok(RefMut { value: NonNull::from(value), borrow: orig.borrow, marker: PhantomData })
1825+
}
1826+
Err(e) => Err((orig, e)),
1827+
}
1828+
}
1829+
17371830
/// Splits a `RefMut` into multiple `RefMut`s for different components of the
17381831
/// borrowed data.
17391832
///

0 commit comments

Comments
 (0)