File: clone.rs

package info (click to toggle)
rustc-web 1.85.0%2Bdfsg3-1~deb12u3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 1,759,988 kB
  • sloc: xml: 158,127; python: 35,830; javascript: 19,497; cpp: 19,002; sh: 17,245; ansic: 13,127; asm: 4,376; makefile: 1,056; lisp: 29; perl: 29; ruby: 19; sql: 11
file content (123 lines) | stat: -rw-r--r-- 3,774 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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());
}