summaryrefslogtreecommitdiffstats
path: root/library/core/src/option.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/core/src/option.rs')
-rw-r--r--library/core/src/option.rs141
1 files changed, 138 insertions, 3 deletions
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 7cc00e3f8..994c08d1f 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -551,8 +551,9 @@ use crate::marker::Destruct;
use crate::panicking::{panic, panic_str};
use crate::pin::Pin;
use crate::{
- convert, hint, mem,
+ cmp, convert, hint, mem,
ops::{self, ControlFlow, Deref, DerefMut},
+ slice,
};
/// The `Option` type. See [the module level documentation](self) for more.
@@ -734,6 +735,124 @@ impl<T> Option<T> {
}
}
+ const fn get_some_offset() -> isize {
+ if mem::size_of::<Option<T>>() == mem::size_of::<T>() {
+ // niche optimization means the `T` is always stored at the same position as the Option.
+ 0
+ } else {
+ assert!(mem::size_of::<Option<T>>() == mem::size_of::<Option<mem::MaybeUninit<T>>>());
+ let some_uninit = Some(mem::MaybeUninit::<T>::uninit());
+ // SAFETY: This gets the byte offset of the `Some(_)` value following the fact that
+ // niche optimization is not active, and thus Option<T> and Option<MaybeUninit<t>> share
+ // the same layout.
+ unsafe {
+ (some_uninit.as_ref().unwrap() as *const mem::MaybeUninit<T>)
+ .byte_offset_from(&some_uninit as *const Option<mem::MaybeUninit<T>>)
+ }
+ }
+ }
+
+ /// Returns a slice of the contained value, if any. If this is `None`, an
+ /// empty slice is returned. This can be useful to have a single type of
+ /// iterator over an `Option` or slice.
+ ///
+ /// Note: Should you have an `Option<&T>` and wish to get a slice of `T`,
+ /// you can unpack it via `opt.map_or(&[], std::slice::from_ref)`.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// #![feature(option_as_slice)]
+ ///
+ /// assert_eq!(
+ /// [Some(1234).as_slice(), None.as_slice()],
+ /// [&[1234][..], &[][..]],
+ /// );
+ /// ```
+ ///
+ /// The inverse of this function is (discounting
+ /// borrowing) [`[_]::first`](slice::first):
+ ///
+ /// ```rust
+ /// #![feature(option_as_slice)]
+ ///
+ /// for i in [Some(1234_u16), None] {
+ /// assert_eq!(i.as_ref(), i.as_slice().first());
+ /// }
+ /// ```
+ #[inline]
+ #[must_use]
+ #[unstable(feature = "option_as_slice", issue = "108545")]
+ pub fn as_slice(&self) -> &[T] {
+ // SAFETY: This is sound as long as `get_some_offset` returns the
+ // correct offset. Though in the `None` case, the slice may be located
+ // at a pointer pointing into padding, the fact that the slice is
+ // empty, and the padding is at a properly aligned position for a
+ // value of that type makes it sound.
+ unsafe {
+ slice::from_raw_parts(
+ (self as *const Option<T>).wrapping_byte_offset(Self::get_some_offset())
+ as *const T,
+ self.is_some() as usize,
+ )
+ }
+ }
+
+ /// Returns a mutable slice of the contained value, if any. If this is
+ /// `None`, an empty slice is returned. This can be useful to have a
+ /// single type of iterator over an `Option` or slice.
+ ///
+ /// Note: Should you have an `Option<&mut T>` instead of a
+ /// `&mut Option<T>`, which this method takes, you can obtain a mutable
+ /// slice via `opt.map_or(&mut [], std::slice::from_mut)`.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// #![feature(option_as_slice)]
+ ///
+ /// assert_eq!(
+ /// [Some(1234).as_mut_slice(), None.as_mut_slice()],
+ /// [&mut [1234][..], &mut [][..]],
+ /// );
+ /// ```
+ ///
+ /// The result is a mutable slice of zero or one items that points into
+ /// our original `Option`:
+ ///
+ /// ```rust
+ /// #![feature(option_as_slice)]
+ ///
+ /// let mut x = Some(1234);
+ /// x.as_mut_slice()[0] += 1;
+ /// assert_eq!(x, Some(1235));
+ /// ```
+ ///
+ /// The inverse of this method (discounting borrowing)
+ /// is [`[_]::first_mut`](slice::first_mut):
+ ///
+ /// ```rust
+ /// #![feature(option_as_slice)]
+ ///
+ /// assert_eq!(Some(123).as_mut_slice().first_mut(), Some(&mut 123))
+ /// ```
+ #[inline]
+ #[must_use]
+ #[unstable(feature = "option_as_slice", issue = "108545")]
+ pub fn as_mut_slice(&mut self) -> &mut [T] {
+ // SAFETY: This is sound as long as `get_some_offset` returns the
+ // correct offset. Though in the `None` case, the slice may be located
+ // at a pointer pointing into padding, the fact that the slice is
+ // empty, and the padding is at a properly aligned position for a
+ // value of that type makes it sound.
+ unsafe {
+ slice::from_raw_parts_mut(
+ (self as *mut Option<T>).wrapping_byte_offset(Self::get_some_offset()) as *mut T,
+ self.is_some() as usize,
+ )
+ }
+ }
+
/////////////////////////////////////////////////////////////////////////
// Getting to contained values
/////////////////////////////////////////////////////////////////////////
@@ -943,7 +1062,7 @@ impl<T> Option<T> {
// Transforming contained values
/////////////////////////////////////////////////////////////////////////
- /// Maps an `Option<T>` to `Option<U>` by applying a function to a contained value.
+ /// Maps an `Option<T>` to `Option<U>` by applying a function to a contained value (if `Some`) or returns `None` (if `None`).
///
/// # Examples
///
@@ -955,8 +1074,10 @@ impl<T> Option<T> {
/// let maybe_some_string = Some(String::from("Hello, World!"));
/// // `Option::map` takes self *by value*, consuming `maybe_some_string`
/// let maybe_some_len = maybe_some_string.map(|s| s.len());
- ///
/// assert_eq!(maybe_some_len, Some(13));
+ ///
+ /// let x: Option<&str> = None;
+ /// assert_eq!(x.map(|s| s.len()), None);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -2090,6 +2211,12 @@ impl<T: PartialEq> PartialEq for Option<T> {
}
}
+/// This specialization trait is a workaround for LLVM not currently (2023-01)
+/// being able to optimize this itself, even though Alive confirms that it would
+/// be legal to do so: <https://github.com/llvm/llvm-project/issues/52622>
+///
+/// Once that's fixed, `Option` should go back to deriving `PartialEq`, as
+/// it used to do before <https://github.com/rust-lang/rust/pull/103556>.
#[unstable(feature = "spec_option_partial_eq", issue = "none", reason = "exposed only for rustc")]
#[doc(hidden)]
pub trait SpecOptionPartialEq: Sized {
@@ -2146,6 +2273,14 @@ impl<T> SpecOptionPartialEq for crate::ptr::NonNull<T> {
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl SpecOptionPartialEq for cmp::Ordering {
+ #[inline]
+ fn eq(l: &Option<Self>, r: &Option<Self>) -> bool {
+ l.map_or(2, |x| x as i8) == r.map_or(2, |x| x as i8)
+ }
+}
+
/////////////////////////////////////////////////////////////////////////////
// The Option Iterators
/////////////////////////////////////////////////////////////////////////////