I know that in a file, there’s a Vec<u8> of size N (which I know in runtime), that I need to read. And I can’t figure out from the examples that I see if this is doable, or I just need to create a vector and write a cycle that reads every byte as a fixed-length struct into the target vector.
Is there a recipe for this?
In Golang, I use some memory mapping code to read fixed-size data structures, and process them one by one. Pseudocode:
struct MyStruct { a: u32, b: i32, c: f64 } // let's say it's 16 bytes long
let mut file_handler = os.Open(path_to_file).unwrap();
let my_map = Memmap(file_handler);
// might be fallible, I can't remember now
let my_var: MyStruct = some_class.read(my_map[some_offset..some_offset+16]);
then the other way around, I call some_class.write and give the offset and the new data.
The recommended crate for using memory maps is memmap2. But is there a reason you want to use a memory map for this? I would normally recommend just reading and writing to/from the file directly.
The code you shared shows the struct's bare data being written directly to the file. You can do that with the zerocopy crate, but be aware that it makes your file platform dependent. The same file might not work when transferred from one machine to another. The advantage of bincode is that the data is always the same no matter what machine you use it on.
But if that's what you want, you can look at this example:
Here, the read_from_io and write_to_io methods write the struct's raw data directly to the file. The number of bytes written will be size_of::<MyStruct>().
Actually, the issue seems to be different. Your original code works out of the box, and Rust is able to automatically find the write_to_io method on [T] when you call it on a Vec<T>. I didn't check your error properly.
Your real problem is not enabling required features:
[dependencies]
zerocopy = { version = "0.8.26", features = ["derive", "std"] }
An update: I thought bincode is slow, and I was wrong. I just used it wrong way.
Instead of
let f = File::open("path...").unwrap();
my_obj: MyType = bincode::deserialize_from(f).unwrap()
I tried to wrap the File into a BufReader and voila, -97% on benchmarks! (consistently, on both small, and big datasets)
let f = File::open("path...").unwrap();
let br = BufReader::new(f);
my_obj: MyType = bincode::deserialize_from(br).unwrap()
save with serde time: [10.520 ms 10.538 ms 10.559 ms]
change: [-97.866% -97.858% -97.852%] (p = 0.00 < 0.05)
Performance has improved.
Found 13 outliers among 100 measurements (13.00%)
1 (1.00%) high mild
12 (12.00%) high severe
deserialize rtree with serde
time: [9.9014 ms 9.9562 ms 10.009 ms]
change: [-97.268% -97.253% -97.237%] (p = 0.00 < 0.05)
Performance has improved.
I guess, all my code that worked to save to Zerocopy isn't necessary anymore. Sigh.
Nope, back to Zerocopy, because it doesn't slow down the editor as Serde derive traits do. (See messages below)
Another update, also dramatic: #[derive(Deserialize, Serialize)] is waaaay slower to check or compile. After I switched ~20 structs to Serde, the latency of Ctrl+S has jumped from like 1 second to ~5. Inline autocomplete in VSCode became much slower.