Why is it possible to have multiple mutable references with static lifetime in same scope - static

Why can I have multiple mutable references to a static type in the same scope?
My code:
static mut CURSOR: Option<B> = None;
struct B {
pub field: u16,
}
impl B {
pub fn new(value: u16) -> B {
B { field: value }
}
}
struct A;
impl A {
pub fn get_b(&mut self) -> &'static mut B {
unsafe {
match CURSOR {
Some(ref mut cursor) => cursor,
None => {
CURSOR= Some(B::new(10));
self.get_b()
}
}
}
}
}
fn main() {
// first creation of A, get a mutable reference to b and change its field.
let mut a = A {};
let mut b = a.get_b();
b.field = 15;
println!("{}", b.field);
// second creation of A, a the mutable reference to b and change its field.
let mut a_1 = A {};
let mut b_1 = a_1.get_b();
b_1.field = 16;
println!("{}", b_1.field);
// Third creation of A, get a mutable reference to b and change its field.
let mut a_2 = A {};
let b_2 = a_2.get_b();
b_2.field = 17;
println!("{}", b_1.field);
// now I can change them all
b.field = 1;
b_1.field = 2;
b_2.field = 3;
}
I am aware of the borrowing rules
one or more references (&T) to a resource,
exactly one mutable reference (&mut T).
In the above code, I have a struct A with the get_b() method for returning a mutable reference to B. With this reference, I can mutate the fields of struct B.
The strange thing is that more than one mutable reference can be created in the same scope (b, b_1, b_2) and I can use all of them to modify B.
Why can I have multiple mutable references with the 'static lifetime shown in main()?
My attempt at explaining this is behavior is that because I am returning a mutable reference with a 'static lifetime. Every time I call get_b() it is returning the same mutable reference. And at the end, it is just one identical reference. Is this thought right? Why am I able to use all of the mutable references got from get_b() individually?

There is only one reason for this: you have lied to the compiler. You are misusing unsafe code and have violated Rust's core tenet about mutable aliasing. You state that you are aware of the borrowing rules, but then you go out of your way to break them!
unsafe code gives you a small set of extra abilities, but in exchange you are now responsible for avoiding every possible kind of undefined behavior. Multiple mutable aliases are undefined behavior.
The fact that there's a static involved is completely orthogonal to the problem. You can create multiple mutable references to anything (or nothing) with whatever lifetime you care about:
fn foo() -> (&'static i32, &'static i32, &'static i32) {
let somewhere = 0x42 as *mut i32;
unsafe { (&*somewhere, &*somewhere, &*somewhere) }
}
In your original code, you state that calling get_b is safe for anyone to do any number of times. This is not true. The entire function should be marked unsafe, along with copious documentation about what is and is not allowed to prevent triggering unsafety. Any unsafe block should then have corresponding comments explaining why that specific usage doesn't break the rules needed. All of this makes creating and using unsafe code more tedious than safe code, but compared to C where every line of code is conceptually unsafe, it's still a lot better.
You should only use unsafe code when you know better than the compiler. For most people in most cases, there is very little reason to create unsafe code.
A concrete reminder from the Firefox developers:

Related

Can't initialize array of not copyable structs [duplicate]

I’m trying to initialize a fixed-size array of some nullable, non-copyable type, like an Option<Box<Thing>> for some kind of Thing. I’d like to pack two of them into a struct without any extra indirection. I’d like to write something like this:
let array: [Option<Box<Thing>>; SIZE] = [None; SIZE];
But it doesn’t work because the [e; n] syntax requires that e implements Copy. Of course, I could expand it into SIZE Nones, but that can be unwieldy when SIZE is large. I don’t believe this can be done with a macro without an unnatural encoding of SIZE. Is there a good way to do it?
Yes, this is easy with unsafe; is there a way to do it without unsafe?
As of Rust 1.38 (released in September 2019), a cleaner alternative to previously posted answers is possible using an intermediate const initializer. This approach works for arrays of any size:
const SIZE: usize = 100;
const INIT: Option<Box<Thing>> = None;
let array: [Option<Box<Thing>>; SIZE] = [INIT; SIZE];
(It works with or without the Box; the example uses Box because it was used in the question.)
One limitation is that the array item must have a default representation that can be evaluated at compile time - a constant, enum variant, or a primitive container composed of those. None or a tuple of numbers will work, but a non-empty Vec or String won't.
You could use the Default trait to initialize the array with default values:
let array: [Option<Box<Thing>>; SIZE] = Default::default();
See this playground for a working example.
Note that this will only work for arrays with up to 32 elements, because Default::default is only implemented for up to [T; 32]. See https://doc.rust-lang.org/std/default/trait.Default.html#impl-Default-for-%5BT%3B%2032%5D.
As of Rust 1.55.0 (which introduced [T]::map()), the following will work:
const SIZE: usize = 100;
#[derive(Debug)]
struct THING { data: i64 }
let array = [(); SIZE].map(|_| Option::<THING>::default());
for x in array {
println!("x: {:?}", x);
}
Rust Playground
I'm copying the answer by chris-morgan and adapting it to match the question better, to follow the recommendation by dbaupp downthread, and to match recent syntax changes:
use std::mem;
use std::ptr;
#[derive(Debug)]
struct Thing {
number: usize,
}
macro_rules! make_array {
($n:expr, $constructor:expr) => {{
let mut items: [_; $n] = mem::uninitialized();
for (i, place) in items.iter_mut().enumerate() {
ptr::write(place, $constructor(i));
}
items
}}
}
const SIZE: usize = 50;
fn main() {
let items = unsafe { make_array!(SIZE, |i| Box::new(Some(Thing { number: i }))) };
println!("{:?}", &items[..]);
}
Note the need to use unsafe here: The problem is that if the constructor function panic!s, this would lead to undefined behavior.
Go through the heap
If you can create a Vec of your type, you can convert it into an array:
use std::convert::TryInto;
#[derive(Clone)]
struct Thing;
const SIZE: usize = 100;
fn main() {
let v: Vec<Option<Thing>> = vec![None; SIZE];
let v: Box<[Option<Thing>; SIZE]> = match v.into_boxed_slice().try_into() {
Ok(v) => v,
Err(_) => unreachable!(),
};
let v: [Option<Thing>; SIZE] = *v;
}
In many cases, you actually want to leave it as a Vec<T>, Box<[T]>, or Box<[T; N]> as these types all put the data in the heap. Large arrays tend to be... large... and you don't want all that data on the stack.
See also:
What is the use of into_boxed_slice() methods?
How to get a slice as an array in Rust?
How do I get an owned value out of a `Box`?
Keep it simple
Type out all the values:
struct Thing;
const SIZE: usize = 5;
fn main() {
let array: [Option<Box<Thing>>; SIZE] = [None, None, None, None, None];
}
You could use a build script to generate this code for you. For an example of this, see:
How to create a static string at compile time
An alternative approach using the arrayvec crate that generalizes easily to situations other than initializing everything with a fixed value:
use arrayvec::ArrayVec;
let array = std::iter::repeat(None)
.take(SIZE)
.collect::<ArrayVec<Option<Box<Thing>>, SIZE>>()
.into_inner()
.unwrap();
(playground)
On nightly Rust, you can use inline const. This is a variant of the answer by #user4815162342, but one that doesn't require you to declare a separate constant and repeat the type:
#![feature(inline_const)]
let array: [Option<Box<Thing>>; SIZE] = [const { None }; SIZE];
Until this is stabilized (hopefully soon), you can also use the inline-const crate, but this does require you to repeat the type.
let stackoverflow: [Option<&mut ()>;0xDEADBEEF] = std::array::from_fn(|_| None);
dbg!(stackoverflow);
playground

Rust: iterating over iter() or vector itself

I was watching a Rust lecture and seen I think two ways of iterating over a vector. I could iterate over "vector itself" or over "iter() method". Could you please tell me what is the difference here?
fn call(from: &mut Vec<i32>, to: &mut Vec<i32>) {
for e in from.iter() {
to.push(*e);
}
for e in from {
to.push(*e);
}
}
fn printvec(from: & Vec<i32>) {
for e in from {
print!("{} ", e);
}
println!("");
}
fn main() {
let mut v1 = vec![1,2,3];
let mut v2 = vec![1,2,3];
call(&mut v1, &mut v2);
printvec(&v1);
printvec(&v2);
}
Could you please tell me what is the difference here?
Here there is no difference as Stargateur notes. To know what's happening, you simply need to follow the white rabbit trait implementation: Rust's for loop "simply" calls IntoIterator on the "RHS". Now if we go down the list of implementors
We can see an implementation for &Vec
It's not documented per-se but looking at the code it just calls self.iter(), so here we do have the confirmation that Stargateur is correct, &Vec and Vec::iter do the exact same thing
Vec::iter
The documentation is a bit terse but it links to std::slice::Iter which is "Immutable slice iterator", not necessarily super helpful in and of itself but the trait implementation is pretty clear
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T
}
So Vec<T>::iter -> Iter<T> -> Iterator<Item=&a>, meaning when you .iter() a vector (or you iterate an &Vec) you iterate on immutable references to the items. And since iter takes &self (and &Vec is obviously a reference) it also means that the iteration only borrows the vector, so once you're done iterating the vector is still there unchanged.
&mut Vec and Vec::iter_mut
Though you didn't mention it that's the second iterator, it's similar to the one above except it yields a std::slice::IterMut which
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T
}
so instead of yielding immutable references to items it yields mutable ones, which means you can modify items in-place, e.g. increment them, pretty cool.
Vec itself
So we come to this, and if you expand the definition you see essentially this:
impl<T> IntoIterator for Vec<T> {
type Item = T
type IntoIter = IntoIter<T, A>
pub fn into_iter(self) -> IntoIter<T, A>
Creates a consuming iterator, that is, one that moves each value out of the vector (from start to end). The vector cannot be used after calling this.
Which is pretty self-explanatory: if you iterate on the Vec directly it consumes the vector, meaning you will not be able to use it afterwards.
In return, however, it moves the ownership of the vector's items into the iterator, which provides more flexibility.
From the Rust Reference:
'label: for PATTERN in iter_expr {
/* loop body */
}
is equivalent to
{
let result = match IntoIterator::into_iter(iter_expr) {
mut iter => 'label: loop {
let mut next;
match Iterator::next(&mut iter) {
Option::Some(val) => next = val,
Option::None => break,
};
let PATTERN = next;
let () = { /* loop body */ };
},
};
result
}
The difference between your for loops is that in one the iter_expr is from and in the other it is from.iter(). IntoIterator is implemented like this for a vector reference:
impl<'a, T, A: Allocator> IntoIterator for &'a Vec<T, A> {
type Item = &'a T;
type IntoIter = slice::Iter<'a, T>;
fn into_iter(self) -> slice::Iter<'a, T> {
self.iter()
}
}
Note that it's calling self.iter(), so there is no difference between this iterator and the one you get from your from.iter() for loop.

Initialize array holding struct more efficiently

I have the following code:
const N: usize = 10000;
const S: usize = 7000;
#[derive(Copy, Clone, Debug)]
struct T {
a: f64,
b: f64,
f: f64
}
fn main() {
let mut t: [T; N] = [T {a: 0.0, b: 0.0, f: 0.0}; N];
for i in 0..N {
t[i].a = 0.0;
t[i].b = 1.0;
t[i].f = i as f64 * 0.25;
}
for _ in 0..S {
for i in 0..N {
t[i].a += t[i].b * t[i].f;
t[i].b -= t[i].a * t[i].f;
}
println!("{}", t[1].a);
}
}
I'm unsure why the array t must be initialized that way. The first for-loop is intended to initialize the array with the containing struct to their respective values.
When I try to omit the initialization directly with the array:
let mut t: [T; N];
I get the following error:
error[E0381]: use of possibly uninitialized variable: t
All for-loops are intended to be as such, I just want to know if there is a smarter way for the array and it's initialization with the first for-loop.
I'm unsure why the array t must be initialized that way.
Because Rust doesn't let you touch (entirely or partially) uninitialised values. The compiler isn't smart enough to prove that the loop will definitely initialise everything, so it just forbids it.
Now, the optimiser is a different story. That can notice that the initialisation is redundant and skip it... in theory. It doesn't appear to do so with that code and the current compiler. Such is optimisation.
I just want to know if there is a smarter way for the array and it's initialization with the first for-loop.
The smart way is to just leave the code as-it-is. Statistically speaking, it's unlikely to be a bottleneck. If profiling suggests that it is a bottleneck, then you can use uninitialised. However, note that doing so can lead to undefined behaviour if you use it wrong. Although not an exhaustive list, you definitely avoid using it on any type that is not Copy.
If you do need to use it, I strongly recommend also adjusting the first loop to make forgetting to initialise an element or a field in the structure impossible:
let mut t: [T; N] = unsafe { ::std::mem::uninitialized() };
for (i, e) in t.iter_mut().enumerate() {
*e = T {
a: 0.0,
b: 1.0,
f: i as f64 * 0.25,
}
}
You can use std::mem::uninitialized(). Note, however, that it is considered unsafe and needs to be marked as such:
let mut t: [T; N] = unsafe { std::mem::uninitialized() };
As stated by the aforelinked docs:
This is useful for FFI functions and initializing arrays sometimes,
but should generally be avoided.

How do I move values out of an array one at a time?

I have ownership of an array of size 3 and I would like to iterate on it, moving the elements out as I go. Basically, I would like to have IntoIterator implemented for a fixed-sized array.
Since arrays don't implement this trait in the standard library (I understand why), is there a workaround to get the desired effect? My objects are not Copy nor Clone. I'd be okay creating a Vec from the array and then iterating into the Vec, but I'm not even sure how to do that.
(For information, I'd like to fulfill an array of Complete)
Here is a simple example of the situation (with a naive iter() attempt):
// No-copy, No-clone struct
#[derive(Debug)]
struct Foo;
// A method that needs an owned Foo
fn bar(foo: Foo) {
println!("{:?}", foo);
}
fn main() {
let v: [Foo; 3] = [Foo, Foo, Foo];
for a in v.iter() {
bar(*a);
}
}
playground
Gives
error[E0507]: cannot move out of borrowed content
--> src/main.rs:14:13
|
14 | bar(*a);
| ^^ cannot move out of borrowed content
Rust 2021 (available from Rust 1.56)
You can iterate the array with a for loop:
fn main() {
let v: [Foo; 3] = [Foo, Foo, Foo];
for a in v {
bar(a);
}
}
struct Foo;
fn bar(_: Foo) {}
Rust 1.51
You can use std::array::IntoIter to get a by-value array iterator:
use std::array::IntoIter;
fn main() {
let v: [Foo; 3] = [Foo, Foo, Foo];
for a in IntoIter::new(v) {
bar(a);
}
}
struct Foo;
fn bar(_: Foo) {}
Previous Rust versions
The core thing you would need is some way of getting the value out of the array without moving it.
This can be done using mem::transmute to convert the array to an array of mem::MaybeUninit, then using ptr::read to leave the value in the array but get an owned value back:
let one = unsafe {
let v = mem::transmute::<_, [MaybeUninit<Foo>; 3]>(v);
ptr::read(&v[0]).assume_init()
};
bar(one);
It's just a matter of doing this a few times in a loop and you are good to go.
There's just one tiny problem: you see that unsafe? You guessed it; this is totally, horribly broken in the wider case:
MaybeUninit does nothing when it is dropped; this can lead to memory leaks.
If a panic happens in the middle of moving the values out (such as somewhere within the bar function), the array will be in a partially-uninitialized state. This is another (subtle) path where the MaybeUninit can be dropped, so now we have to know which values the array still owns and which have been moved out. We are responsible for freeing the values we still own and not the others.
Nothing prevents us from accidentally accessing the newly-invalidated values in the array ourselves.
The right solution is to track how many of the values in the array are valid / invalid. When the array is dropped, you can drop the remaining valid items and ignore the invalid ones. It'd also be really nice if we could make this work for arrays of different sizes...
Which is where arrayvec comes in. It doesn't have the exact same implementation (because it's smarter), but it does have the same semantics:
use arrayvec::ArrayVec; // 0.5.2
#[derive(Debug)]
struct Foo;
fn bar(foo: Foo) {
println!("{:?}", foo)
}
fn main() {
let v = ArrayVec::from([Foo, Foo, Foo]);
for f in v {
bar(f);
}
}
You may use array of Option<Foo> instead array of Foo. It has some memory penalty of course. Function take() replaces value in array with None.
#[derive(Debug)]
struct Foo;
// A method that needs an owned Foo
fn bar(foo: Foo) { println!("{:?}", foo); }
fn main() {
let mut v = [Some(Foo),Some(Foo),Some(Foo)];
for a in &mut v {
a.take().map(|x| bar(x));
}
}
Using the non-lexical lifetimes feature (available since Rust 1.31.0) and a fixed-length slice pattern (available since Rust 1.26.0) you can move out of an array:
#[derive(Debug)]
struct Foo;
fn bar(foo: Foo) {
println!("{:?}", foo);
}
fn main() {
let v: [Foo; 3] = [Foo, Foo, Foo];
let [a, b, c] = v;
bar(a);
bar(b);
bar(c);
}
However, this solution does not scale well if the array is big.
An alternative, if you don't mind the extra allocation, is to box the array and convert it into a Vec:
fn main() {
let v: [Foo; 3] = [Foo, Foo, Foo];
let v = Vec::from(Box::new(v) as Box<[_]>);
for a in v {
bar(a);
}
}
If the array is very big, that may be an issue. But then, if the array is very big, you should not be creating it in the stack in the first place!
stable since Rust 1.65
This is the use case the LendingIterator was developed for:
extern crate lending_iterator;
use ::lending_iterator::prelude::*;
// No-copy, No-clone struct
#[derive(Debug)]
struct Foo;
// A method that needs an owned Foo
fn bar(foo: Foo) {
println!("{:?}", foo);
}
fn main() {
let array: [Foo; 3] = [Foo, Foo, Foo];
let mut iter = array.into_lending_iter();
while let Some(a) = iter.next() {
bar(a);
}
}

How do I create and initialize an immutable array?

I want to create an array. I don't need the array to be mutable, and at the time of creation, I have all the information I need to calculate the i-th member of the array. However, can't figure out how to create an immutable array in Rust.
Here's what I have now:
let mut my_array: [f32; 4] = [0.0; 4];
for i in 0..4 {
// some calculation, doesn't matter what exactly
my_array[i] = some_function(i);
}
And here's what I want:
let my_array: [f32; 4] = array_factory!(4, some_function);
How can I achieve that in Rust?
Here's the macro definition with sample usage:
macro_rules! array_factory(
($size: expr, $factory: expr) => ({
unsafe fn get_item_ptr<T>(slice: *mut [T], index: usize) -> *mut T {
(slice as *mut T).offset(index as isize)
}
let mut arr = ::std::mem::MaybeUninit::<[_; $size]>::uninit();
unsafe {
for i in 0..$size {
::std::ptr::write(get_item_ptr(arr.as_mut_ptr(), i), $factory(i));
}
arr.assume_init()
}
});
);
fn some_function(i: usize) -> f32 {
i as f32 * 3.125
}
fn main() {
let my_array: [f32; 4] = array_factory!(4, some_function);
println!("{} {} {} {}", my_array[0], my_array[1], my_array[2], my_array[3]);
}
The macro's body is essentially your first version, but with a few changes:
The type annotation on the array variable is omitted, because it can be inferred.
The array is created uninitialized, because we're going to overwrite all values immediately anyway. Messing with uninitialized memory is unsafe, so we must operate on it from within an unsafe block. Here, we're using MaybeUninit, which was introduced in Rust 1.36 to replace mem::uninitialized1.
Items are assigned using std::ptr::write() due to the fact that the array is uninitialized. Assignment would try to drop an uninitialized value in the array; the effects depend on the array item type (for types that implement Copy, like f32, it has no effect; for other types, it could crash).
The macro body is a block expression (i.e. it's wrapped in braces), and that block ends with an expression that is not followed by a semicolon, arr.assume_init(). The result of that block expression is therefore arr.assume_init().
Instead of using unsafe features, we can make a safe version of this macro; however, it requires that the array item type implements the Default trait. Note that we must use normal assignment here, to ensure that the default values in the array are properly dropped.
macro_rules! array_factory(
($size: expr, $factory: expr) => ({
let mut arr = [::std::default::Default::default(), ..$size];
for i in 0..$size {
arr[i] = $factory(i);
}
arr
});
)
1 And for a good reason. The previous version of this answer, which used mem::uninitialized, was not memory-safe: if a panic occurred while initializing the array (because the factory function panicked), and the array's item type had a destructor, the compiler would insert code to call the destructor on every item in the array; even the items that were not initialized yet! MaybeUninit avoids this problem because it wraps the value being initialized in ManuallyDrop, which is a magic type in Rust that prevents the destructor from running automatically.
Now, there is a (pretty popular) crate to do that exact thing: array_init
use array_init::array_init;
let my_array: [f32; 4] = array_init(some_function);
PS:
There is a lot of discussion and evolution around creating abstractions around arrays inside the rust team.
For example, the map function for arrays is already available, and it will become stable in rust 1.55.
If you wanted to, you could implement your function with map:
#![feature(array_map)]
let mut i = 0usize;
result = [(); 4].map(|_| {v = some_function(i);i = i+1; v})
And there are even discussions around your particular problem, you can look here
Try to make your macro expand to this:
let my_array = {
let mut tmp: [f32, ..4u] = [0.0, ..4u];
for i in range(0u, 4u) {
tmp[i] = somefunction(i);
}
tmp
};
What I don't know is whether this is properly optimized to avoid moving tmp to my_array. But for 4 f32 values (128 bits) it probably does not make a significant difference.

Resources