I'm trying to type-pun an io::stdio
instance and a BufReader
wrapping a file so that I can write code assuming a buffered input source. I've tried several variations of trying to cast an io::stdio()
to a BufRead
type and all have failed with one or more variations of:
error: mismatched types:
expected `std::io::stdio::StdinLock<'_>`,
found `std::io::buffered::BufReader<std::fs::File>`
(expected struct `std::io::stdio::StdinLock`,
found struct `std::io::buffered::BufReader`) [E0308]
csv_to_json.rs:26 reader = BufReader::new(file.unwrap());
Here's the code:
use std::io;
use std::io::BufReader;
use std::io::prelude::*;
use std::env;
use std::process::exit;
use std::fs::File;
fn usage() {
println!("Usage: cat input.csv | csv_to_json");
}
fn main() {
let stdin = io::stdin();
let mut reader = stdin.lock(); // Assignment. (1)
let args: Vec<String> = env::args().collect();
if args.len() > 1 {
usage();
exit(1);
} else if args.len() == 1 {
let file = File::open(args[0].clone());
if !file.is_ok() {
usage();
exit(1);
}
reader = BufReader::new(file.unwrap()); // Reassignment. This is the line that fails.
}
// Rest of the code works with reader assuming a buffered input source.
}
Things that I have tried:
let mut reader : BufRead = io::stdin(); // Fails.
let mut reader : BufReader<Read> = io::stdin(); // Fails.
let mut reader : BufReader<_> = io::stdin(); // Fails
let mut reader : BufRead = io::stdin().lock(); // Fails later.
let mut reader = BufReader::new(io::stdin()); // Fails with type mismatch.
let mut reader = BufReader::new(io::stdin().lock()); // Fails with type mismatch.
I've even tried extracting that code to its own function and the return type signature fails with similar error conditions. How can I create a "reader" variable that's either a BufferedReader
over stdio
or a BufferedReader
over a File
without facing type errors everywhere?
Your code can be rewritten so that there is no need to reassign reader
variable (see @Vladimir Matveev answer).
If you really need it, then reader
variable must be a trait object:
let mut bufread;//must be defined before reader to avoid lifetime issues
let stdin = io::stdin();
let mut reader = &mut stdin.lock() as &mut BufRead; // Assignment. (1)
//...
bufread = BufReader::new(file.unwrap());//store BufReader value
reader = &mut bufread;// reassign BufRead reference
Boxed form of trait object allows to avoid additional variable bufread
:
let stdin = io::stdin();
let mut reader = Box::new(stdin.lock()) as Box<BufRead>;
//...
reader = Box::new(BufReader::new(file.unwrap()));
This will work.
use std::io;
use std::io::BufReader;
use std::io::prelude::*;
use std::env;
use std::process::exit;
use std::fs::File;
fn usage() {
println!("Usage: cat input.csv | csv_to_json");
}
fn main() {
let stdin = io::stdin();
let mut reader = Box::new(stdin.lock()) as Box<BufRead>;
let args: Vec<String> = env::args().collect();
if args.len() > 1 {
usage();
exit(1);
} else if args.len() == 1 {
let file = File::open(args[0].clone());
if !file.is_ok() {
usage();
exit(1);
}
reader = Box::new(BufReader::new(file.unwrap()));
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With