use std::io::Write;
pub struct A{
pub a: u8,
pub b: u16
}
impl A {
pub fn to_bytes(&self, output: &mut &mut[u8]) -> Result<(), std::io::Error> {
output.write_all(&[self.a])?;
output.write_all(&self.b.to_be_bytes()[..])?;
Ok(())
}
}
fn main() {
let mut buffer: &mut [u8] = &mut [0u8; 10];
let a = A{
a: 7,
b: 100
};
a.to_bytes(&mut buffer);
println!("{:?}", buffer);
}
this prints [0, 0, 0, 0, 0]
because it splits the slice and gives the rest for more writes. playground
What would be the most elegant way to get the actual output after many writes, and not the remainder slice? I don't want to keep track of how many bytes were written just so I can subslice the buffer output.
Context: microcontrollers don't allow for memory allocation so I pass a worst case buffer slice for write and it's almost never filled to the end.
Mutate a reborrow so that buffer
keeps the original range:
impl A {
pub fn to_bytes(&self, mut output: &mut[u8]) -> Result<(), std::io::Error> {
... // ^^^
}
}
fn main() {
...
a.to_bytes(buffer);
...
}
It will print:
[7, 0, 100, 0, 0, 0, 0, 0, 0, 0]
If you want to write the data, keep track of how many bytes were written, and use that to affect buffer
in-place; you can accomplish that like so:
impl A {
pub fn to_bytes(&self, buffer: &mut &mut[u8]) -> Result<(), std::io::Error> {
let mut output = &mut **buffer;
let space = output.len();
output.write_all(&[self.a])?;
output.write_all(&self.b.to_be_bytes()[..])?;
let written = space - output.len();
// see https://stackoverflow.com/questions/61223234/can-i-reassign-a-mutable-slice-reference-to-a-sub-slice-of-itself
// for in-place mutable sub-slicing
let orig = std::mem::replace(buffer, &mut []);
*buffer = &mut orig[..written];
Ok(())
}
}
with your code will print:
[7, 0, 100]
It would likely be more extensible and ergonomic if you just returned the bytes written and slice yourself, but to each their own.