Skip to content

Commit

Permalink
Add unwrap_unchecked() methods for Option and Result
Browse files Browse the repository at this point in the history
In particular:
  - `unwrap_unchecked()` for `Option`.
  - `unwrap_unchecked()` and `unwrap_err_unchecked()` for `Result`.

These complement other `*_unchecked()` methods in `core` etc.

Currently there are a couple of places it may be used inside rustc
(`LinkedList`, `BTree`). It is also easy to find other repositories
with similar functionality.

Fixes rust-lang#48278.

Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
  • Loading branch information
ojeda authored and zaharidichev committed Mar 12, 2021
1 parent d4c980d commit 07d7f25
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 1 deletion.
31 changes: 31 additions & 0 deletions library/core/src/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,37 @@ impl<T> Option<T> {
}
}

/// Returns the contained [`Some`] value, consuming the `self` value,
/// without checking that the value is not [`None`].
///
/// # Safety
///
/// Undefined behavior if the value is [`None`].
///
/// # Examples
///
/// ```
/// #![feature(option_result_unwrap_unchecked)]
/// let x = Some("air");
/// assert_eq!(unsafe { x.unwrap_unchecked() }, "air");
/// ```
///
/// ```no_run
/// #![feature(option_result_unwrap_unchecked)]
/// let x: Option<&str> = None;
/// assert_eq!(unsafe { x.unwrap_unchecked() }, "air"); // Undefined behavior!
/// ```
#[inline]
#[track_caller]
#[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "none")]
pub unsafe fn unwrap_unchecked(self) -> T {
debug_assert!(self.is_some());
match self {
Some(val) => val,
None => unsafe { hint::unreachable_unchecked() },
}
}

/////////////////////////////////////////////////////////////////////////
// Transforming contained values
/////////////////////////////////////////////////////////////////////////
Expand Down
64 changes: 63 additions & 1 deletion library/core/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@

use crate::iter::{self, FromIterator, FusedIterator, TrustedLen};
use crate::ops::{self, Deref, DerefMut};
use crate::{convert, fmt};
use crate::{convert, fmt, hint};

/// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]).
///
Expand Down Expand Up @@ -821,6 +821,68 @@ impl<T, E> Result<T, E> {
Err(e) => op(e),
}
}

/// Returns the contained [`Ok`] value, consuming the `self` value,
/// without checking that the value is not an [`Err`].
///
/// # Safety
///
/// Undefined behavior if the value is an [`Err`].
///
/// # Examples
///
/// ```
/// #![feature(option_result_unwrap_unchecked)]
/// let x: Result<u32, &str> = Ok(2);
/// assert_eq!(unsafe { x.unwrap_unchecked() }, 2);
/// ```
///
/// ```no_run
/// #![feature(option_result_unwrap_unchecked)]
/// let x: Result<u32, &str> = Err("emergency failure");
/// unsafe { x.unwrap_unchecked(); } // Undefined behavior!
/// ```
#[inline]
#[track_caller]
#[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "none")]
pub unsafe fn unwrap_unchecked(self) -> T {
debug_assert!(self.is_ok());
match self {
Ok(t) => t,
Err(_) => unsafe { hint::unreachable_unchecked() },
}
}

/// Returns the contained [`Err`] value, consuming the `self` value,
/// without checking that the value is not an [`Ok`].
///
/// # Safety
///
/// Undefined behavior if the value is an [`Ok`].
///
/// # Examples
///
/// ```no_run
/// #![feature(option_result_unwrap_unchecked)]
/// let x: Result<u32, &str> = Ok(2);
/// unsafe { x.unwrap_err_unchecked() }; // Undefined behavior!
/// ```
///
/// ```
/// #![feature(option_result_unwrap_unchecked)]
/// let x: Result<u32, &str> = Err("emergency failure");
/// assert_eq!(unsafe { x.unwrap_err_unchecked() }, "emergency failure");
/// ```
#[inline]
#[track_caller]
#[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "none")]
pub unsafe fn unwrap_err_unchecked(self) -> E {
debug_assert!(self.is_err());
match self {
Ok(_) => unsafe { hint::unreachable_unchecked() },
Err(e) => e,
}
}
}

impl<T: Copy, E> Result<&T, E> {
Expand Down
1 change: 1 addition & 0 deletions library/core/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
#![feature(const_raw_ptr_deref)]
#![feature(never_type)]
#![feature(unwrap_infallible)]
#![feature(option_result_unwrap_unchecked)]
#![feature(option_unwrap_none)]
#![feature(peekable_next_if)]
#![feature(peekable_peek_mut)]
Expand Down
7 changes: 7 additions & 0 deletions library/core/tests/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,13 @@ fn test_unwrap_or_else() {
assert_eq!(x.unwrap_or_else(|| 2), 2);
}

#[test]
fn test_unwrap_unchecked() {
assert_eq!(unsafe { Some(1).unwrap_unchecked() }, 1);
let s = unsafe { Some("hello".to_string()).unwrap_unchecked() };
assert_eq!(s, "hello");
}

#[test]
fn test_iter() {
let val = 5;
Expand Down
12 changes: 12 additions & 0 deletions library/core/tests/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,18 @@ pub fn test_unwrap_or_else_panic() {
let _: isize = bad_err.unwrap_or_else(handler);
}

#[test]
fn test_unwrap_unchecked() {
let ok: Result<isize, &'static str> = Ok(100);
assert_eq!(unsafe { ok.unwrap_unchecked() }, 100);
}

#[test]
fn test_unwrap_err_unchecked() {
let ok_err: Result<isize, &'static str> = Err("Err");
assert_eq!(unsafe { ok_err.unwrap_err_unchecked() }, "Err");
}

#[test]
pub fn test_expect_ok() {
let ok: Result<isize, &'static str> = Ok(100);
Expand Down

0 comments on commit 07d7f25

Please sign in to comment.