Skip to content

Commit 87ea19f

Browse files
committed
Add Ref/RefMut try_map method
1 parent 66e5852 commit 87ea19f

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
@@ -1547,6 +1547,47 @@ impl<'b, T: ?Sized> Ref<'b, T> {
15471547
}
15481548
}
15491549

1550+
/// Tries to makes a new `Ref` for a component of the borrowed data.
1551+
/// On failure, the original guard is returned alongside with the error
1552+
/// returned by the closure.
1553+
///
1554+
/// The `RefCell` is already immutably borrowed, so this cannot fail.
1555+
///
1556+
/// This is an associated function that needs to be used as
1557+
/// `Ref::try_map(...)`. A method would interfere with methods of the same
1558+
/// name on the contents of a `RefCell` used through `Deref`.
1559+
///
1560+
/// # Examples
1561+
///
1562+
/// ```
1563+
/// #![feature(refcell_try_map)]
1564+
/// use std::cell::{RefCell, Ref};
1565+
/// use std::str::{from_utf8, Utf8Error};
1566+
///
1567+
/// let c = RefCell::new(vec![0xF0, 0x9F, 0xA6 ,0x80]);
1568+
/// let b1: Ref<'_, Vec<u8>> = c.borrow();
1569+
/// let b2: Result<Ref<'_, str>, _> = Ref::try_map(b1, |v| from_utf8(v));
1570+
/// assert_eq!(&*b2.unwrap(), "🦀");
1571+
///
1572+
/// let c = RefCell::new(vec![0xF0, 0x9F, 0xA6]);
1573+
/// let b1: Ref<'_, Vec<u8>> = c.borrow();
1574+
/// let b2: Result<_, (Ref<'_, Vec<u8>>, Utf8Error)> = Ref::try_map(b1, |v| from_utf8(v));
1575+
/// let (b3, e) = b2.unwrap_err();
1576+
/// assert_eq!(*b3, vec![0xF0, 0x9F, 0xA6]);
1577+
/// assert_eq!(e.valid_up_to(), 0);
1578+
/// ```
1579+
#[unstable(feature = "refcell_try_map", issue = "none")]
1580+
#[inline]
1581+
pub fn try_map<U: ?Sized, E, F>(orig: Ref<'b, T>, f: F) -> Result<Ref<'b, U>, (Self, E)>
1582+
where
1583+
F: FnOnce(&T) -> Result<&U, E>,
1584+
{
1585+
match f(&*orig) {
1586+
Ok(value) => Ok(Ref { value: NonNull::from(value), borrow: orig.borrow }),
1587+
Err(e) => Err((orig, e)),
1588+
}
1589+
}
1590+
15501591
/// Splits a `Ref` into multiple `Ref`s for different components of the
15511592
/// borrowed data.
15521593
///
@@ -1707,6 +1748,61 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
17071748
}
17081749
}
17091750

1751+
/// Tries to makes a new `RefMut` for a component of the borrowed data.
1752+
/// On failure, the original guard is returned alongside with the error
1753+
/// returned by the closure.
1754+
///
1755+
/// The `RefCell` is already mutably borrowed, so this cannot fail.
1756+
///
1757+
/// This is an associated function that needs to be used as
1758+
/// `RefMut::try_map(...)`. A method would interfere with methods of the same
1759+
/// name on the contents of a `RefCell` used through `Deref`.
1760+
///
1761+
/// # Examples
1762+
///
1763+
/// ```
1764+
/// #![feature(refcell_try_map)]
1765+
/// use std::cell::{RefCell, RefMut};
1766+
/// use std::str::{from_utf8_mut, Utf8Error};
1767+
///
1768+
/// let c = RefCell::new(vec![0x68, 0x65, 0x6C, 0x6C, 0x6F]);
1769+
/// {
1770+
/// let b1: RefMut<'_, Vec<u8>> = c.borrow_mut();
1771+
/// let b2: Result<RefMut<'_, str>, _> = RefMut::try_map(b1, |v| from_utf8_mut(v));
1772+
/// let mut b2 = b2.unwrap();
1773+
/// assert_eq!(&*b2, "hello");
1774+
/// b2.make_ascii_uppercase();
1775+
/// }
1776+
/// assert_eq!(*c.borrow(), "HELLO".as_bytes());
1777+
///
1778+
/// let c = RefCell::new(vec![0xFF]);
1779+
/// let b1: RefMut<'_, Vec<u8>> = c.borrow_mut();
1780+
/// let b2: Result<_, (RefMut<'_, Vec<u8>>, Utf8Error)> = RefMut::try_map(b1, |v| from_utf8_mut(v));
1781+
/// let (b3, e) = b2.unwrap_err();
1782+
/// assert_eq!(*b3, vec![0xFF]);
1783+
/// assert_eq!(e.valid_up_to(), 0);
1784+
/// ```
1785+
#[unstable(feature = "refcell_try_map", issue = "none")]
1786+
#[inline]
1787+
pub fn try_map<U: ?Sized, E, F>(
1788+
mut orig: RefMut<'b, T>,
1789+
f: F,
1790+
) -> Result<RefMut<'b, U>, (Self, E)>
1791+
where
1792+
F: FnOnce(&mut T) -> Result<&mut U, E>,
1793+
{
1794+
// SAFETY: function holds onto an exclusive reference for the duration
1795+
// of its call through `orig`, and the pointer is only de-referenced
1796+
// inside of the function call never allowing the exclusive reference to
1797+
// escape.
1798+
match f(&mut *orig) {
1799+
Ok(value) => {
1800+
Ok(RefMut { value: NonNull::from(value), borrow: orig.borrow, marker: PhantomData })
1801+
}
1802+
Err(e) => Err((orig, e)),
1803+
}
1804+
}
1805+
17101806
/// Splits a `RefMut` into multiple `RefMut`s for different components of the
17111807
/// borrowed data.
17121808
///

0 commit comments

Comments
 (0)