From dd0846eff26f552b00363be97f56791bd212694d Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: 2025年7月24日 17:09:17 -0400 Subject: [PATCH] add Box::(try_)map --- library/alloc/src/boxed.rs | 82 +++++++++++++++++++ library/alloc/src/lib.rs | 1 + .../ty-variance-issue-124423.stderr | 3 +- .../ty-variance-issue-127971.stderr | 3 +- tests/ui/privacy/suggest-box-new.stderr | 10 +-- .../suggestions/multi-suggestion.ascii.stderr | 4 +- .../multi-suggestion.unicode.stderr | 4 +- 7 files changed, 94 insertions(+), 13 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 98c9f6b51ab86..4003c07c673b7 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -192,11 +192,15 @@ use core::fmt; use core::future::Future; use core::hash::{Hash, Hasher}; use core::marker::{Tuple, Unsize}; +#[cfg(not(no_global_oom_handling))] +use core::mem::MaybeUninit; use core::mem::{self, SizedTypeProperties}; use core::ops::{ AsyncFn, AsyncFnMut, AsyncFnOnce, CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver, }; +#[cfg(not(no_global_oom_handling))] +use core::ops::{Residual, Try}; use core::pin::{Pin, PinCoerceUnsized}; use core::ptr::{self, NonNull, Unique}; use core::task::{Context, Poll}; @@ -389,6 +393,84 @@ impl Box { pub fn try_new_zeroed() -> Result>, AllocError> { Box::try_new_zeroed_in(Global) } + + /// Maps the value in a box, reusing the allocation if possible. + /// + /// `f` is called on the value in the box, and the result is returned, also boxed. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Box::map(b, f)` instead of `b.map(f)`. This + /// is so that there is no conflict with a method on the inner type. + /// + /// # Examples + /// + /// ``` + /// #![feature(smart_pointer_try_map)] + /// + /// let b = Box::new(7); + /// let new = Box::map(b, |i| i + 7); + /// assert_eq!(*new, 14); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "smart_pointer_try_map", issue = "144419")] + pub fn map(this: Self, f: impl FnOnce(T) -> U) -> Box { + if size_of::() == size_of::() && align_of::() == align_of::() { + let (allocation, value) = unsafe { + let ptr = Box::into_raw(this); + let value = ptr.read(); + let allocation = Box::from_raw(ptr.cast::>()); + (allocation, value) + }; + + Box::write(allocation, f(value)) + } else { + Box::new(f(*this)) + } + } + + /// Attempts to map the value in a box, reusing the allocation if possible. + /// + /// `f` is called on the value in the box, and if the operation succeeds, the result is + /// returned, also boxed. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Box::try_map(b, f)` instead of `b.try_map(f)`. This + /// is so that there is no conflict with a method on the inner type. + /// + /// # Examples + /// + /// ``` + /// #![feature(smart_pointer_try_map)] + /// + /// let b = Box::new(7); + /// let new = Box::try_map(b, u32::try_from).unwrap(); + /// assert_eq!(*new, 7); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "smart_pointer_try_map", issue = "144419")] + pub fn try_map( + this: Self, + f: impl FnOnce(T) -> R, + ) -> >>::TryType + where + R: Try, + R::Residual: Residual>, + { + if size_of::() == size_of::() && align_of::() == align_of::() { + let (allocation, value) = unsafe { + let ptr = Box::into_raw(this); + let value = ptr.read(); + let allocation = Box::from_raw(ptr.cast::>()); + (allocation, value) + }; + >>::TryType::from_output(Box::write( + allocation, + f(value)?, + )) + } else { + >>::TryType::from_output(Box::new(f(*this)?)) + } + } } impl Box { diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index cba1ce40f75d5..6a06f6bdfd6c6 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -153,6 +153,7 @@ #![feature(trusted_len)] #![feature(trusted_random_access)] #![feature(try_trait_v2)] +#![feature(try_trait_v2_residual)] #![feature(try_with_capacity)] #![feature(tuple_trait)] #![feature(ub_checks)] diff --git a/tests/ui/parallel-rustc/ty-variance-issue-124423.stderr b/tests/ui/parallel-rustc/ty-variance-issue-124423.stderr index 7ba89f75bd1b5..81ba66c42faa3 100644 --- a/tests/ui/parallel-rustc/ty-variance-issue-124423.stderr +++ b/tests/ui/parallel-rustc/ty-variance-issue-124423.stderr @@ -278,10 +278,9 @@ note: if you're trying to build a new `Box<_, _>` consider using one of the foll Box::::new_uninit Box::::new_zeroed Box::::try_new - and 22 others --> $SRC_DIR/alloc/src/boxed.rs:LL:COL error: aborting due to 30 previous errors Some errors have detailed explanations: E0121, E0224, E0261, E0412, E0599. -For more information about an error, try `rustc --explain E0121`. +For more information about an error, try `rustc --explain E0121`. \ No newline at end of file diff --git a/tests/ui/parallel-rustc/ty-variance-issue-127971.stderr b/tests/ui/parallel-rustc/ty-variance-issue-127971.stderr index 9929d3ee22ced..55d52d35f4a8d 100644 --- a/tests/ui/parallel-rustc/ty-variance-issue-127971.stderr +++ b/tests/ui/parallel-rustc/ty-variance-issue-127971.stderr @@ -104,10 +104,9 @@ note: if you're trying to build a new `Box<_, _>` consider using one of the foll Box::::new_uninit Box::::new_zeroed Box::::try_new - and 22 others --> $SRC_DIR/alloc/src/boxed.rs:LL:COL error: aborting due to 11 previous errors Some errors have detailed explanations: E0121, E0224, E0261, E0599. -For more information about an error, try `rustc --explain E0121`. +For more information about an error, try `rustc --explain E0121`. \ No newline at end of file diff --git a/tests/ui/privacy/suggest-box-new.stderr b/tests/ui/privacy/suggest-box-new.stderr index 37b2989dcc148..7df293e1e1d94 100644 --- a/tests/ui/privacy/suggest-box-new.stderr +++ b/tests/ui/privacy/suggest-box-new.stderr @@ -63,7 +63,7 @@ LL - x: (), LL - })), LL + wtf: Some(Box::new_in(_, _)), | - = and 12 other candidates + = and 13 other candidates help: consider using the `Default` trait | LL - wtf: Some(Box(U { @@ -118,7 +118,7 @@ LL + let _ = Box::new_zeroed(); LL - let _ = Box {}; LL + let _ = Box::new_in(_, _); | - = and 13 other candidates + = and 14 other candidates help: consider using the `Default` trait | LL - let _ = Box {}; @@ -141,12 +141,12 @@ LL - let _ = Box:: {}; LL + let _ = Box::::new_in(_, _); | LL - let _ = Box:: {}; -LL + let _ = Box::::into_inner(_); +LL + let _ = Box::::map(_, _); | LL - let _ = Box:: {}; -LL + let _ = Box::::write(_, _); +LL + let _ = Box::::into_inner(_); | - = and 4 other candidates + = and 5 other candidates help: consider using the `Default` trait | LL - let _ = Box:: {}; diff --git a/tests/ui/suggestions/multi-suggestion.ascii.stderr b/tests/ui/suggestions/multi-suggestion.ascii.stderr index 9c8867a17711e..4bd6c19e0829b 100644 --- a/tests/ui/suggestions/multi-suggestion.ascii.stderr +++ b/tests/ui/suggestions/multi-suggestion.ascii.stderr @@ -63,7 +63,7 @@ LL - x: (), LL - })), LL + wtf: Some(Box::new_in(_, _)), | - = and 12 other candidates + = and 13 other candidates help: consider using the `Default` trait | LL - wtf: Some(Box(U { @@ -118,7 +118,7 @@ LL + let _ = Box::new_zeroed(); LL - let _ = Box {}; LL + let _ = Box::new_in(_, _); | - = and 13 other candidates + = and 14 other candidates help: consider using the `Default` trait | LL - let _ = Box {}; diff --git a/tests/ui/suggestions/multi-suggestion.unicode.stderr b/tests/ui/suggestions/multi-suggestion.unicode.stderr index 4fdab51493e26..b11570f34161c 100644 --- a/tests/ui/suggestions/multi-suggestion.unicode.stderr +++ b/tests/ui/suggestions/multi-suggestion.unicode.stderr @@ -63,7 +63,7 @@ LL - x: (), LL - })), LL + wtf: Some(Box::new_in(_, _)), │ - ╰ and 12 other candidates + ╰ and 13 other candidates help: consider using the `Default` trait ╭╴ LL - wtf: Some(Box(U { @@ -118,7 +118,7 @@ LL + let _ = Box::new_zeroed(); LL - let _ = Box {}; LL + let _ = Box::new_in(_, _); │ - ╰ and 13 other candidates + ╰ and 14 other candidates help: consider using the `Default` trait ╭╴ LL - let _ = Box {};

AltStyle によって変換されたページ (->オリジナル) /