Use of moved value `inb` - rust

I'm trying to write a function, and I'm getting an error message about borrowing that I can't solve because I'm struggling to wrap my head around other responses on this site. Here's the function I've got so far:
use orgize::Org;
fn convert(i: String) -> String {
let inb: Vec<u8> = Vec::new();
Org::parse_string(i).write_html(inb);
let out = String::from_utf8(inb).unwrap();
return out;
}
And it's outputting the following error:
error[E0382]: use of moved value: `inb`
--> src/main.rs:9:30
|
7 | let inb: Vec<u8> = Vec::new();
| --- move occurs because `inb` has type `Vec<u8>`, which does not implement the `Copy` trait
8 | Org::parse_string(i).write_html(inb);
| --- value moved here
9 | let out = String::from_utf8(inb).unwrap();
| ^^^ value used here after move

When you call write_html(inb), you are moving inb. It cannot be used anymore.
Since write_html() accepts a generic W: Write, and Vec<u8> implements Write but also any &mut Write implements Write, you can just pass &mut inb to borrow inb instead of moving it:
fn convert(i: String) -> String {
let mut inb: Vec<u8> = Vec::new();
Org::parse_string(i).write_html(&mut inb);
let out = String::from_utf8(inb).unwrap();
return out;
}

Related

Difficulty creating a mock 'sink' for testing purposes in Rust

Context
I have a function that will use rayon to paralellize some work. Each thread should write its output to a separate consumer. In practice, these consumers will usually write to (separate) files on disc. For testing, I want them to append to vectors, which I can then make assertions on.
Problem
In fact I hit an issue even with a serial version of this code.
The function I want to test is func_under_test. I want get_sink to create and hand out a new 'sink' (a Vec<i32>) each time it is called, which will be inside func_under_test. But I also want to keep a reference to these vectors in my main function, so I can make assertions on them. I've tried writing this:
fn func_under_test<GetSink, F>(
mut get_sink: GetSink
)
where
GetSink: FnMut(usize) -> F,
F: FnMut(i32) -> (),
{
let idxs : Vec<usize> = (0..2).collect();
idxs.iter().for_each(|&i| {
let mut sink = get_sink(i);
sink(0i32);
sink(1i32);
sink(2i32);
});
}
fn main() {
let mut sinks : Vec<&Vec<i32>> = vec![];
let get_sink = |i: usize| {
let mut sink : Vec<i32> = vec![];
sinks.push(&sink);
move |x : i32| sink.push(x)
};
func_under_test(get_sink);
assert_eq!(**sinks.get(0).unwrap(), vec![0i32, 1i32, 2i32]);
}
But I get this compilation error:
error[E0597]: `sink` does not live long enough
--> src/main.rs:23:20
|
20 | let mut sinks : Vec<&Vec<i32>> = vec![];
| --------- lifetime `'1` appears in the type of `sinks`
...
23 | sinks.push(&sink);
| -----------^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `sink` is borrowed for `'1`
24 | move |x : i32| sink.push(x)
25 | };
| - `sink` dropped here while still borrowed
error[E0505]: cannot move out of `sink` because it is borrowed
--> src/main.rs:24:9
|
20 | let mut sinks : Vec<&Vec<i32>> = vec![];
| --------- lifetime `'1` appears in the type of `sinks`
...
23 | sinks.push(&sink);
| -----------------
| | |
| | borrow of `sink` occurs here
| argument requires that `sink` is borrowed for `'1`
24 | move |x : i32| sink.push(x)
| ^^^^^^^^^^^^^^ ---- move occurs due to use in closure
| |
| move out of `sink` occurs here
Am I correct in thinking that I need to use something like an Rc in this context, since I need to have two references to each Vec<i32>?
Since only one of those references needs to be mutable, do I need to use Rc<Cell<Vec<i32>>> in one case, and just Rc<Vec<i32>> in the other?
You could use an Arc<Mutex<i32>> to share mutable access to the vectors. (Rc is not thread-safe.)
A tidier solution would be typed_arena::Arena, which would allow you to write essentially the code you tried, but with the roles swapped: the Vec<i32>s are always owned by the arena (thus it outlives func_under_tests). Then, after all of the references to the arena are gone, you can convert it into a vector of its elements.
use typed_arena::Arena;
fn main() {
let sinks: Arena<Vec<i32>> = Arena::new();
let get_sink = |_i: usize| {
let sink_ref = sinks.alloc(Vec::new());
move |x| sink_ref.push(x)
};
func_under_test(get_sink);
assert_eq!(sinks.into_vec()[0], vec![0i32, 1i32, 2i32]);
}
I think I've figured out the answer to this. The thread doing the testing needs to have access to the inner vectors, and so does the thread that is populating this. So they need to be wrapped in an Arc and a Mutex. But the outer vector does not, since it is only borrowed by the get_sink closure.
So sinks can have type Vec<Arc<Mutex<Vec<i32>>>.
Anyway, I can write this and it does compile and behave and expected:
use rayon::prelude::*;
use std::sync::{Arc, Mutex};
fn func_under_test<G, S>(
get_sink: G)
where
G: Fn(&usize) -> S + Sync,
S: FnMut(i32) -> (),
{
let idxs : Vec<usize> = vec![0, 1, 2];
idxs.par_iter().for_each(|i| {
let mut sink : S = get_sink(i);
for j in 0..3 {
sink(j + 3*(*i) as i32);
}
});
}
fn main() {
let sinks : Vec<Arc<Mutex<Vec<i32>>>> = vec![
Arc::new(Mutex::new(vec![])),
Arc::new(Mutex::new(vec![])),
Arc::new(Mutex::new(vec![])),
];
let get_sink = |i: &usize| {
let m : Arc<Mutex<Vec<i32>>> = sinks.get(*i).unwrap().clone();
move |x: i32| {
m.lock().unwrap().push(x);
}
};
func_under_test(get_sink);
assert_eq!(*sinks.get(0).unwrap().lock().unwrap(), vec![0, 1, 2]);
assert_eq!(*sinks.get(1).unwrap().lock().unwrap(), vec![3, 4, 5]);
assert_eq!(*sinks.get(2).unwrap().lock().unwrap(), vec![6, 7, 8]);
}
It also seems like G implements the correct traits here: it is Sync, since it needs to be shared between threads. But is is not Send, since it does not need to send information between threads.

Iterate through a whole file one character at a time

I'm new to Rust and I'm struggle with the concept of lifetimes. I want to make a struct that iterates through a file a character at a time, but I'm running into issues where I need lifetimes. I've tried to add them where I thought they should be but the compiler isn't happy. Here's my code:
struct Advancer<'a> {
line_iter: Lines<BufReader<File>>,
char_iter: Chars<'a>,
current: Option<char>,
peek: Option<char>,
}
impl<'a> Advancer<'a> {
pub fn new(file: BufReader<File>) -> Result<Self, Error> {
let mut line_iter = file.lines();
if let Some(Ok(line)) = line_iter.next() {
let char_iter = line.chars();
let mut advancer = Advancer {
line_iter,
char_iter,
current: None,
peek: None,
};
// Prime the pump. Populate peek so the next call to advance returns the first char
let _ = advancer.next();
Ok(advancer)
} else {
Err(anyhow!("Failed reading an empty file."))
}
}
pub fn next(&mut self) -> Option<char> {
self.current = self.peek;
if let Some(char) = self.char_iter.next() {
self.peek = Some(char);
} else {
if let Some(Ok(line)) = self.line_iter.next() {
self.char_iter = line.chars();
self.peek = Some('\n');
} else {
self.peek = None;
}
}
self.current
}
pub fn current(&self) -> Option<char> {
self.current
}
pub fn peek(&self) -> Option<char> {
self.peek
}
}
fn main() -> Result<(), Error> {
let file = File::open("input_file.txt")?;
let file_buf = BufReader::new(file);
let mut advancer = Advancer::new(file_buf)?;
while let Some(char) = advancer.next() {
print!("{}", char);
}
Ok(())
}
And here's what the compiler is telling me:
error[E0515]: cannot return value referencing local variable `line`
--> src/main.rs:37:13
|
25 | let char_iter = line.chars();
| ---- `line` is borrowed here
...
37 | Ok(advancer)
| ^^^^^^^^^^^^ returns a value referencing data owned by the current function
error[E0597]: `line` does not live long enough
--> src/main.rs:49:34
|
21 | impl<'a> Advancer<'a> {
| -- lifetime `'a` defined here
...
49 | self.char_iter = line.chars();
| -----------------^^^^--------
| | |
| | borrowed value does not live long enough
| assignment requires that `line` is borrowed for `'a`
50 | self.peek = Some('\n');
51 | } else {
| - `line` dropped here while still borrowed
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0515, E0597.
For more information about an error, try `rustc --explain E0515`.
error: could not compile `advancer`.
Some notes:
The Chars iterator borrows from the String it was created from. So you can't drop the String while the iterator is alive. But that's what happens in your new() method, the line variable owning the String disappears while the iterator referencing it is stored in the struct.
You could also try storing the current line in the struct, then it would live long enough, but that's not an option – a struct cannot hold a reference to itself.
Can you make a char iterator on a String that doesn't store a reference into the String? Yes, probably, for instance by storing the current position in the string as an integer – it shouldn't be the index of the char, because chars can be more than one byte long, so you'd need to deal with the underlying bytes yourself (using e.g. is_char_boundary() to take the next bunch of bytes starting from your current index that form a char).
Is there an easier way? Yes, if performance is not of highest importance, one solution is to make use of Vec's IntoIterator instance (which uses unsafe magic to create an object that hands out parts of itself) :
let char_iter = file_buf.lines().flat_map(|line_res| {
let line = line_res.unwrap_or(String::new());
line.chars().collect::<Vec<_>>()
});
Note that just returning line.chars() would have the same problem as the first point.
You might think that String should have a similar IntoIterator instance, and I wouldn't disagree.

Is there a way to use locked standard input and output in a constructor to live as long as the struct you're constructing?

I'm building a PromptSet that can ask a series of questions in a row. For testing reasons, it allows you to pass a reader and writer instead of using stdin & stdout directly.
Because stdin and stdout are the common use case, I would like to create a default "constructor" that allows the user to produce a PromptSet<StdinLock, StdoutLock> without needing any parameters. Here's the code so far:
use std::io::{self, BufRead, StdinLock, StdoutLock, Write};
pub struct PromptSet<R, W>
where
R: BufRead,
W: Write,
{
pub reader: R,
pub writer: W,
}
impl<R, W> PromptSet<R, W>
where
R: BufRead,
W: Write,
{
pub fn new(reader: R, writer: W) -> PromptSet<R, W> {
return PromptSet {
reader: reader,
writer: writer,
};
}
pub fn default<'a>() -> PromptSet<StdinLock<'a>, StdoutLock<'a>> {
let stdin = io::stdin();
let stdout = io::stdout();
return PromptSet {
reader: stdin.lock(),
writer: stdout.lock(),
};
}
pub fn prompt(&mut self, question: &str) -> String {
let mut input = String::new();
write!(self.writer, "{}: ", question).unwrap();
self.writer.flush().unwrap();
self.reader.read_line(&mut input).unwrap();
return input.trim().to_string();
}
}
fn main() {}
StdinLock and StdoutLock both need a lifetime declared. To complicate it, I think the original stdin()/stdout() handles need to live at least as long as the locks do. I would like the references to StdinLock and StdoutLock to live as long as my PromptSet does but no matter what I try I can't get it to work. Here is the error that I keep getting:
error[E0597]: `stdin` does not live long enough
--> src/main.rs:30:21
|
30 | reader: stdin.lock(),
| ^^^^^ borrowed value does not live long enough
...
33 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the method body at 25:5...
--> src/main.rs:25:5
|
25 | / pub fn default<'a>() -> PromptSet<StdinLock<'a>, StdoutLock<'a>> {
26 | | let stdin = io::stdin();
27 | | let stdout = io::stdout();
28 | |
... |
32 | | };
33 | | }
| |_____^
error[E0597]: `stdout` does not live long enough
--> src/main.rs:31:21
|
31 | writer: stdout.lock(),
| ^^^^^^ borrowed value does not live long enough
32 | };
33 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the method body at 25:5...
--> src/main.rs:25:5
|
25 | / pub fn default<'a>() -> PromptSet<StdinLock<'a>, StdoutLock<'a>> {
26 | | let stdin = io::stdin();
27 | | let stdout = io::stdout();
28 | |
... |
32 | | };
33 | | }
| |_____^
It's perfectly possible I just don't understand the concept of lifetimes or something else super basic.
The lock method's signature is fn lock(&self) -> StdinLock, which, when fully expanded with lifetime annotations, is fn lock<'a>(&'a self) -> StdinLock<'a>. Thus the StdinLock can only live as long as the value that the lock method is called on. Since you defined stdin in this very function, the StdinLock can't outlive the function. This is the same as returning a reference to a local value. You also can't return the reference and the referred-to value together.
You can't do this, and you can't work around it. The only fix is to have the default method take a Stdin and a Stdout object as arguments.
That said, you can work around it. Yes I know, I just said the exact opposite, but it's more of a "no one other than me will ever use stdin/stdout" (a.k.a., println! will not work anymore!).
In Rust 1.26, you can use Box::leak to leak the Stdin to a &'static Stdin, which will yield a StdinLock<'static>. Before Rust 1.26, you can use the leak crate:
pub fn default() -> PromptSet<StdinLock<'static>, StdoutLock<'static>> {
let stdin = Box::leak(Box::new(io::stdin()));
let stdout = Box::leak(Box::new(io::stdout()));
PromptSet {
reader: stdin.lock(),
writer: stdout.lock(),
}
}
Might be not really the answer to your question, but to a similar problem. Here's my solution.
The main trick here is to call stdin.lock() for every single line.
use std::io;
use std::io::prelude::*;
use std::io::Stdin;
struct StdinWrapper {
stdin: Stdin,
}
impl Iterator for StdinWrapper {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
let stdin = &self.stdin;
let mut lines = stdin.lock().lines();
match lines.next() {
Some(result) => Some(result.expect("Cannot read line")),
None => None,
}
}
}
/**
* Callers of this method should not know concrete source of the strings.
* It could be Stdin, a file, DB, or even aliens from SETI.
*/
fn read() -> Box<Iterator<Item = String>> {
let stdin = io::stdin();
Box::new(StdinWrapper { stdin })
}
fn main() {
let lines = read();
for line in lines {
println!("{}", line);
}
}

How to destructure tuple struct with reference

I'm trying to use the hyper library to make some requests. The Headers::get() method returns Option<&H>, where H is a tuple struct with one field. I can use if let Some() to destructure the Option. But how do we destructure the &H? Sure I could always access the field with .0, but I'm curious if Rust has a syntax to do this.
struct s(String);
fn f(input: &s) -> &s {
input
}
fn main() {
let my_struct1 = s("a".to_owned());
let s(foo) = my_struct1;
let my_struct2 = s("b".to_owned());
let &s(bar) = f(&my_struct2); // this does not work
let baz = &my_struct2.0; // this works
}
When you try to compile this, the Rust compiler will tell you how to fix the error with a nice message:
error[E0507]: cannot move out of borrowed content
--> <anon>:11:9
|
11 | let &s(bar) = f(&my_struct2); // this does not work
| ^^^---^
| | |
| | hint: to prevent move, use `ref bar` or `ref mut bar`
| cannot move out of borrowed content
This is needed to tell the compiler that you only want a reference to the field in the struct; the default matching will perform a move and the original struct value will no longer be valid.
Let's fix the example:
struct s(String);
fn f(input: &s) -> &s {
input
}
fn main() {
let my_struct1 = s("a".to_owned());
let s(foo) = my_struct1;
let my_struct2 = s("b".to_owned());
let &s(ref bar) = f(&my_struct2);
}
Another way is to dereference first and drop the &. I think this is preferred in Rust:
struct s(String);
fn f(input: &s) -> &s {
input
}
fn main() {
let my_struct1 = s("a".to_owned());
let s(foo) = my_struct1;
let my_struct2 = s("b".to_owned());
let s(ref bar) = *f(&my_struct2);
}

Get file content as a vector: Borrowed value does not live long enough [duplicate]

I have a simple piece of code that is supposed to read a file into a vector by lines
use std::io::{self, Read};
use std::fs::File;
fn file_to_vec(filename: &str) -> Result<Vec<&str>, io::Error> {
let mut file = try!(File::open(filename));
let mut string = String::new();
try!(file.read_to_string(&mut string));
string.replace("\r", "");
let data: Vec<&str> = string.split('\n').collect();
Ok(data)
}
fn main() {}
I am getting the following error:
error[E0597]: `string` does not live long enough
--> src/main.rs:10:27
|
10 | let data: Vec<&str> = string.split('\n').collect();
| ^^^^^^ does not live long enough
...
13 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 4:1...
--> src/main.rs:4:1
|
4 | / fn file_to_vec(filename: &str) -> Result<Vec<&str>, io::Error> {
5 | | let mut file = try!(File::open(filename));
6 | | let mut string = String::new();
7 | | try!(file.read_to_string(&mut string));
... |
12 | | Ok(data)
13 | | }
| |_^
Why do I keep getting this error? How do I fix this? I imagine that it has something to do with the split method.
I could return the string and then split it into a Vec in the main function, but I really want to return a vector.
The problem is that string is created in your function and will be destroyed when the function returns. The vector you want to return contains slices of string, but those will not be valid outside of your function.
If you're not terribly worried about performance, you can return a Vec<String> from your function. You just have to return type to Result<Vec<String>, io::Error> and change the line
let data: Vec<&str> = string.split('\n').collect();
to
let data: Vec<String> = string.split('\n').map(String::from).collect();

Resources