byteorder
byteorder copied to clipboard
Feature request: Add write_uXX_from to WriteBytesExt trait
I write some kind of protocol parser and I use next code to read protocol data:
reader.read_u32_into::<LittleEndian>(&mut buffer);
I would like to use the same logic for writer:
writer.write_u32_from::<LittleEndian>(&buffer);
Is that already possible? Or it needs implementation?
I think there would be fine to add, yes. I believe the necessary APIs for implementing this are already available on the ByteOrder trait.
@BurntSushi, For now I see no other way except writing each chunk separately:
#[inline]
fn write_u16_from<T: ByteOrder>(&mut self, src: &[u16]) -> Result<()> {
for &n in src {
self.write_u16::<T>(n)?
}
Ok(())
}
The problem here is that we can get an error after some data is already written. In this case we can do nothing to roll back the writer to last stable state.
It is done mostly like write_slice
macro. The only difference is that write_slice
is able to check if src
fits dst
and panic if it doesn't.
If that's the only implementation choice, then we probably shouldn't provide it.
You can do a bit better if you check if T
is the same as NativeEndian
or not; if it is, you can just cast the slice into bytes and use write_all
.
It would look something a bit like
pub trait ByteOrderIo: ByteOrder {
fn write_u16_from<W: Write + ?Sized>(writer: &mut W, src: &[u16]) -> Result<()>;
// ...
}
impl ByteOrderIo for LittleEndian {
#[cfg(target_endian = "little")]
fn write_u16_from<W: Write + ?Sized>(writer: &mut W, src: &[u16]) -> Result<()> {
let base = src.as_ptr() as *const u8;
// SAFETY: I don't think len can overflow here, since creating a slice at all
// requires len * size_of <= isize::MAX, but maybe do some splitting into parts
// if that's a worry.
let casted_slice = unsafe { std::slice::from_raw_parts(base, src.len() * std::mem::size_of::<u16>()) };
writer.write_all(casted_slice)
}
#[cfg(not(target_endian = "little"))]
pub fn write_u16_from<W: Write + ?Sized>(writer: &mut W, src: &[u16]) -> Result<()> {
// But we could also batch calls to write_all here via using a larger buffer.
let mut buf = [0u8; 2];
for &n in src {
Self::write_u16(&mut buf, n);
writer.write_all(&buf)?;
}
Ok(())
}
}