How can I get a random number in Rust 1.0? - random

I tried
use std::rand::{task_rng, Rng};
fn main() {
// a number from [-40.0, 13000.0)
let num: f64 = task_rng().gen_range(-40.0, 1.3e4);
println!("{}", num);
}
but this gives
error[E0432]: unresolved import `std::rand::task_rng`
--> rand.rs:1:17
|
1 | use std::rand::{task_rng, Rng};
| ^^^^^^^^ no `task_rng` in `rand`
error[E0432]: unresolved import `std::rand::Rng`
--> rand.rs:1:27
|
1 | use std::rand::{task_rng, Rng};
| ^^^ no `Rng` in `rand`
error[E0603]: module `rand` is private
--> rand.rs:1:17
|
1 | use std::rand::{task_rng, Rng};
| ^^^^^^^^
error[E0603]: module `rand` is private
--> rand.rs:1:27
|
1 | use std::rand::{task_rng, Rng};
| ^^^
and I tried
extern crate rand;
use rand::Rng;
fn main() {
let mut rng = rand::thread_rng();
if rng.gen() {
// random bool
println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>())
}
let tuple = rand::random::<(f64, char)>();
println!("{:?}", tuple)
}
and got
error[E0425]: cannot find function `thread_rng` in module `rand`
--> rand.rs:5:29
|
5 | let mut rng = rand::thread_rng();
| ^^^^^^^^^^ not found in `rand`
|
help: possible candidate is found in another module, you can import it into scope
| use std::__rand::thread_rng;
error[E0425]: cannot find function `random` in module `rand`
--> rand.rs:10:27
|
10 | let tuple = rand::random::<(f64, char)>();
| ^^^^^^ not found in `rand`
error: use of unstable library feature 'rand': use `rand` from crates.io (see issue #27703)
--> rand.rs:1:5
|
1 | extern crate rand;
| ^^^^^^^^^^^^^^^^^^
error: use of unstable library feature 'rand': use `rand` from crates.io (see issue #27703)
--> rand.rs:2:9
|
2 | use rand::Rng;
| ^^^^^^^^^

In the far past, the rand crate was part of the standard library but has long since been extracted to a crate. This crate should be the one you use:
Specify a Cargo.toml:
[package]
name = "stackoverflow"
version = "0.0.1"
authors = ["A. Developer <developer#example.com>"]
[dependencies]
rand = "0.7.0" # Or a newer version
Then your example code works:
use rand::Rng; // 0.7.2
fn main() {
let mut rng = rand::thread_rng();
if rng.gen() { // random bool
println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>())
}
let tuple = rand::random::<(f64, char)>();
println!("{:?}", tuple)
}
With the output:
$ cargo run
Running `target/debug/so`
i32: 1819776837, u32: 3293137459
(0.6052759716514547, '\u{69a69}')
$ cargo run
Running `target/debug/so`
(0.23882541338214436, '\u{10deee}')
Why were these useful functions removed from stdlib?
Rust has a philosophy of placing as much as possible into crates instead of the standard library. This allows each piece of code to grow and evolve at a different rate than the standard library and also allows the code to stop being used without forcing it to be maintained forever.
A common example is the sequence of HTTP libraries in Python. There are multiple packages that all do the same thing in different ways and the Python maintainers have to keep all of them to provide backwards compatibility.
Crates allow this particular outcome to be avoided. If a crate truly stabilizes for a long time, I'm sure it could be re-added to the standard library.

Related

Generate random float from Standard Normal distribution and multiply by another float

Trying to generate a random number from the Standard Normal distribution. Need to multiply the value by 0.1 to get the number range i'm looking for. I tried using the documentation from rand_dist you can find here: https://docs.rs/rand_distr/0.3.0/rand_distr/struct.StandardNormal.html
My Cargo.toml is the following:
[package]
name = "test_rng"
version = "0.1.0"
authors = ["Jack"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.7.3"
rand_distr = "0.3.0"
The starting rust code is the example provided in the rand_dist docs from above:
use rand::prelude::*;
use rand_distr::StandardNormal;
fn main() {
let val: f64 = thread_rng().sample(StandardNormal);
println!("{}", val);
}
When I run this it works as expected and the output is:
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
Finished dev [unoptimized + debuginfo] target(s) in 2.11s
Running `target\debug\test_rng.exe`
0.48398855288705356
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
This is where I'm hitting an issue, when I try to multiply the number by 0.1 in the following code I get the resulting error:
fn main() {
let val: f64 = 0.1 * thread_rng().sample(StandardNormal);
println!("{}", val);
}
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
error[E0284]: type annotations needed: cannot satisfy `<f64 as std::ops::Mul<_>>::Output == f64`
--> src\main.rs:5:24
|
5 | let val: f64 = 0.1 * thread_rng().sample(StandardNormal);
| ^ cannot satisfy `<f64 as std::ops::Mul<_>>::Output == f64`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0284`.
error: could not compile `test_rng`.
To learn more, run the command again with --verbose.
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
I tried to change 0.1 to 0.1_f64 but that gave the same error.
I tried to convert random number to f64 (which it should already be) with as f64 but that resulted in the following:
fn main() {
let val: f64 = 0.1 * thread_rng().sample(StandardNormal) as f64;
println!("{}", val);
}
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
error[E0282]: type annotations needed
--> src\main.rs:5:39
|
5 | let val: f64 = 0.1 * thread_rng().sample(StandardNormal) as f64;
| ^^^^^^ cannot infer type for type parameter `T` declared on the associated function `sample`
|
= note: type must be known at this point
help: consider specifying the type arguments in the method call
|
5 | let val: f64 = 0.1 * thread_rng().sample::<T, D>(StandardNormal) as f64;
| ^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0282`.
error: could not compile `test_rng`.
To learn more, run the command again with --verbose.
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
Thought it was a precedence issue so I tried wrapping second half in parenthesis but got the same error.
I can get it to work by making the variable mutable and separating the line into two operations like the following:
fn main() {
let mut val: f64 = thread_rng().sample(StandardNormal);
val *= 0.1;
println!("{}", val);
}
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
Finished dev [unoptimized + debuginfo] target(s) in 1.62s
Running `target\debug\test_rng.exe`
-0.034993448117065
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
Any idea what is going on with the multiplication of the f64 with the output of the random number?
You can use the following:
fn main() {
let val: f64 = 0.1 * thread_rng().sample::<f64,_>(StandardNormal);
println!("{}", val);
}
This explicitly forces the sample function to return a f64. What was likely going on is that the rust type inference doesn't realize that the RHS needs to be f64, though I'm not sure exactly why.
Edit:
I think some the blame here goes to the definition of sample, in that it uses an unrestricted type parameter. An MVE for this would be:
pub trait Marker{}
impl Marker for f64{}
impl Marker for f32{}
fn does_not_work<T>() -> T{
unimplemented!()
}
fn does_work<T: Marker>() -> T{
unimplemented!()
}
fn main() {
let val: f64 = 0.1 * does_work();
let val: f64 = 0.1 * does_not_work();
}
It's somewhat understandable that the compiler can't infer types for does_not_work, b/c how is it meant to know about every possible type that could multiply with f64? However of we restrict things to only certain types with a trait, then the list of possible types becomes finite and type inference works again.

How to convert Vec<u8> into bson::document::Document?

I'm gonna receive tungstenite::Message which will contain the bson document from the client. I can convert tungstenite::Message into Vec<u8> but How can I convert it back into bson::document::Document on the server side?
Something like this:-
if msg.is_binary() {
let bin = msg.into_data();
let doc = mongodb::bson::Document::from_reader(&mut bin); //getting error
}
Error:-
error[E0277]: the trait bound `std::vec::Vec<u8>: std::io::Read` is not satisfied
--> src/main.rs:52:60
|
52 | let doc = mongodb::bson::Document::from_reader(&mut bin);
| ^^^^^^^^ the trait `std::io::Read` is not implemented for `std::vec::Vec<u8>`
|
::: /home/voldimot/.cargo/registry/src/github.com-1ecc6299db9ec823/bson-1.0.0/src/document.rs:530:27
|
530 | pub fn from_reader<R: Read + ?Sized>(reader: &mut R) -> crate::de::Result<Document> {
| ---- required by this bound in `bson::document::Document::from_reader`
You can use std::io::Cursor:
if msg.is_binary() {
let mut bin = std:::io::Cursor::new(msg.into_data());
let doc = mongodb::bson::Document::from_reader(&mut bin);
}

How do I store a Random number generator in a struct?

I am trying to store a Random number generator in a struct. I can't seem to get the struct definition for any Rng structs to be recognized, like ThreadRng. This works:
use rand::{
self,
distributions::{Distribution, Uniform},
}; // 0.6.4
fn main() {
let mut rng = rand::thread_rng();
let die_range = Uniform::new_inclusive(1, 6);
let die = die_range.sample(&mut rng);
println!("{}", die);
}
However, if I try to define a variable to have the actual type of the Rng, I get an error:
use rand::{
self,
ThreadRng,
distributions::{Distribution, Uniform},
}; // 0.6.4
fn main() {
let mut rng :ThreadRng = rand::thread_rng();
let die_range = Uniform::new_inclusive(1, 6);
let die = die_range.sample(&mut rng);
println!("{}", die);
}
The error is:
error[E0432]: unresolved import `rand::ThreadRng`
--> src/main.rs:3:5
|
3 | ThreadRng,
| ^^^^^^^^^
| |
| no `ThreadRng` in the root
| help: a similar name exists in the module: `thread_rng`
I want to store the Rng in a struct, and I do not want a trait object. How do I import the definition of ThreadRng? Or XorShiftRng (which might be faster - I do not need cryptographic strength)? Is the type in some sub-module I don't know about? All the examples I read online call a method to get the Rng and use it locally; they never store it in a struct and never define any variables that use the struct name.
If you look at the documentation rand::thread_rng, you can click on its return type to see that its fully qualified name is actually rand::rngs::ThreadRng.

"cannot infer an appropriate lifetime" when using a closure to return a reference to an enum variant's content

I have a function that accepts a reference to an enum, which I need to parse by matching the enum and reading its content. One of the variants of the enum (not in the simplified minimal working example below), may contain as value the type of the enum itself, therefore I may need to recursively call the same function to parse its value.
I would like to write a function that acts as a filter and returns an Option::Some containing a reference to the content of the enum variant, or None if the value must be discarded.
What follows is a minimal working (not-really compiling) example:
enum Data<'a> {
Value(&'a String),
Null,
}
fn main() {
let s = String::new();
let d = Data::Value(&s);
let equal = |d: &Data| -> Option<&String> {
if let Data::Value(s) = d {
Some(s)
} else {
None
}
};
parse(&d, equal);
//parse(&d, equal_filter);
}
fn equal_filter<'a>(d: &'a Data) -> Option<&'a String> {
if let Data::Value(s) = d {
Some(s)
} else {
None
}
}
fn parse<'a, F>(data: &Data<'a>, filter: F)
where
F: Fn(&Data<'a>) -> Option<&'a String>,
{
filter(data);
}
Playground.
I tried to compile the code by using a closure first, but in that case I get the error:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:11:33
|
11 | if let Data::Value(s) = d {
| ^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 10:17...
--> src/main.rs:10:17
|
10 | let equal = |d: &Data| -> Option<&String> {
| _________________^
11 | | if let Data::Value(s) = d {
12 | | Some(s)
13 | | } else {
14 | | None
15 | | }
16 | | };
| |_____^
= note: ...so that the types are compatible:
expected &Data<'_>
found &Data<'_>
note: but, the lifetime must be valid for the expression at 18:5...
--> src/main.rs:18:5
|
18 | parse(&d, equal);
| ^^^^^
note: ...so that a type/lifetime parameter is in scope here
--> src/main.rs:18:5
|
18 | parse(&d, equal);
| ^^^^^
So I tried with a function, but a got another error:
error[E0271]: type mismatch resolving `for<'r> <for<'a, 's> fn(&'a Data<'s>) -> std::option::Option<&'a std::string::String> {equal_filter} as std::ops::FnOnce<(&'r Data<'_>,)>>::Output == std::option::Option<&std::string::String>`
--> src/main.rs:19:5
|
19 | parse(&d, equal_filter);
| ^^^^^ expected bound lifetime parameter, found concrete lifetime
|
note: required by `parse`
--> src/main.rs:30:1
|
30 | / fn parse<'a, F>(data: &Data<'a>, filter: F)
31 | | where
32 | | F: Fn(&Data<'a>) -> Option<&'a String>,
33 | | {
34 | | filter(data);
35 | | }
| |_^
I would prefer to solve the issue using the closure, but I don't know how to proceed even by using the function.
Ultimately, this is caused due to limitations in Rust's type inference. Specifically, if a closure is passed immediately to a function that uses it, the compiler can infer what the argument and return types are. Unfortunately, when it is stored in a variable before being used, the compiler does not perform the same level of inference.
Inline your closure and it works:
enum Data<'a> {
Value(&'a String),
Null,
}
fn main() {
let s = String::new();
let d = Data::Value(&s);
parse(&d, |d| match d {
Data::Value(s) => Some(s),
_ => None,
});
}
fn parse<'a, F>(data: &Data<'a>, filter: F)
where
F: Fn(&Data<'a>) -> Option<&'a String>,
{
filter(data);
}
However, I'd encourage you to instead create methods on the enum and participate in the idiomatic set of conversion functions:
enum Data<'a> {
Value(&'a String),
Null,
}
impl<'a> Data<'a> {
fn as_value(&self) -> Option<&'a str> {
match self {
Data::Value(s) => Some(s),
_ => None,
}
}
}
fn main() {
let s = String::new();
let d = Data::Value(&s);
parse(&d, Data::as_value);
}
fn parse<'a, F>(data: &Data<'a>, filter: F)
where
F: Fn(&Data<'a>) -> Option<&'a str>,
{
filter(data);
}
Your function variant doesn't work because you've put the relevant lifetime in the wrong place:
// Wrong
fn equal_filter<'a>(d: &'a Data) -> Option<&'a String>
// Right
fn equal_filter<'a>(d: &Data<'a>) -> Option<&'a String>
Using either #[deny(elided_lifetimes_in_paths)] or #[deny(rust_2018_idioms)] will guide you to this:
error: hidden lifetime parameters in types are deprecated
--> src/main.rs:12:22
|
12 | let equal = |d: &Data| -> Option<&String> {
| ^^^^- help: indicate the anonymous lifetime: `<'_>`
|
error: hidden lifetime parameters in types are deprecated
--> src/main.rs:24:28
|
24 | fn equal_filter<'a>(d: &'a Data) -> Option<&'a String> {
| ^^^^- help: indicate the anonymous lifetime: `<'_>`
See also:
How to declare a lifetime for a closure argument?

Vector is empty after cloning struct with uninitialized member

In Rust 1.29.0 one of my tests has started failing. I managed to get the strange bug down to this example:
#[derive(Clone, Debug)]
struct CountDrop<'a>(&'a std::cell::RefCell<usize>);
struct MayContainValue<T> {
value: std::mem::ManuallyDrop<T>,
has_value: u32,
}
impl<T: Clone> Clone for MayContainValue<T> {
fn clone(&self) -> Self {
Self {
value: if self.has_value > 0 {
self.value.clone()
} else {
unsafe { std::mem::uninitialized() }
},
has_value: self.has_value,
}
}
}
impl<T> Drop for MayContainValue<T> {
fn drop(&mut self) {
if self.has_value > 0 {
unsafe {
std::mem::ManuallyDrop::drop(&mut self.value);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn check_drops() {
let n = 2000;
let drops = std::cell::RefCell::new(0usize);
let mut slots = Vec::new();
for _ in 0..n {
slots.push(MayContainValue {
value: std::mem::ManuallyDrop::new(CountDrop(&drops)),
has_value: 1,
});
}
unsafe { std::mem::ManuallyDrop::drop(&mut slots[0].value); }
slots[0].has_value = 0;
assert_eq!(slots.len(), slots.clone().len());
}
}
I know the code looks strange; it is all ripped out of context. I reproduced this problem with cargo test on 64-bit Ubuntu on Rust 1.29.0. A friend could not reproduce on Windows with the same Rust version.
Other things that stop reproduction:
Lowering n below ~900.
Not running the example from within cargo test.
Replacing CountDrop's member with u64.
Using a Rust version before 1.29.0.
What's going on here? Yes, MayContainValue can have an uninitialized member, but this is never used in any way.
I also managed to reproduce this on play.rust-lang.org.
I'm not interested in 'solutions' that involve re-engineering MayContainValue in some safe way with Option or enum, I'm using manual storage and occupied/vacant discrimination for a good reason.
TL;DR: Yes, creating an uninitialized reference is always undefined behavior. You cannot use mem::uninitialized safely with generics. There is not currently a good workaround for your specific case.
Running your code in valgrind reports 3 errors, each with the same stack trace:
==741== Conditional jump or move depends on uninitialised value(s)
==741== at 0x11907F: <alloc::vec::Vec<T> as alloc::vec::SpecExtend<T, I>>::spec_extend (vec.rs:1892)
==741== by 0x11861C: <alloc::vec::Vec<T> as alloc::vec::SpecExtend<&'a T, I>>::spec_extend (vec.rs:1942)
==741== by 0x11895C: <alloc::vec::Vec<T>>::extend_from_slice (vec.rs:1396)
==741== by 0x11C1A2: alloc::slice::hack::to_vec (slice.rs:168)
==741== by 0x11C643: alloc::slice::<impl [T]>::to_vec (slice.rs:369)
==741== by 0x118C1E: <alloc::vec::Vec<T> as core::clone::Clone>::clone (vec.rs:1676)
==741== by 0x11AF89: md::tests::check_drops (main.rs:51)
==741== by 0x119D39: md::__test::TESTS::{{closure}} (main.rs:36)
==741== by 0x11935D: core::ops::function::FnOnce::call_once (function.rs:223)
==741== by 0x11F09E: {{closure}} (lib.rs:1451)
==741== by 0x11F09E: call_once<closure,()> (function.rs:223)
==741== by 0x11F09E: <F as alloc::boxed::FnBox<A>>::call_box (boxed.rs:642)
==741== by 0x17B469: __rust_maybe_catch_panic (lib.rs:105)
==741== by 0x14044F: try<(),std::panic::AssertUnwindSafe<alloc::boxed::Box<FnBox<()>>>> (panicking.rs:289)
==741== by 0x14044F: catch_unwind<std::panic::AssertUnwindSafe<alloc::boxed::Box<FnBox<()>>>,()> (panic.rs:392)
==741== by 0x14044F: {{closure}} (lib.rs:1406)
==741== by 0x14044F: std::sys_common::backtrace::__rust_begin_short_backtrace (backtrace.rs:136)
Reducing while keeping the Valgrind error (or one extremely similar) leads to
use std::{iter, mem};
fn main() {
let a = unsafe { mem::uninitialized::<&()>() };
let mut b = iter::once(a);
let c = b.next();
let _d = match c {
Some(_) => 1,
None => 2,
};
}
Running this smaller reproduction in Miri in the playground leads to this error:
error[E0080]: constant evaluation error: attempted to read undefined bytes
--> src/main.rs:7:20
|
7 | let _d = match c {
| ^ attempted to read undefined bytes
|
note: inside call to `main`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:74:34
|
74| lang_start_internal(&move || main().report(), argc, argv)
| ^^^^^^
note: inside call to `closure`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:59:75
|
59| ::sys_common::backtrace::__rust_begin_short_backtrace(move || main())
| ^^^^^^
note: inside call to `closure`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/sys_common/backtrace.rs:136:5
|
13| f()
| ^^^
note: inside call to `std::sys_common::backtrace::__rust_begin_short_backtrace::<[closure#DefId(1/1:1823 ~ std[82ff]::rt[0]::lang_start_internal[0]::{{closure}}[0]::{{closure}}[0]) 0:&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:59:13
|
59| ::sys_common::backtrace::__rust_begin_short_backtrace(move || main())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside call to `closure`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panicking.rs:310:40
|
31| ptr::write(&mut (*data).r, f());
| ^^^
note: inside call to `std::panicking::try::do_call::<[closure#DefId(1/1:1822 ~ std[82ff]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panicking.rs:306:5
|
30| / fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
30| | unsafe {
30| | let data = data as *mut Data<F, R>;
30| | let f = ptr::read(&mut (*data).f);
31| | ptr::write(&mut (*data).r, f());
31| | }
31| | }
| |_____^
note: inside call to `std::panicking::try::<i32, [closure#DefId(1/1:1822 ~ std[82ff]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe]>`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panic.rs:392:9
|
39| panicking::try(f)
| ^^^^^^^^^^^^^^^^^
note: inside call to `std::panic::catch_unwind::<[closure#DefId(1/1:1822 ~ std[82ff]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:58:25
|
58| let exit_code = panic::catch_unwind(|| {
| _________________________^
59| | ::sys_common::backtrace::__rust_begin_short_backtrace(move || main())
60| | });
| |__________^
note: inside call to `std::rt::lang_start_internal`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:74:5
|
74| lang_start_internal(&move || main().report(), argc, argv)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The short version is that mem::uninitialized creates a null pointer, which is being treated as a reference. That's the undefined behavior.
In your original code, the Vec::clone is implemented by iterating over an iterator. Iterator::next returns an Option<T>, so you have an option of a reference, which causes the null pointer optimization to kick in. This counts as a None, which terminates the iteration early, resulting in your empty second vector.
It turns out that having mem::uninitialized, a piece of code that gives you C-like semantics, is a giant footgun and is frequently misused (surprise!), so you aren't alone here. The main things you should follow as replacements are:
Tracking issue for RFC 1892, "Deprecate uninitialized in favor of a new MaybeUninit type"
Implement MaybeUninit
Rust 1.29.0 changed the definition of ManuallyDrop. It used to be a union (with a single member), but now it's a struct and a lang item. The role of the lang item in the compiler is to force the type to not have a destructor, even if it wraps a type that has once.
I tried copying the old definition of ManuallyDrop (which requires nightly, unless a T: Copy bound is added) and using that instead of the one from std, and it avoids the issue (at least on the Playground). I also tried dropping the second slot (slots[1]) instead of the first (slots[0]) and that also happens to work.
Although I haven't been able to reproduce the problem natively on my system (running Arch Linux x86_64), I found something interesting by using miri:
francis#francis-arch /data/git/miri master
$ MIRI_SYSROOT=~/.xargo/HOST cargo run -- /data/src/rust/so-manually-drop-1_29/src/main.rs
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `target/debug/miri /data/src/rust/so-manually-drop-1_29/src/main.rs`
error[E0080]: constant evaluation error: attempted to read undefined bytes
--> /home/francis/.rustup/toolchains/nightly-2018-09-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/liballoc/vec.rs:1903:32
|
1903 | for element in iterator {
| ^^^^^^^^ attempted to read undefined bytes
|
note: inside call to `<std::vec::Vec<T> as std::vec::SpecExtend<T, I>><MayContainValue<CountDrop>, std::iter::Cloned<std::slice::Iter<MayContainValue<CountDrop>>>>::spec_extend`
--> /home/francis/.rustup/toolchains/nightly-2018-09-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/liballoc/vec.rs:1953:9
|
1953 | self.spec_extend(iterator.cloned())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside call to `<std::vec::Vec<T> as std::vec::SpecExtend<&'a T, I>><MayContainValue<CountDrop>, std::slice::Iter<MayContainValue<CountDrop>>>::spec_extend`
--> /home/francis/.rustup/toolchains/nightly-2018-09-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/liballoc/vec.rs:1402:9
|
1402 | self.spec_extend(other.iter())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside call to `<std::vec::Vec<T>><MayContainValue<CountDrop>>::extend_from_slice`
--> /home/francis/.rustup/toolchains/nightly-2018-09-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/liballoc/slice.rs:168:9
|
168 | vector.extend_from_slice(s);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside call to `std::slice::hack::to_vec::<MayContainValue<CountDrop>>`
--> /home/francis/.rustup/toolchains/nightly-2018-09-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/liballoc/slice.rs:369:9
|
369 | hack::to_vec(self)
| ^^^^^^^^^^^^^^^^^^
note: inside call to `std::slice::<impl [T]><MayContainValue<CountDrop>>::to_vec`
--> /home/francis/.rustup/toolchains/nightly-2018-09-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/liballoc/vec.rs:1687:9
|
1687 | <[T]>::to_vec(&**self)
| ^^^^^^^^^^^^^^^^^^^^^^
note: inside call to `<std::vec::Vec<T> as std::clone::Clone><MayContainValue<CountDrop>>::clone`
--> /data/src/rust/so-manually-drop-1_29/src/main.rs:54:33
|
54 | assert_eq!(slots.len(), slots.clone().len());
| ^^^^^^^^^^^^^
note: inside call to `tests::check_drops`
--> /data/src/rust/so-manually-drop-1_29/src/main.rs:33:5
|
33 | tests::check_drops();
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0080`.
(Note: I can get the same error without using Xargo, but then miri doesn't show the source code for the stack frames in std.)
If I do this again with the original definition of ManuallyDrop, then miri doesn't report any issue. This confirms that the new definition of ManuallyDrop causes your program to have undefined behavior.
When I change std::mem::uninitialized() to std::mem::zeroed(), I can reliably reproduce the issue. When running natively, if it happens that the uninitialized memory is all zeroes, then you'll get the issue, otherwise you won't.
By calling std::mem::zeroed(), I've made the program generate null references, which are documented as undefined behavior in Rust. When the vector is cloned, an iterator is used (as shown in miri's output above). Iterator::next returns an Option<T>; that T here has a reference in it (coming from CountDrops), which causes Option's memory layout to be optimized: instead of having a discrete discriminant, it uses a null reference to represent its None value. Since I am generating null references, the iterator returns None on the first item and thus the vector ends up empty.
What's interesting is that when ManuallyDrop was defined as a union, Option's memory layout was not optimized.
println!("{}", std::mem::size_of::<Option<std::mem::ManuallyDrop<CountDrop<'static>>>>());
// prints 16 in Rust 1.28, but 8 in Rust 1.29
There is a discussion about this situation in #52898.

Resources