I have a binary file which has a header determining the length of each data element in the file. For example byte length of 2, 4 or 8 etc.
How to define to a function that's output can be a vector of i16, i32 or i64 for reading this data?
This would be something like this:
fn read_data<T: NoIdeaTrait>(&mut self, file: &mut File) -> Vec<T> {
let mut data = Vec::new();
let _ = file.read_to_end(&mut data);
self.sampled_data = data
// This is dynamic value
.chunks(self.byte_per_block as usize)
// Depending on the value this code would change
// to take into account byte_per_block
.map(|x| i32::from_le_bytes(x))
.collect()
}
What would be a sensible approach here?
Make up your own FromMyFile
trait for it.
use std::io::{Cursor, Read};
trait FromMyFile<const SIZE: usize> {
fn from_bytes(bytes: [u8; SIZE]) -> Self;
}
impl FromMyFile<4> for i32 {
fn from_bytes(bytes: [u8; 4]) -> Self {
i32::from_le_bytes(bytes)
}
}
impl FromMyFile<8> for i64 {
fn from_bytes(bytes: [u8; 8]) -> Self {
i64::from_le_bytes(bytes)
}
}
fn read_data<T: FromMyFile<SIZE>, const SIZE: usize>(mut bytes: impl Read) -> Vec<T> {
let mut data = Vec::new();
loop {
let mut buf = [0; SIZE];
match bytes.read(&mut buf) {
Ok(s) if s == SIZE => {}
Ok(0) => {
break;
}
Ok(_) => {
panic!("unexpected lenght")
}
Err(e) => {
println!("io error {:?}", e);
panic!()
}
}
data.push(T::from_bytes(buf));
}
data
}
fn main() {
let buffer = Cursor::new([0_u8; 256]);
let vec: Vec<i32> = read_data(buffer.clone());
println!("{:?}", vec);
let vec: Vec<i64> = read_data(buffer);
println!("{:?}", vec);
}
Maybe something like this?
// Result for reading my file
#[derive(Debug)]
pub enum MyFileResult {
I32(Vec<i32>),
I64(Vec<i64>),
}
impl MyFileResult {
pub fn from_read(mut bytes: impl Read) -> Self {
let mut header = [0];
bytes.read(&mut header).unwrap();
match header[0] {
0 => MyFileResult::I32(read_data(bytes)),
1 => MyFileResult::I64(read_data(bytes)),
_ => unreachable!("unknown encoding format"),
}
}
}
fn main() {
// data with the first byte as the header determine the encoding size
// - 0 for i32 encoded
// - 1 for i64 encoded
let mut data = [0_u8; 257];
{
let data = data.clone();
let buffer = Cursor::new(data);
let res = MyFileResult::from_read(buffer);
assert!(matches!(res, MyFileResult::I32(_)));
println!("{:?}", res);
}
{
// change the encoding style to i64 encoded
data[0] = 1;
let buffer = Cursor::new(data);
let res = MyFileResult::from_read(buffer);
assert!(matches!(res, MyFileResult::I64(_)));
println!("{:?}", res);
}
}