From 8bbf1abd0ec903ff4408238e86d712aeba1cbd7f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 21 Jun 2019 03:52:38 +0200 Subject: shared_from_iter: Add more tests. --- src/liballoc/tests/arc.rs | 119 ++++++++++++++++++++++++++++++++++++++++++++++ src/liballoc/tests/lib.rs | 2 + src/liballoc/tests/rc.rs | 117 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 238 insertions(+) (limited to 'src/liballoc/tests') diff --git a/src/liballoc/tests/arc.rs b/src/liballoc/tests/arc.rs index 2759b1b1cac..ce64e2de013 100644 --- a/src/liballoc/tests/arc.rs +++ b/src/liballoc/tests/arc.rs @@ -2,6 +2,8 @@ use std::any::Any; use std::sync::{Arc, Weak}; use std::cell::RefCell; use std::cmp::PartialEq; +use std::iter::TrustedLen; +use std::mem; #[test] fn uninhabited() { @@ -85,3 +87,120 @@ fn eq() { assert!(!(x != x)); assert_eq!(*x.0.borrow(), 0); } + +type Rc = Arc; + +const SHARED_ITER_MAX: u16 = 100; + +fn assert_trusted_len(_: &I) {} + +#[test] +fn shared_from_iter_normal() { + // Exercise the base implementation for non-`TrustedLen` iterators. + { + // `Filter` is never `TrustedLen` since we don't + // know statically how many elements will be kept: + let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new); + + // Collecting into a `Vec` or `Rc<[T]>` should make no difference: + let vec = iter.clone().collect::>(); + let rc = iter.collect::>(); + assert_eq!(&*vec, &*rc); + + // Clone a bit and let these get dropped. + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } // Drop what hasn't been here. +} + +#[test] +fn shared_from_iter_trustedlen_normal() { + // Exercise the `TrustedLen` implementation under normal circumstances + // where `size_hint()` matches `(_, Some(exact_len))`. + { + let iter = (0..SHARED_ITER_MAX).map(Box::new); + assert_trusted_len(&iter); + + // Collecting into a `Vec` or `Rc<[T]>` should make no difference: + let vec = iter.clone().collect::>(); + let rc = iter.collect::>(); + assert_eq!(&*vec, &*rc); + assert_eq!(mem::size_of::>() * SHARED_ITER_MAX as usize, mem::size_of_val(&*rc)); + + // Clone a bit and let these get dropped. + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } // Drop what hasn't been here. + + // Try a ZST to make sure it is handled well. + { + let iter = (0..SHARED_ITER_MAX).map(|_| ()); + let vec = iter.clone().collect::>(); + let rc = iter.collect::>(); + assert_eq!(&*vec, &*rc); + assert_eq!(0, mem::size_of_val(&*rc)); + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } +} + +#[test] +#[should_panic = "I've almost got 99 problems."] +fn shared_from_iter_trustedlen_panic() { + // Exercise the `TrustedLen` implementation when `size_hint()` matches + // `(_, Some(exact_len))` but where `.next()` drops before the last iteration. + let iter = (0..SHARED_ITER_MAX) + .map(|val| { + match val { + 98 => panic!("I've almost got 99 problems."), + _ => Box::new(val), + } + }); + assert_trusted_len(&iter); + let _ = iter.collect::>(); + + panic!("I am unreachable."); +} + +#[test] +fn shared_from_iter_trustedlen_no_fuse() { + // Exercise the `TrustedLen` implementation when `size_hint()` matches + // `(_, Some(exact_len))` but where the iterator does not behave in a fused manner. + struct Iter(std::vec::IntoIter>>); + + unsafe impl TrustedLen for Iter {} + + impl Iterator for Iter { + fn size_hint(&self) -> (usize, Option) { + (2, Some(2)) + } + + type Item = Box; + + fn next(&mut self) -> Option { + self.0.next().flatten() + } + } + + let vec = vec![ + Some(Box::new(42)), + Some(Box::new(24)), + None, + Some(Box::new(12)), + ]; + let iter = Iter(vec.into_iter()); + assert_trusted_len(&iter); + assert_eq!( + &[Box::new(42), Box::new(24)], + &*iter.collect::>() + ); +} diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index ddb3120e89d..5a43c8e09a2 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -2,8 +2,10 @@ #![feature(box_syntax)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] +#![feature(option_flattening)] #![feature(pattern)] #![feature(repeat_generic_slice)] +#![feature(trusted_len)] #![feature(try_reserve)] #![feature(unboxed_closures)] #![deny(rust_2018_idioms)] diff --git a/src/liballoc/tests/rc.rs b/src/liballoc/tests/rc.rs index 18f82e80410..7854ca0fc16 100644 --- a/src/liballoc/tests/rc.rs +++ b/src/liballoc/tests/rc.rs @@ -2,6 +2,8 @@ use std::any::Any; use std::rc::{Rc, Weak}; use std::cell::RefCell; use std::cmp::PartialEq; +use std::mem; +use std::iter::TrustedLen; #[test] fn uninhabited() { @@ -85,3 +87,118 @@ fn eq() { assert!(!(x != x)); assert_eq!(*x.0.borrow(), 0); } + +const SHARED_ITER_MAX: u16 = 100; + +fn assert_trusted_len(_: &I) {} + +#[test] +fn shared_from_iter_normal() { + // Exercise the base implementation for non-`TrustedLen` iterators. + { + // `Filter` is never `TrustedLen` since we don't + // know statically how many elements will be kept: + let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new); + + // Collecting into a `Vec` or `Rc<[T]>` should make no difference: + let vec = iter.clone().collect::>(); + let rc = iter.collect::>(); + assert_eq!(&*vec, &*rc); + + // Clone a bit and let these get dropped. + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } // Drop what hasn't been here. +} + +#[test] +fn shared_from_iter_trustedlen_normal() { + // Exercise the `TrustedLen` implementation under normal circumstances + // where `size_hint()` matches `(_, Some(exact_len))`. + { + let iter = (0..SHARED_ITER_MAX).map(Box::new); + assert_trusted_len(&iter); + + // Collecting into a `Vec` or `Rc<[T]>` should make no difference: + let vec = iter.clone().collect::>(); + let rc = iter.collect::>(); + assert_eq!(&*vec, &*rc); + assert_eq!(mem::size_of::>() * SHARED_ITER_MAX as usize, mem::size_of_val(&*rc)); + + // Clone a bit and let these get dropped. + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } // Drop what hasn't been here. + + // Try a ZST to make sure it is handled well. + { + let iter = (0..SHARED_ITER_MAX).map(|_| ()); + let vec = iter.clone().collect::>(); + let rc = iter.collect::>(); + assert_eq!(&*vec, &*rc); + assert_eq!(0, mem::size_of_val(&*rc)); + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } +} + +#[test] +#[should_panic = "I've almost got 99 problems."] +fn shared_from_iter_trustedlen_panic() { + // Exercise the `TrustedLen` implementation when `size_hint()` matches + // `(_, Some(exact_len))` but where `.next()` drops before the last iteration. + let iter = (0..SHARED_ITER_MAX) + .map(|val| { + match val { + 98 => panic!("I've almost got 99 problems."), + _ => Box::new(val), + } + }); + assert_trusted_len(&iter); + let _ = iter.collect::>(); + + panic!("I am unreachable."); +} + +#[test] +fn shared_from_iter_trustedlen_no_fuse() { + // Exercise the `TrustedLen` implementation when `size_hint()` matches + // `(_, Some(exact_len))` but where the iterator does not behave in a fused manner. + struct Iter(std::vec::IntoIter>>); + + unsafe impl TrustedLen for Iter {} + + impl Iterator for Iter { + fn size_hint(&self) -> (usize, Option) { + (2, Some(2)) + } + + type Item = Box; + + fn next(&mut self) -> Option { + self.0.next().flatten() + } + } + + let vec = vec![ + Some(Box::new(42)), + Some(Box::new(24)), + None, + Some(Box::new(12)), + ]; + let iter = Iter(vec.into_iter()); + assert_trusted_len(&iter); + assert_eq!( + &[Box::new(42), Box::new(24)], + &*iter.collect::>() + ); +} -- cgit 1.4.1-3-g733a5 From 85def307fc83f8c0d164b1506bb855dfaed5f8b5 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 21 Jun 2019 23:01:48 +0200 Subject: shared_from_iter: Polish internal docs. --- src/liballoc/rc.rs | 29 +++++++++++++++-------------- src/liballoc/sync.rs | 32 ++++++++++++++++---------------- src/liballoc/tests/arc.rs | 2 ++ 3 files changed, 33 insertions(+), 30 deletions(-) (limited to 'src/liballoc/tests') diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 9b653fe2d75..94cc0b18133 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -699,11 +699,11 @@ impl Rc { } impl Rc { - // Allocates an `RcBox` with sufficient space for - // an unsized value where the value has the layout provided. - // - // The function `mem_to_rcbox` is called with the data pointer - // and must return back a (potentially fat)-pointer for the `RcBox`. + /// Allocates an `RcBox` with sufficient space for + /// an unsized value where the value has the layout provided. + /// + /// The function `mem_to_rcbox` is called with the data pointer + /// and must return back a (potentially fat)-pointer for the `RcBox`. unsafe fn allocate_for_unsized( value_layout: Layout, mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox @@ -730,7 +730,7 @@ impl Rc { inner } - // Allocates an `RcBox` with sufficient space for an unsized value + /// Allocates an `RcBox` with sufficient space for an unsized value unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox { // Allocate for the `RcBox` using the given value. Self::allocate_for_unsized( @@ -762,7 +762,7 @@ impl Rc { } impl Rc<[T]> { - // Allocates an `RcBox<[T]>` with the given length. + /// Allocates an `RcBox<[T]>` with the given length. unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> { Self::allocate_for_unsized( Layout::array::(len).unwrap(), @@ -771,19 +771,19 @@ impl Rc<[T]> { } } -// Sets the data pointer of a `?Sized` raw pointer. -// -// For a slice/trait object, this sets the `data` field and leaves the rest -// unchanged. For a sized raw pointer, this simply sets the pointer. +/// Sets the data pointer of a `?Sized` raw pointer. +/// +/// For a slice/trait object, this sets the `data` field and leaves the rest +/// unchanged. For a sized raw pointer, this simply sets the pointer. unsafe fn set_data_ptr(mut ptr: *mut T, data: *mut U) -> *mut T { ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8); ptr } impl Rc<[T]> { - // Copy elements from slice into newly allocated Rc<[T]> - // - // Unsafe because the caller must either take ownership or bind `T: Copy` + /// Copy elements from slice into newly allocated Rc<[T]> + /// + /// Unsafe because the caller must either take ownership or bind `T: Copy` unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> { let ptr = Self::allocate_for_slice(v.len()); @@ -847,6 +847,7 @@ impl Rc<[T]> { } } +/// Specialization trait used for `From<&[T]>`. trait RcFromSlice { fn from_slice(slice: &[T]) -> Self; } diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 672481ca0de..0a9ce437978 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -588,11 +588,11 @@ impl Arc { } impl Arc { - // Allocates an `ArcInner` with sufficient space for - // an unsized value where the value has the layout provided. - // - // The function `mem_to_arcinner` is called with the data pointer - // and must return back a (potentially fat)-pointer for the `ArcInner`. + /// Allocates an `ArcInner` with sufficient space for + /// an unsized value where the value has the layout provided. + /// + /// The function `mem_to_arcinner` is called with the data pointer + /// and must return back a (potentially fat)-pointer for the `ArcInner`. unsafe fn allocate_for_unsized( value_layout: Layout, mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner @@ -618,7 +618,7 @@ impl Arc { inner } - // Allocates an `ArcInner` with sufficient space for an unsized value + /// Allocates an `ArcInner` with sufficient space for an unsized value. unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner { // Allocate for the `ArcInner` using the given value. Self::allocate_for_unsized( @@ -650,7 +650,7 @@ impl Arc { } impl Arc<[T]> { - // Allocates an `ArcInner<[T]>` with the given length. + /// Allocates an `ArcInner<[T]>` with the given length. unsafe fn allocate_for_slice(len: usize) -> *mut ArcInner<[T]> { Self::allocate_for_unsized( Layout::array::(len).unwrap(), @@ -659,19 +659,19 @@ impl Arc<[T]> { } } -// Sets the data pointer of a `?Sized` raw pointer. -// -// For a slice/trait object, this sets the `data` field and leaves the rest -// unchanged. For a sized raw pointer, this simply sets the pointer. +/// Sets the data pointer of a `?Sized` raw pointer. +/// +/// For a slice/trait object, this sets the `data` field and leaves the rest +/// unchanged. For a sized raw pointer, this simply sets the pointer. unsafe fn set_data_ptr(mut ptr: *mut T, data: *mut U) -> *mut T { ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8); ptr } impl Arc<[T]> { - // Copy elements from slice into newly allocated Arc<[T]> - // - // Unsafe because the caller must either take ownership or bind `T: Copy` + /// Copy elements from slice into newly allocated Arc<[T]> + /// + /// Unsafe because the caller must either take ownership or bind `T: Copy`. unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> { let ptr = Self::allocate_for_slice(v.len()); @@ -735,7 +735,7 @@ impl Arc<[T]> { } } -// Specialization trait used for From<&[T]> +/// Specialization trait used for `From<&[T]>`. trait ArcFromSlice { fn from_slice(slice: &[T]) -> Self; } @@ -1903,7 +1903,7 @@ impl> ArcFromIter for Arc<[T]> { impl<'a, T: 'a + Clone> ArcFromIter<&'a T, slice::Iter<'a, T>> for Arc<[T]> { fn from_iter(iter: slice::Iter<'a, T>) -> Self { - // Delegate to `impl From<&[T]> for Rc<[T]>`. + // Delegate to `impl From<&[T]> for Arc<[T]>`. // // In the case that `T: Copy`, we get to use `ptr::copy_nonoverlapping` // which is even more performant. diff --git a/src/liballoc/tests/arc.rs b/src/liballoc/tests/arc.rs index ce64e2de013..cf2ad2a8e60 100644 --- a/src/liballoc/tests/arc.rs +++ b/src/liballoc/tests/arc.rs @@ -88,6 +88,8 @@ fn eq() { assert_eq!(*x.0.borrow(), 0); } +// The test code below is identical to that in `rc.rs`. +// For better maintainability we therefore define this type alias. type Rc = Arc; const SHARED_ITER_MAX: u16 = 100; -- cgit 1.4.1-3-g733a5