Vector of enum values creates ownership issues - rust

I have two fragments of code which worked well until a few days ago. They look fairly simple:
1.
let mut mask = 0 as c_ulong;
for bit in bits.iter() {
mask |= *bit as c_ulong;
}
2.
for bit in vec!(...).iter() {
if res & *bit as c_ulong != 0 {
bits.push(*bit);
}
}
The vector iterated vector in both cases contains an enum like:
#[allow(non_camel_case_types)]
#[deriving(PartialEq,Show)]
pub enum SomeEnum {
BLAH = 0x01,
...
}
But unfortunately now that code causes the following error on all *bit expressions.
cannot move out of dereference of `&`-pointer
I don't understand this error. Why is it now not allowed? I have a pointer to an immutable vector with enum variants that are practically just int values.
Also, how can I fix it? I know the first case can be transformed to use .into_iter() - that's ok, I don't need that vector afterwards. But in the second fragment, I actually can't use bit twice after .into_iter(). Even though I only compare it the first time!
Am I missing something trivial here?

Your type used to be Copy, but this trait is now opt-in.
Add #[deriving(Clone, Copy)] (or add Clone and Copy to the list of traits in an existing #[deriving] attribute) to your type. You need to implement both Clone and Copy, because Copy is a subtrait of Clone (as any type that implements Copy can also trivially implement Clone).
pub trait Copy: Clone { }

Related

Rust Data Structure

I am currently learning Rust for fun. I have some experience in C / C++ and other experience in other programming languages that use more complex paradigms like generics.
Background
For my first project (after the tutorial), I wanted to create a N-Dimensional array (or Matrix) data structure to practice development in Rust.
Here is what I have so far for my Matrix struct and a basic fill and new initializations.
Forgive the absent bound checking and parameter testing
pub struct Matrix<'a, T> {
data: Vec<Option<T>>,
dimensions: &'a [usize],
}
impl<'a, T: Clone> Matrix<'a, T> {
pub fn fill(dimensions: &'a [usize], fill: T) -> Matrix<'a, T> {
let mut total = if dimensions.len() > 0 { 1 } else { 0 };
for dim in dimensions.iter() {
total *= dim;
}
Matrix {
data: vec![Some(fill); total],
dimensions: dimensions,
}
}
pub fn new(dimensions: &'a [usize]) -> Matrix<'a, T> {
...
Matrix {
data: vec![None; total],
dimensions: dimensions,
}
}
}
I wanted the ability to create an "empty" N-Dimensional array using the New fn. I thought using the Option enum would be the best way to accomplish this, as I can fill the N-Dimensional with None and it would allocate space for this T generic automatically.
So then it comes down to being able to set the entries for this. I found the IndexMut and Index traits that looked like I could do something like m[&[2, 3]] = 23. Since the logic is similar to each other here is the IndexMut impl for Matrix.
impl<'a, T> ops::IndexMut<&[usize]> for Matrix<'a, T> {
fn index_mut(&mut self, indices: &[usize]) -> &mut Self::Output {
match self.data[get_matrix_index(self.dimensions, indices)].as_mut() {
Some(x) => x,
None => {
NOT SURE WHAT TO DO HERE.
}
}
}
}
Ideally what would happen is that the value (if there) would be changed i.e.
let mut mat = Matrix::fill(&[4, 4], 0)
mat[&[2, 3]] = 23
This would set the value from 0 to 23 (which the above fn does via returning &mut x from Some(x)). But I also want None to set the value i.e.
let mut mat = Matrix::new(&[4, 4])
mat[&[2, 3]] = 23
Question
Finally, is there a way to make m[&[2,3]] = 23 possible with what the Vec struct requires to allocate the memory? If not what should I change and how can I still have an array with "empty" spots. Open to any suggestions as I am trying to learn. :)
Final Thoughts
Through my research, the Vec struct impls I see that the type T is typed and has to be Sized. This could be useful as to allocate the Vec with the appropriate size via vec![pointer of T that is null but of size of T; total]. But I am unsure of how to do this.
So there are a few ways to make this more similar to idiomatic rust, but first, let's look at why the none branch doesn't make sense.
So the Output type for IndexMut I'm going to assume is &mut T as you don't show the index definition but I feel safe in that assumption. The type &mut T means a mutable reference to an initialized T, unlike pointers in C/C++ where they can point to initialized or uninitialized memory. What this means is that you have to return an initialized T which the none branch cannot because there is no initialized value. This leads to the first of the more idiomatic ways.
Return an Option<T>
The easiest way would be to change Index::Output to be an Option<T>. This is better because the user can decide what to do if there was no value there before and is close to what you are actually storing. Then you can also remove the panic in your index method and allow the caller to choose what to do if there is no value. At this point, I think you can go a little further with gentrifying the structure in the next option.
Store a T directly
This method allows the caller to directly change what the type is that's stored rather than wrapping it in an option. This cleans up most of your index code nicely as you just have to access what's already stored. The main problem is now initialization, how do you represent uninitialized values? You were correct that option is the best way to do this1, but now the caller can decide to have this optional initialization capability by storing an Option themselves. So that means we can always store initialized Ts without losing functionality. This only really changes your new function to instead not fill with None values. My suggestion here is to make a bound T: Default for the new function2:
impl<'a, T: Default> Matrix<'a, T> {
pub fn new(dimensions: &'a [usize]) -> Matrix<'a, T> {
Matrix {
data: (0..total).into_iter().map(|_|Default::default()).collect(),
dimensions: dimensions,
}
}
}
This method is much more common in the rust world and allows the caller to choose whether to allow for uninitialized values. Option<T> also implements default for all T and returns None So the functionality is very similar to what you have currently.
Aditional Info
As you're new to rust there are a few comments that I can make about traps that I've fallen into before. To start your struct contains a reference to the dimensions with a lifetime. What this means is that your structs cannot exist longer than the dimension object that created them. This hasn't caused you a problem so far as all you've been passing is statically created dimensions, dimensions that are typed into the code and stored in static memory. This gives your object a lifetime of 'static, but this won't occur if you use dynamic dimensions.
How else can you store these dimensions so that your object always has a 'static lifetime (same as no lifetime)? Since you want an N-dimensional array stack allocation is out of the question since stack arrays must be deterministic at compile time (otherwise known as const in rust). This means you have to use the heap. This leaves two real options Box<[usize]> or Vec<usize>. Box is just another way of saying this is on the heap and adds Sized to values that are ?Sized. Vec is a little more self-explanatory and adds the ability to be resized at the cost of a little overhead. Either would allow your matrix object to always have a 'static lifetime.
1. The other way to represent this without Option<T>'s discriminate is MaybeUninit<T> which is unsafe territory. This allows you to have a chunk of initialized memory big enough to hold a T and then assume it's initialized unsafely. This can cause a lot of problems and is usually not worth it as Option is already heavily optimized in that if it stores a type with a pointer it uses compiler magic to store the discriminate in whether or not that value is a null pointer.
2. The reason this section doesn't just use vec![Default::default(); total] is that this requires T: Clone as the way this macro works the first part is called once and cloned until there are enough values. This is an extra requirement that we don't need to have so the interface is smoother without it.

How do I manually implement the Copy trait for struct containing String? [duplicate]

I have an enum in Rust which has one value that takes a String:
#[derive(Clone, Copy)]
enum Simple {
Error(String),
Okay,
Foo([u32; 5]),
}
fn main() {
let x = Simple::Error(String::from("blah"));
let y = x.clone();
}
The enum value Foo above represents about 10 other enums I use that take copyable types or arrays of them. The compiler doesn't seem to complain about them, only the Error(String) which causes this:
error[E0204]: the trait `Copy` may not be implemented for this type
--> src/main.rs:1:17
|
1 | #[derive(Clone, Copy)]
| ^^^^
2 | enum Simple {
3 | Error(String),
| ------ this field does not implement `Copy`
|
For some reason, String is not copyable. I don't get this. How do I implement Clone for an enum for just the one type which has a problem while using the default impl for the rest?
Copy
Copy designates types for which making a bitwise copy creates a valid instance without invalidating the original instance.
This isn't true for String, because String contains a pointer to the string data on the heap and assumes it has unique ownership of that data. When you drop a String, it deallocates the data on the heap. If you had made a bitwise copy of a String, then both instances would try to deallocate the same memory block, which is undefined behaviour.
Since String doesn't implement Copy, your enum cannot implement Copy either because the compiler enforces that Copy types are composed only of Copy data members.
Clone
Clone merely provides a standard clone method, and it's up to each implementor to decide how to implement it. String does implement Clone, so you can put #[derive(Clone)] on your enum.
I did some exploring to see what a manual implementation would look like for an enum. I came up with this, but keep in mind you can also do #[derive(Clone)] as stated elsewhere and the compiler will do this for you.
enum Simple {
Error(String),
Okay,
Foo([u32; 5]),
}
impl Clone for Simple {
fn clone(&self) -> Simple {
match self {
Error(a) => Error(a.to_string()),
Okay => Okay,
Foo(a) => Foo(a.clone()),
}
}
}

Why does Rust not allow the copy and drop traits on one type?

From the book:
Rust won’t let us annotate a type with the Copy trait if the type, or any of its parts, has implemented the Drop trait. If the type needs something special to happen when the value goes out of scope and we add the Copy annotation to that type, we’ll get a compile time error.
Why was the design decision made to disallow Copy and Drop on the same type?
The Drop trait is used in an RAII context, typically when some resource needs to be released/closed when the object is destroyed.
In the other hand, a Copy type is a trivial type that can be copied with a memcpy only.
With those two descriptions, it is clearer that they are exclusive: it makes no sense to memcpy nontrivial data: what if we copy the data, and we drop one of the copies? The inner resource of the other copy will not be reliable anymore.
In fact, Copy in not even a "real" trait, in that it does not define any function. It is a special marker that says to the compiler: "you can duplicate myself with a simple bytes copy". So you cannot provide a custom implementation of Copy, because there is no implementation at all. However, you can mark a type as copyable:
impl Copy for Foo {}
or better, with a derive:
#[derive(Clone, Copy)]
struct Foo { /* ... */ }
This builds only if all the fields implement Copy. Otherwise, the compiler refuses to compile because this is unsafe.
For the sake of an example, let's suppose that the File struct implements Copy. Of course, this is not the case, and this example is wrong and cannot compile:
fn drop_copy_type<T>(T x)
where
T: Copy + Drop,
{
// The inner file descriptor is closed there:
std::mem::drop(x);
}
fn main() {
let mut file = File::open("foo.txt").unwrap();
drop_copy_type(file);
let mut contents = String::new();
// Oops, this is unsafe!
// We try to read an already closed file descriptor:
file.read_to_string(&mut contents).unwrap();
}
The other answers here are talking about why we don't usually want to implement both Copy and Drop for the same type, but that's not the same as explaining why it's forbidden. It might seem like a toy example like this should work just fine:
#[derive(Copy, Clone)]
struct Foo {
i: i32,
}
impl Drop for Foo {
fn drop(&mut self) {
// No problematic memory management here. Just print.
println!("{}", self.i);
}
}
fn main() {
let foo1 = Foo { i: 42 };
let foo2 = foo1;
// Shouldn't this just print 42 twice?
}
But indeed, if we try to compile that (using Rust 1.52), it fails as expected:
error[E0184]: the trait `Copy` may not be implemented for this type; the type has a destructor
--> src/main.rs:1:10
|
1 | #[derive(Copy, Clone)]
| ^^^^ Copy not allowed on types with destructors
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
For more information about this error, try `rustc --explain E0184`.
See the "For more information" note at the bottom? Those are often helpful. Let's run rustc --explain E0184:
The `Copy` trait was implemented on a type with a `Drop` implementation.
Erroneous code example:
```
#[derive(Copy)]
struct Foo; // error!
impl Drop for Foo {
fn drop(&mut self) {
}
}
```
Explicitly implementing both `Drop` and `Copy` trait on a type is currently
disallowed. This feature can make some sense in theory, but the current
implementation is incorrect and can lead to memory unsafety (see
[issue #20126][iss20126]), so it has been disabled for now.
[iss20126]: https://github.com/rust-lang/rust/issues/20126
Following that issue link leads to a discussion of "zeroing-on-drop". Present-day Rust doesn't do this anymore, but up until around 2016 Rust implemented "dynamic drop" by zeroing all the bits of a value when dropping it. But of course that isn't a valid implementation if a type can be both Copy and Drop -- Rust can't zero out a value that you're allowed to keep using -- so implementing both of those traits on the same type was disallowed. The discussion ends with this interesting comment:
Anyhow, it's easiest to forbid it for now. We can always make it legal later if someone comes up with a persuasive use case. Idempotent destructors seem like a bit of an odd thing.
What's above is the explanation for Rust's current behavior, as best I can tell. But I think there's another reason to keep things the way they are, which I haven't seen discussed: Copy currently implies that a value can be both bitwise copied and also bitwise overwritten. Consider this code:
#[derive(Copy, Clone)]
struct Foo {
i: i32,
}
fn main() {
let mut ten_foos = [Foo { i: 42 }; 10];
let ten_more_foos = [Foo { i: 99 }; 10];
// Overwrite all the bytes of the first array with those of the second.
unsafe {
std::ptr::copy_nonoverlapping(&ten_more_foos, &mut ten_foos, 1);
}
}
This unsafe code is totally fine today. In fact, [T]::copy_from_slice will do exactly the same thing for any T: Copy. But would it still be ok, if Foo (or any other Copy type) were allowed to be Drop? Our code here, and the standard library code in copy_from_slice, would be destroying objects without dropping them!
Now, technically, failing to call the destructor of an object is allowed. There was a very interesting discussion back in the day that led to std::mem::forget going from unsafe to safe shortly before Rust 1.0. So it's possible that Rust could allow Copy + Drop without leading to any undefined behavior, despite this issue. But it would be quite surprising that certain (standard!) functions would fail to call the destructors you expect. The property that "Copy objects can be bitwise copied and bitwise overwritten" seems like a good one to keep.
Quoting the documentation.
[...] [A]ny type implementing Drop can't be Copy, because it's managing some resource besides its own size_of::<T> bytes.

How do I implement Copy and Clone for a type that contains a String (or any type that doesn't implement Copy)?

I have an enum in Rust which has one value that takes a String:
#[derive(Clone, Copy)]
enum Simple {
Error(String),
Okay,
Foo([u32; 5]),
}
fn main() {
let x = Simple::Error(String::from("blah"));
let y = x.clone();
}
The enum value Foo above represents about 10 other enums I use that take copyable types or arrays of them. The compiler doesn't seem to complain about them, only the Error(String) which causes this:
error[E0204]: the trait `Copy` may not be implemented for this type
--> src/main.rs:1:17
|
1 | #[derive(Clone, Copy)]
| ^^^^
2 | enum Simple {
3 | Error(String),
| ------ this field does not implement `Copy`
|
For some reason, String is not copyable. I don't get this. How do I implement Clone for an enum for just the one type which has a problem while using the default impl for the rest?
Copy
Copy designates types for which making a bitwise copy creates a valid instance without invalidating the original instance.
This isn't true for String, because String contains a pointer to the string data on the heap and assumes it has unique ownership of that data. When you drop a String, it deallocates the data on the heap. If you had made a bitwise copy of a String, then both instances would try to deallocate the same memory block, which is undefined behaviour.
Since String doesn't implement Copy, your enum cannot implement Copy either because the compiler enforces that Copy types are composed only of Copy data members.
Clone
Clone merely provides a standard clone method, and it's up to each implementor to decide how to implement it. String does implement Clone, so you can put #[derive(Clone)] on your enum.
I did some exploring to see what a manual implementation would look like for an enum. I came up with this, but keep in mind you can also do #[derive(Clone)] as stated elsewhere and the compiler will do this for you.
enum Simple {
Error(String),
Okay,
Foo([u32; 5]),
}
impl Clone for Simple {
fn clone(&self) -> Simple {
match self {
Error(a) => Error(a.to_string()),
Okay => Okay,
Foo(a) => Foo(a.clone()),
}
}
}

Why is the Copy trait needed for default (struct valued) array initialization?

When I define a struct like this, I can pass it to a function by value without adding anything specific:
#[derive(Debug)]
struct MyType {
member: u16,
}
fn my_function(param: MyType) {
println!("param.member: {}", param.member);
}
When I want to create an array of MyType instances with a default value
fn main() {
let array = [MyType { member: 1234 }; 100];
println!("array[42].member: ", array[42].member);
}
The Rust compiler tells me:
error[E0277]: the trait bound `MyType: std::marker::Copy` is not satisfied
--> src/main.rs:11:17
|
11 | let array = [MyType { member: 1234 }; 100];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `MyType`
|
= note: the `Copy` trait is required because the repeated element will be copied
When I implement Copy and Clone, everything works:
impl Copy for MyType {}
impl Clone for MyType {
fn clone(&self) -> Self {
MyType {
member: self.member.clone(),
}
}
}
Why do I need to specify an empty Copy trait implementation?
Is there a simpler way to do this or do I have to re-think something?
Why does it work when passing an instance of MyType to the function by value? My guess is that it is being moved, so there is no copy in the first place.
Contrary to C/C++, Rust has very explicit distinction between types which are copied and which are moved. Note that this is only a semantic distinction; on the implementation level move is a shallow bytewise copy, however, the compiler places certain restrictions on what you can do with variables you moved from.
By default every type is only moveable (non-copyable). It means that values of such types are moved around:
let x = SomeNonCopyableType::new();
let y = x;
x.do_something(); // error!
do_something_else(x); // error!
You see, the value which was stored in x has been moved to y, and so you can't do anything with x.
Move semantics is a very important part of ownership concept in Rust. You can read more on it in the official guide.
Some types, however, are simple enough so their bytewise copy is also their semantic copy: if you copy a value byte-by-byte, you will get a new completely independent value. For example, primitive numbers are such types. Such property is designated by Copy trait in Rust, i.e. if a type implements Copy, then values of this type are implicitly copyable. Copy does not contain methods; it exists solely to mark that implementing types have certain property and so it is usually called a marker trait (as well as few other traits which do similar things).
However, it does not work for all types. For example, structures like dynamically allocated vectors cannot be automatically copyable: if they were, the address of the allocation contained in them would be byte-copied too, and then the destructor of such vector will be run twice over the same allocation, causing this pointer to be freed twice, which is a memory error.
So by default custom types in Rust are not copyable. But you can opt-in for it using #[derive(Copy, Clone)] (or, as you noticed, using direct impl; they are equivalent, but derive usually reads better):
#[derive(Copy, Clone)]
struct MyType {
member: u16
}
(deriving Clone is necessary because Copy inherits Clone, so everything which is Copy must also be Clone)
If your type can be automatically copyable in principle, that is, it doesn't have an associated destructor and all of its members are Copy, then with derive your type will also be Copy.
You can use Copy types in array initializer precisely because the array will be initialized with bytewise copies of the value used in this initializer, so your type has to implement Copy to designate that it indeed can be automatically copied.
The above was the answer to 1 and 2. As for 3, yes, you are absolutely correct. It does work precisely because the value is moved into the function. If you tried to use a variable of MyType type after you passed it into the function, you would quickly notice an error about using a moved value.
Why do I need to specify an empty Copy trait implementation?
Copy is a special built-in trait such that T implementing Copy represents that it is safe to duplicate a value of type T with a shallow byte copy.
This simple definition mean that one just needs to tell the compiler those semantics are correct, since there's no fundamental change in run-time behaviour: both a move (a non-Copy type) and a "copy" are shallow byte copies, it's just a question of if the source is usable later. See an older answer for more details.
(The compiler will complain if the contents of MyType isn't Copy itself; previously it would be automatically implemented, but that all changed with opt-in built-in traits.)
Creating an array is duplicating the value via shallow copies, and this is guaranteed to be safe if T is Copy. It is safe in more general situations, #5244 covers some of them, but at the core, a non-Copy struct won't be able to be used to create a fixed-length array automatically because the compiler can't tell that the duplication is safe/correct.
Is there a simpler way to do this or do I have to re-think something (I'm coming from C)?
#[derive(Copy)]
struct MyType {
member: u16
}
will insert the appropriate empty implementation (#[derive] works with several other traits, e.g. one often sees #[derive(Copy, Clone, PartialEq, Eq)].)
Why does it work when passing an instance of MyType to the function by value? My guess is that it is being moved, so there is no copy in the first place.
Well, without calling the function one doesn't see the move vs. copy behaviour (if you were to call it twice the same non-Copy value, the compiler would emit an error about moved values). But, a "move" and a "copy" are essentially the same on the machine. All by-value uses of a value are shallow copies semantically in Rust, just like in C.

Resources