diff options
| -rw-r--r-- | library/core/src/lib.rs | 1 | ||||
| -rw-r--r-- | library/core/src/option.rs | 242 | ||||
| -rw-r--r-- | library/core/tests/lib.rs | 2 | ||||
| -rw-r--r-- | library/core/tests/option.rs | 98 |
4 files changed, 282 insertions, 61 deletions
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index da1baa36d6e..67f77f14a6e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -123,6 +123,7 @@ #![feature(const_num_from_num)] #![feature(const_ops)] #![feature(const_option)] +#![feature(const_option_ext)] #![feature(const_pin)] #![feature(const_replace)] #![feature(const_ptr_is_null)] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 015366ed490..5e375d27bdd 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -589,12 +589,13 @@ impl<T> Option<T> { #[must_use] #[inline] #[unstable(feature = "option_result_contains", issue = "62358")] - pub fn contains<U>(&self, x: &U) -> bool + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn contains<U>(&self, x: &U) -> bool where - U: PartialEq<T>, + U: ~const PartialEq<T>, { match self { - Some(y) => x == y, + Some(y) => x.eq(y), None => false, } } @@ -660,10 +661,14 @@ impl<T> Option<T> { #[inline] #[must_use] #[stable(feature = "pin", since = "1.33.0")] - pub fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> { - // SAFETY: `x` is guaranteed to be pinned because it comes from `self` - // which is pinned. - unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) } + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> { + match Pin::get_ref(self).as_ref() { + // SAFETY: `x` is guaranteed to be pinned because it comes from `self` + // which is pinned. + Some(x) => unsafe { Some(Pin::new_unchecked(x)) }, + None => None, + } } /// Converts from <code>[Pin]<[&mut] Option\<T>></code> to <code>Option<[Pin]<[&mut] T>></code>. @@ -672,10 +677,16 @@ impl<T> Option<T> { #[inline] #[must_use] #[stable(feature = "pin", since = "1.33.0")] - pub fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> { // SAFETY: `get_unchecked_mut` is never used to move the `Option` inside `self`. // `x` is guaranteed to be pinned because it comes from `self` which is pinned. - unsafe { Pin::get_unchecked_mut(self).as_mut().map(|x| Pin::new_unchecked(x)) } + unsafe { + match Pin::get_unchecked_mut(self).as_mut() { + Some(x) => Some(Pin::new_unchecked(x)), + None => None, + } + } } ///////////////////////////////////////////////////////////////////////// @@ -764,7 +775,11 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_or(self, default: T) -> T { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn unwrap_or(self, default: T) -> T + where + T: ~const Drop, + { match self { Some(x) => x, None => default, @@ -782,7 +797,12 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn unwrap_or_else<F>(self, f: F) -> T + where + F: ~const FnOnce() -> T, + F: ~const Drop, + { match self { Some(x) => x, None => f(), @@ -812,7 +832,8 @@ impl<T> Option<T> { #[inline] #[track_caller] #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")] - pub unsafe fn unwrap_unchecked(self) -> T { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const unsafe fn unwrap_unchecked(self) -> T { debug_assert!(self.is_some()); match self { Some(val) => val, @@ -842,7 +863,12 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn map<U, F>(self, f: F) -> Option<U> + where + F: ~const FnOnce(T) -> U, + F: ~const Drop, + { match self { Some(x) => Some(f(x)), None => None, @@ -866,7 +892,12 @@ impl<T> Option<T> { /// ``` #[inline] #[unstable(feature = "result_option_inspect", issue = "91345")] - pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn inspect<F>(self, f: F) -> Self + where + F: ~const FnOnce(&T), + F: ~const Drop, + { if let Some(ref x) = self { f(x); } @@ -894,7 +925,13 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn map_or<U, F>(self, default: U, f: F) -> U + where + F: ~const FnOnce(T) -> U, + F: ~const Drop, + U: ~const Drop, + { match self { Some(t) => f(t), None => default, @@ -917,7 +954,14 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn map_or_else<U, D, F>(self, default: D, f: F) -> U + where + D: ~const FnOnce() -> U, + D: ~const Drop, + F: ~const FnOnce(T) -> U, + F: ~const Drop, + { match self { Some(t) => f(t), None => default(), @@ -947,7 +991,11 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn ok_or<E>(self, err: E) -> Result<T, E> { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn ok_or<E>(self, err: E) -> Result<T, E> + where + E: ~const Drop, + { match self { Some(v) => Ok(v), None => Err(err), @@ -972,7 +1020,12 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn ok_or_else<E, F>(self, err: F) -> Result<T, E> + where + F: ~const FnOnce() -> E, + F: ~const Drop, + { match self { Some(v) => Ok(v), None => Err(err()), @@ -1049,7 +1102,12 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn and<U>(self, optb: Option<U>) -> Option<U> { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn and<U>(self, optb: Option<U>) -> Option<U> + where + T: ~const Drop, + U: ~const Drop, + { match self { Some(_) => optb, None => None, @@ -1074,7 +1132,12 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn and_then<U, F: FnOnce(T) -> Option<U>>(self, f: F) -> Option<U> { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn and_then<U, F>(self, f: F) -> Option<U> + where + F: ~const FnOnce(T) -> Option<U>, + F: ~const Drop, + { match self { Some(x) => f(x), None => None, @@ -1107,7 +1170,13 @@ impl<T> Option<T> { /// [`Some(t)`]: Some #[inline] #[stable(feature = "option_filter", since = "1.27.0")] - pub fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn filter<P>(self, predicate: P) -> Self + where + T: ~const Drop, + P: ~const FnOnce(&T) -> bool, + P: ~const Drop, + { if let Some(x) = self { if predicate(&x) { return Some(x); @@ -1145,9 +1214,13 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn or(self, optb: Option<T>) -> Option<T> { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn or(self, optb: Option<T>) -> Option<T> + where + T: ~const Drop, + { match self { - Some(_) => self, + Some(x) => Some(x), None => optb, } } @@ -1167,9 +1240,14 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn or_else<F: FnOnce() -> Option<T>>(self, f: F) -> Option<T> { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn or_else<F>(self, f: F) -> Option<T> + where + F: ~const FnOnce() -> Option<T>, + F: ~const Drop, + { match self { - Some(_) => self, + Some(x) => Some(x), None => f(), } } @@ -1197,7 +1275,11 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "option_xor", since = "1.37.0")] - pub fn xor(self, optb: Option<T>) -> Option<T> { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn xor(self, optb: Option<T>) -> Option<T> + where + T: ~const Drop, + { match (self, optb) { (Some(a), None) => Some(a), (None, Some(b)) => Some(b), @@ -1231,7 +1313,11 @@ impl<T> Option<T> { #[must_use = "if you intended to set a value, consider assignment instead"] #[inline] #[stable(feature = "option_insert", since = "1.53.0")] - pub fn insert(&mut self, value: T) -> &mut T { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn insert(&mut self, value: T) -> &mut T + where + T: ~const Drop, + { *self = Some(value); // SAFETY: the code above just filled the option @@ -1260,8 +1346,18 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "option_entry", since = "1.20.0")] - pub fn get_or_insert(&mut self, value: T) -> &mut T { - self.get_or_insert_with(|| value) + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn get_or_insert(&mut self, value: T) -> &mut T + where + T: ~const Drop, + { + if let None = *self { + *self = Some(value); + } + + // SAFETY: a `None` variant for `self` would have been replaced by a `Some` + // variant in the code above. + unsafe { self.as_mut().unwrap_unchecked() } } /// Inserts the default value into the option if it is [`None`], then @@ -1285,11 +1381,17 @@ impl<T> Option<T> { /// ``` #[inline] #[unstable(feature = "option_get_or_insert_default", issue = "82901")] - pub fn get_or_insert_default(&mut self) -> &mut T + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn get_or_insert_default(&mut self) -> &mut T where - T: Default, + T: ~const Default, { - self.get_or_insert_with(Default::default) + #[rustc_allow_const_fn_unstable(const_fn_trait_bound)] + const fn default<T: ~const Default>() -> T { + T::default() + } + + self.get_or_insert_with(default) } /// Inserts a value computed from `f` into the option if it is [`None`], @@ -1311,17 +1413,21 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "option_entry", since = "1.20.0")] - pub fn get_or_insert_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn get_or_insert_with<F>(&mut self, f: F) -> &mut T + where + F: ~const FnOnce() -> T, + F: ~const Drop, + { if let None = *self { - *self = Some(f()); + // the compiler isn't smart enough to know that we are not dropping a `T` + // here and wants us to ensure `T` can be dropped at compile time. + mem::forget(mem::replace(self, Some(f()))) } - match self { - Some(v) => v, - // SAFETY: a `None` variant for `self` would have been replaced by a `Some` - // variant in the code above. - None => unsafe { hint::unreachable_unchecked() }, - } + // SAFETY: a `None` variant for `self` would have been replaced by a `Some` + // variant in the code above. + unsafe { self.as_mut().unwrap_unchecked() } } ///////////////////////////////////////////////////////////////////////// @@ -1391,7 +1497,12 @@ impl<T> Option<T> { /// assert_eq!(x.zip(z), None); /// ``` #[stable(feature = "option_zip_option", since = "1.46.0")] - pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)> { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn zip<U>(self, other: Option<U>) -> Option<(T, U)> + where + T: ~const Drop, + U: ~const Drop, + { match (self, other) { (Some(a), Some(b)) => Some((a, b)), _ => None, @@ -1427,11 +1538,18 @@ impl<T> Option<T> { /// assert_eq!(x.zip_with(None, Point::new), None); /// ``` #[unstable(feature = "option_zip", issue = "70086")] - pub fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R> + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R> where - F: FnOnce(T, U) -> R, + F: ~const FnOnce(T, U) -> R, + F: ~const Drop, + T: ~const Drop, + U: ~const Drop, { - Some(f(self?, other?)) + match (self, other) { + (Some(a), Some(b)) => Some(f(a, b)), + _ => None, + } } } @@ -1503,8 +1621,12 @@ impl<T: Copy> Option<&mut T> { /// ``` #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "copied", since = "1.35.0")] - pub fn copied(self) -> Option<T> { - self.map(|&mut t| t) + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn copied(self) -> Option<T> { + match self { + Some(&mut t) => Some(t), + None => None, + } } } @@ -1591,7 +1713,11 @@ impl<T: Default> Option<T> { /// [`FromStr`]: crate::str::FromStr #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_or_default(self) -> T { + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn unwrap_or_default(self) -> T + where + T: ~const Default, + { match self { Some(x) => x, None => Default::default(), @@ -1615,8 +1741,15 @@ impl<T: Deref> Option<T> { /// assert_eq!(x.as_deref(), None); /// ``` #[stable(feature = "option_deref", since = "1.40.0")] - pub fn as_deref(&self) -> Option<&T::Target> { - self.as_ref().map(|t| t.deref()) + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn as_deref(&self) -> Option<&T::Target> + where + T: ~const Deref, + { + match self.as_ref() { + Some(t) => Some(t.deref()), + None => None, + } } } @@ -1636,8 +1769,15 @@ impl<T: DerefMut> Option<T> { /// }), Some("HEY".to_owned().as_mut_str())); /// ``` #[stable(feature = "option_deref", since = "1.40.0")] - pub fn as_deref_mut(&mut self) -> Option<&mut T::Target> { - self.as_mut().map(|t| t.deref_mut()) + #[rustc_const_unstable(feature = "const_option_ext", issue = "none")] + pub const fn as_deref_mut(&mut self) -> Option<&mut T::Target> + where + T: ~const DerefMut, + { + match self.as_mut() { + Some(t) => Some(t.deref_mut()), + None => None, + } } } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index dacb33619f8..21562acf3d7 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -70,8 +70,10 @@ #![feature(portable_simd)] #![feature(ptr_metadata)] #![feature(once_cell)] +#![feature(option_result_contains)] #![feature(unsized_tuple_coercion)] #![feature(const_option)] +#![feature(const_option_ext)] #![feature(const_result)] #![feature(integer_atomics)] #![feature(int_roundings)] diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index cd07d6c52c2..da692461261 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -86,17 +86,49 @@ fn test_and() { let x: Option<isize> = None; assert_eq!(x.and(Some(2)), None); assert_eq!(x.and(None::<isize>), None); + + const FOO: Option<isize> = Some(1); + const A: Option<isize> = FOO.and(Some(2)); + const B: Option<isize> = FOO.and(None); + assert_eq!(A, Some(2)); + assert_eq!(B, None); + + const BAR: Option<isize> = None; + const C: Option<isize> = BAR.and(Some(2)); + const D: Option<isize> = BAR.and(None); + assert_eq!(C, None); + assert_eq!(D, None); } #[test] fn test_and_then() { + const fn plus_one(x: isize) -> Option<isize> { + Some(x + 1) + } + + const fn none(_: isize) -> Option<isize> { + None + } + let x: Option<isize> = Some(1); - assert_eq!(x.and_then(|x| Some(x + 1)), Some(2)); - assert_eq!(x.and_then(|_| None::<isize>), None); + assert_eq!(x.and_then(plus_one), Some(2)); + assert_eq!(x.and_then(none), None); let x: Option<isize> = None; - assert_eq!(x.and_then(|x| Some(x + 1)), None); - assert_eq!(x.and_then(|_| None::<isize>), None); + assert_eq!(x.and_then(plus_one), None); + assert_eq!(x.and_then(none), None); + + const FOO: Option<isize> = Some(1); + const A: Option<isize> = FOO.and_then(plus_one); + const B: Option<isize> = FOO.and_then(none); + assert_eq!(A, Some(2)); + assert_eq!(B, None); + + const BAR: Option<isize> = None; + const C: Option<isize> = BAR.and_then(plus_one); + const D: Option<isize> = BAR.and_then(none); + assert_eq!(C, None); + assert_eq!(D, None); } #[test] @@ -108,17 +140,49 @@ fn test_or() { let x: Option<isize> = None; assert_eq!(x.or(Some(2)), Some(2)); assert_eq!(x.or(None), None); + + const FOO: Option<isize> = Some(1); + const A: Option<isize> = FOO.or(Some(2)); + const B: Option<isize> = FOO.or(None); + assert_eq!(A, Some(1)); + assert_eq!(B, Some(1)); + + const BAR: Option<isize> = None; + const C: Option<isize> = BAR.or(Some(2)); + const D: Option<isize> = BAR.or(None); + assert_eq!(C, Some(2)); + assert_eq!(D, None); } #[test] fn test_or_else() { + const fn two() -> Option<isize> { + Some(2) + } + + const fn none() -> Option<isize> { + None + } + let x: Option<isize> = Some(1); - assert_eq!(x.or_else(|| Some(2)), Some(1)); - assert_eq!(x.or_else(|| None), Some(1)); + assert_eq!(x.or_else(two), Some(1)); + assert_eq!(x.or_else(none), Some(1)); let x: Option<isize> = None; - assert_eq!(x.or_else(|| Some(2)), Some(2)); - assert_eq!(x.or_else(|| None), None); + assert_eq!(x.or_else(two), Some(2)); + assert_eq!(x.or_else(none), None); + + const FOO: Option<isize> = Some(1); + const A: Option<isize> = FOO.or_else(two); + const B: Option<isize> = FOO.or_else(none); + assert_eq!(A, Some(1)); + assert_eq!(B, Some(1)); + + const BAR: Option<isize> = None; + const C: Option<isize> = BAR.or_else(two); + const D: Option<isize> = BAR.or_else(none); + assert_eq!(C, Some(2)); + assert_eq!(D, None); } #[test] @@ -149,15 +213,29 @@ fn test_unwrap_or() { let x: Option<isize> = None; assert_eq!(x.unwrap_or(2), 2); + + const A: isize = Some(1).unwrap_or(2); + const B: isize = None.unwrap_or(2); + assert_eq!(A, 1); + assert_eq!(B, 2); } #[test] fn test_unwrap_or_else() { + const fn two() -> isize { + 2 + } + let x: Option<isize> = Some(1); - assert_eq!(x.unwrap_or_else(|| 2), 1); + assert_eq!(x.unwrap_or_else(two), 1); let x: Option<isize> = None; - assert_eq!(x.unwrap_or_else(|| 2), 2); + assert_eq!(x.unwrap_or_else(two), 2); + + const A: isize = Some(1).unwrap_or_else(two); + const B: isize = None.unwrap_or_else(two); + assert_eq!(A, 1); + assert_eq!(B, 2); } #[test] |
