diff options
Diffstat (limited to 'src/libcore')
35 files changed, 2839 insertions, 873 deletions
diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 3d24f8902bd..87144c27c9e 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -59,7 +59,7 @@ unsafe impl<T, A: Unsize<[T]>> FixedSizeArray<T> for A { } /// The error type returned when a conversion from a slice to an array fails. -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] #[derive(Debug, Copy, Clone)] pub struct TryFromSliceError(()); @@ -148,7 +148,7 @@ macro_rules! array_impls { } } - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl<'a, T> TryFrom<&'a [T]> for &'a [T; $N] { type Error = TryFromSliceError; @@ -162,7 +162,7 @@ macro_rules! array_impls { } } - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl<'a, T> TryFrom<&'a mut [T]> for &'a mut [T; $N] { type Error = TryFromSliceError; diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 36618e86968..c8ee166fee3 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -146,13 +146,12 @@ //! //! ``` //! #![feature(core_intrinsics)] -//! #![feature(shared)] //! use std::cell::Cell; -//! use std::ptr::Shared; +//! use std::ptr::NonNull; //! use std::intrinsics::abort; //! //! struct Rc<T: ?Sized> { -//! ptr: Shared<RcBox<T>> +//! ptr: NonNull<RcBox<T>> //! } //! //! struct RcBox<T: ?Sized> { diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 1638f9710f5..718c6b893ed 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -265,7 +265,7 @@ impl FromStr for char { } -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl TryFrom<u32> for char { type Error = CharTryFromError; @@ -280,11 +280,11 @@ impl TryFrom<u32> for char { } /// The error type returned when a conversion from u32 to char fails. -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct CharTryFromError(()); -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl fmt::Display for CharTryFromError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { "converted integer out of range for `char`".fmt(f) @@ -902,6 +902,16 @@ impl<I: Iterator<Item = u8>> Iterator for DecodeUtf8<I> { } }) } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let (lower, upper) = self.0.size_hint(); + + // A code point is at most 4 bytes long. + let min_code_points = lower / 4; + + (min_code_points, upper) + } } #[unstable(feature = "decode_utf8", issue = "33906")] diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 826420a0c00..58a8439162c 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -87,6 +87,23 @@ /// fn clone(&self) -> Stats { *self } /// } /// ``` +/// +/// ## Additional implementors +/// +/// In addition to the [implementors listed below][impls], +/// the following types also implement `Clone`: +/// +/// * Function item types (i.e. the distinct types defined for each function) +/// * Function pointer types (e.g. `fn() -> i32`) +/// * Array types, for all sizes, if the item type also implements `Clone` (e.g. `[i32; 123456]`) +/// * Tuple types, if each component also implements `Clone` (e.g. `()`, `(i32, bool)`) +/// * Closure types, if they capture no value from the environment +/// or if all such captured values implement `Clone` themselves. +/// Note that variables captured by shared reference always implement `Clone` +/// (even if the referent doesn't), +/// while variables captured by mutable reference never implement `Clone`. +/// +/// [impls]: #implementors #[stable(feature = "rust1", since = "1.0.0")] #[lang = "clone"] pub trait Clone : Sized { @@ -100,6 +117,7 @@ pub trait Clone : Sized { /// assert_eq!("Hello", hello.clone()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "cloning is often expensive and is not expected to have side effects"] fn clone(&self) -> Self; /// Performs copy-assignment from `source`. @@ -130,3 +148,68 @@ pub struct AssertParamIsClone<T: Clone + ?Sized> { _field: ::marker::PhantomData reason = "deriving hack, should not be public", issue = "0")] pub struct AssertParamIsCopy<T: Copy + ?Sized> { _field: ::marker::PhantomData<T> } + +/// Implementations of `Clone` for primitive types. +/// +/// Implementations that cannot be described in Rust +/// are implemented in `SelectionContext::copy_clone_conditions()` in librustc. +#[cfg(not(stage0))] +mod impls { + + use super::Clone; + + macro_rules! impl_clone { + ($($t:ty)*) => { + $( + #[stable(feature = "rust1", since = "1.0.0")] + impl Clone for $t { + #[inline] + fn clone(&self) -> Self { + *self + } + } + )* + } + } + + impl_clone! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 + f32 f64 + bool char + } + + #[stable(feature = "never_type", since = "1.26.0")] + impl Clone for ! { + #[inline] + fn clone(&self) -> Self { + *self + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<T: ?Sized> Clone for *const T { + #[inline] + fn clone(&self) -> Self { + *self + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<T: ?Sized> Clone for *mut T { + #[inline] + fn clone(&self) -> Self { + *self + } + } + + // Shared references can be cloned, but mutable references *cannot*! + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, T: ?Sized> Clone for &'a T { + #[inline] + fn clone(&self) -> Self { + *self + } + } + +} diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index d3a83dc795c..63721395784 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -48,25 +48,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use fmt; - -/// A type used as the error type for implementations of fallible conversion -/// traits in cases where conversions cannot actually fail. -/// -/// Because `Infallible` has no variants, a value of this type can never exist. -/// It is used only to satisfy trait signatures that expect an error type, and -/// signals to both the compiler and the user that the error case is impossible. -#[unstable(feature = "try_from", issue = "33417")] -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum Infallible {} - -#[unstable(feature = "try_from", issue = "33417")] -impl fmt::Display for Infallible { - fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { - match *self { - } - } -} /// A cheap reference-to-reference conversion. Used to convert a value to a /// reference value within generic code. /// @@ -341,22 +322,26 @@ pub trait From<T>: Sized { /// /// [`TryFrom`]: trait.TryFrom.html /// [`Into`]: trait.Into.html -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] pub trait TryInto<T>: Sized { /// The type returned in the event of a conversion error. + #[stable(feature = "try_from", since = "1.26.0")] type Error; /// Performs the conversion. + #[stable(feature = "try_from", since = "1.26.0")] fn try_into(self) -> Result<T, Self::Error>; } /// Attempt to construct `Self` via a conversion. -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] pub trait TryFrom<T>: Sized { /// The type returned in the event of a conversion error. + #[stable(feature = "try_from", since = "1.26.0")] type Error; /// Performs the conversion. + #[stable(feature = "try_from", since = "1.26.0")] fn try_from(value: T) -> Result<Self, Self::Error>; } @@ -382,7 +367,7 @@ impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> } } -// FIXME (#23442): replace the above impls for &/&mut with the following more general one: +// FIXME (#45742): replace the above impls for &/&mut with the following more general one: // // As lifts over Deref // impl<D: ?Sized + Deref, U: ?Sized> AsRef<U> for D where D::Target: AsRef<U> { // fn as_ref(&self) -> &U { @@ -399,7 +384,7 @@ impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> } } -// FIXME (#23442): replace the above impl for &mut with the following more general one: +// FIXME (#45742): replace the above impl for &mut with the following more general one: // // AsMut lifts over DerefMut // impl<D: ?Sized + Deref, U: ?Sized> AsMut<U> for D where D::Target: AsMut<U> { // fn as_mut(&mut self) -> &mut U { @@ -424,7 +409,7 @@ impl<T> From<T> for T { // TryFrom implies TryInto -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl<T, U> TryInto<U> for T where U: TryFrom<T> { type Error = U::Error; @@ -436,9 +421,9 @@ impl<T, U> TryInto<U> for T where U: TryFrom<T> // Infallible conversions are semantically equivalent to fallible conversions // with an uninhabited error type. -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl<T, U> TryFrom<U> for T where T: From<U> { - type Error = Infallible; + type Error = !; fn try_from(value: U) -> Result<Self, Self::Error> { Ok(T::from(value)) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 3ecd73873c0..d55219d7226 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -401,10 +401,21 @@ impl<'a> Arguments<'a> { /// safely be done, so no constructors are given and the fields are private /// to prevent modification. /// -/// The [`format_args!`] macro will safely create an instance of this structure -/// and pass it to a function or closure, passed as the first argument. The -/// macro validates the format string at compile-time so usage of the [`write`] -/// and [`format`] functions can be safely performed. +/// The [`format_args!`] macro will safely create an instance of this structure. +/// The macro validates the format string at compile-time so usage of the +/// [`write`] and [`format`] functions can be safely performed. +/// +/// You can use the `Arguments<'a>` that [`format_args!`] returns in `Debug` +/// and `Display` contexts as seen below. The example also shows that `Debug` +/// and `Display` format to the same thing: the interpolated format string +/// in `format_args!`. +/// +/// ```rust +/// let debug = format!("{:?}", format_args!("{} foo {:?}", 1, 2)); +/// let display = format!("{}", format_args!("{} foo {:?}", 1, 2)); +/// assert_eq!("1 foo 2", display); +/// assert_eq!(display, debug); +/// ``` /// /// [`format_args!`]: ../../std/macro.format_args.html /// [`format`]: ../../std/fmt/fn.format.html @@ -1553,10 +1564,12 @@ impl<'a> Formatter<'a> { /// /// ```rust /// use std::fmt; + /// use std::net::Ipv4Addr; /// /// struct Foo { /// bar: i32, /// baz: String, + /// addr: Ipv4Addr, /// } /// /// impl fmt::Debug for Foo { @@ -1564,12 +1577,19 @@ impl<'a> Formatter<'a> { /// fmt.debug_struct("Foo") /// .field("bar", &self.bar) /// .field("baz", &self.baz) + /// .field("addr", &format_args!("{}", self.addr)) /// .finish() /// } /// } /// - /// // prints "Foo { bar: 10, baz: "Hello World" }" - /// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() }); + /// assert_eq!( + /// "Foo { bar: 10, baz: \"Hello World\", addr: 127.0.0.1 }", + /// format!("{:?}", Foo { + /// bar: 10, + /// baz: "Hello World".to_string(), + /// addr: Ipv4Addr::new(127, 0, 0, 1), + /// }) + /// ); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn debug_struct<'b>(&'b mut self, name: &str) -> DebugStruct<'b, 'a> { @@ -1583,20 +1603,24 @@ impl<'a> Formatter<'a> { /// /// ```rust /// use std::fmt; + /// use std::marker::PhantomData; /// - /// struct Foo(i32, String); + /// struct Foo<T>(i32, String, PhantomData<T>); /// - /// impl fmt::Debug for Foo { + /// impl<T> fmt::Debug for Foo<T> { /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { /// fmt.debug_tuple("Foo") /// .field(&self.0) /// .field(&self.1) + /// .field(&format_args!("_")) /// .finish() /// } /// } /// - /// // prints "Foo(10, "Hello World")" - /// println!("{:?}", Foo(10, "Hello World".to_string())); + /// assert_eq!( + /// "Foo(10, \"Hello\", _)", + /// format!("{:?}", Foo(10, "Hello".to_string(), PhantomData::<u8>)) + /// ); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn debug_tuple<'b>(&'b mut self, name: &str) -> DebugTuple<'b, 'a> { @@ -1646,6 +1670,41 @@ impl<'a> Formatter<'a> { /// // prints "{10, 11}" /// println!("{:?}", Foo(vec![10, 11])); /// ``` + /// + /// [`format_args!`]: ../../std/macro.format_args.html + /// + /// In this more complex example, we use [`format_args!`] and `.debug_set()` + /// to build a list of match arms: + /// + /// ```rust + /// use std::fmt; + /// + /// struct Arm<'a, L: 'a, R: 'a>(&'a (L, R)); + /// struct Table<'a, K: 'a, V: 'a>(&'a [(K, V)], V); + /// + /// impl<'a, L, R> fmt::Debug for Arm<'a, L, R> + /// where + /// L: 'a + fmt::Debug, R: 'a + fmt::Debug + /// { + /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + /// L::fmt(&(self.0).0, fmt)?; + /// fmt.write_str(" => ")?; + /// R::fmt(&(self.0).1, fmt) + /// } + /// } + /// + /// impl<'a, K, V> fmt::Debug for Table<'a, K, V> + /// where + /// K: 'a + fmt::Debug, V: 'a + fmt::Debug + /// { + /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + /// fmt.debug_set() + /// .entries(self.0.iter().map(Arm)) + /// .entry(&Arm(&(format_args!("_"), &self.1))) + /// .finish() + /// } + /// } + /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn debug_set<'b>(&'b mut self) -> DebugSet<'b, 'a> { builders::debug_set_new(self) diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index fcf06ea319d..4451ab445cc 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -63,7 +63,7 @@ trait GenericRadix { // characters for a base 2 number. let zero = T::zero(); let is_nonnegative = x >= zero; - let mut buf = [0; 128]; + let mut buf: [u8; 128] = unsafe { mem::uninitialized() }; let mut curr = buf.len(); let base = T::from_u8(Self::BASE); if is_nonnegative { @@ -105,10 +105,6 @@ struct Binary; #[derive(Clone, PartialEq)] struct Octal; -/// A decimal (base 10) radix -#[derive(Clone, PartialEq)] -struct Decimal; - /// A hexadecimal (base 16) radix, formatted with lower-case characters #[derive(Clone, PartialEq)] struct LowerHex; @@ -134,7 +130,6 @@ macro_rules! radix { radix! { Binary, 2, "0b", x @ 0 ... 1 => b'0' + x } radix! { Octal, 8, "0o", x @ 0 ... 7 => b'0' + x } -radix! { Decimal, 10, "", x @ 0 ... 9 => b'0' + x } radix! { LowerHex, 16, "0x", x @ 0 ... 9 => b'0' + x, x @ 10 ... 15 => b'a' + (x - 10) } radix! { UpperHex, 16, "0x", x @ 0 ... 9 => b'0' + x, diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index ab714645675..3e1f21cafe4 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -308,7 +308,7 @@ pub trait Hasher { } /// Writes a single `u128` into this hasher. #[inline] - #[unstable(feature = "i128", issue = "35118")] + #[stable(feature = "i128", since = "1.26.0")] fn write_u128(&mut self, i: u128) { self.write(&unsafe { mem::transmute::<_, [u8; 16]>(i) }) } @@ -348,7 +348,7 @@ pub trait Hasher { } /// Writes a single `i128` into this hasher. #[inline] - #[unstable(feature = "i128", issue = "35118")] + #[stable(feature = "i128", since = "1.26.0")] fn write_i128(&mut self, i: i128) { self.write_u128(i as u128) } diff --git a/src/libcore/heap.rs b/src/libcore/heap.rs new file mode 100644 index 00000000000..fe19c923a58 --- /dev/null +++ b/src/libcore/heap.rs @@ -0,0 +1,1075 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "allocator_api", + reason = "the precise API and guarantees it provides may be tweaked \ + slightly, especially to possibly take into account the \ + types being stored to make room for a future \ + tracing garbage collector", + issue = "32838")] + +use cmp; +use fmt; +use mem; +use usize; +use ptr::{self, NonNull}; + +/// Represents the combination of a starting address and +/// a total capacity of the returned block. +#[derive(Debug)] +pub struct Excess(pub *mut u8, pub usize); + +fn size_align<T>() -> (usize, usize) { + (mem::size_of::<T>(), mem::align_of::<T>()) +} + +/// Layout of a block of memory. +/// +/// An instance of `Layout` describes a particular layout of memory. +/// You build a `Layout` up as an input to give to an allocator. +/// +/// All layouts have an associated non-negative size and a +/// power-of-two alignment. +/// +/// (Note however that layouts are *not* required to have positive +/// size, even though many allocators require that all memory +/// requests have positive size. A caller to the `Alloc::alloc` +/// method must either ensure that conditions like this are met, or +/// use specific allocators with looser requirements.) +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Layout { + // size of the requested block of memory, measured in bytes. + size: usize, + + // alignment of the requested block of memory, measured in bytes. + // we ensure that this is always a power-of-two, because API's + // like `posix_memalign` require it and it is a reasonable + // constraint to impose on Layout constructors. + // + // (However, we do not analogously require `align >= sizeof(void*)`, + // even though that is *also* a requirement of `posix_memalign`.) + align: usize, +} + + +// FIXME: audit default implementations for overflow errors, +// (potentially switching to overflowing_add and +// overflowing_mul as necessary). + +impl Layout { + /// Constructs a `Layout` from a given `size` and `align`, + /// or returns `None` if either of the following conditions + /// are not met: + /// + /// * `align` must be a power of two, + /// + /// * `size`, when rounded up to the nearest multiple of `align`, + /// must not overflow (i.e. the rounded value must be less than + /// `usize::MAX`). + #[inline] + pub fn from_size_align(size: usize, align: usize) -> Option<Layout> { + if !align.is_power_of_two() { + return None; + } + + // (power-of-two implies align != 0.) + + // Rounded up size is: + // size_rounded_up = (size + align - 1) & !(align - 1); + // + // We know from above that align != 0. If adding (align - 1) + // does not overflow, then rounding up will be fine. + // + // Conversely, &-masking with !(align - 1) will subtract off + // only low-order-bits. Thus if overflow occurs with the sum, + // the &-mask cannot subtract enough to undo that overflow. + // + // Above implies that checking for summation overflow is both + // necessary and sufficient. + if size > usize::MAX - (align - 1) { + return None; + } + + unsafe { + Some(Layout::from_size_align_unchecked(size, align)) + } + } + + /// Creates a layout, bypassing all checks. + /// + /// # Safety + /// + /// This function is unsafe as it does not verify that `align` is + /// a power-of-two nor `size` aligned to `align` fits within the + /// address space (i.e. the `Layout::from_size_align` preconditions). + #[inline] + pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout { + Layout { size: size, align: align } + } + + /// The minimum size in bytes for a memory block of this layout. + #[inline] + pub fn size(&self) -> usize { self.size } + + /// The minimum byte alignment for a memory block of this layout. + #[inline] + pub fn align(&self) -> usize { self.align } + + /// Constructs a `Layout` suitable for holding a value of type `T`. + pub fn new<T>() -> Self { + let (size, align) = size_align::<T>(); + Layout::from_size_align(size, align).unwrap() + } + + /// Produces layout describing a record that could be used to + /// allocate backing structure for `T` (which could be a trait + /// or other unsized type like a slice). + pub fn for_value<T: ?Sized>(t: &T) -> Self { + let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); + Layout::from_size_align(size, align).unwrap() + } + + /// Creates a layout describing the record that can hold a value + /// of the same layout as `self`, but that also is aligned to + /// alignment `align` (measured in bytes). + /// + /// If `self` already meets the prescribed alignment, then returns + /// `self`. + /// + /// Note that this method does not add any padding to the overall + /// size, regardless of whether the returned layout has a different + /// alignment. In other words, if `K` has size 16, `K.align_to(32)` + /// will *still* have size 16. + /// + /// # Panics + /// + /// Panics if the combination of `self.size` and the given `align` + /// violates the conditions listed in `from_size_align`. + #[inline] + pub fn align_to(&self, align: usize) -> Self { + Layout::from_size_align(self.size, cmp::max(self.align, align)).unwrap() + } + + /// Returns the amount of padding we must insert after `self` + /// to ensure that the following address will satisfy `align` + /// (measured in bytes). + /// + /// E.g. if `self.size` is 9, then `self.padding_needed_for(4)` + /// returns 3, because that is the minimum number of bytes of + /// padding required to get a 4-aligned address (assuming that the + /// corresponding memory block starts at a 4-aligned address). + /// + /// The return value of this function has no meaning if `align` is + /// not a power-of-two. + /// + /// Note that the utility of the returned value requires `align` + /// to be less than or equal to the alignment of the starting + /// address for the whole allocated block of memory. One way to + /// satisfy this constraint is to ensure `align <= self.align`. + #[inline] + pub fn padding_needed_for(&self, align: usize) -> usize { + let len = self.size(); + + // Rounded up value is: + // len_rounded_up = (len + align - 1) & !(align - 1); + // and then we return the padding difference: `len_rounded_up - len`. + // + // We use modular arithmetic throughout: + // + // 1. align is guaranteed to be > 0, so align - 1 is always + // valid. + // + // 2. `len + align - 1` can overflow by at most `align - 1`, + // so the &-mask wth `!(align - 1)` will ensure that in the + // case of overflow, `len_rounded_up` will itself be 0. + // Thus the returned padding, when added to `len`, yields 0, + // which trivially satisfies the alignment `align`. + // + // (Of course, attempts to allocate blocks of memory whose + // size and padding overflow in the above manner should cause + // the allocator to yield an error anyway.) + + let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); + return len_rounded_up.wrapping_sub(len); + } + + /// Creates a layout describing the record for `n` instances of + /// `self`, with a suitable amount of padding between each to + /// ensure that each instance is given its requested size and + /// alignment. On success, returns `(k, offs)` where `k` is the + /// layout of the array and `offs` is the distance between the start + /// of each element in the array. + /// + /// On arithmetic overflow, returns `None`. + #[inline] + pub fn repeat(&self, n: usize) -> Option<(Self, usize)> { + let padded_size = self.size.checked_add(self.padding_needed_for(self.align))?; + let alloc_size = padded_size.checked_mul(n)?; + + // We can assume that `self.align` is a power-of-two. + // Furthermore, `alloc_size` has already been rounded up + // to a multiple of `self.align`; therefore, the call to + // `Layout::from_size_align` below should never panic. + Some((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) + } + + /// Creates a layout describing the record for `self` followed by + /// `next`, including any necessary padding to ensure that `next` + /// will be properly aligned. Note that the result layout will + /// satisfy the alignment properties of both `self` and `next`. + /// + /// Returns `Some((k, offset))`, where `k` is layout of the concatenated + /// record and `offset` is the relative location, in bytes, of the + /// start of the `next` embedded within the concatenated record + /// (assuming that the record itself starts at offset 0). + /// + /// On arithmetic overflow, returns `None`. + pub fn extend(&self, next: Self) -> Option<(Self, usize)> { + let new_align = cmp::max(self.align, next.align); + let realigned = Layout::from_size_align(self.size, new_align)?; + + let pad = realigned.padding_needed_for(next.align); + + let offset = self.size.checked_add(pad)?; + let new_size = offset.checked_add(next.size)?; + + let layout = Layout::from_size_align(new_size, new_align)?; + Some((layout, offset)) + } + + /// Creates a layout describing the record for `n` instances of + /// `self`, with no padding between each instance. + /// + /// Note that, unlike `repeat`, `repeat_packed` does not guarantee + /// that the repeated instances of `self` will be properly + /// aligned, even if a given instance of `self` is properly + /// aligned. In other words, if the layout returned by + /// `repeat_packed` is used to allocate an array, it is not + /// guaranteed that all elements in the array will be properly + /// aligned. + /// + /// On arithmetic overflow, returns `None`. + pub fn repeat_packed(&self, n: usize) -> Option<Self> { + let size = self.size().checked_mul(n)?; + Layout::from_size_align(size, self.align) + } + + /// Creates a layout describing the record for `self` followed by + /// `next` with no additional padding between the two. Since no + /// padding is inserted, the alignment of `next` is irrelevant, + /// and is not incorporated *at all* into the resulting layout. + /// + /// Returns `(k, offset)`, where `k` is layout of the concatenated + /// record and `offset` is the relative location, in bytes, of the + /// start of the `next` embedded within the concatenated record + /// (assuming that the record itself starts at offset 0). + /// + /// (The `offset` is always the same as `self.size()`; we use this + /// signature out of convenience in matching the signature of + /// `extend`.) + /// + /// On arithmetic overflow, returns `None`. + pub fn extend_packed(&self, next: Self) -> Option<(Self, usize)> { + let new_size = self.size().checked_add(next.size())?; + let layout = Layout::from_size_align(new_size, self.align)?; + Some((layout, self.size())) + } + + /// Creates a layout describing the record for a `[T; n]`. + /// + /// On arithmetic overflow, returns `None`. + pub fn array<T>(n: usize) -> Option<Self> { + Layout::new::<T>() + .repeat(n) + .map(|(k, offs)| { + debug_assert!(offs == mem::size_of::<T>()); + k + }) + } +} + +/// The `AllocErr` error specifies whether an allocation failure is +/// specifically due to resource exhaustion or if it is due to +/// something wrong when combining the given input arguments with this +/// allocator. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum AllocErr { + /// Error due to hitting some resource limit or otherwise running + /// out of memory. This condition strongly implies that *some* + /// series of deallocations would allow a subsequent reissuing of + /// the original allocation request to succeed. + Exhausted { request: Layout }, + + /// Error due to allocator being fundamentally incapable of + /// satisfying the original request. This condition implies that + /// such an allocation request will never succeed on the given + /// allocator, regardless of environment, memory pressure, or + /// other contextual conditions. + /// + /// For example, an allocator that does not support requests for + /// large memory blocks might return this error variant. + Unsupported { details: &'static str }, +} + +impl AllocErr { + #[inline] + pub fn invalid_input(details: &'static str) -> Self { + AllocErr::Unsupported { details: details } + } + #[inline] + pub fn is_memory_exhausted(&self) -> bool { + if let AllocErr::Exhausted { .. } = *self { true } else { false } + } + #[inline] + pub fn is_request_unsupported(&self) -> bool { + if let AllocErr::Unsupported { .. } = *self { true } else { false } + } + #[inline] + pub fn description(&self) -> &str { + match *self { + AllocErr::Exhausted { .. } => "allocator memory exhausted", + AllocErr::Unsupported { .. } => "unsupported allocator request", + } + } +} + +// (we need this for downstream impl of trait Error) +impl fmt::Display for AllocErr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +/// The `CannotReallocInPlace` error is used when `grow_in_place` or +/// `shrink_in_place` were unable to reuse the given memory block for +/// a requested layout. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct CannotReallocInPlace; + +impl CannotReallocInPlace { + pub fn description(&self) -> &str { + "cannot reallocate allocator's memory in place" + } +} + +// (we need this for downstream impl of trait Error) +impl fmt::Display for CannotReallocInPlace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +/// Augments `AllocErr` with a CapacityOverflow variant. +#[derive(Clone, PartialEq, Eq, Debug)] +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +pub enum CollectionAllocErr { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + /// Error due to the allocator (see the `AllocErr` type's docs). + AllocErr(AllocErr), +} + +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +impl From<AllocErr> for CollectionAllocErr { + fn from(err: AllocErr) -> Self { + CollectionAllocErr::AllocErr(err) + } +} + +/// An implementation of `Alloc` can allocate, reallocate, and +/// deallocate arbitrary blocks of data described via `Layout`. +/// +/// Some of the methods require that a memory block be *currently +/// allocated* via an allocator. This means that: +/// +/// * the starting address for that memory block was previously +/// returned by a previous call to an allocation method (`alloc`, +/// `alloc_zeroed`, `alloc_excess`, `alloc_one`, `alloc_array`) or +/// reallocation method (`realloc`, `realloc_excess`, or +/// `realloc_array`), and +/// +/// * the memory block has not been subsequently deallocated, where +/// blocks are deallocated either by being passed to a deallocation +/// method (`dealloc`, `dealloc_one`, `dealloc_array`) or by being +/// passed to a reallocation method (see above) that returns `Ok`. +/// +/// A note regarding zero-sized types and zero-sized layouts: many +/// methods in the `Alloc` trait state that allocation requests +/// must be non-zero size, or else undefined behavior can result. +/// +/// * However, some higher-level allocation methods (`alloc_one`, +/// `alloc_array`) are well-defined on zero-sized types and can +/// optionally support them: it is left up to the implementor +/// whether to return `Err`, or to return `Ok` with some pointer. +/// +/// * If an `Alloc` implementation chooses to return `Ok` in this +/// case (i.e. the pointer denotes a zero-sized inaccessible block) +/// then that returned pointer must be considered "currently +/// allocated". On such an allocator, *all* methods that take +/// currently-allocated pointers as inputs must accept these +/// zero-sized pointers, *without* causing undefined behavior. +/// +/// * In other words, if a zero-sized pointer can flow out of an +/// allocator, then that allocator must likewise accept that pointer +/// flowing back into its deallocation and reallocation methods. +/// +/// Some of the methods require that a layout *fit* a memory block. +/// What it means for a layout to "fit" a memory block means (or +/// equivalently, for a memory block to "fit" a layout) is that the +/// following two conditions must hold: +/// +/// 1. The block's starting address must be aligned to `layout.align()`. +/// +/// 2. The block's size must fall in the range `[use_min, use_max]`, where: +/// +/// * `use_min` is `self.usable_size(layout).0`, and +/// +/// * `use_max` is the capacity that was (or would have been) +/// returned when (if) the block was allocated via a call to +/// `alloc_excess` or `realloc_excess`. +/// +/// Note that: +/// +/// * the size of the layout most recently used to allocate the block +/// is guaranteed to be in the range `[use_min, use_max]`, and +/// +/// * a lower-bound on `use_max` can be safely approximated by a call to +/// `usable_size`. +/// +/// * if a layout `k` fits a memory block (denoted by `ptr`) +/// currently allocated via an allocator `a`, then it is legal to +/// use that layout to deallocate it, i.e. `a.dealloc(ptr, k);`. +/// +/// # Unsafety +/// +/// The `Alloc` trait is an `unsafe` trait for a number of reasons, and +/// implementors must ensure that they adhere to these contracts: +/// +/// * Pointers returned from allocation functions must point to valid memory and +/// retain their validity until at least the instance of `Alloc` is dropped +/// itself. +/// +/// * It's undefined behavior if global allocators unwind. This restriction may +/// be lifted in the future, but currently a panic from any of these +/// functions may lead to memory unsafety. Note that as of the time of this +/// writing allocators *not* intending to be global allocators can still panic +/// in their implementation without violating memory safety. +/// +/// * `Layout` queries and calculations in general must be correct. Callers of +/// this trait are allowed to rely on the contracts defined on each method, +/// and implementors must ensure such contracts remain true. +/// +/// Note that this list may get tweaked over time as clarifications are made in +/// the future. Additionally global allocators may gain unique requirements for +/// how to safely implement one in the future as well. +pub unsafe trait Alloc { + + // (Note: existing allocators have unspecified but well-defined + // behavior in response to a zero size allocation request ; + // e.g. in C, `malloc` of 0 will either return a null pointer or a + // unique pointer, but will not have arbitrary undefined + // behavior. Rust should consider revising the alloc::heap crate + // to reflect this reality.) + + /// Returns a pointer meeting the size and alignment guarantees of + /// `layout`. + /// + /// If this method returns an `Ok(addr)`, then the `addr` returned + /// will be non-null address pointing to a block of storage + /// suitable for holding an instance of `layout`. + /// + /// The returned block of storage may or may not have its contents + /// initialized. (Extension subtraits might restrict this + /// behavior, e.g. to ensure initialization to particular sets of + /// bit patterns.) + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure that `layout` has non-zero size. + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints. + /// + /// Implementations are encouraged to return `Err` on memory + /// exhaustion rather than panicking or aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; + + /// Deallocate the memory referenced by `ptr`. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must denote a block of memory currently allocated via + /// this allocator, + /// + /// * `layout` must *fit* that block of memory, + /// + /// * In addition to fitting the block of memory `layout`, the + /// alignment of the `layout` must match the alignment used + /// to allocate that block of memory. + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); + + /// Allocator-specific method for signaling an out-of-memory + /// condition. + /// + /// `oom` aborts the thread or process, optionally performing + /// cleanup or logging diagnostic information before panicking or + /// aborting. + /// + /// `oom` is meant to be used by clients unable to cope with an + /// unsatisfied allocation request (signaled by an error such as + /// `AllocErr::Exhausted`), and wish to abandon computation rather + /// than attempt to recover locally. Such clients should pass the + /// signaling error value back into `oom`, where the allocator + /// may incorporate that error value into its diagnostic report + /// before aborting. + /// + /// Implementations of the `oom` method are discouraged from + /// infinitely regressing in nested calls to `oom`. In + /// practice this means implementors should eschew allocating, + /// especially from `self` (directly or indirectly). + /// + /// Implementations of the allocation and reallocation methods + /// (e.g. `alloc`, `alloc_one`, `realloc`) are discouraged from + /// panicking (or aborting) in the event of memory exhaustion; + /// instead they should return an appropriate error from the + /// invoked method, and let the client decide whether to invoke + /// this `oom` method in response. + fn oom(&mut self, _: AllocErr) -> ! { + unsafe { ::intrinsics::abort() } + } + + // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS == + // usable_size + + /// Returns bounds on the guaranteed usable size of a successful + /// allocation created with the specified `layout`. + /// + /// In particular, if one has a memory block allocated via a given + /// allocator `a` and layout `k` where `a.usable_size(k)` returns + /// `(l, u)`, then one can pass that block to `a.dealloc()` with a + /// layout in the size range [l, u]. + /// + /// (All implementors of `usable_size` must ensure that + /// `l <= k.size() <= u`) + /// + /// Both the lower- and upper-bounds (`l` and `u` respectively) + /// are provided, because an allocator based on size classes could + /// misbehave if one attempts to deallocate a block without + /// providing a correct value for its size (i.e., one within the + /// range `[l, u]`). + /// + /// Clients who wish to make use of excess capacity are encouraged + /// to use the `alloc_excess` and `realloc_excess` instead, as + /// this method is constrained to report conservative values that + /// serve as valid bounds for *all possible* allocation method + /// calls. + /// + /// However, for clients that do not wish to track the capacity + /// returned by `alloc_excess` locally, this method is likely to + /// produce useful results. + #[inline] + fn usable_size(&self, layout: &Layout) -> (usize, usize) { + (layout.size(), layout.size()) + } + + // == METHODS FOR MEMORY REUSE == + // realloc. alloc_excess, realloc_excess + + /// Returns a pointer suitable for holding data described by + /// `new_layout`, meeting its size and alignment guarantees. To + /// accomplish this, this may extend or shrink the allocation + /// referenced by `ptr` to fit `new_layout`. + /// + /// If this returns `Ok`, then ownership of the memory block + /// referenced by `ptr` has been transferred to this + /// allocator. The memory may or may not have been freed, and + /// should be considered unusable (unless of course it was + /// transferred back to the caller again via the return value of + /// this method). + /// + /// If this method returns `Err`, then ownership of the memory + /// block has not been transferred to this allocator, and the + /// contents of the memory block are unaltered. + /// + /// For best results, `new_layout` should not impose a different + /// alignment constraint than `layout`. (In other words, + /// `new_layout.align()` should equal `layout.align()`.) However, + /// behavior is well-defined (though underspecified) when this + /// constraint is violated; further discussion below. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above). (The `new_layout` + /// argument need not fit it.) + /// + /// * `new_layout` must have size greater than zero. + /// + /// * the alignment of `new_layout` is non-zero. + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// # Errors + /// + /// Returns `Err` only if `new_layout` does not match the + /// alignment of `layout`, or does not meet the allocator's size + /// and alignment constraints of the allocator, or if reallocation + /// otherwise fails. + /// + /// (Note the previous sentence did not say "if and only if" -- in + /// particular, an implementation of this method *can* return `Ok` + /// if `new_layout.align() != old_layout.align()`; or it can + /// return `Err` in that scenario, depending on whether this + /// allocator can dynamically adjust the alignment constraint for + /// the block.) + /// + /// Implementations are encouraged to return `Err` on memory + /// exhaustion rather than panicking or aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an + /// reallocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn realloc(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<*mut u8, AllocErr> { + let new_size = new_layout.size(); + let old_size = layout.size(); + let aligns_match = layout.align == new_layout.align; + + if new_size >= old_size && aligns_match { + if let Ok(()) = self.grow_in_place(ptr, layout.clone(), new_layout.clone()) { + return Ok(ptr); + } + } else if new_size < old_size && aligns_match { + if let Ok(()) = self.shrink_in_place(ptr, layout.clone(), new_layout.clone()) { + return Ok(ptr); + } + } + + // otherwise, fall back on alloc + copy + dealloc. + let result = self.alloc(new_layout); + if let Ok(new_ptr) = result { + ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size)); + self.dealloc(ptr, layout); + } + result + } + + /// Behaves like `alloc`, but also ensures that the contents + /// are set to zero before being returned. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `alloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `alloc`. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + let size = layout.size(); + let p = self.alloc(layout); + if let Ok(p) = p { + ptr::write_bytes(p, 0, size); + } + p + } + + /// Behaves like `alloc`, but also returns the whole size of + /// the returned block. For some `layout` inputs, like arrays, this + /// may include extra storage usable for additional data. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `alloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `alloc`. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> { + let usable_size = self.usable_size(&layout); + self.alloc(layout).map(|p| Excess(p, usable_size.1)) + } + + /// Behaves like `realloc`, but also returns the whole size of + /// the returned block. For some `layout` inputs, like arrays, this + /// may include extra storage usable for additional data. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `realloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `realloc`. + /// + /// Clients wishing to abort computation in response to an + /// reallocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn realloc_excess(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<Excess, AllocErr> { + let usable_size = self.usable_size(&new_layout); + self.realloc(ptr, layout, new_layout) + .map(|p| Excess(p, usable_size.1)) + } + + /// Attempts to extend the allocation referenced by `ptr` to fit `new_layout`. + /// + /// If this returns `Ok`, then the allocator has asserted that the + /// memory block referenced by `ptr` now fits `new_layout`, and thus can + /// be used to carry data of that layout. (The allocator is allowed to + /// expend effort to accomplish this, such as extending the memory block to + /// include successor blocks, or virtual memory tricks.) + /// + /// Regardless of what this method returns, ownership of the + /// memory block referenced by `ptr` has not been transferred, and + /// the contents of the memory block are unaltered. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above); note the + /// `new_layout` argument need not fit it, + /// + /// * `new_layout.size()` must not be less than `layout.size()`, + /// + /// * `new_layout.align()` must equal `layout.align()`. + /// + /// # Errors + /// + /// Returns `Err(CannotReallocInPlace)` when the allocator is + /// unable to assert that the memory block referenced by `ptr` + /// could fit `layout`. + /// + /// Note that one cannot pass `CannotReallocInPlace` to the `oom` + /// method; clients are expected either to be able to recover from + /// `grow_in_place` failures without aborting, or to fall back on + /// another reallocation method before resorting to an abort. + unsafe fn grow_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + let _ = ptr; // this default implementation doesn't care about the actual address. + debug_assert!(new_layout.size >= layout.size); + debug_assert!(new_layout.align == layout.align); + let (_l, u) = self.usable_size(&layout); + // _l <= layout.size() [guaranteed by usable_size()] + // layout.size() <= new_layout.size() [required by this method] + if new_layout.size <= u { + return Ok(()); + } else { + return Err(CannotReallocInPlace); + } + } + + /// Attempts to shrink the allocation referenced by `ptr` to fit `new_layout`. + /// + /// If this returns `Ok`, then the allocator has asserted that the + /// memory block referenced by `ptr` now fits `new_layout`, and + /// thus can only be used to carry data of that smaller + /// layout. (The allocator is allowed to take advantage of this, + /// carving off portions of the block for reuse elsewhere.) The + /// truncated contents of the block within the smaller layout are + /// unaltered, and ownership of block has not been transferred. + /// + /// If this returns `Err`, then the memory block is considered to + /// still represent the original (larger) `layout`. None of the + /// block has been carved off for reuse elsewhere, ownership of + /// the memory block has not been transferred, and the contents of + /// the memory block are unaltered. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above); note the + /// `new_layout` argument need not fit it, + /// + /// * `new_layout.size()` must not be greater than `layout.size()` + /// (and must be greater than zero), + /// + /// * `new_layout.align()` must equal `layout.align()`. + /// + /// # Errors + /// + /// Returns `Err(CannotReallocInPlace)` when the allocator is + /// unable to assert that the memory block referenced by `ptr` + /// could fit `layout`. + /// + /// Note that one cannot pass `CannotReallocInPlace` to the `oom` + /// method; clients are expected either to be able to recover from + /// `shrink_in_place` failures without aborting, or to fall back + /// on another reallocation method before resorting to an abort. + unsafe fn shrink_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + let _ = ptr; // this default implementation doesn't care about the actual address. + debug_assert!(new_layout.size <= layout.size); + debug_assert!(new_layout.align == layout.align); + let (l, _u) = self.usable_size(&layout); + // layout.size() <= _u [guaranteed by usable_size()] + // new_layout.size() <= layout.size() [required by this method] + if l <= new_layout.size { + return Ok(()); + } else { + return Err(CannotReallocInPlace); + } + } + + + // == COMMON USAGE PATTERNS == + // alloc_one, dealloc_one, alloc_array, realloc_array. dealloc_array + + /// Allocates a block suitable for holding an instance of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` + /// must be considered "currently allocated" and must be + /// acceptable input to methods such as `realloc` or `dealloc`, + /// *even if* `T` is a zero-sized type. In other words, if your + /// `Alloc` implementation overrides this method in a manner + /// that can return a zero-sized `ptr`, then all reallocation and + /// deallocation methods need to be similarly overridden to accept + /// such values as input. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `T` does not meet allocator's size or alignment constraints. + /// + /// For zero-sized `T`, may return either of `Ok` or `Err`, but + /// will *not* yield undefined behavior. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + fn alloc_one<T>(&mut self) -> Result<NonNull<T>, AllocErr> + where Self: Sized + { + let k = Layout::new::<T>(); + if k.size() > 0 { + unsafe { self.alloc(k).map(|p| NonNull::new_unchecked(p as *mut T)) } + } else { + Err(AllocErr::invalid_input("zero-sized type invalid for alloc_one")) + } + } + + /// Deallocates a block suitable for holding an instance of `T`. + /// + /// The given block must have been produced by this allocator, + /// and must be suitable for storing a `T` (in terms of alignment + /// as well as minimum and maximum size); otherwise yields + /// undefined behavior. + /// + /// Captures a common usage pattern for allocators. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure both: + /// + /// * `ptr` must denote a block of memory currently allocated via this allocator + /// + /// * the layout of `T` must *fit* that block of memory. + unsafe fn dealloc_one<T>(&mut self, ptr: NonNull<T>) + where Self: Sized + { + let raw_ptr = ptr.as_ptr() as *mut u8; + let k = Layout::new::<T>(); + if k.size() > 0 { + self.dealloc(raw_ptr, k); + } + } + + /// Allocates a block suitable for holding `n` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` + /// must be considered "currently allocated" and must be + /// acceptable input to methods such as `realloc` or `dealloc`, + /// *even if* `T` is a zero-sized type. In other words, if your + /// `Alloc` implementation overrides this method in a manner + /// that can return a zero-sized `ptr`, then all reallocation and + /// deallocation methods need to be similarly overridden to accept + /// such values as input. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `[T; n]` does not meet allocator's size or alignment + /// constraints. + /// + /// For zero-sized `T` or `n == 0`, may return either of `Ok` or + /// `Err`, but will *not* yield undefined behavior. + /// + /// Always returns `Err` on arithmetic overflow. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + fn alloc_array<T>(&mut self, n: usize) -> Result<NonNull<T>, AllocErr> + where Self: Sized + { + match Layout::array::<T>(n) { + Some(ref layout) if layout.size() > 0 => { + unsafe { + self.alloc(layout.clone()) + .map(|p| { + NonNull::new_unchecked(p as *mut T) + }) + } + } + _ => Err(AllocErr::invalid_input("invalid layout for alloc_array")), + } + } + + /// Reallocates a block previously suitable for holding `n_old` + /// instances of `T`, returning a block suitable for holding + /// `n_new` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * the layout of `[T; n_old]` must *fit* that block of memory. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `[T; n_new]` does not meet allocator's size or alignment + /// constraints. + /// + /// For zero-sized `T` or `n_new == 0`, may return either of `Ok` or + /// `Err`, but will *not* yield undefined behavior. + /// + /// Always returns `Err` on arithmetic overflow. + /// + /// Clients wishing to abort computation in response to an + /// reallocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn realloc_array<T>(&mut self, + ptr: NonNull<T>, + n_old: usize, + n_new: usize) -> Result<NonNull<T>, AllocErr> + where Self: Sized + { + match (Layout::array::<T>(n_old), Layout::array::<T>(n_new), ptr.as_ptr()) { + (Some(ref k_old), Some(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { + self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone()) + .map(|p| NonNull::new_unchecked(p as *mut T)) + } + _ => { + Err(AllocErr::invalid_input("invalid layout for realloc_array")) + } + } + } + + /// Deallocates a block suitable for holding `n` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure both: + /// + /// * `ptr` must denote a block of memory currently allocated via this allocator + /// + /// * the layout of `[T; n]` must *fit* that block of memory. + /// + /// # Errors + /// + /// Returning `Err` indicates that either `[T; n]` or the given + /// memory block does not meet allocator's size or alignment + /// constraints. + /// + /// Always returns `Err` on arithmetic overflow. + unsafe fn dealloc_array<T>(&mut self, ptr: NonNull<T>, n: usize) -> Result<(), AllocErr> + where Self: Sized + { + let raw_ptr = ptr.as_ptr() as *mut u8; + match Layout::array::<T>(n) { + Some(ref k) if k.size() > 0 => { + Ok(self.dealloc(raw_ptr, k.clone())) + } + _ => { + Err(AllocErr::invalid_input("invalid layout for dealloc_array")) + } + } + } +} diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 830ebad0654..3b740adc468 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1314,6 +1314,11 @@ extern "rust-intrinsic" { /// [`std::u32::overflowing_mul`](../../std/primitive.u32.html#method.overflowing_mul) pub fn mul_with_overflow<T>(x: T, y: T) -> (T, bool); + /// Performs an exact division, resulting in undefined behavior where + /// `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` + #[cfg(not(stage0))] + pub fn exact_div<T>(x: T, y: T) -> T; + /// Performs an unchecked division, resulting in undefined behavior /// where y = 0 or x = `T::min_value()` and y = -1 pub fn unchecked_div<T>(x: T, y: T) -> T; @@ -1396,3 +1401,8 @@ extern "rust-intrinsic" { /// Probably will never become stable. pub fn nontemporal_store<T>(ptr: *mut T, val: T); } + +#[cfg(stage0)] +pub unsafe fn exact_div<T>(a: T, b: T) -> T { + unchecked_div(a, b) +} diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 2cfbc092293..4ccf446aa63 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -974,13 +974,13 @@ pub trait Iterator { /// // each iteration, we'll multiply the state by the element /// *state = *state * x; /// - /// // the value passed on to the next iteration - /// Some(*state) + /// // then, we'll yield the negation of the state + /// Some(-*state) /// }); /// - /// assert_eq!(iter.next(), Some(1)); - /// assert_eq!(iter.next(), Some(2)); - /// assert_eq!(iter.next(), Some(6)); + /// assert_eq!(iter.next(), Some(-1)); + /// assert_eq!(iter.next(), Some(-2)); + /// assert_eq!(iter.next(), Some(-6)); /// assert_eq!(iter.next(), None); /// ``` #[inline] @@ -1368,6 +1368,7 @@ pub trait Iterator { /// [`Result`]: ../../std/result/enum.Result.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"] fn collect<B: FromIterator<Self::Item>>(self) -> B where Self: Sized { FromIterator::from_iter(self) } @@ -1446,7 +1447,6 @@ pub trait Iterator { /// Basic usage: /// /// ``` - /// #![feature(iterator_try_fold)] /// let a = [1, 2, 3]; /// /// // the checked sum of all of the elements of the array @@ -1458,7 +1458,6 @@ pub trait Iterator { /// Short-circuiting: /// /// ``` - /// #![feature(iterator_try_fold)] /// let a = [10, 20, 30, 100, 40, 50]; /// let mut it = a.iter(); /// @@ -1472,7 +1471,7 @@ pub trait Iterator { /// assert_eq!(it.next(), Some(&40)); /// ``` #[inline] - #[unstable(feature = "iterator_try_fold", issue = "45594")] + #[stable(feature = "iterator_try_fold", since = "1.27.0")] fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B> { @@ -1495,7 +1494,6 @@ pub trait Iterator { /// # Examples /// /// ``` - /// #![feature(iterator_try_fold)] /// use std::fs::rename; /// use std::io::{stdout, Write}; /// use std::path::Path; @@ -1512,7 +1510,7 @@ pub trait Iterator { /// assert_eq!(it.next(), Some("stale_bread.json")); /// ``` #[inline] - #[unstable(feature = "iterator_try_fold", issue = "45594")] + #[stable(feature = "iterator_try_fold", since = "1.27.0")] fn try_for_each<F, R>(&mut self, mut f: F) -> R where Self: Sized, F: FnMut(Self::Item) -> R, R: Try<Ok=()> { @@ -1745,6 +1743,38 @@ pub trait Iterator { }).break_value() } + /// Applies function to the elements of iterator and returns + /// the first non-none result. + /// + /// `iter.find_map(f)` is equivalent to `iter.filter_map(f).next()`. + /// + /// + /// # Examples + /// + /// ``` + /// #![feature(iterator_find_map)] + /// let a = ["lol", "NaN", "2", "5"]; + /// + /// let mut first_number = a.iter().find_map(|s| s.parse().ok()); + /// + /// assert_eq!(first_number, Some(2)); + /// ``` + #[inline] + #[unstable(feature = "iterator_find_map", + reason = "unstable new API", + issue = "49602")] + fn find_map<B, F>(&mut self, mut f: F) -> Option<B> where + Self: Sized, + F: FnMut(Self::Item) -> Option<B>, + { + self.try_for_each(move |x| { + match f(x) { + Some(x) => LoopState::Break(x), + None => LoopState::Continue(()), + } + }).break_value() + } + /// Searches for an element in an iterator, returning its index. /// /// `position()` takes a closure that returns `true` or `false`. It applies diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index b1b783b47c7..1e8476d3880 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -1872,7 +1872,7 @@ impl<I: Iterator> Iterator for Peekable<I> { #[inline] fn nth(&mut self, n: usize) -> Option<I::Item> { - // FIXME(#6393): merge these when borrow-checking gets better. + // FIXME(#43234): merge these when borrow-checking gets better. if n == 0 { match self.peeked.take() { Some(v) => v, diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 8d1080bb876..5d57207763e 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -91,7 +91,7 @@ macro_rules! step_impl_unsigned { #[inline] #[allow(unreachable_patterns)] fn add_usize(&self, n: usize) -> Option<Self> { - match <$t>::try_from(n) { + match <$t>::private_try_from(n) { Ok(n_as_t) => self.checked_add(n_as_t), Err(_) => None, } @@ -123,7 +123,7 @@ macro_rules! step_impl_signed { #[inline] #[allow(unreachable_patterns)] fn add_usize(&self, n: usize) -> Option<Self> { - match <$unsigned>::try_from(n) { + match <$unsigned>::private_try_from(n) { Ok(n_as_unsigned) => { // Wrapping in unsigned space handles cases like // `-120_i8.add_usize(200) == Some(80_i8)`, @@ -461,3 +461,74 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> { #[stable(feature = "fused", since = "1.26.0")] impl<A: Step> FusedIterator for ops::RangeInclusive<A> {} + +/// Compensate removal of some impls per +/// https://github.com/rust-lang/rust/pull/49305#issuecomment-376293243 +trait PrivateTryFromUsize: Sized { + fn private_try_from(n: usize) -> Result<Self, ()>; +} + +impl<T> PrivateTryFromUsize for T where T: TryFrom<usize> { + #[inline] + fn private_try_from(n: usize) -> Result<Self, ()> { + T::try_from(n).map_err(|_| ()) + } +} + +// no possible bounds violation +macro_rules! try_from_unbounded { + ($($target:ty),*) => {$( + impl PrivateTryFromUsize for $target { + #[inline] + fn private_try_from(value: usize) -> Result<Self, ()> { + Ok(value as $target) + } + } + )*} +} + +// unsigned to signed (only positive bound) +#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] +macro_rules! try_from_upper_bounded { + ($($target:ty),*) => {$( + impl PrivateTryFromUsize for $target { + #[inline] + fn private_try_from(u: usize) -> Result<$target, ()> { + if u > (<$target>::max_value() as usize) { + Err(()) + } else { + Ok(u as $target) + } + } + } + )*} +} + + +#[cfg(target_pointer_width = "16")] +mod ptr_try_from_impls { + use super::PrivateTryFromUsize; + + try_from_unbounded!(u16, u32, u64, u128); + try_from_unbounded!(i32, i64, i128); +} + +#[cfg(target_pointer_width = "32")] +mod ptr_try_from_impls { + use super::PrivateTryFromUsize; + + try_from_upper_bounded!(u16); + try_from_unbounded!(u32, u64, u128); + try_from_upper_bounded!(i32); + try_from_unbounded!(i64, i128); +} + +#[cfg(target_pointer_width = "64")] +mod ptr_try_from_impls { + use super::PrivateTryFromUsize; + + try_from_upper_bounded!(u16, u32); + try_from_unbounded!(u64, u128); + try_from_upper_bounded!(i32, i64); + try_from_unbounded!(i128); +} diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 0267fcd3754..ddbb5998942 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -427,7 +427,6 @@ pub trait DoubleEndedIterator: Iterator { /// Basic usage: /// /// ``` - /// #![feature(iterator_try_fold)] /// let a = ["1", "2", "3"]; /// let sum = a.iter() /// .map(|&s| s.parse::<i32>()) @@ -438,7 +437,6 @@ pub trait DoubleEndedIterator: Iterator { /// Short-circuiting: /// /// ``` - /// #![feature(iterator_try_fold)] /// let a = ["1", "rust", "3"]; /// let mut it = a.iter(); /// let sum = it @@ -452,7 +450,7 @@ pub trait DoubleEndedIterator: Iterator { /// assert_eq!(it.next_back(), Some(&"1")); /// ``` #[inline] - #[unstable(feature = "iterator_try_fold", issue = "45594")] + #[stable(feature = "iterator_try_fold", since = "1.27.0")] fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B> { @@ -491,7 +489,6 @@ pub trait DoubleEndedIterator: Iterator { /// Basic usage: /// /// ``` - /// #![feature(iter_rfold)] /// let a = [1, 2, 3]; /// /// // the sum of all of the elements of a @@ -505,7 +502,6 @@ pub trait DoubleEndedIterator: Iterator { /// and continuing with each element from the back until the front: /// /// ``` - /// #![feature(iter_rfold)] /// let numbers = [1, 2, 3, 4, 5]; /// /// let zero = "0".to_string(); @@ -517,14 +513,14 @@ pub trait DoubleEndedIterator: Iterator { /// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))"); /// ``` #[inline] - #[unstable(feature = "iter_rfold", issue = "44705")] + #[stable(feature = "iter_rfold", since = "1.27.0")] fn rfold<B, F>(mut self, accum: B, mut f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { self.try_rfold(accum, move |acc, x| AlwaysOk(f(acc, x))).0 } - /// Searches for an element of an iterator from the right that satisfies a predicate. + /// Searches for an element of an iterator from the back that satisfies a predicate. /// /// `rfind()` takes a closure that returns `true` or `false`. It applies /// this closure to each element of the iterator, starting at the end, and if any @@ -547,8 +543,6 @@ pub trait DoubleEndedIterator: Iterator { /// Basic usage: /// /// ``` - /// #![feature(iter_rfind)] - /// /// let a = [1, 2, 3]; /// /// assert_eq!(a.iter().rfind(|&&x| x == 2), Some(&2)); @@ -559,8 +553,6 @@ pub trait DoubleEndedIterator: Iterator { /// Stopping at the first `true`: /// /// ``` - /// #![feature(iter_rfind)] - /// /// let a = [1, 2, 3]; /// /// let mut iter = a.iter(); @@ -571,7 +563,7 @@ pub trait DoubleEndedIterator: Iterator { /// assert_eq!(iter.next_back(), Some(&1)); /// ``` #[inline] - #[unstable(feature = "iter_rfind", issue = "39480")] + #[stable(feature = "iter_rfind", since = "1.27.0")] fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item> where Self: Sized, P: FnMut(&Self::Item) -> bool @@ -901,6 +893,15 @@ impl<I, T, E> Iterator for ResultShunt<I, E> None => None, } } + + fn size_hint(&self) -> (usize, Option<usize>) { + if self.error.is_some() { + (0, Some(0)) + } else { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } + } } #[stable(feature = "iter_arith_traits_result", since="1.16.0")] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 9aebe2e4ee4..5a62b8438f9 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -78,7 +78,7 @@ #![feature(doc_spotlight)] #![feature(fn_must_use)] #![feature(fundamental)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(intrinsics)] #![feature(iterator_flatten)] @@ -86,6 +86,7 @@ #![feature(lang_items)] #![feature(link_llvm_intrinsics)] #![feature(exhaustive_patterns)] +#![feature(macro_at_most_once_rep)] #![feature(no_core)] #![feature(on_unimplemented)] #![feature(optin_builtin_traits)] @@ -185,6 +186,10 @@ pub mod hash; pub mod fmt; pub mod time; +/* Heap memory allocator trait */ +#[allow(missing_docs)] +pub mod heap; + // note: does not need to be public mod char_private; mod iter_private; diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index f8a33961811..885aabe0806 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -260,6 +260,21 @@ pub trait Unsize<T: ?Sized> { /// non-`Copy` in the future, it could be prudent to omit the `Copy` implementation now, to /// avoid a breaking API change. /// +/// ## Additional implementors +/// +/// In addition to the [implementors listed below][impls], +/// the following types also implement `Copy`: +/// +/// * Function item types (i.e. the distinct types defined for each function) +/// * Function pointer types (e.g. `fn() -> i32`) +/// * Array types, for all sizes, if the item type also implements `Copy` (e.g. `[i32; 123456]`) +/// * Tuple types, if each component also implements `Copy` (e.g. `()`, `(i32, bool)`) +/// * Closure types, if they capture no value from the environment +/// or if all such captured values implement `Copy` themselves. +/// Note that variables captured by shared reference always implement `Copy` +/// (even if the referent doesn't), +/// while variables captured by mutable reference never implement `Copy`. +/// /// [`Vec<T>`]: ../../std/vec/struct.Vec.html /// [`String`]: ../../std/string/struct.String.html /// [`Drop`]: ../../std/ops/trait.Drop.html @@ -267,6 +282,7 @@ pub trait Unsize<T: ?Sized> { /// [`Clone`]: ../clone/trait.Clone.html /// [`String`]: ../../std/string/struct.String.html /// [`i32`]: ../../std/primitive.i32.html +/// [impls]: #implementors #[stable(feature = "rust1", since = "1.0.0")] #[lang = "copy"] pub trait Copy : Clone { @@ -588,3 +604,43 @@ unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} /// This trait is automatically implemented for almost every type. #[unstable(feature = "pin", issue = "49150")] pub unsafe auto trait Unpin {} + +/// Implementations of `Copy` for primitive types. +/// +/// Implementations that cannot be described in Rust +/// are implemented in `SelectionContext::copy_clone_conditions()` in librustc. +#[cfg(not(stage0))] +mod copy_impls { + + use super::Copy; + + macro_rules! impl_copy { + ($($t:ty)*) => { + $( + #[stable(feature = "rust1", since = "1.0.0")] + impl Copy for $t {} + )* + } + } + + impl_copy! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 + f32 f64 + bool char + } + + #[stable(feature = "never_type", since = "1.26.0")] + impl Copy for ! {} + + #[stable(feature = "rust1", since = "1.0.0")] + impl<T: ?Sized> Copy for *const T {} + + #[stable(feature = "rust1", since = "1.0.0")] + impl<T: ?Sized> Copy for *mut T {} + + // Shared references can be copied, but mutable references *cannot*! + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, T: ?Sized> Copy for &'a T {} + +} diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 2c966eb3b57..19836d98844 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -9,9 +9,10 @@ // except according to those terms. //! Exposes the NonZero lang item which provides optimization hints. -#![unstable(feature = "nonzero", - reason = "needs an RFC to flesh out the design", - issue = "27730")] +#![unstable(feature = "nonzero", reason = "deprecated", issue = "49137")] +#![rustc_deprecated(reason = "use `std::ptr::NonNull` or `std::num::NonZero*` instead", + since = "1.26.0")] +#![allow(deprecated)] use ops::CoerceUnsized; @@ -62,14 +63,11 @@ impl_zeroable_for_integer_types! { /// NULL or 0 that might allow certain optimizations. #[lang = "non_zero"] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] -pub struct NonZero<T: Zeroable>(T); +pub struct NonZero<T: Zeroable>(pub(crate) T); impl<T: Zeroable> NonZero<T> { /// Creates an instance of NonZero with the provided value. /// You must indeed ensure that the value is actually "non-zero". - #[unstable(feature = "nonzero", - reason = "needs an RFC to flesh out the design", - issue = "27730")] #[inline] pub const unsafe fn new_unchecked(inner: T) -> Self { NonZero(inner) diff --git a/src/libcore/num/i128.rs b/src/libcore/num/i128.rs index 04354e2e33f..989376d1ac2 100644 --- a/src/libcore/num/i128.rs +++ b/src/libcore/num/i128.rs @@ -12,6 +12,6 @@ //! //! *[See also the `i128` primitive type](../../std/primitive.i128.html).* -#![unstable(feature = "i128", issue="35118")] +#![stable(feature = "i128", since = "1.26.0")] -int_module! { i128, #[unstable(feature = "i128", issue="35118")] } +int_module! { i128, #[stable(feature = "i128", since="1.26.0")] } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 09ab7060d37..dcda404721c 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -12,12 +12,111 @@ #![stable(feature = "rust1", since = "1.0.0")] -use convert::{Infallible, TryFrom}; +use convert::TryFrom; use fmt; use intrinsics; +#[allow(deprecated)] use nonzero::NonZero; use ops; use str::FromStr; +macro_rules! impl_nonzero_fmt { + ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { + $( + #[$stability] + #[allow(deprecated)] + impl fmt::$Trait for $Ty { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.get().fmt(f) + } + } + )+ + } +} + +macro_rules! nonzero_integers { + ( #[$stability: meta] #[$deprecation: meta] $( $Ty: ident($Int: ty); )+ ) => { + $( + /// An integer that is known not to equal zero. + /// + /// This may enable some memory layout optimization such as: + /// + /// ```rust + /// # #![feature(nonzero)] + /// use std::mem::size_of; + /// assert_eq!(size_of::<Option<std::num::NonZeroU32>>(), size_of::<u32>()); + /// ``` + #[$stability] + #[$deprecation] + #[allow(deprecated)] + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] + pub struct $Ty(NonZero<$Int>); + + #[allow(deprecated)] + impl $Ty { + /// Create a non-zero without checking the value. + /// + /// # Safety + /// + /// The value must not be zero. + #[$stability] + #[inline] + pub const unsafe fn new_unchecked(n: $Int) -> Self { + $Ty(NonZero(n)) + } + + /// Create a non-zero if the given value is not zero. + #[$stability] + #[inline] + pub fn new(n: $Int) -> Option<Self> { + if n != 0 { + Some($Ty(NonZero(n))) + } else { + None + } + } + + /// Returns the value as a primitive type. + #[$stability] + #[inline] + pub fn get(self) -> $Int { + self.0 .0 + } + + } + + impl_nonzero_fmt! { + #[$stability] + (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty + } + )+ + } +} + +nonzero_integers! { + #[unstable(feature = "nonzero", issue = "49137")] + #[allow(deprecated)] // Redundant, works around "error: inconsistent lockstep iteration" + NonZeroU8(u8); + NonZeroU16(u16); + NonZeroU32(u32); + NonZeroU64(u64); + NonZeroU128(u128); + NonZeroUsize(usize); +} + +nonzero_integers! { + #[unstable(feature = "nonzero", issue = "49137")] + #[rustc_deprecated(since = "1.26.0", reason = "\ + signed non-zero integers are considered for removal due to lack of known use cases. \ + If you’re using them, please comment on https://github.com/rust-lang/rust/issues/49137")] + NonZeroI8(i8); + NonZeroI16(i16); + NonZeroI32(i32); + NonZeroI64(i64); + NonZeroI128(i128); + NonZeroIsize(isize); +} + /// Provides intentionally-wrapped arithmetic on `T`. /// /// Operations like `+` on `u32` values is intended to never overflow, @@ -1546,11 +1645,7 @@ impl i64 { #[lang = "i128"] impl i128 { int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, - 170141183460469231731687303715884105727, "#![feature(i128_type)] -#![feature(i128)] -# fn main() { -", " -# }" } + 170141183460469231731687303715884105727, "", "" } } #[cfg(target_pointer_width = "16")] @@ -3404,12 +3499,7 @@ impl u64 { #[lang = "u128"] impl u128 { - uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "#![feature(i128_type)] -#![feature(i128)] - -# fn main() { -", " -# }" } + uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "", "" } } #[cfg(target_pointer_width = "16")] @@ -3573,7 +3663,7 @@ macro_rules! from_str_radix_int_impl { from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } /// The error type returned when a checked integral type conversion fails. -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] #[derive(Debug, Copy, Clone)] pub struct TryFromIntError(()); @@ -3588,40 +3678,24 @@ impl TryFromIntError { } } -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl fmt::Display for TryFromIntError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { self.__description().fmt(fmt) } } -#[unstable(feature = "try_from", issue = "33417")] -impl From<Infallible> for TryFromIntError { - fn from(infallible: Infallible) -> TryFromIntError { - match infallible { - } +#[stable(feature = "try_from", since = "1.26.0")] +impl From<!> for TryFromIntError { + fn from(never: !) -> TryFromIntError { + never } } -// no possible bounds violation -macro_rules! try_from_unbounded { - ($source:ty, $($target:ty),*) => {$( - #[unstable(feature = "try_from", issue = "33417")] - impl TryFrom<$source> for $target { - type Error = Infallible; - - #[inline] - fn try_from(value: $source) -> Result<Self, Self::Error> { - Ok(value as $target) - } - } - )*} -} - // only negative bounds macro_rules! try_from_lower_bounded { ($source:ty, $($target:ty),*) => {$( - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -3640,7 +3714,7 @@ macro_rules! try_from_lower_bounded { // unsigned to signed (only positive bound) macro_rules! try_from_upper_bounded { ($source:ty, $($target:ty),*) => {$( - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -3659,7 +3733,7 @@ macro_rules! try_from_upper_bounded { // all other cases macro_rules! try_from_both_bounded { ($source:ty, $($target:ty),*) => {$( - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -3716,82 +3790,44 @@ try_from_both_bounded!(i128, u64, u32, u16, u8); try_from_upper_bounded!(usize, isize); try_from_lower_bounded!(isize, usize); +try_from_upper_bounded!(usize, u8); +try_from_upper_bounded!(usize, i8, i16); +try_from_both_bounded!(isize, u8); +try_from_both_bounded!(isize, i8); + #[cfg(target_pointer_width = "16")] mod ptr_try_from_impls { use super::TryFromIntError; - use convert::{Infallible, TryFrom}; - - try_from_upper_bounded!(usize, u8); - try_from_unbounded!(usize, u16, u32, u64, u128); - try_from_upper_bounded!(usize, i8, i16); - try_from_unbounded!(usize, i32, i64, i128); + use convert::TryFrom; - try_from_both_bounded!(isize, u8); + // Fallible across platfoms, only implementation differs try_from_lower_bounded!(isize, u16, u32, u64, u128); - try_from_both_bounded!(isize, i8); - try_from_unbounded!(isize, i16, i32, i64, i128); - - rev!(try_from_unbounded, usize, u16); - rev!(try_from_upper_bounded, usize, u32, u64, u128); rev!(try_from_lower_bounded, usize, i8, i16); rev!(try_from_both_bounded, usize, i32, i64, i128); - - rev!(try_from_unbounded, isize, u8); - rev!(try_from_upper_bounded, isize, u16, u32, u64, u128); - rev!(try_from_unbounded, isize, i16); - rev!(try_from_both_bounded, isize, i32, i64, i128); } #[cfg(target_pointer_width = "32")] mod ptr_try_from_impls { use super::TryFromIntError; - use convert::{Infallible, TryFrom}; - - try_from_upper_bounded!(usize, u8, u16); - try_from_unbounded!(usize, u32, u64, u128); - try_from_upper_bounded!(usize, i8, i16, i32); - try_from_unbounded!(usize, i64, i128); + use convert::TryFrom; - try_from_both_bounded!(isize, u8, u16); + // Fallible across platfoms, only implementation differs + try_from_both_bounded!(isize, u16); try_from_lower_bounded!(isize, u32, u64, u128); - try_from_both_bounded!(isize, i8, i16); - try_from_unbounded!(isize, i32, i64, i128); - - rev!(try_from_unbounded, usize, u16, u32); - rev!(try_from_upper_bounded, usize, u64, u128); rev!(try_from_lower_bounded, usize, i8, i16, i32); rev!(try_from_both_bounded, usize, i64, i128); - - rev!(try_from_unbounded, isize, u8, u16); - rev!(try_from_upper_bounded, isize, u32, u64, u128); - rev!(try_from_unbounded, isize, i16, i32); - rev!(try_from_both_bounded, isize, i64, i128); } #[cfg(target_pointer_width = "64")] mod ptr_try_from_impls { use super::TryFromIntError; - use convert::{Infallible, TryFrom}; - - try_from_upper_bounded!(usize, u8, u16, u32); - try_from_unbounded!(usize, u64, u128); - try_from_upper_bounded!(usize, i8, i16, i32, i64); - try_from_unbounded!(usize, i128); + use convert::TryFrom; - try_from_both_bounded!(isize, u8, u16, u32); + // Fallible across platfoms, only implementation differs + try_from_both_bounded!(isize, u16, u32); try_from_lower_bounded!(isize, u64, u128); - try_from_both_bounded!(isize, i8, i16, i32); - try_from_unbounded!(isize, i64, i128); - - rev!(try_from_unbounded, usize, u16, u32, u64); - rev!(try_from_upper_bounded, usize, u128); rev!(try_from_lower_bounded, usize, i8, i16, i32, i64); rev!(try_from_both_bounded, usize, i128); - - rev!(try_from_unbounded, isize, u8, u16, u32); - rev!(try_from_upper_bounded, isize, u64, u128); - rev!(try_from_unbounded, isize, i16, i32, i64); - rev!(try_from_both_bounded, isize, i128); } #[doc(hidden)] @@ -3967,39 +4003,53 @@ macro_rules! impl_from { impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u8, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, u128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u8, u128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { u8, usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u16, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u16, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, u128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u16, u128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { u32, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u32, u128, #[unstable(feature = "i128", issue = "35118")] } -impl_from! { u64, u128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u32, u128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u64, u128, #[stable(feature = "i128", since = "1.26.0")] } // Signed -> Signed impl_from! { i8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { i8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { i8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i8, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { i8, i128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { i8, isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { i16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { i16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i16, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { i16, i128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { i32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i32, i128, #[unstable(feature = "i128", issue = "35118")] } -impl_from! { i64, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { i32, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { i64, i128, #[stable(feature = "i128", since = "1.26.0")] } // Unsigned -> Signed impl_from! { u8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u8, i128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { u16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u16, i128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { u32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u32, i128, #[unstable(feature = "i128", issue = "35118")] } -impl_from! { u64, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u32, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u64, i128, #[stable(feature = "i128", since = "1.26.0")] } + +// The C99 standard defines bounds on INTPTR_MIN, INTPTR_MAX, and UINTPTR_MAX +// which imply that pointer-sized integers must be at least 16 bits: +// https://port70.net/~nsz/c/c99/n1256.html#7.18.2.4 +impl_from! { u16, usize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } +impl_from! { u8, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } +impl_from! { i16, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } + +// RISC-V defines the possibility of a 128-bit address space (RV128). + +// CHERI proposes 256-bit “capabilities”. Unclear if this would be relevant to usize/isize. +// https://www.cl.cam.ac.uk/research/security/ctsrd/pdfs/20171017a-cheri-poster.pdf +// http://www.csl.sri.com/users/neumann/2012resolve-cheri.pdf + // Note: integers can only be represented with full precision in a float if // they fit in the significand, which is 24 bits in f32 and 53 bits in f64. diff --git a/src/libcore/num/u128.rs b/src/libcore/num/u128.rs index 987ac3e0007..e8c783a1bb5 100644 --- a/src/libcore/num/u128.rs +++ b/src/libcore/num/u128.rs @@ -12,5 +12,5 @@ //! //! *[See also the `u128` primitive type](../../std/primitive.u128.html).* -#![unstable(feature = "i128", issue="35118")] -uint_module! { u128, #[unstable(feature = "i128", issue="35118")] } +#![stable(feature = "i128", since = "1.26.0")] +uint_module! { u128, #[stable(feature = "i128", since="1.26.0")] } diff --git a/src/libcore/ops/drop.rs b/src/libcore/ops/drop.rs index 70ab7b2f3b7..474f7e34c34 100644 --- a/src/libcore/ops/drop.rs +++ b/src/libcore/ops/drop.rs @@ -95,7 +95,7 @@ pub trait Drop { /// Executes the destructor for this type. /// - /// This method is called implilcitly when the value goes out of scope, + /// This method is called implicitly when the value goes out of scope, /// and cannot be called explicitly (this is compiler error [E0040]). /// However, the [`std::mem::drop`] function in the prelude can be /// used to call the argument's `Drop` implementation. diff --git a/src/libcore/ops/generator.rs b/src/libcore/ops/generator.rs index dc7669d195c..4b70c5398be 100644 --- a/src/libcore/ops/generator.rs +++ b/src/libcore/ops/generator.rs @@ -56,11 +56,11 @@ pub enum GeneratorState<Y, R> { /// return "foo" /// }; /// -/// match generator.resume() { +/// match unsafe { generator.resume() } { /// GeneratorState::Yielded(1) => {} /// _ => panic!("unexpected return from resume"), /// } -/// match generator.resume() { +/// match unsafe { generator.resume() } { /// GeneratorState::Complete("foo") => {} /// _ => panic!("unexpected return from resume"), /// } @@ -98,6 +98,10 @@ pub trait Generator { /// generator will continue executing until it either yields or returns, at /// which point this function will return. /// + /// The function is unsafe because it can be used on an immovable generator. + /// After such a call, the immovable generator must not move again, but + /// this is not enforced by the compiler. + /// /// # Return value /// /// The `GeneratorState` enum returned from this function indicates what @@ -116,7 +120,7 @@ pub trait Generator { /// been returned previously. While generator literals in the language are /// guaranteed to panic on resuming after `Complete`, this is not guaranteed /// for all implementations of the `Generator` trait. - fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>; + unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>; } #[unstable(feature = "generator_trait", issue = "43122")] @@ -125,7 +129,7 @@ impl<'a, T> Generator for &'a mut T { type Yield = T::Yield; type Return = T::Return; - fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> { + unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> { (**self).resume() } } diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index 234970a81fa..ce4f45762de 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -161,7 +161,6 @@ mod drop; mod function; mod generator; mod index; -mod place; mod range; mod try; mod unsize; @@ -192,7 +191,7 @@ pub use self::index::{Index, IndexMut}; pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; #[stable(feature = "inclusive_range", since = "1.26.0")] -pub use self::range::{RangeInclusive, RangeToInclusive}; +pub use self::range::{RangeInclusive, RangeToInclusive, RangeBounds, Bound}; #[unstable(feature = "try_trait", issue = "42327")] pub use self::try::Try; @@ -200,8 +199,5 @@ pub use self::try::Try; #[unstable(feature = "generator_trait", issue = "43122")] pub use self::generator::{Generator, GeneratorState}; -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub use self::place::{Place, Placer, InPlace, Boxed, BoxPlace}; - #[unstable(feature = "coerce_unsized", issue = "27732")] pub use self::unsize::CoerceUnsized; diff --git a/src/libcore/ops/place.rs b/src/libcore/ops/place.rs deleted file mode 100644 index b3dcf4e7ee9..00000000000 --- a/src/libcore/ops/place.rs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// Both `PLACE <- EXPR` and `box EXPR` desugar into expressions -/// that allocate an intermediate "place" that holds uninitialized -/// state. The desugaring evaluates EXPR, and writes the result at -/// the address returned by the `pointer` method of this trait. -/// -/// A `Place` can be thought of as a special representation for a -/// hypothetical `&uninit` reference (which Rust cannot currently -/// express directly). That is, it represents a pointer to -/// uninitialized storage. -/// -/// The client is responsible for two steps: First, initializing the -/// payload (it can access its address via `pointer`). Second, -/// converting the agent to an instance of the owning pointer, via the -/// appropriate `finalize` method (see the `InPlace`. -/// -/// If evaluating EXPR fails, then it is up to the destructor for the -/// implementation of Place to clean up any intermediate state -/// (e.g. deallocate box storage, pop a stack, etc). -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub unsafe trait Place<Data: ?Sized> { - /// Returns the address where the input value will be written. - /// Note that the data at this address is generally uninitialized, - /// and thus one should use `ptr::write` for initializing it. - /// - /// This function must return a pointer through which a value - /// of type `Data` can be written. - fn pointer(&mut self) -> *mut Data; -} - -/// Interface to implementations of `PLACE <- EXPR`. -/// -/// `PLACE <- EXPR` effectively desugars into: -/// -/// ``` -/// # #![feature(placement_new_protocol, box_heap)] -/// # use std::ops::{Placer, Place, InPlace}; -/// # #[allow(non_snake_case)] -/// # fn main() { -/// # let PLACE = std::boxed::HEAP; -/// # let EXPR = 1; -/// let p = PLACE; -/// let mut place = Placer::make_place(p); -/// let raw_place = Place::pointer(&mut place); -/// let value = EXPR; -/// unsafe { -/// std::ptr::write(raw_place, value); -/// InPlace::finalize(place) -/// } -/// # ; } -/// ``` -/// -/// The type of `PLACE <- EXPR` is derived from the type of `PLACE`; -/// if the type of `PLACE` is `P`, then the final type of the whole -/// expression is `P::Place::Owner` (see the `InPlace` and `Boxed` -/// traits). -/// -/// Values for types implementing this trait usually are transient -/// intermediate values (e.g. the return value of `Vec::emplace_back`) -/// or `Copy`, since the `make_place` method takes `self` by value. -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait Placer<Data: ?Sized> { - /// `Place` is the intermediate agent guarding the - /// uninitialized state for `Data`. - type Place: InPlace<Data>; - - /// Creates a fresh place from `self`. - fn make_place(self) -> Self::Place; -} - -/// Specialization of `Place` trait supporting `PLACE <- EXPR`. -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait InPlace<Data: ?Sized>: Place<Data> { - /// `Owner` is the type of the end value of `PLACE <- EXPR` - /// - /// Note that when `PLACE <- EXPR` is solely used for - /// side-effecting an existing data-structure, - /// e.g. `Vec::emplace_back`, then `Owner` need not carry any - /// information at all (e.g. it can be the unit type `()` in that - /// case). - type Owner; - - /// Converts self into the final value, shifting - /// deallocation/cleanup responsibilities (if any remain), over to - /// the returned instance of `Owner` and forgetting self. - unsafe fn finalize(self) -> Self::Owner; -} - -/// Core trait for the `box EXPR` form. -/// -/// `box EXPR` effectively desugars into: -/// -/// ``` -/// # #![feature(placement_new_protocol)] -/// # use std::ops::{BoxPlace, Place, Boxed}; -/// # #[allow(non_snake_case)] -/// # fn main() { -/// # let EXPR = 1; -/// let mut place = BoxPlace::make_place(); -/// let raw_place = Place::pointer(&mut place); -/// let value = EXPR; -/// # let _: Box<_> = -/// unsafe { -/// ::std::ptr::write(raw_place, value); -/// Boxed::finalize(place) -/// } -/// # ; } -/// ``` -/// -/// The type of `box EXPR` is supplied from its surrounding -/// context; in the above expansion, the result type `T` is used -/// to determine which implementation of `Boxed` to use, and that -/// `<T as Boxed>` in turn dictates determines which -/// implementation of `BoxPlace` to use, namely: -/// `<<T as Boxed>::Place as BoxPlace>`. -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait Boxed { - /// The kind of data that is stored in this kind of box. - type Data; /* (`Data` unused b/c cannot yet express below bound.) */ - /// The place that will negotiate the storage of the data. - type Place: BoxPlace<Self::Data>; - - /// Converts filled place into final owning value, shifting - /// deallocation/cleanup responsibilities (if any remain), over to - /// returned instance of `Self` and forgetting `filled`. - unsafe fn finalize(filled: Self::Place) -> Self; -} - -/// Specialization of `Place` trait supporting `box EXPR`. -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait BoxPlace<Data: ?Sized> : Place<Data> { - /// Creates a globally fresh place. - fn make_place() -> Self; -} diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index be51f5239b0..3f667407125 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -442,3 +442,267 @@ impl<Idx: PartialOrd<Idx>> RangeToInclusive<Idx> { // RangeToInclusive<Idx> cannot impl From<RangeTo<Idx>> // because underflow would be possible with (..0).into() + +/// An endpoint of a range of keys. +/// +/// # Examples +/// +/// `Bound`s are range endpoints: +/// +/// ``` +/// #![feature(collections_range)] +/// +/// use std::ops::Bound::*; +/// use std::ops::RangeBounds; +/// +/// assert_eq!((..100).start(), Unbounded); +/// assert_eq!((1..12).start(), Included(&1)); +/// assert_eq!((1..12).end(), Excluded(&12)); +/// ``` +/// +/// Using a tuple of `Bound`s as an argument to [`BTreeMap::range`]. +/// Note that in most cases, it's better to use range syntax (`1..5`) instead. +/// +/// ``` +/// use std::collections::BTreeMap; +/// use std::ops::Bound::{Excluded, Included, Unbounded}; +/// +/// let mut map = BTreeMap::new(); +/// map.insert(3, "a"); +/// map.insert(5, "b"); +/// map.insert(8, "c"); +/// +/// for (key, value) in map.range((Excluded(3), Included(8))) { +/// println!("{}: {}", key, value); +/// } +/// +/// assert_eq!(Some((&3, &"a")), map.range((Unbounded, Included(5))).next()); +/// ``` +/// +/// [`BTreeMap::range`]: ../../std/collections/btree_map/struct.BTreeMap.html#method.range +#[stable(feature = "collections_bound", since = "1.17.0")] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] +pub enum Bound<T> { + /// An inclusive bound. + #[stable(feature = "collections_bound", since = "1.17.0")] + Included(#[stable(feature = "collections_bound", since = "1.17.0")] T), + /// An exclusive bound. + #[stable(feature = "collections_bound", since = "1.17.0")] + Excluded(#[stable(feature = "collections_bound", since = "1.17.0")] T), + /// An infinite endpoint. Indicates that there is no bound in this direction. + #[stable(feature = "collections_bound", since = "1.17.0")] + Unbounded, +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +/// `RangeBounds` is implemented by Rust's built-in range types, produced +/// by range syntax like `..`, `a..`, `..b` or `c..d`. +pub trait RangeBounds<T: ?Sized> { + /// Start index bound. + /// + /// Returns the start value as a `Bound`. + /// + /// # Examples + /// + /// ``` + /// #![feature(collections_range)] + /// + /// # fn main() { + /// use std::ops::Bound::*; + /// use std::ops::RangeBounds; + /// + /// assert_eq!((..10).start(), Unbounded); + /// assert_eq!((3..10).start(), Included(&3)); + /// # } + /// ``` + fn start(&self) -> Bound<&T>; + + /// End index bound. + /// + /// Returns the end value as a `Bound`. + /// + /// # Examples + /// + /// ``` + /// #![feature(collections_range)] + /// + /// # fn main() { + /// use std::ops::Bound::*; + /// use std::ops::RangeBounds; + /// + /// assert_eq!((3..).end(), Unbounded); + /// assert_eq!((3..10).end(), Excluded(&10)); + /// # } + /// ``` + fn end(&self) -> Bound<&T>; +} + +use self::Bound::{Excluded, Included, Unbounded}; + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<T: ?Sized> RangeBounds<T> for RangeFull { + fn start(&self) -> Bound<&T> { + Unbounded + } + fn end(&self) -> Bound<&T> { + Unbounded + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<T> RangeBounds<T> for RangeFrom<T> { + fn start(&self) -> Bound<&T> { + Included(&self.start) + } + fn end(&self) -> Bound<&T> { + Unbounded + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<T> RangeBounds<T> for RangeTo<T> { + fn start(&self) -> Bound<&T> { + Unbounded + } + fn end(&self) -> Bound<&T> { + Excluded(&self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<T> RangeBounds<T> for Range<T> { + fn start(&self) -> Bound<&T> { + Included(&self.start) + } + fn end(&self) -> Bound<&T> { + Excluded(&self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<T> RangeBounds<T> for RangeInclusive<T> { + fn start(&self) -> Bound<&T> { + Included(&self.start) + } + fn end(&self) -> Bound<&T> { + Included(&self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<T> RangeBounds<T> for RangeToInclusive<T> { + fn start(&self) -> Bound<&T> { + Unbounded + } + fn end(&self) -> Bound<&T> { + Included(&self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<T> RangeBounds<T> for (Bound<T>, Bound<T>) { + fn start(&self) -> Bound<&T> { + match *self { + (Included(ref start), _) => Included(start), + (Excluded(ref start), _) => Excluded(start), + (Unbounded, _) => Unbounded, + } + } + + fn end(&self) -> Bound<&T> { + match *self { + (_, Included(ref end)) => Included(end), + (_, Excluded(ref end)) => Excluded(end), + (_, Unbounded) => Unbounded, + } + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<'a, T: ?Sized + 'a> RangeBounds<T> for (Bound<&'a T>, Bound<&'a T>) { + fn start(&self) -> Bound<&T> { + self.0 + } + + fn end(&self) -> Bound<&T> { + self.1 + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<'a, T> RangeBounds<T> for RangeFrom<&'a T> { + fn start(&self) -> Bound<&T> { + Included(self.start) + } + fn end(&self) -> Bound<&T> { + Unbounded + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<'a, T> RangeBounds<T> for RangeTo<&'a T> { + fn start(&self) -> Bound<&T> { + Unbounded + } + fn end(&self) -> Bound<&T> { + Excluded(self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<'a, T> RangeBounds<T> for Range<&'a T> { + fn start(&self) -> Bound<&T> { + Included(self.start) + } + fn end(&self) -> Bound<&T> { + Excluded(self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<'a, T> RangeBounds<T> for RangeInclusive<&'a T> { + fn start(&self) -> Bound<&T> { + Included(self.start) + } + fn end(&self) -> Bound<&T> { + Included(self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<'a, T> RangeBounds<T> for RangeToInclusive<&'a T> { + fn start(&self) -> Bound<&T> { + Unbounded + } + fn end(&self) -> Bound<&T> { + Included(self.end) + } +} diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs index 81e5cb5c350..ef6a8fb6a61 100644 --- a/src/libcore/ops/try.rs +++ b/src/libcore/ops/try.rs @@ -20,7 +20,7 @@ any(from_method="from_error", from_method="from_ok"), from_desugaring="?"), message="the `?` operator can only be used in a \ - function that returns `Result` \ + function that returns `Result` or `Option` \ (or another type that implements `{Try}`)", label="cannot use the `?` operator in a function that returns `{Self}`"), on(all(from_method="into_result", from_desugaring="?"), diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 570f745f833..61ef6798b2e 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -1188,6 +1188,16 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> { None => None, } } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + if self.found_none { + (0, Some(0)) + } else { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } + } } let mut adapter = Adapter { iter: iter.into_iter(), found_none: false }; diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 6270e5892b3..5a54de06b5e 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -23,7 +23,7 @@ use fmt; use hash; use marker::{PhantomData, Unsize}; use mem; -use nonzero::NonZero; +#[allow(deprecated)] use nonzero::NonZero; use cmp::Ordering::{self, Less, Equal, Greater}; @@ -669,7 +669,7 @@ impl<T: ?Sized> *const T { /// `mem::size_of::<T>()` then the result of the division is rounded towards /// zero. /// - /// This function returns `None` if `T` is a zero-sized typed. + /// This function returns `None` if `T` is a zero-sized type. /// /// # Examples /// @@ -700,6 +700,124 @@ impl<T: ?Sized> *const T { } } + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`. + /// + /// This function is the inverse of [`offset`]. + /// + /// [`offset`]: #method.offset + /// [`wrapping_offset_from`]: #method.wrapping_offset_from + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and other pointer must be either in bounds or one + /// byte past the end of the same allocated object. + /// + /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. + /// + /// * The distance between the pointers, in bytes, must be an exact multiple + /// of the size of `T`. + /// + /// * The distance being in bounds cannot rely on "wrapping around" the address space. + /// + /// The compiler and standard library generally try to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `ptr_into_vec.offset_from(vec.as_ptr())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using [`wrapping_offset_from`] instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// # Panics + /// + /// This function panics if `T` is a Zero-Sized Type ("ZST"). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_offset_from)] + /// + /// let a = [0; 5]; + /// let ptr1: *const i32 = &a[1]; + /// let ptr2: *const i32 = &a[3]; + /// unsafe { + /// assert_eq!(ptr2.offset_from(ptr1), 2); + /// assert_eq!(ptr1.offset_from(ptr2), -2); + /// assert_eq!(ptr1.offset(2), ptr2); + /// assert_eq!(ptr2.offset(-2), ptr1); + /// } + /// ``` + #[unstable(feature = "ptr_offset_from", issue = "41079")] + #[inline] + pub unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized { + let pointee_size = mem::size_of::<T>(); + assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); + + // This is the same sequence that Clang emits for pointer subtraction. + // It can be neither `nsw` nor `nuw` because the input is treated as + // unsigned but then the output is treated as signed, so neither works. + let d = isize::wrapping_sub(self as _, origin as _); + intrinsics::exact_div(d, pointee_size as _) + } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`. + /// + /// If the address different between the two pointers is not a multiple of + /// `mem::size_of::<T>()` then the result of the division is rounded towards + /// zero. + /// + /// Though this method is safe for any two pointers, note that its result + /// will be mostly useless if the two pointers aren't into the same allocated + /// object, for example if they point to two different local variables. + /// + /// # Panics + /// + /// This function panics if `T` is a zero-sized type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_wrapping_offset_from)] + /// + /// let a = [0; 5]; + /// let ptr1: *const i32 = &a[1]; + /// let ptr2: *const i32 = &a[3]; + /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); + /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2); + /// assert_eq!(ptr1.wrapping_offset(2), ptr2); + /// assert_eq!(ptr2.wrapping_offset(-2), ptr1); + /// + /// let ptr1: *const i32 = 3 as _; + /// let ptr2: *const i32 = 13 as _; + /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); + /// ``` + #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")] + #[inline] + pub fn wrapping_offset_from(self, origin: *const T) -> isize where T: Sized { + let pointee_size = mem::size_of::<T>(); + assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); + + let d = isize::wrapping_sub(self as _, origin as _); + d.wrapping_div(pointee_size as _) + } + /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). /// /// `count` is in units of T; e.g. a `count` of 3 represents a pointer @@ -1316,7 +1434,7 @@ impl<T: ?Sized> *mut T { /// `mem::size_of::<T>()` then the result of the division is rounded towards /// zero. /// - /// This function returns `None` if `T` is a zero-sized typed. + /// This function returns `None` if `T` is a zero-sized type. /// /// # Examples /// @@ -1347,6 +1465,113 @@ impl<T: ?Sized> *mut T { } } + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`. + /// + /// This function is the inverse of [`offset`]. + /// + /// [`offset`]: #method.offset-1 + /// [`wrapping_offset_from`]: #method.wrapping_offset_from-1 + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and other pointer must be either in bounds or one + /// byte past the end of the same allocated object. + /// + /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. + /// + /// * The distance between the pointers, in bytes, must be an exact multiple + /// of the size of `T`. + /// + /// * The distance being in bounds cannot rely on "wrapping around" the address space. + /// + /// The compiler and standard library generally try to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `ptr_into_vec.offset_from(vec.as_ptr())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using [`wrapping_offset_from`] instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// # Panics + /// + /// This function panics if `T` is a Zero-Sized Type ("ZST"). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_offset_from)] + /// + /// let mut a = [0; 5]; + /// let ptr1: *mut i32 = &mut a[1]; + /// let ptr2: *mut i32 = &mut a[3]; + /// unsafe { + /// assert_eq!(ptr2.offset_from(ptr1), 2); + /// assert_eq!(ptr1.offset_from(ptr2), -2); + /// assert_eq!(ptr1.offset(2), ptr2); + /// assert_eq!(ptr2.offset(-2), ptr1); + /// } + /// ``` + #[unstable(feature = "ptr_offset_from", issue = "41079")] + #[inline] + pub unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized { + (self as *const T).offset_from(origin) + } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`. + /// + /// If the address different between the two pointers is not a multiple of + /// `mem::size_of::<T>()` then the result of the division is rounded towards + /// zero. + /// + /// Though this method is safe for any two pointers, note that its result + /// will be mostly useless if the two pointers aren't into the same allocated + /// object, for example if they point to two different local variables. + /// + /// # Panics + /// + /// This function panics if `T` is a zero-sized type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_wrapping_offset_from)] + /// + /// let mut a = [0; 5]; + /// let ptr1: *mut i32 = &mut a[1]; + /// let ptr2: *mut i32 = &mut a[3]; + /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); + /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2); + /// assert_eq!(ptr1.wrapping_offset(2), ptr2); + /// assert_eq!(ptr2.wrapping_offset(-2), ptr1); + /// + /// let ptr1: *mut i32 = 3 as _; + /// let ptr2: *mut i32 = 13 as _; + /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); + /// ``` + #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")] + #[inline] + pub fn wrapping_offset_from(self, origin: *const T) -> isize where T: Sized { + (self as *const T).wrapping_offset_from(origin) + } + /// Computes the byte offset that needs to be applied in order to /// make the pointer aligned to `align`. /// If it is not possible to align the pointer, the implementation returns @@ -2285,6 +2510,7 @@ impl<T: ?Sized> PartialOrd for *mut T { #[unstable(feature = "ptr_internals", issue = "0", reason = "use NonNull instead and consider PhantomData<T> \ (if you also use #[may_dangle]), Send, and/or Sync")] +#[allow(deprecated)] pub struct Unique<T: ?Sized> { pointer: NonZero<*const T>, // NOTE: this marker has no consequences for variance, but is necessary @@ -2332,6 +2558,7 @@ impl<T: Sized> Unique<T> { } #[unstable(feature = "ptr_internals", issue = "0")] +#[allow(deprecated)] impl<T: ?Sized> Unique<T> { /// Creates a new `Unique`. /// @@ -2339,17 +2566,21 @@ impl<T: ?Sized> Unique<T> { /// /// `ptr` must be non-null. pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { - Unique { pointer: NonZero::new_unchecked(ptr), _marker: PhantomData } + Unique { pointer: NonZero(ptr as _), _marker: PhantomData } } /// Creates a new `Unique` if `ptr` is non-null. pub fn new(ptr: *mut T) -> Option<Self> { - NonZero::new(ptr as *const T).map(|nz| Unique { pointer: nz, _marker: PhantomData }) + if !ptr.is_null() { + Some(Unique { pointer: NonZero(ptr as _), _marker: PhantomData }) + } else { + None + } } /// Acquires the underlying `*mut` pointer. pub fn as_ptr(self) -> *mut T { - self.pointer.get() as *mut T + self.pointer.0 as *mut T } /// Dereferences the content. @@ -2392,16 +2623,18 @@ impl<T: ?Sized> fmt::Pointer for Unique<T> { } #[unstable(feature = "ptr_internals", issue = "0")] +#[allow(deprecated)] impl<'a, T: ?Sized> From<&'a mut T> for Unique<T> { fn from(reference: &'a mut T) -> Self { - Unique { pointer: NonZero::from(reference), _marker: PhantomData } + Unique { pointer: NonZero(reference as _), _marker: PhantomData } } } #[unstable(feature = "ptr_internals", issue = "0")] +#[allow(deprecated)] impl<'a, T: ?Sized> From<&'a T> for Unique<T> { fn from(reference: &'a T) -> Self { - Unique { pointer: NonZero::from(reference), _marker: PhantomData } + Unique { pointer: NonZero(reference as _), _marker: PhantomData } } } @@ -2412,11 +2645,6 @@ impl<'a, T: ?Sized> From<NonNull<T>> for Unique<T> { } } -/// Previous name of `NonNull`. -#[rustc_deprecated(since = "1.25.0", reason = "renamed to `NonNull`")] -#[unstable(feature = "shared", issue = "27730")] -pub type Shared<T> = NonNull<T>; - /// `*mut T` but non-zero and covariant. /// /// This is often the correct thing to use when building data structures using @@ -2425,7 +2653,7 @@ pub type Shared<T> = NonNull<T>; /// /// Unlike `*mut T`, the pointer must always be non-null, even if the pointer /// is never dereferenced. This is so that enums may use this forbidden value -/// as a discriminant -- `Option<NonNull<T>>` has the same size as `NonNull<T>`. +/// as a discriminant -- `Option<NonNull<T>>` has the same size as `*mut T`. /// However the pointer may still dangle if it isn't dereferenced. /// /// Unlike `*mut T`, `NonNull<T>` is covariant over `T`. If this is incorrect @@ -2436,7 +2664,7 @@ pub type Shared<T> = NonNull<T>; /// provide a public API that follows the normal shared XOR mutable rules of Rust. #[stable(feature = "nonnull", since = "1.25.0")] pub struct NonNull<T: ?Sized> { - pointer: NonZero<*const T>, + #[allow(deprecated)] pointer: NonZero<*const T>, } /// `NonNull` pointers are not `Send` because the data they reference may be aliased. @@ -2463,6 +2691,7 @@ impl<T: Sized> NonNull<T> { } } +#[allow(deprecated)] impl<T: ?Sized> NonNull<T> { /// Creates a new `NonNull`. /// @@ -2471,19 +2700,23 @@ impl<T: ?Sized> NonNull<T> { /// `ptr` must be non-null. #[stable(feature = "nonnull", since = "1.25.0")] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { - NonNull { pointer: NonZero::new_unchecked(ptr) } + NonNull { pointer: NonZero(ptr as _) } } /// Creates a new `NonNull` if `ptr` is non-null. #[stable(feature = "nonnull", since = "1.25.0")] pub fn new(ptr: *mut T) -> Option<Self> { - NonZero::new(ptr as *const T).map(|nz| NonNull { pointer: nz }) + if !ptr.is_null() { + Some(NonNull { pointer: NonZero(ptr as _) }) + } else { + None + } } /// Acquires the underlying `*mut` pointer. #[stable(feature = "nonnull", since = "1.25.0")] pub fn as_ptr(self) -> *mut T { - self.pointer.get() as *mut T + self.pointer.0 as *mut T } /// Dereferences the content. @@ -2581,15 +2814,17 @@ impl<T: ?Sized> From<Unique<T>> for NonNull<T> { } #[stable(feature = "nonnull", since = "1.25.0")] +#[allow(deprecated)] impl<'a, T: ?Sized> From<&'a mut T> for NonNull<T> { fn from(reference: &'a mut T) -> Self { - NonNull { pointer: NonZero::from(reference) } + NonNull { pointer: NonZero(reference as _) } } } #[stable(feature = "nonnull", since = "1.25.0")] +#[allow(deprecated)] impl<'a, T: ?Sized> From<&'a T> for NonNull<T> { fn from(reference: &'a T) -> Self { - NonNull { pointer: NonZero::from(reference) } + NonNull { pointer: NonZero(reference as _) } } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 9cf862bd936..1185b7acaae 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -165,6 +165,37 @@ Section: Creating a string /// /// [`String`]: ../../std/string/struct.String.html#method.from_utf8 /// [`&str`]: ../../std/str/fn.from_utf8.html +/// +/// # Examples +/// +/// This error type’s methods can be used to create functionality +/// similar to `String::from_utf8_lossy` without allocating heap memory: +/// +/// ``` +/// fn from_utf8_lossy<F>(mut input: &[u8], mut push: F) where F: FnMut(&str) { +/// loop { +/// match ::std::str::from_utf8(input) { +/// Ok(valid) => { +/// push(valid); +/// break +/// } +/// Err(error) => { +/// let (valid, after_valid) = input.split_at(error.valid_up_to()); +/// unsafe { +/// push(::std::str::from_utf8_unchecked(valid)) +/// } +/// push("\u{FFFD}"); +/// +/// if let Some(invalid_sequence_length) = error.error_len() { +/// input = &after_valid[invalid_sequence_length..] +/// } else { +/// break +/// } +/// } +/// } +/// } +/// } +/// ``` #[derive(Copy, Eq, PartialEq, Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Utf8Error { diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 25827edee7d..d336934ec72 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -205,8 +205,11 @@ pub enum Ordering { /// [`Release`]: http://llvm.org/docs/Atomics.html#release #[stable(feature = "rust1", since = "1.0.0")] Acquire, - /// When coupled with a load, uses [`Acquire`] ordering, and with a store - /// [`Release`] ordering. + /// Has the effects of both [`Acquire`] and [`Release`] together. + /// + /// This ordering is only applicable for operations that combine both loads and stores. + /// + /// For loads it uses [`Acquire`] ordering. For stores it uses the [`Release`] ordering. /// /// [`Acquire`]: http://llvm.org/docs/Atomics.html#acquire /// [`Release`]: http://llvm.org/docs/Atomics.html#release @@ -948,6 +951,8 @@ macro_rules! atomic_int { $stable_from:meta, $stable_nand:meta, $s_int_type:expr, $int_ref:expr, + $extra_feature:expr, + $min_fn:ident, $max_fn:ident, $int_type:ident $atomic_type:ident $atomic_init:ident) => { /// An integer type which can be safely shared between threads. /// @@ -959,12 +964,7 @@ macro_rules! atomic_int { /// ). For more about the differences between atomic types and /// non-atomic types, please see the [module-level documentation]. /// - /// Please note that examples are shared between atomic variants of - /// primitive integer types, so it's normal that they are all - /// demonstrating [`AtomicIsize`]. - /// /// [module-level documentation]: index.html - /// [`AtomicIsize`]: struct.AtomicIsize.html #[$stable] pub struct $atomic_type { v: UnsafeCell<$int_type>, @@ -1001,396 +1001,549 @@ macro_rules! atomic_int { unsafe impl Sync for $atomic_type {} impl $atomic_type { - /// Creates a new atomic integer. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::AtomicIsize; - /// - /// let atomic_forty_two = AtomicIsize::new(42); - /// ``` - #[inline] - #[$stable] - pub const fn new(v: $int_type) -> Self { - $atomic_type {v: UnsafeCell::new(v)} + doc_comment! { + concat!("Creates a new atomic integer. + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::", stringify!($atomic_type), "; + +let atomic_forty_two = ", stringify!($atomic_type), "::new(42); +```"), + #[inline] + #[$stable] + pub const fn new(v: $int_type) -> Self { + $atomic_type {v: UnsafeCell::new(v)} + } } - /// Returns a mutable reference to the underlying integer. - /// - /// This is safe because the mutable reference guarantees that no other threads are - /// concurrently accessing the atomic data. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let mut some_isize = AtomicIsize::new(10); - /// assert_eq!(*some_isize.get_mut(), 10); - /// *some_isize.get_mut() = 5; - /// assert_eq!(some_isize.load(Ordering::SeqCst), 5); - /// ``` - #[inline] - #[$stable_access] - pub fn get_mut(&mut self) -> &mut $int_type { - unsafe { &mut *self.v.get() } + doc_comment! { + concat!("Returns a mutable reference to the underlying integer. + +This is safe because the mutable reference guarantees that no other threads are +concurrently accessing the atomic data. + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let mut some_var = ", stringify!($atomic_type), "::new(10); +assert_eq!(*some_var.get_mut(), 10); +*some_var.get_mut() = 5; +assert_eq!(some_var.load(Ordering::SeqCst), 5); +```"), + #[inline] + #[$stable_access] + pub fn get_mut(&mut self) -> &mut $int_type { + unsafe { &mut *self.v.get() } + } } - /// Consumes the atomic and returns the contained value. - /// - /// This is safe because passing `self` by value guarantees that no other threads are - /// concurrently accessing the atomic data. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::AtomicIsize; - /// - /// let some_isize = AtomicIsize::new(5); - /// assert_eq!(some_isize.into_inner(), 5); - /// ``` - #[inline] - #[$stable_access] - pub fn into_inner(self) -> $int_type { - self.v.into_inner() + doc_comment! { + concat!("Consumes the atomic and returns the contained value. + +This is safe because passing `self` by value guarantees that no other threads are +concurrently accessing the atomic data. + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::", stringify!($atomic_type), "; + +let some_var = ", stringify!($atomic_type), "::new(5); +assert_eq!(some_var.into_inner(), 5); +```"), + #[inline] + #[$stable_access] + pub fn into_inner(self) -> $int_type { + self.v.into_inner() + } } - /// Loads a value from the atomic integer. - /// - /// `load` takes an [`Ordering`] argument which describes the memory ordering of this - /// operation. - /// - /// # Panics - /// - /// Panics if `order` is [`Release`] or [`AcqRel`]. - /// - /// [`Ordering`]: enum.Ordering.html - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let some_isize = AtomicIsize::new(5); - /// - /// assert_eq!(some_isize.load(Ordering::Relaxed), 5); - /// ``` - #[inline] - #[$stable] - pub fn load(&self, order: Ordering) -> $int_type { - unsafe { atomic_load(self.v.get(), order) } + doc_comment! { + concat!("Loads a value from the atomic integer. + +`load` takes an [`Ordering`] argument which describes the memory ordering of this operation. + +# Panics + +Panics if `order` is [`Release`] or [`AcqRel`]. + +[`Ordering`]: enum.Ordering.html +[`Release`]: enum.Ordering.html#variant.Release +[`AcqRel`]: enum.Ordering.html#variant.AcqRel + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let some_var = ", stringify!($atomic_type), "::new(5); + +assert_eq!(some_var.load(Ordering::Relaxed), 5); +```"), + #[inline] + #[$stable] + pub fn load(&self, order: Ordering) -> $int_type { + unsafe { atomic_load(self.v.get(), order) } + } } - /// Stores a value into the atomic integer. - /// - /// `store` takes an [`Ordering`] argument which describes the memory ordering of this - /// operation. - /// - /// [`Ordering`]: enum.Ordering.html - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let some_isize = AtomicIsize::new(5); - /// - /// some_isize.store(10, Ordering::Relaxed); - /// assert_eq!(some_isize.load(Ordering::Relaxed), 10); - /// ``` - /// - /// # Panics - /// - /// Panics if `order` is [`Acquire`] or [`AcqRel`]. - /// - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - #[inline] - #[$stable] - pub fn store(&self, val: $int_type, order: Ordering) { - unsafe { atomic_store(self.v.get(), val, order); } + doc_comment! { + concat!("Stores a value into the atomic integer. + +`store` takes an [`Ordering`] argument which describes the memory ordering of this operation. + +[`Ordering`]: enum.Ordering.html + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let some_var = ", stringify!($atomic_type), "::new(5); + +some_var.store(10, Ordering::Relaxed); +assert_eq!(some_var.load(Ordering::Relaxed), 10); +``` + +# Panics + +Panics if `order` is [`Acquire`] or [`AcqRel`]. + +[`Acquire`]: enum.Ordering.html#variant.Acquire +[`AcqRel`]: enum.Ordering.html#variant.AcqRel"), + #[inline] + #[$stable] + pub fn store(&self, val: $int_type, order: Ordering) { + unsafe { atomic_store(self.v.get(), val, order); } + } } - /// Stores a value into the atomic integer, returning the previous value. - /// - /// `swap` takes an [`Ordering`] argument which describes the memory ordering of this - /// operation. - /// - /// [`Ordering`]: enum.Ordering.html - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let some_isize = AtomicIsize::new(5); - /// - /// assert_eq!(some_isize.swap(10, Ordering::Relaxed), 5); - /// ``` - #[inline] - #[$stable] - pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type { - unsafe { atomic_swap(self.v.get(), val, order) } + doc_comment! { + concat!("Stores a value into the atomic integer, returning the previous value. + +`swap` takes an [`Ordering`] argument which describes the memory ordering of this operation. + +[`Ordering`]: enum.Ordering.html + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let some_var = ", stringify!($atomic_type), "::new(5); + +assert_eq!(some_var.swap(10, Ordering::Relaxed), 5); +```"), + #[inline] + #[$stable] + pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { atomic_swap(self.v.get(), val, order) } + } } - /// Stores a value into the atomic integer if the current value is the same as the - /// `current` value. - /// - /// The return value is always the previous value. If it is equal to `current`, then the - /// value was updated. - /// - /// `compare_and_swap` also takes an [`Ordering`] argument which describes the memory - /// ordering of this operation. - /// - /// [`Ordering`]: enum.Ordering.html - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let some_isize = AtomicIsize::new(5); - /// - /// assert_eq!(some_isize.compare_and_swap(5, 10, Ordering::Relaxed), 5); - /// assert_eq!(some_isize.load(Ordering::Relaxed), 10); - /// - /// assert_eq!(some_isize.compare_and_swap(6, 12, Ordering::Relaxed), 10); - /// assert_eq!(some_isize.load(Ordering::Relaxed), 10); - /// ``` - #[inline] - #[$stable] - pub fn compare_and_swap(&self, - current: $int_type, - new: $int_type, - order: Ordering) -> $int_type { - match self.compare_exchange(current, - new, - order, - strongest_failure_ordering(order)) { - Ok(x) => x, - Err(x) => x, + doc_comment! { + concat!("Stores a value into the atomic integer if the current value is the same as +the `current` value. + +The return value is always the previous value. If it is equal to `current`, then the +value was updated. + +`compare_and_swap` also takes an [`Ordering`] argument which describes the memory +ordering of this operation. + +[`Ordering`]: enum.Ordering.html + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let some_var = ", stringify!($atomic_type), "::new(5); + +assert_eq!(some_var.compare_and_swap(5, 10, Ordering::Relaxed), 5); +assert_eq!(some_var.load(Ordering::Relaxed), 10); + +assert_eq!(some_var.compare_and_swap(6, 12, Ordering::Relaxed), 10); +assert_eq!(some_var.load(Ordering::Relaxed), 10); +```"), + #[inline] + #[$stable] + pub fn compare_and_swap(&self, + current: $int_type, + new: $int_type, + order: Ordering) -> $int_type { + match self.compare_exchange(current, + new, + order, + strongest_failure_ordering(order)) { + Ok(x) => x, + Err(x) => x, + } } } - /// Stores a value into the atomic integer if the current value is the same as the - /// `current` value. - /// - /// The return value is a result indicating whether the new value was written and - /// containing the previous value. On success this value is guaranteed to be equal to - /// `current`. - /// - /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory - /// ordering of this operation. The first describes the required ordering if - /// the operation succeeds while the second describes the required ordering when - /// the operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and - /// must be equivalent or weaker than the success ordering. - /// - /// [`Ordering`]: enum.Ordering.html - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let some_isize = AtomicIsize::new(5); - /// - /// assert_eq!(some_isize.compare_exchange(5, 10, - /// Ordering::Acquire, - /// Ordering::Relaxed), - /// Ok(5)); - /// assert_eq!(some_isize.load(Ordering::Relaxed), 10); - /// - /// assert_eq!(some_isize.compare_exchange(6, 12, - /// Ordering::SeqCst, - /// Ordering::Acquire), - /// Err(10)); - /// assert_eq!(some_isize.load(Ordering::Relaxed), 10); - /// ``` - #[inline] - #[$stable_cxchg] - pub fn compare_exchange(&self, - current: $int_type, - new: $int_type, - success: Ordering, - failure: Ordering) -> Result<$int_type, $int_type> { - unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) } + doc_comment! { + concat!("Stores a value into the atomic integer if the current value is the same as +the `current` value. + +The return value is a result indicating whether the new value was written and +containing the previous value. On success this value is guaranteed to be equal to +`current`. + +`compare_exchange` takes two [`Ordering`] arguments to describe the memory +ordering of this operation. The first describes the required ordering if +the operation succeeds while the second describes the required ordering when +the operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and +must be equivalent or weaker than the success ordering. + +[`Ordering`]: enum.Ordering.html +[`Release`]: enum.Ordering.html#variant.Release +[`AcqRel`]: enum.Ordering.html#variant.AcqRel + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let some_var = ", stringify!($atomic_type), "::new(5); + +assert_eq!(some_var.compare_exchange(5, 10, + Ordering::Acquire, + Ordering::Relaxed), + Ok(5)); +assert_eq!(some_var.load(Ordering::Relaxed), 10); + +assert_eq!(some_var.compare_exchange(6, 12, + Ordering::SeqCst, + Ordering::Acquire), + Err(10)); +assert_eq!(some_var.load(Ordering::Relaxed), 10); +```"), + #[inline] + #[$stable_cxchg] + pub fn compare_exchange(&self, + current: $int_type, + new: $int_type, + success: Ordering, + failure: Ordering) -> Result<$int_type, $int_type> { + unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) } + } } - /// Stores a value into the atomic integer if the current value is the same as the - /// `current` value. - /// - /// Unlike [`compare_exchange`], this function is allowed to spuriously fail even - /// when the comparison succeeds, which can result in more efficient code on some - /// platforms. The return value is a result indicating whether the new value was - /// written and containing the previous value. - /// - /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory - /// ordering of this operation. The first describes the required ordering if the - /// operation succeeds while the second describes the required ordering when the - /// operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and - /// must be equivalent or weaker than the success ordering. - /// - /// [`compare_exchange`]: #method.compare_exchange - /// [`Ordering`]: enum.Ordering.html - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let val = AtomicIsize::new(4); - /// - /// let mut old = val.load(Ordering::Relaxed); - /// loop { - /// let new = old * 2; - /// match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) { - /// Ok(_) => break, - /// Err(x) => old = x, - /// } - /// } - /// ``` - #[inline] - #[$stable_cxchg] - pub fn compare_exchange_weak(&self, - current: $int_type, - new: $int_type, - success: Ordering, - failure: Ordering) -> Result<$int_type, $int_type> { - unsafe { - atomic_compare_exchange_weak(self.v.get(), current, new, success, failure) + doc_comment! { + concat!("Stores a value into the atomic integer if the current value is the same as +the `current` value. + +Unlike [`compare_exchange`], this function is allowed to spuriously fail even +when the comparison succeeds, which can result in more efficient code on some +platforms. The return value is a result indicating whether the new value was +written and containing the previous value. + +`compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory +ordering of this operation. The first describes the required ordering if the +operation succeeds while the second describes the required ordering when the +operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and +must be equivalent or weaker than the success ordering. + +[`compare_exchange`]: #method.compare_exchange +[`Ordering`]: enum.Ordering.html +[`Release`]: enum.Ordering.html#variant.Release +[`AcqRel`]: enum.Ordering.html#variant.AcqRel + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let val = ", stringify!($atomic_type), "::new(4); + +let mut old = val.load(Ordering::Relaxed); +loop { + let new = old * 2; + match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) { + Ok(_) => break, + Err(x) => old = x, + } +} +```"), + #[inline] + #[$stable_cxchg] + pub fn compare_exchange_weak(&self, + current: $int_type, + new: $int_type, + success: Ordering, + failure: Ordering) -> Result<$int_type, $int_type> { + unsafe { + atomic_compare_exchange_weak(self.v.get(), current, new, success, failure) + } } } - /// Adds to the current value, returning the previous value. - /// - /// This operation wraps around on overflow. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let foo = AtomicIsize::new(0); - /// assert_eq!(foo.fetch_add(10, Ordering::SeqCst), 0); - /// assert_eq!(foo.load(Ordering::SeqCst), 10); - /// ``` - #[inline] - #[$stable] - pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type { - unsafe { atomic_add(self.v.get(), val, order) } + doc_comment! { + concat!("Adds to the current value, returning the previous value. + +This operation wraps around on overflow. + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(0); +assert_eq!(foo.fetch_add(10, Ordering::SeqCst), 0); +assert_eq!(foo.load(Ordering::SeqCst), 10); +```"), + #[inline] + #[$stable] + pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { atomic_add(self.v.get(), val, order) } + } } - /// Subtracts from the current value, returning the previous value. - /// - /// This operation wraps around on overflow. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let foo = AtomicIsize::new(0); - /// assert_eq!(foo.fetch_sub(10, Ordering::SeqCst), 0); - /// assert_eq!(foo.load(Ordering::SeqCst), -10); - /// ``` - #[inline] - #[$stable] - pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type { - unsafe { atomic_sub(self.v.get(), val, order) } + doc_comment! { + concat!("Subtracts from the current value, returning the previous value. + +This operation wraps around on overflow. + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(20); +assert_eq!(foo.fetch_sub(10, Ordering::SeqCst), 20); +assert_eq!(foo.load(Ordering::SeqCst), 10); +```"), + #[inline] + #[$stable] + pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { atomic_sub(self.v.get(), val, order) } + } } - /// Bitwise "and" with the current value. - /// - /// Performs a bitwise "and" operation on the current value and the argument `val`, and - /// sets the new value to the result. - /// - /// Returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let foo = AtomicIsize::new(0b101101); - /// assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101); - /// assert_eq!(foo.load(Ordering::SeqCst), 0b100001); - #[inline] - #[$stable] - pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type { - unsafe { atomic_and(self.v.get(), val, order) } + doc_comment! { + concat!("Bitwise \"and\" with the current value. + +Performs a bitwise \"and\" operation on the current value and the argument `val`, and +sets the new value to the result. + +Returns the previous value. + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(0b101101); +assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101); +assert_eq!(foo.load(Ordering::SeqCst), 0b100001); +```"), + #[inline] + #[$stable] + pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { atomic_and(self.v.get(), val, order) } + } } - /// Bitwise "nand" with the current value. - /// - /// Performs a bitwise "nand" operation on the current value and the argument `val`, and - /// sets the new value to the result. - /// - /// Returns the previous value. - /// - /// # Examples - /// - /// ``` - /// #![feature(atomic_nand)] - /// - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let foo = AtomicIsize::new(0xf731); - /// assert_eq!(foo.fetch_nand(0x137f, Ordering::SeqCst), 0xf731); - /// assert_eq!(foo.load(Ordering::SeqCst), !(0xf731 & 0x137f)); - #[inline] - #[$stable_nand] - pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type { - unsafe { atomic_nand(self.v.get(), val, order) } + doc_comment! { + concat!("Bitwise \"nand\" with the current value. + +Performs a bitwise \"nand\" operation on the current value and the argument `val`, and +sets the new value to the result. + +Returns the previous value. + +# Examples + +``` +", $extra_feature, "#![feature(atomic_nand)] + +use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(0x13); +assert_eq!(foo.fetch_nand(0x31, Ordering::SeqCst), 0x13); +assert_eq!(foo.load(Ordering::SeqCst), !(0x13 & 0x31)); +```"), + #[inline] + #[$stable_nand] + pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { atomic_nand(self.v.get(), val, order) } + } } - /// Bitwise "or" with the current value. - /// - /// Performs a bitwise "or" operation on the current value and the argument `val`, and - /// sets the new value to the result. - /// - /// Returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let foo = AtomicIsize::new(0b101101); - /// assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101); - /// assert_eq!(foo.load(Ordering::SeqCst), 0b111111); - #[inline] - #[$stable] - pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type { - unsafe { atomic_or(self.v.get(), val, order) } + doc_comment! { + concat!("Bitwise \"or\" with the current value. + +Performs a bitwise \"or\" operation on the current value and the argument `val`, and +sets the new value to the result. + +Returns the previous value. + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(0b101101); +assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101); +assert_eq!(foo.load(Ordering::SeqCst), 0b111111); +```"), + #[inline] + #[$stable] + pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { atomic_or(self.v.get(), val, order) } + } } - /// Bitwise "xor" with the current value. - /// - /// Performs a bitwise "xor" operation on the current value and the argument `val`, and - /// sets the new value to the result. - /// - /// Returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let foo = AtomicIsize::new(0b101101); - /// assert_eq!(foo.fetch_xor(0b110011, Ordering::SeqCst), 0b101101); - /// assert_eq!(foo.load(Ordering::SeqCst), 0b011110); - #[inline] - #[$stable] - pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type { - unsafe { atomic_xor(self.v.get(), val, order) } + doc_comment! { + concat!("Bitwise \"xor\" with the current value. + +Performs a bitwise \"xor\" operation on the current value and the argument `val`, and +sets the new value to the result. + +Returns the previous value. + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(0b101101); +assert_eq!(foo.fetch_xor(0b110011, Ordering::SeqCst), 0b101101); +assert_eq!(foo.load(Ordering::SeqCst), 0b011110); +```"), + #[inline] + #[$stable] + pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { atomic_xor(self.v.get(), val, order) } + } + } + + doc_comment! { + concat!("Fetches the value, and applies a function to it that returns an optional +new value. Returns a `Result` (`Ok(_)` if the function returned `Some(_)`, else `Err(_)`) of the +previous value. + +Note: This may call the function multiple times if the value has been changed from other threads in +the meantime, as long as the function returns `Some(_)`, but the function will have been applied +but once to the stored value. + +# Examples + +```rust +#![feature(no_more_cas)] +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let x = ", stringify!($atomic_type), "::new(7); +assert_eq!(x.fetch_update(|_| None, Ordering::SeqCst, Ordering::SeqCst), Err(7)); +assert_eq!(x.fetch_update(|x| Some(x + 1), Ordering::SeqCst, Ordering::SeqCst), Ok(7)); +assert_eq!(x.fetch_update(|x| Some(x + 1), Ordering::SeqCst, Ordering::SeqCst), Ok(8)); +assert_eq!(x.load(Ordering::SeqCst), 9); +```"), + #[inline] + #[unstable(feature = "no_more_cas", + reason = "no more CAS loops in user code", + issue = "48655")] + pub fn fetch_update<F>(&self, + mut f: F, + fetch_order: Ordering, + set_order: Ordering) -> Result<$int_type, $int_type> + where F: FnMut($int_type) -> Option<$int_type> { + let mut prev = self.load(fetch_order); + while let Some(next) = f(prev) { + match self.compare_exchange_weak(prev, next, set_order, fetch_order) { + x @ Ok(_) => return x, + Err(next_prev) => prev = next_prev + } + } + Err(prev) + } + } + + doc_comment! { + concat!("Maximum with the current value. + +Finds the maximum of the current value and the argument `val`, and +sets the new value to the result. + +Returns the previous value. + +# Examples + +``` +#![feature(atomic_min_max)] +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(23); +assert_eq!(foo.fetch_max(42, Ordering::SeqCst), 23); +assert_eq!(foo.load(Ordering::SeqCst), 42); +``` + +If you want to obtain the maximum value in one step, you can use the following: + +``` +#![feature(atomic_min_max)] +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(23); +let bar = 42; +let max_foo = foo.fetch_max(bar, Ordering::SeqCst).max(bar); +assert!(max_foo == 42); +```"), + #[inline] + #[unstable(feature = "atomic_min_max", + reason = "easier and faster min/max than writing manual CAS loop", + issue = "48655")] + pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { $max_fn(self.v.get(), val, order) } + } + } + + doc_comment! { + concat!("Minimum with the current value. + +Finds the minimum of the current value and the argument `val`, and +sets the new value to the result. + +Returns the previous value. + +# Examples + +``` +#![feature(atomic_min_max)] +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(23); +assert_eq!(foo.fetch_min(42, Ordering::Relaxed), 23); +assert_eq!(foo.load(Ordering::Relaxed), 23); +assert_eq!(foo.fetch_min(22, Ordering::Relaxed), 23); +assert_eq!(foo.load(Ordering::Relaxed), 22); +``` + +If you want to obtain the minimum value in one step, you can use the following: + +``` +#![feature(atomic_min_max)] +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(23); +let bar = 12; +let min_foo = foo.fetch_min(bar, Ordering::SeqCst).min(bar); +assert_eq!(min_foo, 12); +```"), + #[inline] + #[unstable(feature = "atomic_min_max", + reason = "easier and faster min/max than writing manual CAS loop", + issue = "48655")] + pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { $min_fn(self.v.get(), val, order) } + } } + } } } @@ -1404,6 +1557,8 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "atomic_nand", issue = "13226"), "i8", "../../../std/primitive.i8.html", + "#![feature(integer_atomics)]\n\n", + atomic_min, atomic_max, i8 AtomicI8 ATOMIC_I8_INIT } #[cfg(target_has_atomic = "8")] @@ -1415,6 +1570,8 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "atomic_nand", issue = "13226"), "u8", "../../../std/primitive.u8.html", + "#![feature(integer_atomics)]\n\n", + atomic_umin, atomic_umax, u8 AtomicU8 ATOMIC_U8_INIT } #[cfg(target_has_atomic = "16")] @@ -1426,6 +1583,8 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "atomic_nand", issue = "13226"), "i16", "../../../std/primitive.i16.html", + "#![feature(integer_atomics)]\n\n", + atomic_min, atomic_max, i16 AtomicI16 ATOMIC_I16_INIT } #[cfg(target_has_atomic = "16")] @@ -1437,6 +1596,8 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "atomic_nand", issue = "13226"), "u16", "../../../std/primitive.u16.html", + "#![feature(integer_atomics)]\n\n", + atomic_umin, atomic_umax, u16 AtomicU16 ATOMIC_U16_INIT } #[cfg(target_has_atomic = "32")] @@ -1448,6 +1609,8 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "atomic_nand", issue = "13226"), "i32", "../../../std/primitive.i32.html", + "#![feature(integer_atomics)]\n\n", + atomic_min, atomic_max, i32 AtomicI32 ATOMIC_I32_INIT } #[cfg(target_has_atomic = "32")] @@ -1459,6 +1622,8 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "atomic_nand", issue = "13226"), "u32", "../../../std/primitive.u32.html", + "#![feature(integer_atomics)]\n\n", + atomic_umin, atomic_umax, u32 AtomicU32 ATOMIC_U32_INIT } #[cfg(target_has_atomic = "64")] @@ -1470,6 +1635,8 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "atomic_nand", issue = "13226"), "i64", "../../../std/primitive.i64.html", + "#![feature(integer_atomics)]\n\n", + atomic_min, atomic_max, i64 AtomicI64 ATOMIC_I64_INIT } #[cfg(target_has_atomic = "64")] @@ -1481,6 +1648,8 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "atomic_nand", issue = "13226"), "u64", "../../../std/primitive.u64.html", + "#![feature(integer_atomics)]\n\n", + atomic_umin, atomic_umax, u64 AtomicU64 ATOMIC_U64_INIT } #[cfg(target_has_atomic = "ptr")] @@ -1492,6 +1661,8 @@ atomic_int!{ stable(feature = "atomic_from", since = "1.23.0"), unstable(feature = "atomic_nand", issue = "13226"), "isize", "../../../std/primitive.isize.html", + "", + atomic_min, atomic_max, isize AtomicIsize ATOMIC_ISIZE_INIT } #[cfg(target_has_atomic = "ptr")] @@ -1503,6 +1674,8 @@ atomic_int!{ stable(feature = "atomic_from", since = "1.23.0"), unstable(feature = "atomic_nand", issue = "13226"), "usize", "../../../std/primitive.usize.html", + "", + atomic_umin, atomic_umax, usize AtomicUsize ATOMIC_USIZE_INIT } @@ -1680,6 +1853,58 @@ unsafe fn atomic_xor<T>(dst: *mut T, val: T, order: Ordering) -> T { } } +/// returns the max value (signed comparison) +#[inline] +unsafe fn atomic_max<T>(dst: *mut T, val: T, order: Ordering) -> T { + match order { + Acquire => intrinsics::atomic_max_acq(dst, val), + Release => intrinsics::atomic_max_rel(dst, val), + AcqRel => intrinsics::atomic_max_acqrel(dst, val), + Relaxed => intrinsics::atomic_max_relaxed(dst, val), + SeqCst => intrinsics::atomic_max(dst, val), + __Nonexhaustive => panic!("invalid memory ordering"), + } +} + +/// returns the min value (signed comparison) +#[inline] +unsafe fn atomic_min<T>(dst: *mut T, val: T, order: Ordering) -> T { + match order { + Acquire => intrinsics::atomic_min_acq(dst, val), + Release => intrinsics::atomic_min_rel(dst, val), + AcqRel => intrinsics::atomic_min_acqrel(dst, val), + Relaxed => intrinsics::atomic_min_relaxed(dst, val), + SeqCst => intrinsics::atomic_min(dst, val), + __Nonexhaustive => panic!("invalid memory ordering"), + } +} + +/// returns the max value (signed comparison) +#[inline] +unsafe fn atomic_umax<T>(dst: *mut T, val: T, order: Ordering) -> T { + match order { + Acquire => intrinsics::atomic_umax_acq(dst, val), + Release => intrinsics::atomic_umax_rel(dst, val), + AcqRel => intrinsics::atomic_umax_acqrel(dst, val), + Relaxed => intrinsics::atomic_umax_relaxed(dst, val), + SeqCst => intrinsics::atomic_umax(dst, val), + __Nonexhaustive => panic!("invalid memory ordering"), + } +} + +/// returns the min value (signed comparison) +#[inline] +unsafe fn atomic_umin<T>(dst: *mut T, val: T, order: Ordering) -> T { + match order { + Acquire => intrinsics::atomic_umin_acq(dst, val), + Release => intrinsics::atomic_umin_rel(dst, val), + AcqRel => intrinsics::atomic_umin_acqrel(dst, val), + Relaxed => intrinsics::atomic_umin_relaxed(dst, val), + SeqCst => intrinsics::atomic_umin(dst, val), + __Nonexhaustive => panic!("invalid memory ordering"), + } +} + /// An atomic fence. /// /// Depending on the specified order, a fence prevents the compiler and CPU from diff --git a/src/libcore/tests/ascii.rs b/src/libcore/tests/ascii.rs index 4d43067ad2c..950222dbcfa 100644 --- a/src/libcore/tests/ascii.rs +++ b/src/libcore/tests/ascii.rs @@ -9,7 +9,6 @@ // except according to those terms. use core::char::from_u32; -use std::ascii::AsciiExt; #[test] fn test_is_ascii() { @@ -143,8 +142,6 @@ macro_rules! assert_all { stringify!($what), b); } } - assert!($str.$what()); - assert!($str.as_bytes().$what()); )+ }}; ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+)) diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index a962efadd64..2abac0cf1d5 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1147,6 +1147,33 @@ fn test_find() { } #[test] +fn test_find_map() { + let xs: &[isize] = &[]; + assert_eq!(xs.iter().find_map(half_if_even), None); + let xs: &[isize] = &[3, 5]; + assert_eq!(xs.iter().find_map(half_if_even), None); + let xs: &[isize] = &[4, 5]; + assert_eq!(xs.iter().find_map(half_if_even), Some(2)); + let xs: &[isize] = &[3, 6]; + assert_eq!(xs.iter().find_map(half_if_even), Some(3)); + + let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7]; + let mut iter = xs.iter(); + assert_eq!(iter.find_map(half_if_even), Some(1)); + assert_eq!(iter.find_map(half_if_even), Some(2)); + assert_eq!(iter.find_map(half_if_even), Some(3)); + assert_eq!(iter.next(), Some(&7)); + + fn half_if_even(x: &isize) -> Option<isize> { + if x % 2 == 0 { + Some(x / 2) + } else { + None + } + } +} + +#[test] fn test_position() { let v = &[1, 3, 9, 27, 103, 14, 11]; assert_eq!(v.iter().position(|x| *x & 1 == 0).unwrap(), 5); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index e9a8113ef10..de7211e718c 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -23,13 +23,10 @@ #![feature(fmt_internals)] #![feature(hashmap_internals)] #![feature(iterator_step_by)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] -#![feature(iterator_try_fold)] #![feature(iterator_flatten)] -#![feature(conservative_impl_trait)] -#![feature(iter_rfind)] -#![feature(iter_rfold)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(iterator_repeat_with)] #![feature(nonzero)] #![feature(pattern)] @@ -43,12 +40,12 @@ #![feature(step_trait)] #![feature(test)] #![feature(trusted_len)] -#![feature(try_from)] #![feature(try_trait)] #![feature(exact_chunks)] #![feature(atomic_nand)] #![feature(reverse_bits)] #![feature(inclusive_range_fields)] +#![feature(iterator_find_map)] extern crate core; extern crate test; diff --git a/src/libcore/tests/nonzero.rs b/src/libcore/tests/nonzero.rs index a795dd57504..8d39298bac3 100644 --- a/src/libcore/tests/nonzero.rs +++ b/src/libcore/tests/nonzero.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::nonzero::NonZero; +use core::num::NonZeroU32; use core::option::Option; use core::option::Option::{Some, None}; use std::mem::size_of; @@ -16,28 +16,28 @@ use std::mem::size_of; #[test] fn test_create_nonzero_instance() { let _a = unsafe { - NonZero::new_unchecked(21) + NonZeroU32::new_unchecked(21) }; } #[test] fn test_size_nonzero_in_option() { - assert_eq!(size_of::<NonZero<u32>>(), size_of::<Option<NonZero<u32>>>()); + assert_eq!(size_of::<NonZeroU32>(), size_of::<Option<NonZeroU32>>()); } #[test] fn test_match_on_nonzero_option() { let a = Some(unsafe { - NonZero::new_unchecked(42) + NonZeroU32::new_unchecked(42) }); match a { Some(val) => assert_eq!(val.get(), 42), - None => panic!("unexpected None while matching on Some(NonZero(_))") + None => panic!("unexpected None while matching on Some(NonZeroU32(_))") } - match unsafe { Some(NonZero::new_unchecked(43)) } { + match unsafe { Some(NonZeroU32::new_unchecked(43)) } { Some(val) => assert_eq!(val.get(), 43), - None => panic!("unexpected None while matching on Some(NonZero(_))") + None => panic!("unexpected None while matching on Some(NonZeroU32(_))") } } @@ -98,3 +98,26 @@ fn test_match_option_string() { None => panic!("unexpected None while matching on Some(String { ... })") } } + +mod atom { + use core::num::NonZeroU32; + + #[derive(PartialEq, Eq)] + pub struct Atom { + index: NonZeroU32, // private + } + pub const FOO_ATOM: Atom = Atom { index: unsafe { NonZeroU32::new_unchecked(7) } }; +} + +macro_rules! atom { + ("foo") => { atom::FOO_ATOM } +} + +#[test] +fn test_match_nonzero_const_pattern() { + match atom!("foo") { + // Using as a pattern is supported by the compiler: + atom!("foo") => {} + _ => panic!("Expected the const item as a pattern to match.") + } +} diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index 587dcbe6d67..c7edb55b378 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -37,15 +37,6 @@ mod flt2dec; mod dec2flt; mod bignum; - -/// Adds the attribute to all items in the block. -macro_rules! cfg_block { - ($(#[$attr:meta]{$($it:item)*})*) => {$($( - #[$attr] - $it - )*)*} -} - /// Groups items that assume the pointer width is either 16/32/64, and has to be altered if /// support for larger/smaller pointer widths are added in the future. macro_rules! assume_usize_width { @@ -318,42 +309,6 @@ assume_usize_width! { test_impl_try_from_always_ok! { test_try_u16usize, u16, usize } test_impl_try_from_always_ok! { test_try_i16isize, i16, isize } - - test_impl_try_from_always_ok! { test_try_usizeu64, usize, u64 } - test_impl_try_from_always_ok! { test_try_usizeu128, usize, u128 } - test_impl_try_from_always_ok! { test_try_usizei128, usize, i128 } - - test_impl_try_from_always_ok! { test_try_isizei64, isize, i64 } - test_impl_try_from_always_ok! { test_try_isizei128, isize, i128 } - - cfg_block!( - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_always_ok! { test_try_usizeu16, usize, u16 } - test_impl_try_from_always_ok! { test_try_isizei16, isize, i16 } - test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } - test_impl_try_from_always_ok! { test_try_usizei32, usize, i32 } - test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } - test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } - } - - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } - test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } - test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } - test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } - test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } - test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } - } - - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } - test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } - test_impl_try_from_always_ok! { test_try_u32isize, u32, isize } - test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } - test_impl_try_from_always_ok! { test_try_u64usize, u64, usize } - test_impl_try_from_always_ok! { test_try_i64isize, i64, isize } - } - ); } /// Conversions where max of $source can be represented as $target, @@ -402,24 +357,6 @@ assume_usize_width! { test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu64, isize, u64 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu128, isize, u128 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeusize, isize, usize } - - cfg_block!( - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu16, isize, u16 } - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } - } - - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } - - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } - } - - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64usize, i64, usize } - } - ); } /// Conversions where max of $source can not be represented as $target, @@ -461,29 +398,9 @@ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i64, u128, i64 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i128, u128, i128 } assume_usize_width! { - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64isize, u64, isize } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128isize, u128, isize } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei8, usize, i8 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei16, usize, i16 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizeisize, usize, isize } - - cfg_block!( - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16isize, u16, isize } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } - } - - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } - } - - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei64, usize, i64 } - } - ); } /// Conversions where min/max of $source can not be represented as $target. @@ -543,34 +460,6 @@ test_impl_try_from_same_sign_err! { test_try_i128i64, i128, i64 } assume_usize_width! { test_impl_try_from_same_sign_err! { test_try_usizeu8, usize, u8 } - test_impl_try_from_same_sign_err! { test_try_u128usize, u128, usize } - test_impl_try_from_same_sign_err! { test_try_i128isize, i128, isize } - - cfg_block!( - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_same_sign_err! { test_try_u32usize, u32, usize } - test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } - - test_impl_try_from_same_sign_err! { test_try_i32isize, i32, isize } - test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } - } - - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } - test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } - - test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } - test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } - } - - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } - test_impl_try_from_same_sign_err! { test_try_usizeu32, usize, u32 } - - test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } - test_impl_try_from_same_sign_err! { test_try_isizei32, isize, i32 } - } - ); } /// Conversions where neither the min nor the max of $source can be represented by @@ -615,22 +504,6 @@ test_impl_try_from_signed_to_unsigned_err! { test_try_i128u64, i128, u64 } assume_usize_width! { test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu8, isize, u8 } test_impl_try_from_signed_to_unsigned_err! { test_try_i128usize, i128, usize } - - cfg_block! { - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_signed_to_unsigned_err! { test_try_i32usize, i32, usize } - test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } - } - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } - - test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } - } - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } - test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu32, isize, u32 } - } - } } macro_rules! test_float { |
