I need to do a simple read/process/write in Rust like this:
#[derive(serde::Deserialize)]
struct Incoming {
first: String,
last: String,
}
#[derive(serde::Serialize)]
struct Outgoing {
name: String,
}
// Keep the read/write traits as generic as possible
fn stream_things<R: std::io::Read, W: std::io::Write>(reader: R, writer: W) {
let incoming: Vec<Incoming> = serde_json::from_reader(reader).unwrap();
for a in incoming {
let b = Outgoing {
name: format!("{} {}", a.first, a.last),
};
serde_json::to_writer(writer, &b).unwrap();
}
}
fn main() {
stream_things(std::io::stdin(), std::io::stdout());
}
This does not compile because:
error[E0382]: use of moved value: `writer`
--> src/main.rs:20:31
|
13 | fn stream_things<R: std::io::Read, W: std::io::Write>(reader: R, writer: W) {
| -- ------ move occurs because `writer` has type `W`, which does not implement the `Copy` trait
| |
| help: consider further restricting this bound: `W: Copy +`
...
20 | serde_json::to_writer(writer, &b).unwrap();
| ^^^^^^ value moved here, in previous iteration of loop
What is the correct way to write to std::io::Write
in a loop?
Also how to correctly do it with serde's to_writer
?
See the plaground.
Given W
is io::Write
, then &mut W
is also io::Write
:
impl<'_, W: Write + ?Sized> Write for &'_ mut W
so the following compiles:
fn stream_things<R: std::io::Read, W: std::io::Write>(reader: R, mut writer: W) {
let incoming: Vec<Incoming> = serde_json::from_reader(reader).unwrap();
for a in incoming {
let b = Outgoing {
name: format!("{} {}", a.first, a.last),
};
serde_json::to_writer(&mut writer, &b).unwrap();
}
}
Do you mind me asking how you got to the
&mut
from that error message? Would never occur to me.@DmytriiNagirniak nothing specially really. Using a value by itself will consume it, whereas by its reference or mutable reference will not. Reading any Rust API signature, that's one thing dictates how it is intended to be used.