Skip to content

Commit 679f6f3

Browse files
committed
Add unwrap_unchecked() methods for Option and Result
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 #48278. Signed-off-by: Miguel Ojeda <[email protected]>
1 parent 7a19392 commit 679f6f3

File tree

5 files changed

+114
-1
lines changed

5 files changed

+114
-1
lines changed

library/core/src/option.rs

+31
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,37 @@ impl<T> Option<T> {
428428
}
429429
}
430430

431+
/// Returns the contained [`Some`] value, consuming the `self` value,
432+
/// without checking that the value is not [`None`].
433+
///
434+
/// # Safety
435+
///
436+
/// Undefined behavior if the value is [`None`].
437+
///
438+
/// # Examples
439+
///
440+
/// ```
441+
/// #![feature(option_result_unwrap_unchecked)]
442+
/// let x = Some("air");
443+
/// assert_eq!(unsafe { x.unwrap_unchecked() }, "air");
444+
/// ```
445+
///
446+
/// ```no_run
447+
/// #![feature(option_result_unwrap_unchecked)]
448+
/// let x: Option<&str> = None;
449+
/// assert_eq!(unsafe { x.unwrap_unchecked() }, "air"); // Undefined behavior!
450+
/// ```
451+
#[inline]
452+
#[track_caller]
453+
#[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "none")]
454+
pub unsafe fn unwrap_unchecked(self) -> T {
455+
debug_assert!(self.is_some());
456+
match self {
457+
Some(val) => val,
458+
None => unsafe { hint::unreachable_unchecked() },
459+
}
460+
}
461+
431462
/////////////////////////////////////////////////////////////////////////
432463
// Transforming contained values
433464
/////////////////////////////////////////////////////////////////////////

library/core/src/result.rs

+63-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@
229229

230230
use crate::iter::{self, FromIterator, FusedIterator, TrustedLen};
231231
use crate::ops::{self, Deref, DerefMut};
232-
use crate::{convert, fmt};
232+
use crate::{convert, fmt, hint};
233233

234234
/// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]).
235235
///
@@ -821,6 +821,68 @@ impl<T, E> Result<T, E> {
821821
Err(e) => op(e),
822822
}
823823
}
824+
825+
/// Returns the contained [`Ok`] value, consuming the `self` value,
826+
/// without checking that the value is not an [`Err`].
827+
///
828+
/// # Safety
829+
///
830+
/// Undefined behavior if the value is an [`Err`].
831+
///
832+
/// # Examples
833+
///
834+
/// ```
835+
/// #![feature(option_result_unwrap_unchecked)]
836+
/// let x: Result<u32, &str> = Ok(2);
837+
/// assert_eq!(unsafe { x.unwrap_unchecked() }, 2);
838+
/// ```
839+
///
840+
/// ```no_run
841+
/// #![feature(option_result_unwrap_unchecked)]
842+
/// let x: Result<u32, &str> = Err("emergency failure");
843+
/// unsafe { x.unwrap_unchecked(); } // Undefined behavior!
844+
/// ```
845+
#[inline]
846+
#[track_caller]
847+
#[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "none")]
848+
pub unsafe fn unwrap_unchecked(self) -> T {
849+
debug_assert!(self.is_ok());
850+
match self {
851+
Ok(t) => t,
852+
Err(_) => unsafe { hint::unreachable_unchecked() },
853+
}
854+
}
855+
856+
/// Returns the contained [`Err`] value, consuming the `self` value,
857+
/// without checking that the value is not an [`Ok`].
858+
///
859+
/// # Safety
860+
///
861+
/// Undefined behavior if the value is an [`Ok`].
862+
///
863+
/// # Examples
864+
///
865+
/// ```no_run
866+
/// #![feature(option_result_unwrap_unchecked)]
867+
/// let x: Result<u32, &str> = Ok(2);
868+
/// unsafe { x.unwrap_err_unchecked() }; // Undefined behavior!
869+
/// ```
870+
///
871+
/// ```
872+
/// #![feature(option_result_unwrap_unchecked)]
873+
/// let x: Result<u32, &str> = Err("emergency failure");
874+
/// assert_eq!(unsafe { x.unwrap_err_unchecked() }, "emergency failure");
875+
/// ```
876+
#[inline]
877+
#[track_caller]
878+
#[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "none")]
879+
pub unsafe fn unwrap_err_unchecked(self) -> E {
880+
debug_assert!(self.is_err());
881+
match self {
882+
Ok(_) => unsafe { hint::unreachable_unchecked() },
883+
Err(e) => e,
884+
}
885+
}
824886
}
825887

826888
impl<T: Copy, E> Result<&T, E> {

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
#![feature(const_raw_ptr_deref)]
6363
#![feature(never_type)]
6464
#![feature(unwrap_infallible)]
65+
#![feature(option_result_unwrap_unchecked)]
6566
#![feature(option_unwrap_none)]
6667
#![feature(peekable_next_if)]
6768
#![feature(peekable_peek_mut)]

library/core/tests/option.rs

+7
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,13 @@ fn test_unwrap_or_else() {
160160
assert_eq!(x.unwrap_or_else(|| 2), 2);
161161
}
162162

163+
#[test]
164+
fn test_unwrap_unchecked() {
165+
assert_eq!(unsafe { Some(1).unwrap_unchecked() }, 1);
166+
let s = unsafe { Some("hello".to_string()).unwrap_unchecked() };
167+
assert_eq!(s, "hello");
168+
}
169+
163170
#[test]
164171
fn test_iter() {
165172
let val = 5;

library/core/tests/result.rs

+12
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,18 @@ pub fn test_unwrap_or_else_panic() {
119119
let _: isize = bad_err.unwrap_or_else(handler);
120120
}
121121

122+
#[test]
123+
fn test_unwrap_unchecked() {
124+
let ok: Result<isize, &'static str> = Ok(100);
125+
assert_eq!(unsafe { ok.unwrap_unchecked() }, 100);
126+
}
127+
128+
#[test]
129+
fn test_unwrap_err_unchecked() {
130+
let ok_err: Result<isize, &'static str> = Err("Err");
131+
assert_eq!(unsafe { ok_err.unwrap_err_unchecked() }, "Err");
132+
}
133+
122134
#[test]
123135
pub fn test_expect_ok() {
124136
let ok: Result<isize, &'static str> = Ok(100);

0 commit comments

Comments
 (0)