Skip to content

Commit e8757af

Browse files
committed
Use Result and rename to filter_map
The use of Result allows for making use of a reconstructed original value on failed projections.
1 parent 0660b8b commit e8757af

File tree

1 file changed

+34
-18
lines changed

1 file changed

+34
-18
lines changed

library/core/src/cell.rs

+34-18
Original file line numberDiff line numberDiff line change
@@ -1261,34 +1261,38 @@ impl<'b, T: ?Sized> Ref<'b, T> {
12611261
Ref { value: f(orig.value), borrow: orig.borrow }
12621262
}
12631263

1264-
/// Makes a new `Ref` for an optional component of the borrowed data.
1264+
/// Makes a new `Ref` for an optional component of the borrowed data. The
1265+
/// original guard is returned as an `Err(..)` if the closure returns
1266+
/// `None`.
12651267
///
12661268
/// The `RefCell` is already immutably borrowed, so this cannot fail.
12671269
///
12681270
/// This is an associated function that needs to be used as
1269-
/// `Ref::try_map(...)`. A method would interfere with methods of the same
1271+
/// `Ref::filter_map(...)`. A method would interfere with methods of the same
12701272
/// name on the contents of a `RefCell` used through `Deref`.
12711273
///
12721274
/// # Examples
12731275
///
12741276
/// ```
1275-
/// #![feature(cell_try_map)]
1277+
/// #![feature(cell_filter_map)]
12761278
///
12771279
/// use std::cell::{RefCell, Ref};
12781280
///
12791281
/// let c = RefCell::new(vec![1, 2, 3]);
12801282
/// let b1: Ref<Vec<u32>> = c.borrow();
1281-
/// let b2: Option<Ref<u32>> = Ref::try_map(b1, |v| v.get(1));
1282-
/// assert_eq!(b2.as_deref(), Some(&2))
1283+
/// let b2: Result<Ref<u32>, _> = Ref::filter_map(b1, |v| v.get(1));
1284+
/// assert_eq!(*b2.unwrap(), 2);
12831285
/// ```
1284-
#[unstable(feature = "cell_try_map", reason = "recently added", issue = "none")]
1286+
#[unstable(feature = "cell_filter_map", reason = "recently added", issue = "none")]
12851287
#[inline]
1286-
pub fn try_map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Option<Ref<'b, U>>
1288+
pub fn filter_map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Result<Ref<'b, U>, Self>
12871289
where
12881290
F: FnOnce(&T) -> Option<&U>,
12891291
{
1290-
let value = f(orig.value)?;
1291-
Some(Ref { value, borrow: orig.borrow })
1292+
match f(orig.value) {
1293+
Some(value) => Ok(Ref { value, borrow: orig.borrow }),
1294+
None => Err(orig),
1295+
}
12921296
}
12931297

12941298
/// Splits a `Ref` into multiple `Ref`s for different components of the
@@ -1402,44 +1406,56 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
14021406
RefMut { value: f(value), borrow }
14031407
}
14041408

1405-
/// Makes a new `RefMut` for an optional component of the borrowed data.
1409+
/// Makes a new `RefMut` for an optional component of the borrowed data. The
1410+
/// original guard is returned as an `Err(..)` if the closure returns
1411+
/// `None`.
14061412
///
14071413
/// The `RefCell` is already mutably borrowed, so this cannot fail.
14081414
///
14091415
/// This is an associated function that needs to be used as
1410-
/// `RefMut::try_map(...)`. A method would interfere with methods of the
1416+
/// `RefMut::filter_map(...)`. A method would interfere with methods of the
14111417
/// same name on the contents of a `RefCell` used through `Deref`.
14121418
///
14131419
/// # Examples
14141420
///
14151421
/// ```
1416-
/// #![feature(cell_try_map)]
1422+
/// #![feature(cell_filter_map)]
14171423
///
14181424
/// use std::cell::{RefCell, RefMut};
14191425
///
14201426
/// let c = RefCell::new(vec![1, 2, 3]);
14211427
///
14221428
/// {
14231429
/// let b1: RefMut<Vec<u32>> = c.borrow_mut();
1424-
/// let mut b2: Option<RefMut<u32>> = RefMut::try_map(b1, |v| v.get_mut(1));
1430+
/// let mut b2: Result<RefMut<u32>, _> = RefMut::filter_map(b1, |v| v.get_mut(1));
14251431
///
1426-
/// if let Some(mut b2) = b2 {
1432+
/// if let Ok(mut b2) = b2 {
14271433
/// *b2 += 2;
14281434
/// }
14291435
/// }
14301436
///
14311437
/// assert_eq!(*c.borrow(), vec![1, 4, 3]);
14321438
/// ```
1433-
#[unstable(feature = "cell_try_map", reason = "recently added", issue = "none")]
1439+
#[unstable(feature = "cell_filter_map", reason = "recently added", issue = "none")]
14341440
#[inline]
1435-
pub fn try_map<U: ?Sized, F>(orig: RefMut<'b, T>, f: F) -> Option<RefMut<'b, U>>
1441+
pub fn filter_map<U: ?Sized, F>(orig: RefMut<'b, T>, f: F) -> Result<RefMut<'b, U>, Self>
14361442
where
14371443
F: FnOnce(&mut T) -> Option<&mut U>,
14381444
{
14391445
// FIXME(nll-rfc#40): fix borrow-check
14401446
let RefMut { value, borrow } = orig;
1441-
let value = f(value)?;
1442-
Some(RefMut { value, borrow })
1447+
let value = value as *mut T;
1448+
// SAFETY: function holds onto an exclusive reference for the duration
1449+
// of its call through `orig`, and the pointer is only de-referenced
1450+
// inside of the function call never allowing the exclusive reference to
1451+
// escape.
1452+
match f(unsafe { &mut *value }) {
1453+
Some(value) => Ok(RefMut { value, borrow }),
1454+
None => {
1455+
// SAFETY: same as above.
1456+
Err(RefMut { value: unsafe { &mut *value }, borrow })
1457+
}
1458+
}
14431459
}
14441460

14451461
/// Splits a `RefMut` into multiple `RefMut`s for different components of the

0 commit comments

Comments
 (0)