Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read (std::io::Read) from a Vec or Slice?

Tags:

io

rust

traits

Vecs support std::io::Write, so code can be written that takes a File or Vec, for example. From the API reference, it looks like neither Vec nor slices support std::io::Read.

Is there a convenient way to achieve this? Does it require writing a wrapper struct?

Here is an example of working code, that reads and writes a file, with a single line commented that should read a vector.

use ::std::io;  // Generic IO fn write_4_bytes<W>(mut file: W) -> Result<usize, io::Error>     where W: io::Write, {     let len = file.write(b"1234")?;     Ok(len) }  fn read_4_bytes<R>(mut file: R) -> Result<[u8; 4], io::Error>     where R: io::Read, {     let mut buf: [u8; 4] = [0; 4];     file.read(&mut buf)?;     Ok(buf) }  // Type specific  fn write_read_vec() {     let mut vec_as_file: Vec<u8> = Vec::new();      {   // Write         println!("Writing Vec... {}", write_4_bytes(&mut vec_as_file).unwrap());     }      {   // Read //      println!("Reading File... {:?}", read_4_bytes(&vec_as_file).unwrap());         //                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^         //                               Comment this line above to avoid an error!     } }  fn write_read_file() {     let filepath = "temp.txt";     {   // Write         let mut file_as_file = ::std::fs::File::create(filepath).expect("open failed");         println!("Writing File... {}", write_4_bytes(&mut file_as_file).unwrap());     }      {   // Read         let mut file_as_file = ::std::fs::File::open(filepath).expect("open failed");         println!("Reading File... {:?}", read_4_bytes(&mut file_as_file).unwrap());     } }  fn main() {     write_read_vec();     write_read_file(); } 

This fails with the error:

error[E0277]: the trait bound `std::vec::Vec<u8>: std::io::Read` is not satisfied   --> src/main.rs:29:42    | 29 |         println!("Reading File... {:?}", read_4_bytes(&vec_as_file).unwrap());    |                                          ^^^^^^^^^^^^ the trait `std::io::Read` is not implemented for `std::vec::Vec<u8>`    |    = note: required by `read_4_bytes` 

I'd like to write tests for a file format encoder/decoder, without having to write to the file-system.

like image 450
ideasman42 Avatar asked Feb 15 '17 04:02

ideasman42


People also ask

How do you read in Rust?

The first and simplest method to read a file in Rust is to load it as an entire string. We can accomplish this using the std::fs::read_to_string method. The previous code imports the File struct and the prelude module. In the main function, we create a mutable variable called file and load open the arp.

What is VEC in Rust?

Vector is a module in Rust that provides the container space to store values. It is a contiguous resizable array type, with heap-allocated contents. It is denoted by Vec<T>. Vectors in Rust have O(1) indexing and push and pop operations in vector also take O(1) complexity.

How do you initialize VEC in Rust?

In Rust, there are several ways to initialize a vector. In order to initialize a vector via the new() method call, we use the double colon operator: let mut vec = Vec::new();

How do you clear a vector in Rust?

To remove all elements from a vector in Rust, use . retain() method to keep all elements the do not match. let mut v = vec![


1 Answers

While vectors don't support std::io::Read, slices do.

There is some confusion here caused by Rust being able to coerce a Vec into a slice in some situations but not others.

In this case, an explicit coercion to a slice is needed because at the stage coercions are applied, the compiler doesn't know that Vec<u8> doesn't implement Read.


The code in the question will work when the vector is coerced into a slice using one of the following methods:

  • read_4_bytes(&*vec_as_file)
  • read_4_bytes(&vec_as_file[..])
  • read_4_bytes(vec_as_file.as_slice()).

Note:

  • When asking the question initially, I was taking &Read instead of Read. This made passing a reference to a slice fail, unless I'd passed in &&*vec_as_file which I didn't think to do.
  • Recent versions of rust you can also use as_slice() to convert a Vec to a slice.
  • Thanks to @arete on #rust for finding the solution!
like image 70
ideasman42 Avatar answered Sep 19 '22 19:09

ideasman42