Why can't I mutably borrow a primitive from an enum? - enums

I would like to be able to obtain references (both immutable and mutable) to the usize wrapped in Bar in the Foo enum:
use Foo::*;
#[derive(Debug, PartialEq, Clone)]
pub enum Foo {
Bar(usize)
}
impl Foo {
/* this works */
fn get_bar_ref(&self) -> &usize {
match *self {
Bar(ref n) => &n
}
}
/* this doesn't */
fn get_bar_ref_mut(&mut self) -> &mut usize {
match *self {
Bar(ref mut n) => &mut n
}
}
}
But I can't obtain the mutable reference because:
n does not live long enough
I was able to provide both variants of similar functions accessing other contents of Foo that are Boxed - why does the mutable borrow (and why only it) fail with an unboxed primitive?

You need to replace Bar(ref mut n) => &mut n with Bar(ref mut n) => n.
When you use ref mut n in Bar(ref mut n), it creates a mutable
reference to the data in Bar, so the type of n is &mut usize.
Then you try to return &mut n of &mut &mut u32 type.
This part is most likely incorrect.
Now deref coercion kicks in
and converts &mut n into &mut *n, creating a temporary value *n
of type usize, which doesn't live long enough.

These examples show the sample problem:
fn implicit_reborrow<T>(x: &mut T) -> &mut T {
x
}
fn explicit_reborrow<T>(x: &mut T) -> &mut T {
&mut *x
}
fn implicit_reborrow_bad<T>(x: &mut T) -> &mut T {
&mut x
}
fn explicit_reborrow_bad<T>(x: &mut T) -> &mut T {
&mut **&mut x
}
The explicit_ versions show what the compiler deduces through deref coercions.
The _bad versions both error in the exact same way, while the other two compile.
This is either a bug, or a limitation in how lifetimes are currently implemented in the compiler. The invariance of &mut T over T might have something to do with it, because it results in &mut &'a mut T being invariant over 'a and thus more restrictive during inference than the shared reference (&&'a T) case, even though in this situation the strictness is unnecessary.

Related

Is there any way to not link the lifetime of the iterator to the struct?

I am trying to implement a filter function which receives an iterator to a vector and returns an iterator with the filter. Is there any way by which I don't link the lifetime of the iterator to the struct? I am able to make it work by making lifetime of iterator depend on the struct but that is not what I intend to do.
Here is a simplified code:
struct Structure {
low: i32,
}
impl Structure {
pub fn find_low<'a>(
&mut self,
packets: impl Iterator<Item = &'a i32>,
) -> impl Iterator<Item = &'a i32> {
packets.filter(|packet| **packet < self.low)
}
pub fn new() -> Self {
Structure { low: 10 }
}
}
fn main() {
let strct = Structure::new();
let vec = [1, 2, 3, 11, 12, 13];
let mut it = strct.find_low(vec.iter());
assert_eq!(it.next().unwrap(), &vec[0]);
}
By doing so, I get an error
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> src/main.rs:9:10
|
7 | &mut self,
| --------- hidden type `Filter<impl Iterator<Item = &'a i32>, [closure#src/main.rs:10:24: 10:52]>` captures the anonymous lifetime defined here
8 | packets: impl Iterator<Item = &'a i32>,
9 | ) -> impl Iterator<Item = &'a i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
|
9 | ) -> impl Iterator<Item = &'a i32> + '_ {
| ++++
Playground
Yes, there is a way not to link the lifetime of the returned iterator to that of the reference to self: you need to move the data the filtering closure needs into the closure so that it doesn't reference it. To accomplish this, copy self.low into a local variable and move it into the closure.
Once you fix this, you will uncover a second problem: your main() as written can't invoke strct.find_low() as strct is not declared mut -- but it shouldn't need to be. find_low needlessly takes self as a mutable reference, when an immutable reference will do. Replace &mut self with &self.
pub fn find_low<'a>(
&self,
packets: impl Iterator<Item = &'a i32>,
) -> impl Iterator<Item = &'a i32> {
let low = self.low;
packets.filter(move |packet| **packet < low)
}
(Playground)
An alternative to moving a copy of self.low into the closure is to restrict the lifetime of &self to include 'a as well, though this does link the lifetime of the returned iterator to that of Structure.
pub fn find_low<'a>(
&'a self,
packets: impl Iterator<Item = &'a i32>,
) -> impl Iterator<Item = &'a i32> {
packets.filter(move |packet| **packet < self.low)
}
(Playground)

Random string generator with minimal allocations

I want to generate a large file of pseudo-random ASCII characters given the parameters: size per line and number of lines. I cannot figure out a way to do this without allocating new Strings for each line. This is what I have: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=42f5b803910e3a15ff20561117bf9176
use rand::{Rng, SeedableRng};
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let mut data: Vec<u8> = Vec::new();
write_random_lines(&mut data, 10, 10)?;
println!("{}", std::str::from_utf8(&data)?);
Ok(())
}
fn write_random_lines<W>(
file: &mut W,
line_size: usize,
line_count: usize,
) -> Result<(), Box<dyn Error>>
where
W: std::io::Write,
{
for _ in 0..line_count {
let mut s: String = rand::rngs::SmallRng::from_entropy()
.sample_iter(rand::distributions::Alphanumeric)
.take(line_size)
.collect();
s.push('\n');
file.write(s.as_bytes())?;
}
Ok(())
}
I'm creating a new String every line, so I believe this is not memory efficient. There is fn fill_bytes(&mut self, dest: &mut [u8]) but this is for bytes.
I would preferably not create a new SmallRng for each line, but it is used in a loop and SmallRng cannot be copied.
How can I generate a random file in a more memory and time efficient way?
You can easily reuse a String in a loop by creating it outside the loop and clearing it after using the contents:
// Use Kevin's suggestion not to make a new `SmallRng` each time:
let mut rng_iter =
rand::rngs::SmallRng::from_entropy().sample_iter(rand::distributions::Alphanumeric);
let mut s = String::with_capacity(line_size + 1); // allocate the buffer
for _ in 0..line_count {
s.extend(rng_iter.by_ref().take(line_size)); // fill the buffer
s.push('\n');
file.write(s.as_bytes())?; // use the contents
s.clear(); // clear the buffer
}
String::clear erases the contents of the String (dropping if necessary), but does not free its backing buffer, so it can be reused without needing to reallocate.
See also
Weird behaviour when using read_line in a loop
Why does Iterator::take_while take ownership of the iterator? explains why by_ref is needed
This modification of your code does not allocate any Strings and also does not construct a new SmallRng each time, but I have not benchmarked it:
fn write_random_lines<W>(
file: &mut W,
line_size: usize,
line_count: usize,
) -> Result<(), Box<dyn Error>>
where
W: std::io::Write,
{
// One random data iterator.
let mut rng_iter = rand::rngs::SmallRng::from_entropy()
.sample_iter(rand::distributions::Alphanumeric);
// Temporary storage for encoding of chars. If the characters used
// are not all ASCII then its size should be increased to 4.
let mut char_buffer = [0; 1];
for _ in 0..line_count {
for _ in 0..line_size {
file.write(
rng_iter.next()
.unwrap() // iterator is infinite so this never fails
.encode_utf8(&mut char_buffer)
.as_bytes())?;
}
file.write("\n".as_bytes())?;
}
Ok(())
}
I am new to Rust so it may be missing some ways to tidy it up. Also, note that this writes only one character at a time; if your W is more expensive per operation than an in-memory buffer, you probably want to wrap it in std::io::BufWriter, which will batch writes to the destination (using a buffer that needs to be allocated, but only once).
I (MakotoE) benchmarked Kevin Reid's answer, and it seems their method is faster though memory allocation seems to be the same.
Benchmarking time-wise:
#[cfg(test)]
mod tests {
extern crate test;
use test::Bencher;
use super::*;
#[bench]
fn bench_write_random_lines0(b: &mut Bencher) {
let mut data: Vec<u8> = Vec::new();
data.reserve(100 * 1000000);
b.iter(|| {
write_random_lines0(&mut data, 100, 1000000).unwrap();
data.clear();
});
}
#[bench]
fn bench_write_random_lines1(b: &mut Bencher) {
let mut data: Vec<u8> = Vec::new();
data.reserve(100 * 1000000);
b.iter(|| {
// This is Kevin's implementation
write_random_lines1(&mut data, 100, 1000000).unwrap();
data.clear();
});
}
}
test tests::bench_write_random_lines0 ... bench: 764,953,658 ns/iter (+/- 7,597,989)
test tests::bench_write_random_lines1 ... bench: 360,662,595 ns/iter (+/- 886,456)
Benchmarking memory usage using valgrind's Massif shows that both are about the same. Mine used 3.072 Gi total, 101.0 MB at peak level. Kevin's used 4.166 Gi total, 128.0 MB peak.

Speedup counter game

I'm trying to solve a Rust algorithm question on hackerrank. My answer times out on some of the larger test cases. There are about 5 people who've completed it, so I believe it is possible and I assume they compile in release mode. Is there any speed-ups I'm missing?
The gist of the game is a counter (inp in main) is conditionally reduced and based on who can't reduce it any more, the winner is chosen.
use std::io;
fn main() {
let n: usize = read_one_line().
trim().parse().unwrap();
for _i in 0..n{
let inp: u64 = read_one_line().
trim().parse().unwrap();
println!("{:?}", find_winner(inp));
}
return;
}
fn find_winner(mut n: u64) -> String{
let mut win = 0;
while n>1{
if n.is_power_of_two(){
n /= 2;
}
else{
n -= n.next_power_of_two()/2;
}
win += 1;
}
let winner =
if win % 2 == 0{
String::from("Richard")
} else{
String::from("Louise")
};
winner
}
fn read_one_line() -> String{
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read");
input
}
Your inner loop can be replaced by a combination of builtin functions:
let win = if n > 0 {
n.count_ones() + n.trailing_zeros() - 1
} else {
0
};
Also, instead of allocating a string every time find_winner is called,
a string slice may be returned:
fn find_winner(n: u64) -> &'static str {
let win = if n > 0 {
n.count_ones() + n.trailing_zeros() - 1
} else {
0
};
if win % 2 == 0 {
"Richard"
} else{
"Louise"
}
}
Avoiding memory allocation can help speeding up the application.
At the moment, the read_one_line function is doing one memory allocation per call, which can be avoided if you supply the String as a &mut parameter:
fn read_one_line(input: &mut String) -> &str {
io::stdin().read_line(input).expect("Failed to read");
input
}
Note how I also alter the return type to return a slice (which borrows input): further uses here do not need to modify the original string.
Another improvement is I/O. Rust is all about explicitness, and it means that io::stdin() is raw I/O: each call to read_line triggers interactions with the kernel.
You can (and should) instead used buffered I/O with std::io::BufReader. Build it once, then pass it as an argument:
fn read_one_line<'a, R>(reader: &mut R, input: &'a mut String) -> &'a str
where R: io::BufRead
{
reader.read_line(input).expect("Failed to read");
input
}
Note:
it's easier to make it generic (R) than to specify the exact type of BufReader :)
annotating the lifetime is mandatory because the return type could borrow either parameter
Putting it altogether:
fn read_one_line<'a, R>(reader: &mut R, input: &'a mut String) -> &'a str
where R: io::BufRead
{
reader.read_line(input).expect("Failed to read");
input
}
fn main() {
let mut reader = io::BufReader::new(io::stdin());
let mut input = String::new();
let n: usize = read_one_line(&mut reader, &mut input).
trim().parse().unwrap();
for _i in 0..n{
let inp: u64 = read_one_line(&mut reader, &mut input).
trim().parse().unwrap();
println!("{:?}", find_winner(inp));
}
return;
}
with the bigger win probably being I/O (might even be sufficient in itself).
Don't forget to also apply #John's advices, this way you'll be allocation-free in your main loop!

Let &mut syntax

It is possible to make the following binding in Rust:
let &mut a = &mut 5;
But what does it mean exactly? For example, let a = &mut 5 creates an immutable binding of type &mut i32, let mut a = &mut 5 creates a mutable binding of type &mut i32. What about let &mut?
An easy way to test the type of something is to assign it to the wrong type:
let _: () = a;
In this case the value is an "integral variable", or a by-value integer. It is not mutable (as testing with a += 1 shows).
This is because you are using destructuring syntax. You are pattern matching your &mut 5 against an &mut _, much like if you wrote
match &mut 5 { &mut a => {
// rest of code
} };
Thus you are adding a mutable reference and immediately dereferencing it.
To bind a mutable reference to a value instead, you can do
let ref mut a = 5;
This is useful in destructuring to take references to multiple inner values.

What is the reason for requiring &mut foo instead of &foo when foo has been declared mutable?

For a C routine like
MPI_Comm_rank(MPI_Comm comm, int *rank);
The Rust foreign function interface could be declared like this:
use libc::c_int; // 0.2.79
#[link(name = "mpi")]
extern "C" {
fn MPI_Comm_rank(mpi_comm: c_int, rank: *mut c_int);
}
I call the binding like this, which works, but left me puzzled about syntax:
pub static MPI_COMM_WORLD: libc::c_int = 0x44000000;
fn main() {
let mut rank: c_int = 999999;
/* but why '&mut rank' and not simply '&rank' ? */
unsafe { MPI_Comm_rank(MPI_COMM_WORLD, &mut rank) }
}
I originally tried
unsafe { MPI_Comm_rank(MPI_COMM_WORLD, &rank) }
but this gives a compiler error:
error[E0308]: mismatched types
--> src/main.rs:12:44
|
12 | unsafe { MPI_Comm_rank(MPI_COMM_WORLD, &rank) }
| ^^^^^ types differ in mutability
|
= note: expected raw pointer `*mut i32`
found reference `&i32`
I declared 'rank' as mut, so what gives?
You’re conflating two completely distinct features.
let mut x; makes a mutable binding x, allowing you to modify what x is bound to (x = 42) and for non-reference types to modify its contents (x.y = 42). It does not control the mutability of the target of references.
This is different from the type of references you’re dealing with.
&mut T is a mutable reference and can be coerced to *mut T.
&T is an immutable reference can be coerced to *const T.
As the function you are calling wants *mut T, you must pass it a *mut T or a &mut T; *const T or &T will not do.
To be sure, you can only take a mutable reference to mutable data, so let x = 42; &mut x doesn’t work as it needs let mut x instead of let x, but that’s still entirely distinct and is a part of Rust’s rules about mutability.
Your function expects *mut c_int pointer (a mutable raw pointer), and you need to use &mut operator to obtain it. However, you can only take &mut pointer to mut variables, hence you need to declare rank variable as mut rank.
If your function expected *const c_int pointer, you would be able to use &, but this is not the case.

Resources