blob: 68871dbccf07b5eaf5b9436626638d09d374dcba [file] [log] [blame]
use core::clone::CloneToUninit;
use core::ffi::CStr;
use core::mem::MaybeUninit;
use core::ptr;
#[test]
#[allow(suspicious_double_ref_op)]
fn test_borrowed_clone() {
let x = 5;
let y: &i32 = &x;
let z: &i32 = (&y).clone();
assert_eq!(*z, 5);
}
#[test]
fn test_clone_from() {
let a = Box::new(5);
let mut b = Box::new(10);
b.clone_from(&a);
assert_eq!(*b, 5);
}
#[test]
fn test_clone_to_uninit_slice_success() {
// Using `String`s to exercise allocation and Drop of the individual elements;
// if something is aliased or double-freed, at least Miri will catch that.
let a: [String; 3] = ["a", "b", "c"].map(String::from);
let mut storage: MaybeUninit<[String; 3]> = MaybeUninit::uninit();
let b: [String; 3] = unsafe {
a[..].clone_to_uninit(storage.as_mut_ptr().cast());
storage.assume_init()
};
assert_eq!(a, b);
}
#[test]
#[cfg(panic = "unwind")]
fn test_clone_to_uninit_slice_drops_on_panic() {
use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering::Relaxed;
/// A static counter is OK to use as long as _this one test_ isn't run several times in
/// multiple threads.
static COUNTER: AtomicUsize = AtomicUsize::new(0);
/// Counts how many instances are live, and panics if a fifth one is created
struct CountsDropsAndPanics {}
impl CountsDropsAndPanics {
fn new() -> Self {
COUNTER.fetch_add(1, Relaxed);
Self {}
}
}
impl Clone for CountsDropsAndPanics {
fn clone(&self) -> Self {
if COUNTER.load(Relaxed) == 4 { panic!("intentional panic") } else { Self::new() }
}
}
impl Drop for CountsDropsAndPanics {
fn drop(&mut self) {
COUNTER.fetch_sub(1, Relaxed);
}
}
let a: [CountsDropsAndPanics; 3] = core::array::from_fn(|_| CountsDropsAndPanics::new());
assert_eq!(COUNTER.load(Relaxed), 3);
let panic_payload = std::panic::catch_unwind(|| {
let mut storage: MaybeUninit<[CountsDropsAndPanics; 3]> = MaybeUninit::uninit();
// This should panic halfway through
unsafe {
a[..].clone_to_uninit(storage.as_mut_ptr().cast());
}
})
.unwrap_err();
assert_eq!(panic_payload.downcast().unwrap(), Box::new("intentional panic"));
// Check for lack of leak, which is what this test is looking for
assert_eq!(COUNTER.load(Relaxed), 3, "leaked during clone!");
// Might as well exercise the rest of the drops
drop(a);
assert_eq!(COUNTER.load(Relaxed), 0);
}
#[test]
fn test_clone_to_uninit_str() {
let a = "hello";
let mut storage: MaybeUninit<[u8; 5]> = MaybeUninit::uninit();
unsafe { a.clone_to_uninit(storage.as_mut_ptr().cast()) };
assert_eq!(a.as_bytes(), unsafe { storage.assume_init() }.as_slice());
let mut b: Box<str> = "world".into();
assert_eq!(a.len(), b.len());
assert_ne!(a, &*b);
unsafe { a.clone_to_uninit(ptr::from_mut::<str>(&mut b).cast()) };
assert_eq!(a, &*b);
}
#[test]
fn test_clone_to_uninit_cstr() {
let a = c"hello";
let mut storage: MaybeUninit<[u8; 6]> = MaybeUninit::uninit();
unsafe { a.clone_to_uninit(storage.as_mut_ptr().cast()) };
assert_eq!(a.to_bytes_with_nul(), unsafe { storage.assume_init() }.as_slice());
let mut b: Box<CStr> = c"world".into();
assert_eq!(a.count_bytes(), b.count_bytes());
assert_ne!(a, &*b);
unsafe { a.clone_to_uninit(ptr::from_mut::<CStr>(&mut b).cast()) };
assert_eq!(a, &*b);
}
#[test]
fn cstr_metadata_is_length_with_nul() {
let s: &CStr = c"abcdef";
let p: *const CStr = ptr::from_ref(s);
let bytes: *const [u8] = p as *const [u8];
assert_eq!(s.to_bytes_with_nul().len(), bytes.len());
}
#[test]
fn test_const_clone() {
const {
let bool: bool = Default::default();
let char: char = Default::default();
let ascii_char: std::ascii::Char = Default::default();
let usize: usize = Default::default();
let u8: u8 = Default::default();
let u16: u16 = Default::default();
let u32: u32 = Default::default();
let u64: u64 = Default::default();
let u128: u128 = Default::default();
let i8: i8 = Default::default();
let i16: i16 = Default::default();
let i32: i32 = Default::default();
let i64: i64 = Default::default();
let i128: i128 = Default::default();
let f16: f16 = Default::default();
let f32: f32 = Default::default();
let f64: f64 = Default::default();
let f128: f128 = Default::default();
let bool_clone: bool = bool.clone();
let char_clone: char = char.clone();
let ascii_char_clone: std::ascii::Char = ascii_char.clone();
let usize_clone: usize = usize.clone();
let u8_clone: u8 = u8.clone();
let u16_clone: u16 = u16.clone();
let u32_clone: u32 = u32.clone();
let u64_clone: u64 = u64.clone();
let u128_clone: u128 = u128.clone();
let i8_clone: i8 = i8.clone();
let i16_clone: i16 = i16.clone();
let i32_clone: i32 = i32.clone();
let i64_clone: i64 = i64.clone();
let i128_clone: i128 = i128.clone();
let f16_clone: f16 = f16.clone();
let f32_clone: f32 = f32.clone();
let f64_clone: f64 = f64.clone();
let f128_clone: f128 = f128.clone();
assert!(bool == bool_clone);
assert!(char == char_clone);
assert!(ascii_char == ascii_char_clone);
assert!(usize == usize_clone);
assert!(u8 == u8_clone);
assert!(u16 == u16_clone);
assert!(u32 == u32_clone);
assert!(u64 == u64_clone);
assert!(u128 == u128_clone);
assert!(i8 == i8_clone);
assert!(i16 == i16_clone);
assert!(i32 == i32_clone);
assert!(i64 == i64_clone);
assert!(i128 == i128_clone);
assert!(f16 == f16_clone);
assert!(f32 == f32_clone);
assert!(f64 == f64_clone);
assert!(f128 == f128_clone);
let src: [i32; 4] = [1, 2, 3, 4];
let mut dst: [i32; 2] = [0, 0];
dst.clone_from_slice(&src[2..]);
assert!(src == [1, 2, 3, 4]);
assert!(dst == [3, 4]);
}
}