diff --git a/src/tools.rs b/src/tools.rs index f5ed3296..4da9c491 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -31,6 +31,8 @@ pub mod tty; pub mod signalfd; pub mod daemon; pub mod procfs; +pub mod read; +pub mod write; mod process_locker; pub use process_locker::*; diff --git a/src/tools/read.rs b/src/tools/read.rs new file mode 100644 index 00000000..0c64699f --- /dev/null +++ b/src/tools/read.rs @@ -0,0 +1,50 @@ +//! Utility traits for types which implement `std::io::Read` to quickly read primitively typed +//! values such as binary integers from a stream. + +use std::io; +use std::mem; + +use endian_trait::Endian; + +pub trait ReadUtilOps { + /// Read a value of type `T`. + /// Note that it *should* be `repr(C, packed)` or similar. + fn read_value(&mut self) -> io::Result; + + /// Read a big-endian value of type `T`. + /// Note that it *should* be `repr(C, packed)` or similar. + fn read_value_be(&mut self) -> io::Result { + Ok(self.read_value::()?.from_be()) + } + + /// Read a little-endian value of type `T`. + /// Note that it *should* be `repr(C, packed)` or similar. + fn read_value_le(&mut self) -> io::Result { + Ok(self.read_value::()?.from_le()) + } + + /// Read an exact number of bytes into a newly allocated vector. + fn read_exact_allocated(&mut self, size: usize) -> io::Result>; +} + +impl ReadUtilOps for R { + fn read_value(&mut self) -> io::Result { + let mut data: T = unsafe { mem::uninitialized() }; + self.read_exact(unsafe { + std::slice::from_raw_parts_mut( + &mut data as *mut T as *mut u8, + mem::size_of::(), + ) + })?; + Ok(data) + } + + fn read_exact_allocated(&mut self, size: usize) -> io::Result> { + let mut out = Vec::with_capacity(size); + unsafe { + out.set_len(size); + } + self.read_exact(&mut out)?; + Ok(out) + } +} diff --git a/src/tools/write.rs b/src/tools/write.rs new file mode 100644 index 00000000..1bb4cf57 --- /dev/null +++ b/src/tools/write.rs @@ -0,0 +1,43 @@ +//! Utility traits for types which implement `std::io::Write` to easily write primitively typed +//! values such as binary integers to a stream. + +use std::io; +use std::mem; + +use endian_trait::Endian; + +pub trait WriteUtilOps { + /// Write a value of type `T`. + /// Note that it *should* be `repr(C, packed)` or similar. + fn write_value(&mut self, value: &T) -> io::Result; + + /// Write a big-endian value of type `T`. + /// Note that it *should* be `repr(C, packed)` or similar. + fn write_value_be(&mut self, value: T) -> io::Result { + self.write_value(&value.to_be()) + } + + /// Write a little-endian value of type `T`. + /// Note that it *should* be `repr(C, packed)` or similar. + fn write_value_le(&mut self, value: T) -> io::Result { + self.write_value(&value.to_le()) + } + + /// Convenience `write_all()` alternative returning the length instead of `()`. + fn write_all_len(&mut self, value: &[u8]) -> io::Result; +} + +impl WriteUtilOps for R { + fn write_value(&mut self, value: &T) -> io::Result { + let size = mem::size_of::(); + self.write_all(unsafe { + std::slice::from_raw_parts(value as *const T as *const u8, size) + })?; + Ok(size) + } + + fn write_all_len(&mut self, value: &[u8]) -> io::Result { + self.write_all(value)?; + Ok(value.len()) + } +}