I feel like this has probably been answered before, but I cannot find how to make this work.
Say I have a struct such as struct A { a: usize, b: usize } and I want to read from disk an array of exactly 128 of these structs. I'm using the bincode package and attempting as such:
let entries :[A; 128] = bincode::deserialize(my_file).expect("Error");
I get the following error:
the trait `serde::Deserialize<'_>` is not implemented for `[bat::A; 128]`
= help: the following implementations were found:
<&'a [u8] as serde::Deserialize<'de>>
<[T; 0] as serde::Deserialize<'de>>
<[T; 10] as serde::Deserialize<'de>>
<[T; 11] as serde::Deserialize<'de>>
and 30 others
Looking into the serde code, I found the following:
array_impls! {
1 => (0 a)
2 => (0 a 1 b)
3 => (0 a 1 b 2 c)
... snip ...
30 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z 26 aa 27 ab 28 ac 29 ad)
31 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z 26 aa 27 ab 28 ac 29 ad 30 ae)
32 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z 26 aa 27 ab 28 ac 29 ad 30 ae 31 af)
}
That seems to indicate to me that they only implemented arrays up to 32 items... so what is the best way to get 128 items? Do I need a custom Deserializer here? This seems like overkill and that maybe a simple mem::transmute might be the easiest/fastest way to go here.
Until the const generics lands on stable, using arrays longer than 32 is pure pain in Rust. It's best to avoid them, don't expect them to work smoothly like "normal" types.
@alice it doesn't. The file is initialized with all zeros, and so it doesn't read any of them. Again, I need to tell the deserializer to stop after reading 32 of the structs, and I'm not sure how to do that. Thanks!
It sounds like the data was not serialized using bincode. Consider using the byteorder crate instead which provides a bunch of nice methods in the ReadBytesExt trait, which you can call on anything that implements Read which includes File (and the buffered version BufReader<File>).
Yea, it wasn't I thought it would be able to handle this fairly easily, but using a simple mem::transmuteseems to be the easiest way to go here. In case someone else comes looking:
let mut buff = [0u8; BLOCK_SIZE];
// read in one block
self.device.read_exact(&mut buff)?;
// transmute the buffer to an array
let entries :[A; ENTRIES_PER_BLOCK as usize] = unsafe { std::mem::transmute(buff) };
Note that the mem::transmute is undefined behavior because your A type is not #[repr(C)] and even if you add it, it now depends on the endianess of the system.