mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 22:34:05 +00:00
Auto merge of #76637 - RalfJung:rollup-eaykf93, r=RalfJung
Rollup of 7 pull requests Successful merges: - #76114 (Add saturating methods for `Duration`) - #76297 (rustdoc: fix min_const_generics with ty::Param) - #76484 (Add MaybeUninit::assume_init_drop.) - #76530 (Eliminate mut reference UB in Drop impl for Rc<T>) - #76583 (Update `std::os` module documentation.) - #76599 (Finish off revisions for const generics UI tests.) - #76615 (Add missing examples on binary core traits) Failed merges: r? `@ghost`
This commit is contained in:
commit
2d6cbd21b2
@ -295,6 +295,13 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {}
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Rc<U>> for Rc<T> {}
|
||||
|
||||
impl<T: ?Sized> Rc<T> {
|
||||
#[inline(always)]
|
||||
fn inner(&self) -> &RcBox<T> {
|
||||
// This unsafety is ok because while this Rc is alive we're guaranteed
|
||||
// that the inner pointer is valid.
|
||||
unsafe { self.ptr.as_ref() }
|
||||
}
|
||||
|
||||
fn from_inner(ptr: NonNull<RcBox<T>>) -> Self {
|
||||
Self { ptr, phantom: PhantomData }
|
||||
}
|
||||
@ -469,7 +476,7 @@ impl<T> Rc<T> {
|
||||
// the strong count, and then remove the implicit "strong weak"
|
||||
// pointer while also handling drop logic by just crafting a
|
||||
// fake Weak.
|
||||
this.dec_strong();
|
||||
this.inner().dec_strong();
|
||||
let _weak = Weak { ptr: this.ptr };
|
||||
forget(this);
|
||||
Ok(val)
|
||||
@ -735,7 +742,7 @@ impl<T: ?Sized> Rc<T> {
|
||||
/// ```
|
||||
#[stable(feature = "rc_weak", since = "1.4.0")]
|
||||
pub fn downgrade(this: &Self) -> Weak<T> {
|
||||
this.inc_weak();
|
||||
this.inner().inc_weak();
|
||||
// Make sure we do not create a dangling Weak
|
||||
debug_assert!(!is_dangling(this.ptr));
|
||||
Weak { ptr: this.ptr }
|
||||
@ -756,7 +763,7 @@ impl<T: ?Sized> Rc<T> {
|
||||
#[inline]
|
||||
#[stable(feature = "rc_counts", since = "1.15.0")]
|
||||
pub fn weak_count(this: &Self) -> usize {
|
||||
this.weak() - 1
|
||||
this.inner().weak() - 1
|
||||
}
|
||||
|
||||
/// Gets the number of strong (`Rc`) pointers to this allocation.
|
||||
@ -774,7 +781,7 @@ impl<T: ?Sized> Rc<T> {
|
||||
#[inline]
|
||||
#[stable(feature = "rc_counts", since = "1.15.0")]
|
||||
pub fn strong_count(this: &Self) -> usize {
|
||||
this.strong()
|
||||
this.inner().strong()
|
||||
}
|
||||
|
||||
/// Returns `true` if there are no other `Rc` or [`Weak`] pointers to
|
||||
@ -844,7 +851,9 @@ impl<T: ?Sized> Rc<T> {
|
||||
#[inline]
|
||||
#[unstable(feature = "get_mut_unchecked", issue = "63292")]
|
||||
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
|
||||
unsafe { &mut this.ptr.as_mut().value }
|
||||
// We are careful to *not* create a reference covering the "count" fields, as
|
||||
// this would conflict with accesses to the reference counts (e.g. by `Weak`).
|
||||
unsafe { &mut (*this.ptr.as_ptr()).value }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -931,10 +940,10 @@ impl<T: Clone> Rc<T> {
|
||||
unsafe {
|
||||
let mut swap = Rc::new(ptr::read(&this.ptr.as_ref().value));
|
||||
mem::swap(this, &mut swap);
|
||||
swap.dec_strong();
|
||||
swap.inner().dec_strong();
|
||||
// Remove implicit strong-weak ref (no need to craft a fake
|
||||
// Weak here -- we know other Weaks can clean up for us)
|
||||
swap.dec_weak();
|
||||
swap.inner().dec_weak();
|
||||
forget(swap);
|
||||
}
|
||||
}
|
||||
@ -1192,16 +1201,16 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
|
||||
/// ```
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.dec_strong();
|
||||
if self.strong() == 0 {
|
||||
self.inner().dec_strong();
|
||||
if self.inner().strong() == 0 {
|
||||
// destroy the contained object
|
||||
ptr::drop_in_place(self.ptr.as_mut());
|
||||
ptr::drop_in_place(Self::get_mut_unchecked(self));
|
||||
|
||||
// remove the implicit "strong weak" pointer now that we've
|
||||
// destroyed the contents.
|
||||
self.dec_weak();
|
||||
self.inner().dec_weak();
|
||||
|
||||
if self.weak() == 0 {
|
||||
if self.inner().weak() == 0 {
|
||||
Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
|
||||
}
|
||||
}
|
||||
@ -1227,7 +1236,7 @@ impl<T: ?Sized> Clone for Rc<T> {
|
||||
/// ```
|
||||
#[inline]
|
||||
fn clone(&self) -> Rc<T> {
|
||||
self.inc_strong();
|
||||
self.inner().inc_strong();
|
||||
Self::from_inner(self.ptr)
|
||||
}
|
||||
}
|
||||
@ -1851,6 +1860,13 @@ pub(crate) fn is_dangling<T: ?Sized>(ptr: NonNull<T>) -> bool {
|
||||
address == usize::MAX
|
||||
}
|
||||
|
||||
/// Helper type to allow accessing the reference counts without
|
||||
/// making any assertions about the data field.
|
||||
struct WeakInner<'a> {
|
||||
weak: &'a Cell<usize>,
|
||||
strong: &'a Cell<usize>,
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Weak<T> {
|
||||
/// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying
|
||||
/// dropping of the inner value if successful.
|
||||
@ -1910,11 +1926,21 @@ impl<T: ?Sized> Weak<T> {
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
/// Returns `None` when the pointer is dangling and there is no allocated `RcBox`
|
||||
/// Returns `None` when the pointer is dangling and there is no allocated `RcBox`,
|
||||
/// (i.e., when this `Weak` was created by `Weak::new`).
|
||||
#[inline]
|
||||
fn inner(&self) -> Option<&RcBox<T>> {
|
||||
if is_dangling(self.ptr) { None } else { Some(unsafe { self.ptr.as_ref() }) }
|
||||
fn inner(&self) -> Option<WeakInner<'_>> {
|
||||
if is_dangling(self.ptr) {
|
||||
None
|
||||
} else {
|
||||
// We are careful to *not* create a reference covering the "data" field, as
|
||||
// the field may be mutated concurrently (for example, if the last `Rc`
|
||||
// is dropped, the data field will be dropped in-place).
|
||||
Some(unsafe {
|
||||
let ptr = self.ptr.as_ptr();
|
||||
WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the two `Weak`s point to the same allocation (similar to
|
||||
@ -1992,14 +2018,14 @@ impl<T: ?Sized> Drop for Weak<T> {
|
||||
/// assert!(other_weak_foo.upgrade().is_none());
|
||||
/// ```
|
||||
fn drop(&mut self) {
|
||||
if let Some(inner) = self.inner() {
|
||||
inner.dec_weak();
|
||||
// the weak count starts at 1, and will only go to zero if all
|
||||
// the strong pointers have disappeared.
|
||||
if inner.weak() == 0 {
|
||||
unsafe {
|
||||
Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
|
||||
}
|
||||
let inner = if let Some(inner) = self.inner() { inner } else { return };
|
||||
|
||||
inner.dec_weak();
|
||||
// the weak count starts at 1, and will only go to zero if all
|
||||
// the strong pointers have disappeared.
|
||||
if inner.weak() == 0 {
|
||||
unsafe {
|
||||
Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2065,12 +2091,13 @@ impl<T> Default for Weak<T> {
|
||||
// clone these much in Rust thanks to ownership and move-semantics.
|
||||
|
||||
#[doc(hidden)]
|
||||
trait RcBoxPtr<T: ?Sized> {
|
||||
fn inner(&self) -> &RcBox<T>;
|
||||
trait RcInnerPtr {
|
||||
fn weak_ref(&self) -> &Cell<usize>;
|
||||
fn strong_ref(&self) -> &Cell<usize>;
|
||||
|
||||
#[inline]
|
||||
fn strong(&self) -> usize {
|
||||
self.inner().strong.get()
|
||||
self.strong_ref().get()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -2084,17 +2111,17 @@ trait RcBoxPtr<T: ?Sized> {
|
||||
if strong == 0 || strong == usize::MAX {
|
||||
abort();
|
||||
}
|
||||
self.inner().strong.set(strong + 1);
|
||||
self.strong_ref().set(strong + 1);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn dec_strong(&self) {
|
||||
self.inner().strong.set(self.strong() - 1);
|
||||
self.strong_ref().set(self.strong() - 1);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn weak(&self) -> usize {
|
||||
self.inner().weak.get()
|
||||
self.weak_ref().get()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -2108,26 +2135,36 @@ trait RcBoxPtr<T: ?Sized> {
|
||||
if weak == 0 || weak == usize::MAX {
|
||||
abort();
|
||||
}
|
||||
self.inner().weak.set(weak + 1);
|
||||
self.weak_ref().set(weak + 1);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn dec_weak(&self) {
|
||||
self.inner().weak.set(self.weak() - 1);
|
||||
self.weak_ref().set(self.weak() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> RcBoxPtr<T> for Rc<T> {
|
||||
impl<T: ?Sized> RcInnerPtr for RcBox<T> {
|
||||
#[inline(always)]
|
||||
fn inner(&self) -> &RcBox<T> {
|
||||
unsafe { self.ptr.as_ref() }
|
||||
fn weak_ref(&self) -> &Cell<usize> {
|
||||
&self.weak
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn strong_ref(&self) -> &Cell<usize> {
|
||||
&self.strong
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> RcBoxPtr<T> for RcBox<T> {
|
||||
impl<'a> RcInnerPtr for WeakInner<'a> {
|
||||
#[inline(always)]
|
||||
fn inner(&self) -> &RcBox<T> {
|
||||
self
|
||||
fn weak_ref(&self) -> &Cell<usize> {
|
||||
self.weak
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn strong_ref(&self) -> &Cell<usize> {
|
||||
self.strong
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
|
||||
// dead now (i.e. do not touch). As `idx` was the start of the
|
||||
// alive-zone, the alive zone is now `data[alive]` again, restoring
|
||||
// all invariants.
|
||||
unsafe { self.data.get_unchecked(idx).read() }
|
||||
unsafe { self.data.get_unchecked(idx).assume_init_read() }
|
||||
})
|
||||
}
|
||||
|
||||
@ -136,7 +136,7 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
|
||||
// dead now (i.e. do not touch). As `idx` was the end of the
|
||||
// alive-zone, the alive zone is now `data[alive]` again, restoring
|
||||
// all invariants.
|
||||
unsafe { self.data.get_unchecked(idx).read() }
|
||||
unsafe { self.data.get_unchecked(idx).assume_init_read() }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -100,6 +100,7 @@
|
||||
#![feature(doc_cfg)]
|
||||
#![feature(doc_spotlight)]
|
||||
#![feature(duration_consts_2)]
|
||||
#![feature(duration_saturating_ops)]
|
||||
#![feature(extern_types)]
|
||||
#![feature(fundamental)]
|
||||
#![feature(intrinsics)]
|
||||
|
@ -2,6 +2,7 @@ use crate::any::type_name;
|
||||
use crate::fmt;
|
||||
use crate::intrinsics;
|
||||
use crate::mem::ManuallyDrop;
|
||||
use crate::ptr;
|
||||
|
||||
/// A wrapper type to construct uninitialized instances of `T`.
|
||||
///
|
||||
@ -471,6 +472,8 @@ impl<T> MaybeUninit<T> {
|
||||
/// *immediate* undefined behavior, but will cause undefined behavior with most
|
||||
/// safe operations (including dropping it).
|
||||
///
|
||||
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Correct usage of this method:
|
||||
@ -519,8 +522,8 @@ impl<T> MaybeUninit<T> {
|
||||
/// this initialization invariant.
|
||||
///
|
||||
/// Moreover, this leaves a copy of the same data behind in the `MaybeUninit<T>`. When using
|
||||
/// multiple copies of the data (by calling `read` multiple times, or first
|
||||
/// calling `read` and then [`assume_init`]), it is your responsibility
|
||||
/// multiple copies of the data (by calling `assume_init_read` multiple times, or first
|
||||
/// calling `assume_init_read` and then [`assume_init`]), it is your responsibility
|
||||
/// to ensure that that data may indeed be duplicated.
|
||||
///
|
||||
/// [inv]: #initialization-invariant
|
||||
@ -536,16 +539,16 @@ impl<T> MaybeUninit<T> {
|
||||
///
|
||||
/// let mut x = MaybeUninit::<u32>::uninit();
|
||||
/// x.write(13);
|
||||
/// let x1 = unsafe { x.read() };
|
||||
/// let x1 = unsafe { x.assume_init_read() };
|
||||
/// // `u32` is `Copy`, so we may read multiple times.
|
||||
/// let x2 = unsafe { x.read() };
|
||||
/// let x2 = unsafe { x.assume_init_read() };
|
||||
/// assert_eq!(x1, x2);
|
||||
///
|
||||
/// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit();
|
||||
/// x.write(None);
|
||||
/// let x1 = unsafe { x.read() };
|
||||
/// let x1 = unsafe { x.assume_init_read() };
|
||||
/// // Duplicating a `None` value is okay, so we may read multiple times.
|
||||
/// let x2 = unsafe { x.read() };
|
||||
/// let x2 = unsafe { x.assume_init_read() };
|
||||
/// assert_eq!(x1, x2);
|
||||
/// ```
|
||||
///
|
||||
@ -557,14 +560,14 @@ impl<T> MaybeUninit<T> {
|
||||
///
|
||||
/// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit();
|
||||
/// x.write(Some(vec![0,1,2]));
|
||||
/// let x1 = unsafe { x.read() };
|
||||
/// let x2 = unsafe { x.read() };
|
||||
/// let x1 = unsafe { x.assume_init_read() };
|
||||
/// let x2 = unsafe { x.assume_init_read() };
|
||||
/// // We now created two copies of the same vector, leading to a double-free ⚠️ when
|
||||
/// // they both get dropped!
|
||||
/// ```
|
||||
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn read(&self) -> T {
|
||||
pub unsafe fn assume_init_read(&self) -> T {
|
||||
// SAFETY: the caller must guarantee that `self` is initialized.
|
||||
// Reading from `self.as_ptr()` is safe since `self` should be initialized.
|
||||
unsafe {
|
||||
@ -573,6 +576,34 @@ impl<T> MaybeUninit<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Drops the contained value in place.
|
||||
///
|
||||
/// If you have ownership of the `MaybeUninit`, you can use [`assume_init`] instead.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee that the `MaybeUninit<T>` really is
|
||||
/// in an initialized state. Calling this when the content is not yet fully
|
||||
/// initialized causes undefined behavior.
|
||||
///
|
||||
/// On top of that, all additional invariants of the type `T` must be
|
||||
/// satisfied, as the `Drop` implementation of `T` (or its members) may
|
||||
/// rely on this. For example, a `1`-initialized [`Vec<T>`] is considered
|
||||
/// initialized (under the current implementation; this does not constitute
|
||||
/// a stable guarantee) because the only requirement the compiler knows
|
||||
/// about it is that the data pointer must be non-null. Dropping such a
|
||||
/// `Vec<T>` however will cause undefined behaviour.
|
||||
///
|
||||
/// [`assume_init`]: MaybeUninit::assume_init
|
||||
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
|
||||
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
|
||||
pub unsafe fn assume_init_drop(&mut self) {
|
||||
// SAFETY: the caller must guarantee that `self` is initialized and
|
||||
// satisfies all invariants of `T`.
|
||||
// Dropping the value in place is safe if that is the case.
|
||||
unsafe { ptr::drop_in_place(self.as_mut_ptr()) }
|
||||
}
|
||||
|
||||
/// Gets a shared reference to the contained value.
|
||||
///
|
||||
/// This can be useful when we want to access a `MaybeUninit` that has been
|
||||
|
@ -36,6 +36,15 @@ pub trait Not {
|
||||
type Output;
|
||||
|
||||
/// Performs the unary `!` operation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// assert_eq!(!true, false);
|
||||
/// assert_eq!(!false, true);
|
||||
/// assert_eq!(!1u8, 254);
|
||||
/// assert_eq!(!0u8, 255);
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn not(self) -> Self::Output;
|
||||
@ -122,6 +131,15 @@ pub trait BitAnd<Rhs = Self> {
|
||||
type Output;
|
||||
|
||||
/// Performs the `&` operation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// assert_eq!(true & false, false);
|
||||
/// assert_eq!(true & true, true);
|
||||
/// assert_eq!(5u8 & 1u8, 1);
|
||||
/// assert_eq!(5u8 & 2u8, 0);
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn bitand(self, rhs: Rhs) -> Self::Output;
|
||||
@ -208,6 +226,15 @@ pub trait BitOr<Rhs = Self> {
|
||||
type Output;
|
||||
|
||||
/// Performs the `|` operation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// assert_eq!(true | false, true);
|
||||
/// assert_eq!(false | false, false);
|
||||
/// assert_eq!(5u8 | 1u8, 5);
|
||||
/// assert_eq!(5u8 | 2u8, 7);
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn bitor(self, rhs: Rhs) -> Self::Output;
|
||||
@ -297,6 +324,15 @@ pub trait BitXor<Rhs = Self> {
|
||||
type Output;
|
||||
|
||||
/// Performs the `^` operation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// assert_eq!(true ^ false, true);
|
||||
/// assert_eq!(true ^ true, false);
|
||||
/// assert_eq!(5u8 ^ 1u8, 4);
|
||||
/// assert_eq!(5u8 ^ 2u8, 7);
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn bitxor(self, rhs: Rhs) -> Self::Output;
|
||||
@ -387,6 +423,13 @@ pub trait Shl<Rhs = Self> {
|
||||
type Output;
|
||||
|
||||
/// Performs the `<<` operation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// assert_eq!(5u8 << 1, 10);
|
||||
/// assert_eq!(1u8 << 1, 2);
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn shl(self, rhs: Rhs) -> Self::Output;
|
||||
@ -498,6 +541,13 @@ pub trait Shr<Rhs = Self> {
|
||||
type Output;
|
||||
|
||||
/// Performs the `>>` operation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// assert_eq!(5u8 >> 1, 2);
|
||||
/// assert_eq!(2u8 >> 1, 1);
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn shr(self, rhs: Rhs) -> Self::Output;
|
||||
@ -612,6 +662,26 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
|
||||
)]
|
||||
pub trait BitAndAssign<Rhs = Self> {
|
||||
/// Performs the `&=` operation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let mut x = true;
|
||||
/// x &= false;
|
||||
/// assert_eq!(x, false);
|
||||
///
|
||||
/// let mut x = true;
|
||||
/// x &= true;
|
||||
/// assert_eq!(x, true);
|
||||
///
|
||||
/// let mut x: u8 = 5;
|
||||
/// x &= 1;
|
||||
/// assert_eq!(x, 1);
|
||||
///
|
||||
/// let mut x: u8 = 5;
|
||||
/// x &= 2;
|
||||
/// assert_eq!(x, 0);
|
||||
/// ```
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
fn bitand_assign(&mut self, rhs: Rhs);
|
||||
}
|
||||
@ -663,6 +733,26 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
|
||||
)]
|
||||
pub trait BitOrAssign<Rhs = Self> {
|
||||
/// Performs the `|=` operation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let mut x = true;
|
||||
/// x |= false;
|
||||
/// assert_eq!(x, true);
|
||||
///
|
||||
/// let mut x = false;
|
||||
/// x |= false;
|
||||
/// assert_eq!(x, false);
|
||||
///
|
||||
/// let mut x: u8 = 5;
|
||||
/// x |= 1;
|
||||
/// assert_eq!(x, 5);
|
||||
///
|
||||
/// let mut x: u8 = 5;
|
||||
/// x |= 2;
|
||||
/// assert_eq!(x, 7);
|
||||
/// ```
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
fn bitor_assign(&mut self, rhs: Rhs);
|
||||
}
|
||||
@ -714,6 +804,26 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
|
||||
)]
|
||||
pub trait BitXorAssign<Rhs = Self> {
|
||||
/// Performs the `^=` operation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let mut x = true;
|
||||
/// x ^= false;
|
||||
/// assert_eq!(x, true);
|
||||
///
|
||||
/// let mut x = true;
|
||||
/// x ^= true;
|
||||
/// assert_eq!(x, false);
|
||||
///
|
||||
/// let mut x: u8 = 5;
|
||||
/// x ^= 1;
|
||||
/// assert_eq!(x, 4);
|
||||
///
|
||||
/// let mut x: u8 = 5;
|
||||
/// x ^= 2;
|
||||
/// assert_eq!(x, 7);
|
||||
/// ```
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
fn bitxor_assign(&mut self, rhs: Rhs);
|
||||
}
|
||||
@ -763,6 +873,18 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
|
||||
)]
|
||||
pub trait ShlAssign<Rhs = Self> {
|
||||
/// Performs the `<<=` operation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let mut x: u8 = 5;
|
||||
/// x <<= 1;
|
||||
/// assert_eq!(x, 10);
|
||||
///
|
||||
/// let mut x: u8 = 1;
|
||||
/// x <<= 1;
|
||||
/// assert_eq!(x, 2);
|
||||
/// ```
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
fn shl_assign(&mut self, rhs: Rhs);
|
||||
}
|
||||
@ -833,6 +955,18 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
|
||||
)]
|
||||
pub trait ShrAssign<Rhs = Self> {
|
||||
/// Performs the `>>=` operation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let mut x: u8 = 5;
|
||||
/// x >>= 1;
|
||||
/// assert_eq!(x, 2);
|
||||
///
|
||||
/// let mut x: u8 = 2;
|
||||
/// x >>= 1;
|
||||
/// assert_eq!(x, 1);
|
||||
/// ```
|
||||
#[stable(feature = "op_assign_traits", since = "1.8.0")]
|
||||
fn shr_assign(&mut self, rhs: Rhs);
|
||||
}
|
||||
|
@ -108,6 +108,34 @@ impl Duration {
|
||||
#[unstable(feature = "duration_constants", issue = "57391")]
|
||||
pub const NANOSECOND: Duration = Duration::from_nanos(1);
|
||||
|
||||
/// The minimum duration.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(duration_constants)]
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// assert_eq!(Duration::MIN, Duration::new(0, 0));
|
||||
/// ```
|
||||
#[unstable(feature = "duration_constants", issue = "57391")]
|
||||
pub const MIN: Duration = Duration::from_nanos(0);
|
||||
|
||||
/// The maximum duration.
|
||||
///
|
||||
/// It is roughly equal to a duration of 584,942,417,355 years.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(duration_constants)]
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// assert_eq!(Duration::MAX, Duration::new(u64::MAX, 1_000_000_000 - 1));
|
||||
/// ```
|
||||
#[unstable(feature = "duration_constants", issue = "57391")]
|
||||
pub const MAX: Duration = Duration::new(u64::MAX, NANOS_PER_SEC - 1);
|
||||
|
||||
/// Creates a new `Duration` from the specified number of whole seconds and
|
||||
/// additional nanoseconds.
|
||||
///
|
||||
@ -450,6 +478,29 @@ impl Duration {
|
||||
}
|
||||
}
|
||||
|
||||
/// Saturating `Duration` addition. Computes `self + other`, returning [`Duration::MAX`]
|
||||
/// if overflow occurred.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(duration_saturating_ops)]
|
||||
/// #![feature(duration_constants)]
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1));
|
||||
/// assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX);
|
||||
/// ```
|
||||
#[unstable(feature = "duration_saturating_ops", issue = "76416")]
|
||||
#[inline]
|
||||
#[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
|
||||
pub const fn saturating_add(self, rhs: Duration) -> Duration {
|
||||
match self.checked_add(rhs) {
|
||||
Some(res) => res,
|
||||
None => Duration::MAX,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checked `Duration` subtraction. Computes `self - other`, returning [`None`]
|
||||
/// if the result would be negative or if overflow occurred.
|
||||
///
|
||||
@ -485,6 +536,29 @@ impl Duration {
|
||||
}
|
||||
}
|
||||
|
||||
/// Saturating `Duration` subtraction. Computes `self - other`, returning [`Duration::MIN`]
|
||||
/// if the result would be negative or if overflow occurred.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(duration_saturating_ops)]
|
||||
/// #![feature(duration_constants)]
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// assert_eq!(Duration::new(0, 1).saturating_sub(Duration::new(0, 0)), Duration::new(0, 1));
|
||||
/// assert_eq!(Duration::new(0, 0).saturating_sub(Duration::new(0, 1)), Duration::MIN);
|
||||
/// ```
|
||||
#[unstable(feature = "duration_saturating_ops", issue = "76416")]
|
||||
#[inline]
|
||||
#[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
|
||||
pub const fn saturating_sub(self, rhs: Duration) -> Duration {
|
||||
match self.checked_sub(rhs) {
|
||||
Some(res) => res,
|
||||
None => Duration::MIN,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checked `Duration` multiplication. Computes `self * other`, returning
|
||||
/// [`None`] if overflow occurred.
|
||||
///
|
||||
@ -515,6 +589,29 @@ impl Duration {
|
||||
None
|
||||
}
|
||||
|
||||
/// Saturating `Duration` multiplication. Computes `self * other`, returning
|
||||
/// [`Duration::MAX`] if overflow occurred.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(duration_saturating_ops)]
|
||||
/// #![feature(duration_constants)]
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// assert_eq!(Duration::new(0, 500_000_001).saturating_mul(2), Duration::new(1, 2));
|
||||
/// assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX);
|
||||
/// ```
|
||||
#[unstable(feature = "duration_saturating_ops", issue = "76416")]
|
||||
#[inline]
|
||||
#[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
|
||||
pub const fn saturating_mul(self, rhs: u32) -> Duration {
|
||||
match self.checked_mul(rhs) {
|
||||
Some(res) => res,
|
||||
None => Duration::MAX,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checked `Duration` division. Computes `self / other`, returning [`None`]
|
||||
/// if `other == 0`.
|
||||
///
|
||||
|
@ -10,6 +10,8 @@
|
||||
#![feature(core_private_diy_float)]
|
||||
#![feature(debug_non_exhaustive)]
|
||||
#![feature(dec2flt)]
|
||||
#![feature(duration_constants)]
|
||||
#![feature(duration_saturating_ops)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(fixed_size_array)]
|
||||
#![feature(flt2dec)]
|
||||
|
@ -89,6 +89,16 @@ fn checked_add() {
|
||||
assert_eq!(Duration::new(1, 0).checked_add(Duration::new(u64::MAX, 0)), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn saturating_add() {
|
||||
assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1));
|
||||
assert_eq!(
|
||||
Duration::new(0, 500_000_000).saturating_add(Duration::new(0, 500_000_001)),
|
||||
Duration::new(1, 1)
|
||||
);
|
||||
assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub() {
|
||||
assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), Duration::new(0, 1));
|
||||
@ -107,6 +117,17 @@ fn checked_sub() {
|
||||
assert_eq!(zero.checked_sub(one_sec), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn saturating_sub() {
|
||||
let zero = Duration::new(0, 0);
|
||||
let one_nano = Duration::new(0, 1);
|
||||
let one_sec = Duration::new(1, 0);
|
||||
assert_eq!(one_nano.saturating_sub(zero), Duration::new(0, 1));
|
||||
assert_eq!(one_sec.saturating_sub(one_nano), Duration::new(0, 999_999_999));
|
||||
assert_eq!(zero.saturating_sub(one_nano), Duration::MIN);
|
||||
assert_eq!(zero.saturating_sub(one_sec), Duration::MIN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn sub_bad1() {
|
||||
@ -136,6 +157,15 @@ fn checked_mul() {
|
||||
assert_eq!(Duration::new(u64::MAX - 1, 0).checked_mul(2), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn saturating_mul() {
|
||||
assert_eq!(Duration::new(0, 1).saturating_mul(2), Duration::new(0, 2));
|
||||
assert_eq!(Duration::new(1, 1).saturating_mul(3), Duration::new(3, 3));
|
||||
assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4), Duration::new(2, 4));
|
||||
assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4000), Duration::new(2000, 4000));
|
||||
assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn div() {
|
||||
assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0));
|
||||
|
@ -1,3 +1,5 @@
|
||||
//! Linux-specific extensions to primitives in the `std::fs` module.
|
||||
|
||||
#![stable(feature = "metadata_ext", since = "1.1.0")]
|
||||
|
||||
use crate::fs::Metadata;
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! Linux-specific definitions
|
||||
//! Linux-specific definitions.
|
||||
|
||||
#![stable(feature = "raw_ext", since = "1.1.0")]
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! Linux-specific raw type definitions
|
||||
//! Linux-specific raw type definitions.
|
||||
|
||||
#![stable(feature = "raw_ext", since = "1.1.0")]
|
||||
#![rustc_deprecated(
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! Unix-specific extension to the primitives in the `std::ffi` module
|
||||
//! Unix-specific extension to the primitives in the `std::ffi` module.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! Unix-specific extensions to general I/O primitives
|
||||
//! Unix-specific extensions to general I/O primitives.
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#![stable(feature = "unix_socket", since = "1.10.0")]
|
||||
//! Unix-specific networking functionality.
|
||||
|
||||
//! Unix-specific networking functionality
|
||||
#![stable(feature = "unix_socket", since = "1.10.0")]
|
||||
|
||||
#[cfg(all(test, not(target_os = "emscripten")))]
|
||||
mod tests;
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! Unix-specific primitives available on all unix platforms
|
||||
//! Unix-specific primitives available on all unix platforms.
|
||||
|
||||
#![stable(feature = "raw_ext", since = "1.1.0")]
|
||||
#![rustc_deprecated(
|
||||
|
@ -1,3 +1,5 @@
|
||||
//! Windows-specific extensions to general I/O primitives.
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use crate::fs;
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! Windows-specific primitives
|
||||
//! Windows-specific primitives.
|
||||
|
||||
#![stable(feature = "raw_ext", since = "1.1.0")]
|
||||
|
||||
|
@ -1364,16 +1364,16 @@ impl Clean<Type> for hir::Ty<'_> {
|
||||
TyKind::Slice(ref ty) => Slice(box ty.clean(cx)),
|
||||
TyKind::Array(ref ty, ref length) => {
|
||||
let def_id = cx.tcx.hir().local_def_id(length.hir_id);
|
||||
let length = match cx.tcx.const_eval_poly(def_id.to_def_id()) {
|
||||
Ok(length) => {
|
||||
print_const(cx, ty::Const::from_value(cx.tcx, length, cx.tcx.types.usize))
|
||||
}
|
||||
Err(_) => cx
|
||||
.sess()
|
||||
.source_map()
|
||||
.span_to_snippet(cx.tcx.def_span(def_id))
|
||||
.unwrap_or_else(|_| "_".to_string()),
|
||||
};
|
||||
// NOTE(min_const_generics): We can't use `const_eval_poly` for constants
|
||||
// as we currently do not supply the parent generics to anonymous constants
|
||||
// but do allow `ConstKind::Param`.
|
||||
//
|
||||
// `const_eval_poly` tries to to first substitute generic parameters which
|
||||
// results in an ICE while manually constructing the constant and using `eval`
|
||||
// does nothing for `ConstKind::Param`.
|
||||
let ct = ty::Const::from_anon_const(cx.tcx, def_id);
|
||||
let param_env = cx.tcx.param_env(def_id);
|
||||
let length = print_const(cx, ct.eval(cx.tcx, param_env));
|
||||
Array(box ty.clean(cx), length)
|
||||
}
|
||||
TyKind::Tup(ref tys) => Tuple(tys.clean(cx)),
|
||||
|
6
src/test/rustdoc/const-generics/type-alias.rs
Normal file
6
src/test/rustdoc/const-generics/type-alias.rs
Normal file
@ -0,0 +1,6 @@
|
||||
// ignore-tidy-linelength
|
||||
#![feature(min_const_generics)]
|
||||
#![crate_name = "foo"]
|
||||
|
||||
// @has foo/type.CellIndex.html '//pre[@class="rust typedef"]' 'type CellIndex<const D: usize> = [i64; D];'
|
||||
pub type CellIndex<const D: usize> = [i64; D];
|
@ -1,5 +1,5 @@
|
||||
error: constant expression depends on a generic parameter
|
||||
--> $DIR/feature-gate-const_evaluatable_checked.rs:6:30
|
||||
--> $DIR/feature-gate-const_evaluatable_checked.rs:9:30
|
||||
|
|
||||
LL | fn test<const N: usize>() -> Arr<N> where Arr<N>: Default {
|
||||
| ^^^^^^
|
@ -0,0 +1,10 @@
|
||||
error: generic parameters must not be used inside of non trivial constant values
|
||||
--> $DIR/feature-gate-const_evaluatable_checked.rs:6:33
|
||||
|
|
||||
LL | type Arr<const N: usize> = [u8; N - 1];
|
||||
| ^ non-trivial anonymous constants must not depend on the parameter `N`
|
||||
|
|
||||
= help: it is currently only allowed to use either `N` or `{ N }` as generic constants
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -1,10 +1,13 @@
|
||||
#![feature(const_generics)]
|
||||
#![allow(incomplete_features)]
|
||||
// revisions: full min
|
||||
#![cfg_attr(full, feature(const_generics))]
|
||||
#![cfg_attr(full, allow(incomplete_features))]
|
||||
#![cfg_attr(min, feature(min_const_generics))]
|
||||
|
||||
type Arr<const N: usize> = [u8; N - 1];
|
||||
//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values
|
||||
|
||||
fn test<const N: usize>() -> Arr<N> where Arr<N>: Default {
|
||||
//~^ ERROR constant expression depends
|
||||
//[full]~^ ERROR constant expression depends
|
||||
Default::default()
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,10 @@
|
||||
error: generic parameters must not be used inside of non trivial constant values
|
||||
--> $DIR/simple.rs:8:33
|
||||
|
|
||||
LL | type Arr<const N: usize> = [u8; N - 1];
|
||||
| ^ non-trivial anonymous constants must not depend on the parameter `N`
|
||||
|
|
||||
= help: it is currently only allowed to use either `N` or `{ N }` as generic constants
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -1,8 +1,12 @@
|
||||
// run-pass
|
||||
#![feature(const_generics, const_evaluatable_checked)]
|
||||
// [full] run-pass
|
||||
// revisions: full min
|
||||
#![cfg_attr(full, feature(const_generics))]
|
||||
#![cfg_attr(min, feature(min_const_generics))]
|
||||
#![feature(const_evaluatable_checked)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
type Arr<const N: usize> = [u8; N - 1];
|
||||
//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values
|
||||
|
||||
fn test<const N: usize>() -> Arr<N> where Arr<N>: Default {
|
||||
Default::default()
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/simple_fail.rs:4:33
|
||||
--> $DIR/simple_fail.rs:7:33
|
||||
|
|
||||
LL | type Arr<const N: usize> = [u8; N - 1];
|
||||
| ^^^^^ attempt to compute `0_usize - 1_usize` which would overflow
|
@ -0,0 +1,10 @@
|
||||
error: generic parameters must not be used inside of non trivial constant values
|
||||
--> $DIR/simple_fail.rs:7:33
|
||||
|
|
||||
LL | type Arr<const N: usize> = [u8; N - 1];
|
||||
| ^ non-trivial anonymous constants must not depend on the parameter `N`
|
||||
|
|
||||
= help: it is currently only allowed to use either `N` or `{ N }` as generic constants
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -1,7 +1,11 @@
|
||||
#![feature(const_generics, const_evaluatable_checked)]
|
||||
// revisions: full min
|
||||
#![cfg_attr(full, feature(const_generics))]
|
||||
#![cfg_attr(min, feature(min_const_generics))]
|
||||
#![feature(const_evaluatable_checked)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
type Arr<const N: usize> = [u8; N - 1]; //~ ERROR evaluation of constant
|
||||
type Arr<const N: usize> = [u8; N - 1]; //[full]~ ERROR evaluation of constant
|
||||
//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values
|
||||
|
||||
fn test<const N: usize>() -> Arr<N> where Arr<N>: Sized {
|
||||
todo!()
|
||||
|
@ -1,5 +1,6 @@
|
||||
#![feature(const_generics)]
|
||||
#![allow(incomplete_features)]
|
||||
#![cfg_attr(full, feature(const_generics))]
|
||||
#![cfg_attr(full, allow(incomplete_features))]
|
||||
#![cfg_attr(min, feature(min_const_generics))]
|
||||
|
||||
pub struct Struct<const N: usize>(());
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#![feature(const_panic)]
|
||||
#![feature(duration_consts_2)]
|
||||
#![feature(div_duration)]
|
||||
#![feature(duration_saturating_ops)]
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
@ -15,29 +16,29 @@ fn duration() {
|
||||
|
||||
const MAX : Duration = Duration::new(u64::MAX, 1_000_000_000 - 1);
|
||||
|
||||
const MAX_ADD_ZERO : Option<Duration> = MAX.checked_add(ZERO);
|
||||
assert_eq!(MAX_ADD_ZERO, Some(MAX));
|
||||
const MAX_CHECKED_ADD_ZERO : Option<Duration> = MAX.checked_add(ZERO);
|
||||
assert_eq!(MAX_CHECKED_ADD_ZERO, Some(MAX));
|
||||
|
||||
const MAX_ADD_ONE : Option<Duration> = MAX.checked_add(ONE);
|
||||
assert_eq!(MAX_ADD_ONE, None);
|
||||
const MAX_CHECKED_ADD_ONE : Option<Duration> = MAX.checked_add(ONE);
|
||||
assert_eq!(MAX_CHECKED_ADD_ONE, None);
|
||||
|
||||
const ONE_SUB_ONE : Option<Duration> = ONE.checked_sub(ONE);
|
||||
assert_eq!(ONE_SUB_ONE, Some(ZERO));
|
||||
const ONE_CHECKED_SUB_ONE : Option<Duration> = ONE.checked_sub(ONE);
|
||||
assert_eq!(ONE_CHECKED_SUB_ONE, Some(ZERO));
|
||||
|
||||
const ZERO_SUB_ONE : Option<Duration> = ZERO.checked_sub(ONE);
|
||||
assert_eq!(ZERO_SUB_ONE, None);
|
||||
const ZERO_CHECKED_SUB_ONE : Option<Duration> = ZERO.checked_sub(ONE);
|
||||
assert_eq!(ZERO_CHECKED_SUB_ONE, None);
|
||||
|
||||
const ONE_MUL_ONE : Option<Duration> = ONE.checked_mul(1);
|
||||
assert_eq!(ONE_MUL_ONE, Some(ONE));
|
||||
const ONE_CHECKED_MUL_ONE : Option<Duration> = ONE.checked_mul(1);
|
||||
assert_eq!(ONE_CHECKED_MUL_ONE, Some(ONE));
|
||||
|
||||
const MAX_MUL_TWO : Option<Duration> = MAX.checked_mul(2);
|
||||
assert_eq!(MAX_MUL_TWO, None);
|
||||
const MAX_CHECKED_MUL_TWO : Option<Duration> = MAX.checked_mul(2);
|
||||
assert_eq!(MAX_CHECKED_MUL_TWO, None);
|
||||
|
||||
const ONE_DIV_ONE : Option<Duration> = ONE.checked_div(1);
|
||||
assert_eq!(ONE_DIV_ONE, Some(ONE));
|
||||
const ONE_CHECKED_DIV_ONE : Option<Duration> = ONE.checked_div(1);
|
||||
assert_eq!(ONE_CHECKED_DIV_ONE, Some(ONE));
|
||||
|
||||
const ONE_DIV_ZERO : Option<Duration> = ONE.checked_div(0);
|
||||
assert_eq!(ONE_DIV_ZERO, None);
|
||||
const ONE_CHECKED_DIV_ZERO : Option<Duration> = ONE.checked_div(0);
|
||||
assert_eq!(ONE_CHECKED_DIV_ZERO, None);
|
||||
|
||||
const MAX_AS_F32 : f32 = MAX.as_secs_f32();
|
||||
assert_eq!(MAX_AS_F32, 18446744000000000000.0_f32);
|
||||
@ -50,6 +51,15 @@ fn duration() {
|
||||
|
||||
const ONE_AS_F64 : f64 = ONE.div_duration_f64(ONE);
|
||||
assert_eq!(ONE_AS_F64, 1.0_f64);
|
||||
|
||||
const MAX_SATURATING_ADD_ONE : Duration = MAX.saturating_add(ONE);
|
||||
assert_eq!(MAX_SATURATING_ADD_ONE, MAX);
|
||||
|
||||
const ZERO_SATURATING_SUB_ONE : Duration = ZERO.saturating_sub(ONE);
|
||||
assert_eq!(ZERO_SATURATING_SUB_ONE, ZERO);
|
||||
|
||||
const MAX_SATURATING_MUL_TWO : Duration = MAX.saturating_mul(2);
|
||||
assert_eq!(MAX_SATURATING_MUL_TWO, MAX);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
Loading…
Reference in New Issue
Block a user