Hello!
This is my first post here, so I apologise if this has ended up in the wrong place. Have made an attempt to search for the answer to this question, but can't really piece it together. I am quite the beginner when it comes to Rust, so my searches may be hindered by me lacking the right terminology.
In essence, I seem to be having problems with getting slices and arrays working happily/ergonomically together. Specifically, I need to write/read a little binary blob that needs to be in a specific format, i.e. basically
struct SomeRecord {
... values of various types ...
}
impl SomeRecord {
fn encode(&self) -> [u8; 32] { ... }
fn decode(bytes: [u8; 32]) -> Self { ... }
I can get it to work, but I suspect I am missing something because it seems a bit clunky. Beginning from the beginning, this works fine:
fn encode1(number: u64) -> [u8; 8] {
number.to_le_bytes()
}
fn decode1(bytes: [u8; 8]) -> u64 {
u64::from_le_bytes(bytes)
}
Trying to pack more than one thing into an array, I would naïvely start with something like this:
fn encode(...) -> [u8; 32] {
// a zero-initialised u8 array of the right length
let mut output [u8; 32] = [0; 32];
// won't compile: left side is a slice, right side is an array
output[0..4] = self.some_u32.to_le_bytes();
...
output
}
After a few iterations, I end up with something like this instead:
fn encode2(n1: u64, n2: u64) -> [u8; 16] {
let mut output : [u8; 16] = [0;16];
output[0..8].copy_from_slice(n1.to_le_bytes().as_slice());
output[8..16].copy_from_slice(n2.to_le_bytes().as_slice());
output
}
As for decoding, I have a [u8; 16]
(for example) and conceptually I want to do this:
u64::from_le_bytes(bytes[8..16])
but now I have the same problem again: from_le_bytes
takes an array and bytes[8..16]
is a slice. Here, again it seems to me like the size should be known at compile time since 8..16 is rather constant. Anyway, what I end up with is something like:
fn decode2(bytes: [u8;16]) -> (u64, u64) {
let first = u64::from_le_bytes(bytes[0..8].try_into().unwrap());
let second = u64::from_le_bytes(bytes[8..16].try_into().unwrap());
(first, second)
}
Given that I am working with fixed-size records and fixed-size data types, I do not worry about the try_into().unwrap()
. But it seems like it defeats the purpose a bit: given we are working with an array and constant ranges, is there a more ergonomic way of doing this?
I have tried looking into the serde
codebase but it is a bit overwhelming for a noob, I have to admit