Constify additional Result functions

This commit is contained in:
Evgenii Zheltonozhskii 2025-08-01 08:55:50 +03:00
parent adcb3d3b4c
commit 9377e0af52
3 changed files with 197 additions and 25 deletions

View file

@ -534,6 +534,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
use crate::iter::{self, FusedIterator, TrustedLen};
use crate::marker::Destruct;
use crate::ops::{self, ControlFlow, Deref, DerefMut};
use crate::{convert, fmt, hint};
@ -606,7 +607,13 @@ impl<T, E> Result<T, E> {
#[must_use]
#[inline]
#[stable(feature = "is_some_and", since = "1.70.0")]
pub fn is_ok_and(self, f: impl FnOnce(T) -> bool) -> bool {
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn is_ok_and<F>(self, f: F) -> bool
where
F: ~const FnOnce(T) -> bool + ~const Destruct,
T: ~const Destruct,
E: ~const Destruct,
{
match self {
Err(_) => false,
Ok(x) => f(x),
@ -655,7 +662,13 @@ impl<T, E> Result<T, E> {
#[must_use]
#[inline]
#[stable(feature = "is_some_and", since = "1.70.0")]
pub fn is_err_and(self, f: impl FnOnce(E) -> bool) -> bool {
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn is_err_and<F>(self, f: F) -> bool
where
F: ~const FnOnce(E) -> bool + ~const Destruct,
E: ~const Destruct,
T: ~const Destruct,
{
match self {
Ok(_) => false,
Err(e) => f(e),
@ -682,8 +695,13 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
#[rustc_diagnostic_item = "result_ok_method"]
pub fn ok(self) -> Option<T> {
pub const fn ok(self) -> Option<T>
where
T: ~const Destruct,
E: ~const Destruct,
{
match self {
Ok(x) => Some(x),
Err(_) => None,
@ -706,7 +724,12 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn err(self) -> Option<E> {
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn err(self) -> Option<E>
where
T: ~const Destruct,
E: ~const Destruct,
{
match self {
Ok(_) => None,
Err(x) => Some(x),
@ -796,7 +819,11 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Result<U, E> {
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn map<U, F>(self, op: F) -> Result<U, E>
where
F: ~const FnOnce(T) -> U + ~const Destruct,
{
match self {
Ok(t) => Ok(op(t)),
Err(e) => Err(e),
@ -823,8 +850,15 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "result_map_or", since = "1.41.0")]
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
#[must_use = "if you don't need the returned value, use `if let` instead"]
pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
pub const fn map_or<U, F>(self, default: U, f: F) -> U
where
F: ~const FnOnce(T) -> U + ~const Destruct,
T: ~const Destruct,
E: ~const Destruct,
U: ~const Destruct,
{
match self {
Ok(t) => f(t),
Err(_) => default,
@ -851,7 +885,12 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "result_map_or_else", since = "1.41.0")]
pub fn map_or_else<U, D: FnOnce(E) -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn map_or_else<U, D, F>(self, default: D, f: F) -> U
where
D: ~const FnOnce(E) -> U + ~const Destruct,
F: ~const FnOnce(T) -> U + ~const Destruct,
{
match self {
Ok(t) => f(t),
Err(e) => default(e),
@ -877,10 +916,13 @@ impl<T, E> Result<T, E> {
/// [default value]: Default::default
#[inline]
#[unstable(feature = "result_option_map_or_default", issue = "138099")]
pub fn map_or_default<U, F>(self, f: F) -> U
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn map_or_default<U, F>(self, f: F) -> U
where
U: Default,
F: FnOnce(T) -> U,
F: ~const FnOnce(T) -> U + ~const Destruct,
U: ~const Default,
T: ~const Destruct,
E: ~const Destruct,
{
match self {
Ok(t) => f(t),
@ -908,7 +950,11 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn map_err<F, O: FnOnce(E) -> F>(self, op: O) -> Result<T, F> {
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn map_err<F, O>(self, op: O) -> Result<T, F>
where
O: ~const FnOnce(E) -> F + ~const Destruct,
{
match self {
Ok(t) => Ok(t),
Err(e) => Err(op(e)),
@ -930,7 +976,11 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "result_option_inspect", since = "1.76.0")]
pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self {
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn inspect<F>(self, f: F) -> Self
where
F: ~const FnOnce(&T) + ~const Destruct,
{
if let Ok(ref t) = self {
f(t);
}
@ -954,7 +1004,11 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "result_option_inspect", since = "1.76.0")]
pub fn inspect_err<F: FnOnce(&E)>(self, f: F) -> Self {
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn inspect_err<F>(self, f: F) -> Self
where
F: ~const FnOnce(&E) + ~const Destruct,
{
if let Err(ref e) = self {
f(e);
}
@ -1033,7 +1087,8 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter(&self) -> Iter<'_, T> {
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn iter(&self) -> Iter<'_, T> {
Iter { inner: self.as_ref().ok() }
}
@ -1056,7 +1111,8 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn iter_mut(&mut self) -> IterMut<'_, T> {
IterMut { inner: self.as_mut().ok() }
}
@ -1195,9 +1251,11 @@ impl<T, E> Result<T, E> {
/// [`FromStr`]: crate::str::FromStr
#[inline]
#[stable(feature = "result_unwrap_or_default", since = "1.16.0")]
pub fn unwrap_or_default(self) -> T
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn unwrap_or_default(self) -> T
where
T: Default,
T: ~const Default + ~const Destruct,
E: ~const Destruct,
{
match self {
Ok(x) => x,
@ -1370,7 +1428,13 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn and<U>(self, res: Result<U, E>) -> Result<U, E> {
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn and<U>(self, res: Result<U, E>) -> Result<U, E>
where
T: ~const Destruct,
E: ~const Destruct,
U: ~const Destruct,
{
match self {
Ok(_) => res,
Err(e) => Err(e),
@ -1409,8 +1473,12 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
#[rustc_confusables("flat_map", "flatmap")]
pub fn and_then<U, F: FnOnce(T) -> Result<U, E>>(self, op: F) -> Result<U, E> {
pub const fn and_then<U, F>(self, op: F) -> Result<U, E>
where
F: ~const FnOnce(T) -> Result<U, E> + ~const Destruct,
{
match self {
Ok(t) => op(t),
Err(e) => Err(e),
@ -1446,7 +1514,13 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn or<F>(self, res: Result<T, F>) -> Result<T, F> {
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn or<F>(self, res: Result<T, F>) -> Result<T, F>
where
T: ~const Destruct,
E: ~const Destruct,
F: ~const Destruct,
{
match self {
Ok(v) => Ok(v),
Err(_) => res,
@ -1471,7 +1545,11 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn or_else<F, O: FnOnce(E) -> Result<T, F>>(self, op: O) -> Result<T, F> {
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn or_else<F, O>(self, op: O) -> Result<T, F>
where
O: ~const FnOnce(E) -> Result<T, F> + ~const Destruct,
{
match self {
Ok(t) => Ok(t),
Err(e) => op(e),
@ -1498,7 +1576,12 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn unwrap_or(self, default: T) -> T {
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn unwrap_or(self, default: T) -> T
where
T: ~const Destruct,
E: ~const Destruct,
{
match self {
Ok(t) => t,
Err(_) => default,
@ -1519,7 +1602,11 @@ impl<T, E> Result<T, E> {
#[inline]
#[track_caller]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn unwrap_or_else<F: FnOnce(E) -> T>(self, op: F) -> T {
#[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")]
pub const fn unwrap_or_else<F>(self, op: F) -> T
where
F: ~const FnOnce(E) -> T + ~const Destruct,
{
match self {
Ok(t) => t,
Err(e) => op(e),
@ -1762,7 +1849,7 @@ impl<T, E> Result<Result<T, E>, E> {
#[cold]
#[track_caller]
fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! {
panic!("{msg}: {error:?}")
panic!("{msg}: {error:?}");
}
// This is a separate function to avoid constructing a `dyn Debug`
@ -1773,7 +1860,7 @@ fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! {
#[inline]
#[cold]
#[track_caller]
fn unwrap_failed<T>(_msg: &str, _error: &T) -> ! {
const fn unwrap_failed<T>(_msg: &str, _error: &T) -> ! {
panic!()
}

View file

@ -20,6 +20,7 @@
#![feature(const_eval_select)]
#![feature(const_ops)]
#![feature(const_ref_cell)]
#![feature(const_result_trait_fn)]
#![feature(const_trait_impl)]
#![feature(core_float_math)]
#![feature(core_intrinsics)]
@ -82,6 +83,7 @@
#![feature(pointer_is_aligned_to)]
#![feature(portable_simd)]
#![feature(ptr_metadata)]
#![feature(result_option_map_or_default)]
#![feature(slice_from_ptr_range)]
#![feature(slice_internals)]
#![feature(slice_partition_dedup)]

View file

@ -421,3 +421,86 @@ fn result_try_trait_v2_branch() {
assert_eq!(Ok::<NonZero<u32>, ()>(one).branch(), Continue(one));
assert_eq!(Err::<NonZero<u32>, ()>(()).branch(), Break(Err(())));
}
// helper functions for const contexts
const fn eq10(x: u8) -> bool {
x == 10
}
const fn eq20(e: u8) -> bool {
e == 20
}
const fn double_u16(x: u8) -> u16 {
x as u16 * 2
}
const fn to_u16(x: u8) -> u16 {
x as u16
}
const fn err_to_u16_plus1(e: u8) -> u16 {
e as u16 + 1
}
const fn inc_u8(x: u8) -> u8 {
x + 1
}
const fn noop_u8_ref(_x: &u8) {}
const fn add1_result(x: u8) -> Result<u8, u8> {
Ok(x + 1)
}
const fn add5_result(e: u8) -> Result<u8, u8> {
Ok(e + 5)
}
const fn plus7_u8(e: u8) -> u8 {
e + 7
}
#[test]
fn test_const_result() {
const {
let r_ok: Result<u8, u8> = Ok(10);
let r_err: Result<u8, u8> = Err(20);
assert!(r_ok.is_ok());
assert!(r_err.is_err());
let ok_and = r_ok.is_ok_and(eq10);
let err_and = r_err.is_err_and(eq20);
assert!(ok_and);
assert!(err_and);
let opt_ok: Option<u8> = r_ok.ok();
let opt_err: Option<u8> = r_err.err();
assert!(opt_ok.unwrap() == 10);
assert!(opt_err.unwrap() == 20);
let mapped: Result<u16, u8> = r_ok.map(double_u16);
let map_or: u16 = r_ok.map_or(0, to_u16);
let map_or_else: u16 = r_err.map_or_else(err_to_u16_plus1, to_u16);
let map_or_default: u8 = r_err.map_or_default(inc_u8);
assert!(mapped.unwrap_or_default() == 20);
assert!(map_or == 10);
assert!(map_or_else == 21);
assert!(map_or_default == 0);
let _map_err: Result<u8, u16> = r_err.map_err(to_u16);
//FIXME: currently can't unwrap const error
// assert!(map_err.unwrap_err() == 20);
let inspected_ok: Result<u8, u8> = r_ok.inspect(noop_u8_ref);
let inspected_err: Result<u8, u8> = r_err.inspect_err(noop_u8_ref);
assert!(inspected_ok.is_ok());
assert!(inspected_err.is_err());
let unwrapped_default: u8 = r_err.unwrap_or_default();
assert!(unwrapped_default == 0);
let and_then: Result<u8, u8> = r_ok.and_then(add1_result);
let or: Result<u8, u8> = r_err.or(Ok(5));
let or_else: Result<u8, u8> = r_err.or_else(add5_result);
assert!(and_then.unwrap_or_default() == 11);
assert!(or.unwrap_or_default() == 5);
assert!(or_else.unwrap_or_default() == 25);
let u_or: u8 = r_err.unwrap_or(7);
let u_or_else: u8 = r_err.unwrap_or_else(plus7_u8);
assert!(u_or == 7);
assert!(u_or_else == 27);
};
}