From 186cae627963f4e8ae2c6a4fb568d6f078170561 Mon Sep 17 00:00:00 2001 From: Le0X8 <84378319+Le0X8@users.noreply.github.com> Date: Thu, 17 Apr 2025 11:17:35 +0200 Subject: [PATCH 1/7] first changes for v0.9 --- Cargo.lock | 47 +- Cargo.toml | 5 +- README.md | 11 +- src/data.rs | 474 ----------- src/data/ref.rs | 386 --------- src/error.rs | 2 + src/file.rs | 258 ------ src/lib.rs | 88 +- src/limited.rs | 314 -------- src/prelude.rs | 5 - src/primitive.rs | 82 ++ src/read.rs | 1967 +-------------------------------------------- src/read/val.rs | 98 +++ src/rw.rs | 69 -- src/seek.rs | 97 --- src/type.rs | 20 - src/write.rs | 1923 -------------------------------------------- tests/data.rs | 113 --- tests/data_ref.rs | 63 -- tests/file.rs | 114 --- tests/limited.rs | 93 --- tests/read.rs | 242 ++++++ tests/samples/000 | 1 - tests/samples/001 | 1 - 24 files changed, 483 insertions(+), 5990 deletions(-) delete mode 100644 src/data.rs delete mode 100644 src/data/ref.rs create mode 100644 src/error.rs delete mode 100644 src/file.rs delete mode 100644 src/limited.rs delete mode 100644 src/prelude.rs create mode 100644 src/primitive.rs create mode 100644 src/read/val.rs delete mode 100644 src/rw.rs delete mode 100644 src/seek.rs delete mode 100644 src/type.rs delete mode 100644 src/write.rs delete mode 100644 tests/data.rs delete mode 100644 tests/data_ref.rs delete mode 100644 tests/file.rs delete mode 100644 tests/limited.rs create mode 100644 tests/read.rs delete mode 100644 tests/samples/000 delete mode 100644 tests/samples/001 diff --git a/Cargo.lock b/Cargo.lock index 945f5d2..6886733 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,11 +1,21 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 + +[[package]] +name = "casey" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e779867f62d81627d1438e0d3fb6ed7d7c9d64293ca6d87a1e88781b94ece1c" +dependencies = [ + "syn", +] [[package]] name = "dh" version = "0.8.1" dependencies = [ + "casey", "murmur3", ] @@ -14,3 +24,38 @@ name = "murmur3" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9252111cf132ba0929b6f8e030cac2a24b507f3a4d6db6fb2896f27b354c714b" + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" diff --git a/Cargo.toml b/Cargo.toml index 6718600..cc0a0ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,6 @@ readme = "README.md" keywords = [ "data", "files", "read", "write", "rw" ] categories = [ "data-structures", "encoding", "filesystem", "parsing" ] -[dependencies] - [dev-dependencies] -murmur3 = "0.5.2" \ No newline at end of file +casey = "0.4.2" +murmur3 = "0.5.2" diff --git a/README.md b/README.md index 91df2fd..1b85d70 100644 --- a/README.md +++ b/README.md @@ -16,16 +16,15 @@ ## Features - Read and write files in streams -- No unsafe code -- Support for a lot of data types (including variable length integers and custom length integers) +- Support for a lot of data types (including custom length integers) - Read and write u8 vectors -- std::io::Read and std::io::Write implementations for `Readable` and `Writable` (happens automatically as they extend these traits) -- Copying data from a `Readable` to a `Writable` -- Partial read & write access +- std::io::Read and std::io::Write implementations for `ReadVal` and `WriteVal` (happens automatically as they extend these traits) +- Copying data from `ReadVal` to `WriteVal` +- Partial read & write access with `limit` +- Floating point number support ### Planned features -- Floating point number support - Zero-cost cloning - Zero-cost subarray clones - Reading and writing of data that does not fill a whole byte diff --git a/src/data.rs b/src/data.rs deleted file mode 100644 index 7e84e8b..0000000 --- a/src/data.rs +++ /dev/null @@ -1,474 +0,0 @@ -//! ## Create a data editor -//! -//! ### References (recommended) -//! -//! - [`read_ref`][crate::data::read_ref] creates a reader from a [`Vec`] reference. -//! - [`write_ref`][crate::data::write_ref] creates a writer from a mutable [`Vec`] reference. -//! - [`rw_ref`][crate::data::rw_ref] creates a reader and writer from a mutable [`Vec`] reference. -//! -//! ### Owned data -//! -//! - [`read`][crate::data::read] creates a reader from a [`Vec`]. -//! - [`write`][crate::data::write] creates a writer from a [`Vec`]. -//! - [`rw`][crate::data::rw] creates a reader and writer from a [`Vec`]. -//! -//! ## Close a data editor and get the data -//! -//! - [`close_ref`][crate::data::close_ref] closes a reader, writer, or reader and writer and returns the reference to the data. -//! - [`close_mut`][crate::data::close_mut] closes a writer or reader and writer and returns the mutable reference to the data. -//! - [`close`][crate::data::close] closes a reader, writer, or reader and writer and returns the data. - -#![allow(rustdoc::broken_intra_doc_links)] // rustdoc has some issues with the links above -use crate::{DataType, Readable, Rw, Seekable, Source, Writable}; -use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom, Write}; - -mod r#ref; -pub use r#ref::{ - close as close_ref, close_mut, read as read_ref, rw as rw_ref, write as write_ref, - ClosableMutData, ClosableRefData, RRefData, RwRefData, WRefData, -}; - -/// A [`Vec`] reader. -pub struct RData { - data: Vec, - pos: usize, -} - -impl Read for RData { - fn read(&mut self, buf: &mut [u8]) -> Result { - let len = buf.len(); - let data_len = self.data.len(); - let pos = self.pos; - if pos >= data_len { - return Ok(0); - } - let end = pos + len; - let end = if end > data_len { data_len } else { end }; - let len = end - pos; - buf[..len].copy_from_slice(&self.data[pos..end]); - self.pos = end; - Ok(len) - } -} - -impl Seek for RData { - fn seek(&mut self, pos: SeekFrom) -> Result { - use SeekFrom::*; - let pos = match pos { - Start(pos) => pos as i64, - End(pos) => self.data.len() as i64 + pos, - Current(pos) => self.pos as i64 + pos, - }; - if pos < 0 { - return Err(Error::new( - ErrorKind::InvalidInput, - "invalid seek to a negative position", - )); - } - self.pos = pos as usize; - Ok(pos as u64) - } -} - -impl Seekable for RData {} - -impl<'a> Readable<'a> for RData { - fn as_trait(&mut self) -> &mut dyn Readable<'a> { - self - } - - fn close(self) -> Result>> { - Ok(Some(DataType::Vec(self.data))) - } - - fn source(&mut self) -> Source { - Source::Vec(&mut self.data) - } -} - -/// A [`Vec`] writer. -pub struct WData { - data: Vec, - pos: usize, -} - -impl Write for WData { - fn write(&mut self, buf: &[u8]) -> Result { - let len = buf.len(); - let data_len = self.data.len(); - let pos = self.pos; - if pos > data_len { - return Err(Error::new( - ErrorKind::InvalidInput, - "invalid write position", - )); - } - if pos == data_len { - self.data.extend_from_slice(buf); - } else { - let end = pos + len; - if end > data_len { - self.data.resize(end, 0); - } - self.data[pos..end].copy_from_slice(buf); - } - self.pos += len; - Ok(len) - } - - fn flush(&mut self) -> Result<()> { - Ok(()) - } -} - -impl Seek for WData { - fn seek(&mut self, pos: SeekFrom) -> Result { - use SeekFrom::*; - let pos = match pos { - Start(pos) => pos as i64, - End(pos) => self.data.len() as i64 + pos, - Current(pos) => self.pos as i64 + pos, - }; - if pos < 0 { - return Err(Error::new( - ErrorKind::InvalidInput, - "invalid seek to a negative position", - )); - } - self.pos = pos as usize; - Ok(pos as u64) - } -} - -impl Seekable for WData {} - -impl<'a> Writable<'a> for WData { - fn as_trait(&mut self) -> &mut dyn Writable<'a> { - self - } - - fn close(self) -> Result>> - where - Self: 'a, - { - Ok(Some(DataType::Vec(self.data))) - } - - fn source(&mut self) -> Source { - Source::Vec(&mut self.data) - } -} - -/// A [`Vec`] reader and writer. -pub struct RwData { - data: Vec, - pos: usize, -} - -impl Read for RwData { - fn read(&mut self, buf: &mut [u8]) -> Result { - let len = buf.len(); - let data_len = self.data.len(); - let pos = self.pos; - if pos >= data_len { - return Ok(0); - } - let end = pos + len; - let end = if end > data_len { data_len } else { end }; - let len = end - pos; - buf[..len].copy_from_slice(&self.data[pos..end]); - self.pos = end; - Ok(len) - } -} - -impl Write for RwData { - fn write(&mut self, buf: &[u8]) -> Result { - let len = buf.len(); - let data_len = self.data.len(); - let pos = self.pos; - if pos > data_len { - return Err(Error::new( - ErrorKind::InvalidInput, - "invalid write position", - )); - } - if pos == data_len { - self.data.extend_from_slice(buf); - } else { - let end = pos + len; - if end > data_len { - self.data.resize(end, 0); - } - self.data[pos..end].copy_from_slice(buf); - } - self.pos += len; - Ok(len) - } - - fn flush(&mut self) -> Result<()> { - Ok(()) - } -} - -impl Seek for RwData { - fn seek(&mut self, pos: SeekFrom) -> Result { - use SeekFrom::*; - let pos = match pos { - Start(pos) => pos as i64, - End(pos) => self.data.len() as i64 + pos, - Current(pos) => self.pos as i64 + pos, - }; - if pos < 0 { - return Err(Error::new( - ErrorKind::InvalidInput, - "invalid seek to a negative position", - )); - } - self.pos = pos as usize; - Ok(pos as u64) - } -} - -impl Seekable for RwData {} - -impl<'a> Readable<'a> for RwData { - fn as_trait(&mut self) -> &mut dyn Readable<'a> { - self - } - - fn close(self) -> Result>> { - Ok(Some(DataType::Vec(self.data))) - } - - fn source(&mut self) -> Source { - Source::Vec(&mut self.data) - } -} - -impl<'a> Writable<'a> for RwData { - fn as_trait(&mut self) -> &mut dyn Writable<'a> { - self - } - - fn close(self) -> Result>> - where - Self: 'a, - { - Ok(Some(DataType::Vec(self.data))) - } - - fn source(&mut self) -> Source { - Source::Vec(&mut self.data) - } -} - -impl<'a> Rw<'a> for RwData { - fn rw_as_trait(&mut self) -> &mut dyn Rw<'a> { - self - } - - fn rw_close(self) -> Result>> { - Ok(Some(DataType::Vec(self.data))) - } - - fn rw_source(&mut self) -> Source { - Source::Vec(&mut self.data) - } -} - -/// Enumerates all the possible data types that can be passed into the [`close`] function. -pub enum ClosableData { - R(RData), - W(WData), - Rw(RwData), -} - -impl From for ClosableData { - fn from(r: RData) -> Self { - ClosableData::R(r) - } -} - -impl From for ClosableData { - fn from(w: WData) -> Self { - ClosableData::W(w) - } -} - -impl From for ClosableData { - fn from(rw: RwData) -> Self { - ClosableData::Rw(rw) - } -} - -/// Creates a new reader from a [`Vec`]. -/// -/// ### Example -/// -/// ```rust -/// use dh::recommended::*; -/// -/// let data = vec![0, 1, 2, 3, 4, 5, 6, 7]; -/// let mut reader = dh::data::read(data); -/// -/// assert_eq!(reader.read_u8_at(0).unwrap(), 0); -/// -/// let data = dh::data::close(reader); // gets the data back -/// ``` -pub fn read(data: Vec) -> RData { - RData { data, pos: 0 } -} - -/// Creates a new writer from a [`Vec`]. -/// -/// ### Example -/// -/// ```rust -/// use dh::recommended::*; -/// -/// let mut writer = dh::data::write(vec![0; 2]); -/// -/// writer.write_u16be(0xabcd).unwrap(); // sets the first byte -/// -/// let data = dh::data::close(writer); // gets the data back -/// assert_eq!(data, vec![0xab, 0xcd]); -/// ``` -pub fn write(data: Vec) -> WData { - WData { data, pos: 0 } -} - -/// Creates an empty [`Vec`] writer. -/// -/// ### Example -/// -/// ```rust -/// use dh::recommended::*; -/// -/// let mut writer = dh::data::write_empty(); -/// -/// writer.write_utf8_at(0, "Hello, world!").unwrap(); -/// -/// let data = dh::data::close(writer); // gets the data back -/// assert_eq!(data, "Hello, world!".as_bytes()); -/// ``` -pub fn write_empty() -> WData { - WData { - data: Vec::new(), - pos: 0, - } -} - -/// Creates a new [`Vec`] writer with a specific length. -/// -/// ### Example -/// -/// ```rust -/// use dh::recommended::*; -/// -/// let mut writer = dh::data::write_new(13); -/// -/// writer.write_utf8_at(0, "Hello, world!").unwrap(); -/// -/// let data = dh::data::close(writer); // gets the data back -/// assert_eq!(data, "Hello, world!".as_bytes()); -/// ``` -pub fn write_new(len: u64) -> WData { - WData { - data: vec![0; len as usize], - pos: 0, - } -} - -/// Creates a new reader and writer from a [`Vec`]. -/// -/// ### Example -/// -/// ```rust -/// use dh::recommended::*; -/// -/// let data = vec![0, 1, 2, 3, 4, 5, 6, 7]; -/// let mut rw = dh::data::rw(data); -/// -/// rw.write_u8(8).unwrap(); -/// -/// assert_eq!(rw.read_bytes_at(0, 8).unwrap(), vec![8, 1, 2, 3, 4, 5, 6, 7]); -/// rw.rw_close(); // we don't need the data back -/// ``` -pub fn rw(data: Vec) -> RwData { - RwData { data, pos: 0 } -} - -/// Creates an empty [`Vec`] reader and writer. -/// -/// ### Example -/// -/// ```rust -/// use dh::recommended::*; -/// -/// let mut rw = dh::data::rw_empty(); -/// -/// rw.write_utf8_at(0, &"Hello, world!".to_string()).unwrap(); -/// assert_eq!(rw.read_utf8(13).unwrap(), "Hello, world!"); -/// -/// rw.rw_close(); // we don't need the data back -/// ``` -pub fn rw_empty() -> RwData { - RwData { - data: Vec::new(), - pos: 0, - } -} - -/// Creates a new [`Vec`] reader and writer with a specific length. -/// -/// ### Example -/// -/// ```rust -/// use dh::recommended::*; -/// -/// let mut rw = dh::data::rw_new(13); -/// -/// rw.write_utf8_at(0, &"Hello, world!".to_string()).unwrap(); -/// assert_eq!(rw.read_utf8(13).unwrap(), "Hello, world!"); -/// -/// rw.rw_close(); // we don't need the data back -/// ``` -pub fn rw_new(len: u64) -> RwData { - RwData { - data: vec![0; len as usize], - pos: 0, - } -} - -/// Closes a reader, writer, or reader and writer and returns the data the structure was holding. -/// -/// **Note**: This function only takes [`RData`], [`WData`], and [`RwData`] as input. -/// -/// For references, please use the [`close_ref`] and [`close_mut`] functions. -/// -/// ### Example -/// -/// ```rust -/// use dh::recommended::*; -/// -/// let data = vec![0, 1, 2, 3, 4, 5, 6, 7]; -/// let clone = data.clone(); -/// let mut reader = dh::data::read(data); -/// -/// // do something with the reader -/// -/// let data = dh::data::close(reader); // gets the data back -/// assert_eq!(data, clone); -/// ``` -pub fn close>(closable: T) -> Vec { - // these unwraps are safe because the data is always returned - match match closable.into() { - ClosableData::R(r) => r.close().unwrap().unwrap(), - ClosableData::W(w) => w.close().unwrap().unwrap(), - ClosableData::Rw(rw) => rw.rw_close().unwrap().unwrap(), - } { - DataType::Vec(data) => data, - _ => unreachable!(), - } -} diff --git a/src/data/ref.rs b/src/data/ref.rs deleted file mode 100644 index b3c1d63..0000000 --- a/src/data/ref.rs +++ /dev/null @@ -1,386 +0,0 @@ -use crate::{DataType, Readable, Rw, Seekable, Source, Writable}; -use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom, Write}; - -/// A [`[u8]`] reference reader. -pub struct RRefData<'a> { - data: &'a [u8], - pos: usize, -} - -impl Read for RRefData<'_> { - fn read(&mut self, buf: &mut [u8]) -> Result { - let len = buf.len(); - let data_len = self.data.len(); - let pos = self.pos; - if pos >= data_len { - return Ok(0); - } - let end = pos + len; - let end = if end > data_len { data_len } else { end }; - let len = end - pos; - buf[..len].copy_from_slice(&self.data[pos..end]); - self.pos = end; - Ok(len) - } -} - -impl Seek for RRefData<'_> { - fn seek(&mut self, pos: SeekFrom) -> Result { - use SeekFrom::*; - let pos = match pos { - Start(pos) => pos as i64, - End(pos) => self.data.len() as i64 + pos, - Current(pos) => self.pos as i64 + pos, - }; - if pos < 0 { - return Err(Error::new( - ErrorKind::InvalidInput, - "invalid seek to a negative position", - )); - } - self.pos = pos as usize; - Ok(pos as u64) - } -} - -impl Seekable for RRefData<'_> {} - -impl<'a> Readable<'a> for RRefData<'a> { - fn as_trait(&mut self) -> &mut dyn Readable<'a> { - self - } - - fn close(self) -> Result>> { - Ok(Some(DataType::Ref(self.data))) - } - - fn source(&mut self) -> Source { - Source::Ref(self.data) - } -} - -/// A [`[u8]`] reference writer. -pub struct WRefData<'a> { - data: &'a mut [u8], - pos: usize, -} - -impl Write for WRefData<'_> { - fn write(&mut self, buf: &[u8]) -> Result { - let len = buf.len(); - let data_len = self.data.len(); - let pos = self.pos; - if pos >= data_len { - return Ok(0); - } - let end = pos + len; - let end = if end > data_len { data_len } else { end }; - let len = end - pos; - self.data[pos..end].copy_from_slice(buf); - self.pos = end; - Ok(len) - } - - fn flush(&mut self) -> Result<()> { - Ok(()) - } -} - -impl Seek for WRefData<'_> { - fn seek(&mut self, pos: SeekFrom) -> Result { - use SeekFrom::*; - let pos = match pos { - Start(pos) => pos as i64, - End(pos) => self.data.len() as i64 + pos, - Current(pos) => self.pos as i64 + pos, - }; - if pos < 0 { - return Err(Error::new( - ErrorKind::InvalidInput, - "invalid seek to a negative position", - )); - } - self.pos = pos as usize; - Ok(pos as u64) - } -} - -impl Seekable for WRefData<'_> {} - -impl<'a> Writable<'a> for WRefData<'a> { - fn as_trait(&mut self) -> &mut dyn Writable<'a> { - self - } - - fn close(self) -> Result>> { - Ok(Some(DataType::Mut(self.data))) - } - - fn source(&mut self) -> Source { - Source::Mut(self.data) - } -} - -/// A [`[u8]`] reference reader and writer. -pub struct RwRefData<'a> { - data: &'a mut [u8], - pos: usize, -} - -impl Read for RwRefData<'_> { - fn read(&mut self, buf: &mut [u8]) -> Result { - let len = buf.len(); - let data_len = self.data.len(); - let pos = self.pos; - if pos >= data_len { - return Ok(0); - } - let end = pos + len; - let end = if end > data_len { data_len } else { end }; - let len = end - pos; - buf[..len].copy_from_slice(&self.data[pos..end]); - self.pos = end; - Ok(len) - } -} - -impl Write for RwRefData<'_> { - fn write(&mut self, buf: &[u8]) -> Result { - let len = buf.len(); - let data_len = self.data.len(); - let pos = self.pos; - if pos >= data_len { - return Ok(0); - } - let end = pos + len; - let end = if end > data_len { data_len } else { end }; - let len = end - pos; - self.data[pos..end].copy_from_slice(buf); - self.pos = end; - Ok(len) - } - - fn flush(&mut self) -> Result<()> { - Ok(()) - } -} - -impl Seek for RwRefData<'_> { - fn seek(&mut self, pos: SeekFrom) -> Result { - use SeekFrom::*; - let pos = match pos { - Start(pos) => pos as i64, - End(pos) => self.data.len() as i64 + pos, - Current(pos) => self.pos as i64 + pos, - }; - if pos < 0 { - return Err(Error::new( - ErrorKind::InvalidInput, - "invalid seek to a negative position", - )); - } - self.pos = pos as usize; - Ok(pos as u64) - } -} - -impl Seekable for RwRefData<'_> {} - -impl<'a> Readable<'a> for RwRefData<'a> { - fn as_trait(&mut self) -> &mut dyn Readable<'a> { - self - } - - fn close(self) -> Result>> { - Ok(Some(DataType::Mut(self.data))) - } - - fn source(&mut self) -> Source { - Source::Mut(self.data) - } -} - -impl<'a> Writable<'a> for RwRefData<'a> { - fn as_trait(&mut self) -> &mut dyn Writable<'a> { - self - } - - fn close(self) -> Result>> { - Ok(Some(DataType::Mut(self.data))) - } - - fn source(&mut self) -> Source { - Source::Mut(self.data) - } -} - -impl<'a> Rw<'a> for RwRefData<'a> { - fn rw_as_trait(&mut self) -> &mut dyn Rw<'a> { - self - } - - fn rw_close(self) -> Result>> { - Ok(Some(DataType::Mut(self.data))) - } - - fn rw_source(&mut self) -> Source { - Source::Mut(self.data) - } -} - -/// Enumerates all the possible data types that can be passed into the [`close_ref`][close] function. -pub enum ClosableRefData<'a> { - R(RRefData<'a>), - W(WRefData<'a>), - Rw(RwRefData<'a>), -} - -impl<'a> From> for ClosableRefData<'a> { - fn from(r: RRefData<'a>) -> Self { - ClosableRefData::R(r) - } -} - -impl<'a> From> for ClosableRefData<'a> { - fn from(w: WRefData<'a>) -> Self { - ClosableRefData::W(w) - } -} - -impl<'a> From> for ClosableRefData<'a> { - fn from(rw: RwRefData<'a>) -> Self { - ClosableRefData::Rw(rw) - } -} - -/// Enumerates all the possible data types that can be passed into the [`close_mut`] function. -pub enum ClosableMutData<'a> { - W(WRefData<'a>), - Rw(RwRefData<'a>), -} - -impl<'a> From> for ClosableMutData<'a> { - fn from(w: WRefData<'a>) -> Self { - ClosableMutData::W(w) - } -} - -impl<'a> From> for ClosableMutData<'a> { - fn from(rw: RwRefData<'a>) -> Self { - ClosableMutData::Rw(rw) - } -} - -/// Creates a new reader from a [`[u8]`] reference. -/// -/// ### Example -/// -/// ```rust -/// use dh::recommended::*; -/// -/// let data = vec![0, 1, 2, 3, 4, 5, 6, 7]; -/// let mut reader = dh::data::read_ref(&data); -/// -/// assert_eq!(reader.read_u8_at(0).unwrap(), 0); -/// ``` -pub fn read(data: &[u8]) -> RRefData { - RRefData { data, pos: 0 } -} - -/// Creates a new writer from a [`[u8]`] reference. -/// -/// ### Example -/// ```rust -/// use dh::recommended::*; -/// -/// let mut data = "Hello, world!".as_bytes().to_vec(); -/// let mut writer = dh::data::write_ref(&mut data); -/// -/// writer.write_utf8_at(7, &"Rust!".to_string()).unwrap(); -/// writer.close().unwrap(); -/// -/// assert_eq!(data, "Hello, Rust!!".as_bytes()); -/// ``` -pub fn write(data: &mut [u8]) -> WRefData { - WRefData { data, pos: 0 } -} - -/// Creates a new reader and writer from a [`[u8]`] reference. -/// -/// ### Example -/// ```rust -/// use dh::recommended::*; -/// -/// let mut data = vec![0u8; 2]; -/// let mut rw = dh::data::rw_ref(&mut data); -/// -/// rw.write_u16be(0x1234).unwrap(); -/// assert_eq!(rw.read_u16be_at(0).unwrap(), 0x1234); -/// -/// rw.rw_close().unwrap(); // removes the mutable reference -/// ``` -pub fn rw(data: &mut [u8]) -> RwRefData { - RwRefData { data, pos: 0 } -} - -/// Closes a reader, writer, or reader and writer and returns the reference to the data it refers to. -/// -/// **Note**: This function only takes [`RRefData`], [`WRefData`], and [`RwRefData`] as input. -/// -/// To get the mutable reference to the data, use the [`close_mut`] function instead. -/// -/// ### Example -/// -/// ```rust -/// use dh::recommended::*; -/// -/// let data = "Hello, world!".as_bytes().to_vec(); -/// let mut reader = dh::data::read_ref(&data); -/// -/// let size = reader.size().unwrap(); -/// assert_eq!(reader.read_utf8_at(0, size).unwrap(), "Hello, world!"); -/// -/// assert_eq!(dh::data::close_ref(reader), &data); -/// ``` -pub fn close<'a, T: Into>>(closable: T) -> &'a [u8] { - // these unwraps are safe because the data is always returned - match match closable.into() { - ClosableRefData::R(r) => r.close().unwrap().unwrap(), - ClosableRefData::W(w) => w.close().unwrap().unwrap(), - ClosableRefData::Rw(rw) => rw.rw_close().unwrap().unwrap(), - } { - DataType::Ref(data) => data, - DataType::Mut(data) => data, - _ => unreachable!(), - } -} - -/// Closes a writer or reader and writer and returns the mutable reference to the data it refers to. -/// -/// **Note**: This function only takes [`WRefData`] and [`RwRefData`] as input. -/// -/// To get the immutable reference to the data, use the [`close_ref`][close] function instead. -/// -/// ### Example -/// -/// ```rust -/// use dh::recommended::*; -/// -/// let mut data = "Hello, world!".as_bytes().to_vec(); -/// let mut writer = dh::data::write_ref(&mut data); -/// -/// writer.write_utf8_at(7, &"Rust!".to_string()).unwrap(); -/// let data_ref = dh::data::close_mut(writer); -/// -/// assert_eq!(data_ref, &mut "Hello, Rust!!".as_bytes().to_vec()); -/// ``` -pub fn close_mut<'a, T: Into>>(closable: T) -> &'a mut [u8] { - // these unwraps are safe because the data is always returned - match match closable.into() { - ClosableMutData::W(w) => w.close().unwrap().unwrap(), - ClosableMutData::Rw(rw) => rw.rw_close().unwrap().unwrap(), - } { - DataType::Mut(data) => data, - _ => unreachable!(), - } -} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..1d93bf1 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,2 @@ +pub type Error = std::io::Error; +pub type Result = std::result::Result; diff --git a/src/file.rs b/src/file.rs deleted file mode 100644 index 739d99e..0000000 --- a/src/file.rs +++ /dev/null @@ -1,258 +0,0 @@ -//! ## Open a file -//! - [`open_r`][crate::file::open_r] opens a file in read-only mode. -//! - [`open_w`][crate::file::open_w] opens a file in write-only mode. -//! - [`open_rw`][crate::file::open_rw] opens a file in read-write mode. - -use crate::{DataType, Readable, Rw, Seekable, Source, Writable}; -use std::{ - fs::{File, OpenOptions}, - io::{Read, Result, Seek, Write}, - path::Path, -}; - -/// A file reader. -pub struct RFile { - file: File, -} - -impl Read for RFile { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.file.read(buf) - } -} - -impl Seek for RFile { - fn seek(&mut self, pos: std::io::SeekFrom) -> Result { - self.file.seek(pos) - } -} - -impl Drop for RFile { - fn drop(&mut self) { - self.file.sync_all().unwrap(); - } -} - -impl Seekable for RFile {} - -impl<'a> Readable<'a> for RFile { - fn source(&mut self) -> Source { - Source::File(&mut self.file) - } - - fn as_trait(&mut self) -> &mut dyn Readable<'a> { - self - } - - fn close(self) -> Result>> { - self.file.sync_all()?; - Ok(None) - } -} - -/// Opens a file in read-only mode. -/// -/// ### Example -/// -/// ```rust -/// use dh::recommended::*; -/// -/// let mut reader = dh::file::open_r("tests/samples/000").unwrap(); -/// -/// let size = reader.size().unwrap(); -/// assert_eq!(reader.read_utf8_at(0, size).unwrap(), "Hello, world!"); -/// -/// reader.close().unwrap(); -/// ``` -pub fn open_r

(path: P) -> Result -where - P: AsRef, -{ - Ok(RFile { - file: match File::open(path) { - Ok(file) => file, - Err(e) => return Err(e), - }, - }) -} - -/// A file writer. -pub struct WFile { - file: File, -} - -impl Write for WFile { - fn write(&mut self, buf: &[u8]) -> Result { - self.file.write(buf) - } - - fn flush(&mut self) -> Result<()> { - self.file.flush() - } -} - -impl Seek for WFile { - fn seek(&mut self, pos: std::io::SeekFrom) -> Result { - self.file.seek(pos) - } -} - -impl Drop for WFile { - fn drop(&mut self) { - self.file.sync_all().unwrap(); - } -} - -impl Seekable for WFile {} - -impl<'a> Writable<'a> for WFile { - fn as_trait(&mut self) -> &mut dyn Writable<'a> { - self - } - - fn close(self) -> Result>> { - self.file.sync_all()?; - - Ok(None) - } - - fn source(&mut self) -> Source { - Source::File(&mut self.file) - } -} - -/// Opens a file in write-only mode. -/// -/// ### Example -/// -/// ```rust -/// use dh::recommended::*; -/// -/// let mut writer = dh::file::open_w("doctest-file-open_w").unwrap(); -/// writer.write_utf8(&"Hello, world!".to_string()).unwrap(); -/// -/// writer.close().unwrap(); -/// ``` -pub fn open_w

(path: P) -> Result -where - P: AsRef, -{ - match OpenOptions::new() - .write(true) - .create(true) - .truncate(false) - .open(path) - { - Ok(file) => Ok(WFile { file }), - Err(e) => Err(e), - } -} - -/// A file reader and writer. -pub struct RwFile { - file: File, -} - -impl Read for RwFile { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.file.read(buf) - } -} - -impl Write for RwFile { - fn write(&mut self, buf: &[u8]) -> Result { - self.file.write(buf) - } - - fn flush(&mut self) -> Result<()> { - self.file.flush() - } -} - -impl Seek for RwFile { - fn seek(&mut self, pos: std::io::SeekFrom) -> Result { - self.file.seek(pos) - } -} - -impl Drop for RwFile { - fn drop(&mut self) { - self.file.sync_all().unwrap(); - } -} - -impl Seekable for RwFile {} - -impl<'a> Readable<'a> for RwFile { - fn as_trait(&mut self) -> &mut dyn Readable<'a> { - self - } - - fn close(self) -> Result>> { - self.file.sync_all()?; - Ok(None) - } - - fn source(&mut self) -> Source { - Source::File(&mut self.file) - } -} - -impl<'a> Writable<'a> for RwFile { - fn as_trait(&mut self) -> &mut dyn Writable<'a> { - self - } - - fn close(self) -> Result>> { - self.file.sync_all()?; - Ok(None) - } - - fn source(&mut self) -> Source { - Source::File(&mut self.file) - } -} - -impl<'a> Rw<'a> for RwFile { - fn rw_as_trait(&mut self) -> &mut dyn Rw<'a> { - self - } - - fn rw_close(self) -> Result>> { - self.file.sync_all()?; - Ok(None) - } - - fn rw_source(&mut self) -> Source { - Source::File(&mut self.file) - } -} - -/// Opens a file in read-write mode. -/// -/// ### Example -/// -/// ```rust -/// use dh::recommended::*; -/// -/// let mut rw = dh::file::open_rw("doctest-file-open_rw").unwrap(); -/// -/// rw.write_utf8(&"Hello, world!".to_string()).unwrap(); -/// rw.rewind().unwrap(); -/// assert_eq!(rw.read_utf8(13).unwrap(), "Hello, world!"); -/// ``` -pub fn open_rw

(path: P) -> Result -where - P: AsRef, -{ - match OpenOptions::new() - .read(true) - .write(true) - .create(true) - .truncate(false) - .open(path) - { - Ok(file) => Ok(RwFile { file }), - Err(e) => Err(e), - } -} diff --git a/src/lib.rs b/src/lib.rs index a0a5db6..725cd6f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,85 +1,7 @@ -//! Data handling in Rust, made easy. -//! -//! --- -//! -//! This library provides a set of traits and structs to handle data in Rust, -//! with support for reading, writing, and reading/writing at the same time. -//! -//! Basically, you can read and write files and buffers with the same API. -//! -//! ## Examples -//! -//! ### Reading a file -//! -//! ```rust -//! use dh::recommended::*; // import the crate with all the traits needed -//! -//! let mut file = dh::file::open_r("tests/samples/000").unwrap(); // this opens a file exclusively for reading -//! -//! let size = file.size().unwrap(); // get the size of the file -//! let str = file.read_utf8(size).unwrap(); // read the whole file as UTF-8, read_utf8_at can be used to read at a specific position -//! -//! // file will be closed automatically when it goes out of scope, you can also close it manually with file.close() -//! -//! assert_eq!(str, "Hello, world!"); // check if the content is correct -//! -//! println!("{}", str); // print the content -//! ``` -//! -//! ### Writing a u8 vector in R/W mode -//! -//! ```rust -//! use dh::recommended::*; // import the crate with all the traits needed -//! -//! let mut data = vec![0, 1, 2, 3, 4, 5, 6, 7]; // create a vector -//! let mut rw = dh::data::rw_ref(&mut data); // open the vector in R/W mode, just using dh::data::rw would move the vector -//! -//! rw.write_u8_at(0, 8).unwrap(); // write 8 at the beginning -//! // note how the position stays at 0 -//! assert_eq!(rw.read_u64be().unwrap(), 0x0801020304050607); // read a u64 in big-endian -//! -//! dh::data::close_ref(rw); // close the R/W object and get the reference back -//! // you can drop the rw object too if you don't need the reference anymore -//! // you can get the whole vector back with dh::data::close(rw) if it was moved -//! // you can also get the mutable reference back with dh::data::close_mut(rw) -//! -//! assert_eq!(data, vec![8, 1, 2, 3, 4, 5, 6, 7]); // check if the data is correct - -/// The whole set of structs and functions to handle u8 vectors. -pub mod data; - -/// The whole set of structs and functions to handle files. -pub mod file; - -/// Imports all the traits and the crate itself. -/// -/// This is the recommended way to import the crate. -/// [`import`], [`recommended`], [`essentials`], -/// [`common`] and [`core`] are aliases for this module. -/// -/// ```rust -/// use dh::prelude::*; -/// ``` -pub mod prelude; - -pub use prelude as import; -pub use prelude as recommended; -pub use prelude as essentials; -pub use prelude as common; -pub use prelude as core; - -mod limited; +mod error; +mod primitive; mod read; -mod rw; -mod seek; -mod r#type; -mod write; -pub use data::{ClosableData, ClosableRefData}; -pub use limited::*; -pub use prelude::*; -pub use r#type::*; -pub use read::*; -pub use rw::*; -pub use seek::*; -pub use write::*; +pub use error::{Error, Result}; +pub use primitive::Primitive; +pub use read::val::ReadVal; diff --git a/src/limited.rs b/src/limited.rs deleted file mode 100644 index 814e043..0000000 --- a/src/limited.rs +++ /dev/null @@ -1,314 +0,0 @@ -use std::io::{Read, Result, Seek, SeekFrom, Write}; - -use crate::{Readable, Rw, Seekable, Source, Writable}; - -/// A limited reader. -/// -/// See [`Readable::limit`] for more information. -pub struct RLimited<'a> { - data: &'a mut dyn Readable<'a>, - start: u64, - end: u64, -} - -impl<'a> RLimited<'a> { - /// Gets the reference back. - /// This can be useful if you run into borrow checker issues. - pub fn unlimit(self) -> &'a mut dyn Readable<'a> { - self.data - } -} - -impl<'a> Read for RLimited<'a> { - fn read(&mut self, buf: &mut [u8]) -> Result { - let start_pos = self.data.pos()?; - let end_pos = start_pos + buf.len() as u64; - - if start_pos < self.start { - return Err(std::io::Error::new( - std::io::ErrorKind::UnexpectedEof, - "reading out of bounds", - )); - } - - if end_pos > self.end { - let read_len = (self.end - start_pos) as usize; - #[allow(clippy::unused_io_amount)] - self.data.read(&mut buf[..read_len])?; - return Ok(read_len); - } - - self.data.read(buf) - } -} - -impl<'a> Seek for RLimited<'a> { - fn seek(&mut self, pos: SeekFrom) -> Result { - let new_pos = match pos { - SeekFrom::Start(offset) => self.start + offset, - SeekFrom::End(offset) => (self.end as i128 + offset as i128) as u64, - SeekFrom::Current(offset) => { - let current = self.data.pos()?; - (current as i128 + offset as i128) as u64 - } - }; - - if new_pos < self.start || new_pos > self.end { - return Err(std::io::Error::new( - std::io::ErrorKind::UnexpectedEof, - "new position is out of bounds", - )); - } - - Ok(self.data.to(new_pos)? - self.start) - } -} - -impl<'a> Seekable for RLimited<'a> {} - -impl<'a> Readable<'a> for RLimited<'a> { - fn source(&mut self) -> Source { - self.data.source() - } - - fn as_trait(&mut self) -> &mut dyn Readable<'a> { - self - } - - fn close(self) -> Result>> { - Ok(None) - } -} - -pub(crate) fn limit_r<'a>( - data: &'a mut dyn Readable<'a>, - start: u64, - length: u64, -) -> Result> { - data.to(start)?; - Ok(RLimited { - data, - start, - end: start + length, - }) -} - -/// A limited writer. -/// -/// See [`Writable::limit`] for more information. -pub struct WLimited<'a> { - data: &'a mut dyn Writable<'a>, - start: u64, - end: u64, -} - -impl<'a> WLimited<'a> { - /// Gets the reference back. - /// This can be useful if you run into borrow checker issues. - pub fn unlimit(self) -> &'a mut dyn Writable<'a> { - self.data - } -} - -impl<'a> Write for WLimited<'a> { - fn write(&mut self, buf: &[u8]) -> Result { - let start_pos = self.data.pos()?; - let end_pos = start_pos + buf.len() as u64; - - if start_pos < self.start || end_pos > self.end { - return Err(std::io::Error::new( - std::io::ErrorKind::UnexpectedEof, - "writing out of bounds", - )); - } - - self.data.write(buf) - } - - fn flush(&mut self) -> Result<()> { - self.data.flush() - } -} - -impl<'a> Seek for WLimited<'a> { - fn seek(&mut self, pos: SeekFrom) -> Result { - let new_pos = match pos { - SeekFrom::Start(offset) => self.start + offset, - SeekFrom::End(offset) => (self.end as i128 + offset as i128) as u64, - SeekFrom::Current(offset) => { - let current = self.data.pos()?; - (current as i128 + offset as i128) as u64 - } - }; - - if new_pos < self.start || new_pos > self.end { - return Err(std::io::Error::new( - std::io::ErrorKind::UnexpectedEof, - "new position is out of bounds", - )); - } - - Ok(self.data.to(new_pos)? - self.start) - } -} - -impl<'a> Seekable for WLimited<'a> {} - -impl<'a> Writable<'a> for WLimited<'a> { - fn as_trait(&mut self) -> &mut dyn Writable<'a> { - self - } - - fn close(self) -> Result>> { - Ok(None) - } - - fn source(&mut self) -> Source { - self.data.source() - } -} - -pub(crate) fn limit_w<'a>( - data: &'a mut dyn Writable<'a>, - start: u64, - length: u64, -) -> Result> { - data.to(start)?; - Ok(WLimited { - data, - start, - end: start + length, - }) -} - -/// A limited R/W stream. -/// -/// See [`Rw::rw_limit`] for more information. -pub struct RwLimited<'a> { - data: &'a mut dyn Rw<'a>, - start: u64, - end: u64, -} - -impl<'a> RwLimited<'a> { - /// Gets the reference back. - /// This can be useful if you run into borrow checker issues. - pub fn unlimit(self) -> &'a mut dyn Rw<'a> { - self.data - } -} - -impl<'a> Read for RwLimited<'a> { - fn read(&mut self, buf: &mut [u8]) -> Result { - let start_pos = self.data.pos()?; - let end_pos = start_pos + buf.len() as u64; - - if start_pos < self.start || end_pos > self.end { - return Err(std::io::Error::new( - std::io::ErrorKind::UnexpectedEof, - "reading out of bounds", - )); - } - - self.data.read(buf) - } -} - -impl<'a> Write for RwLimited<'a> { - fn write(&mut self, buf: &[u8]) -> Result { - let start_pos = self.data.pos()?; - let end_pos = start_pos + buf.len() as u64; - - if start_pos < self.start || end_pos > self.end { - return Err(std::io::Error::new( - std::io::ErrorKind::UnexpectedEof, - "writing out of bounds", - )); - } - - self.data.write(buf) - } - - fn flush(&mut self) -> Result<()> { - self.data.flush() - } -} - -impl<'a> Seek for RwLimited<'a> { - fn seek(&mut self, pos: SeekFrom) -> Result { - let new_pos = match pos { - SeekFrom::Start(offset) => self.start + offset, - SeekFrom::End(offset) => (self.end as i128 + offset as i128) as u64, - SeekFrom::Current(offset) => { - let current = self.data.pos()?; - (current as i128 + offset as i128) as u64 - } - }; - - if new_pos < self.start || new_pos > self.end { - return Err(std::io::Error::new( - std::io::ErrorKind::UnexpectedEof, - "new position is out of bounds", - )); - } - - Ok(self.data.to(new_pos)? - self.start) - } -} - -impl<'a> Seekable for RwLimited<'a> {} - -impl<'a> Readable<'a> for RwLimited<'a> { - fn as_trait(&mut self) -> &mut dyn Readable<'a> { - self - } - - fn close(self) -> Result>> { - Ok(None) - } - - fn source(&mut self) -> Source { - self.data.rw_source() - } -} - -impl<'a> Writable<'a> for RwLimited<'a> { - fn as_trait(&mut self) -> &mut dyn Writable<'a> { - self - } - - fn close(self) -> Result>> { - Ok(None) - } - - fn source(&mut self) -> Source { - self.data.rw_source() - } -} - -impl<'a> Rw<'a> for RwLimited<'a> { - fn rw_as_trait(&mut self) -> &mut dyn Rw<'a> { - self - } - - fn rw_close(self) -> Result>> { - Ok(None) - } - - fn rw_source(&mut self) -> Source { - self.data.rw_source() - } -} - -pub(crate) fn limit_rw<'a>( - data: &'a mut dyn Rw<'a>, - start: u64, - length: u64, -) -> Result> { - data.to(start)?; - Ok(RwLimited { - data, - start, - end: start + length, - }) -} diff --git a/src/prelude.rs b/src/prelude.rs deleted file mode 100644 index 174a2ee..0000000 --- a/src/prelude.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub use crate::{ - self as dh, Readable as DhCrateReadable, Rw as DhCrateRw, Seekable as DhCrateSeekable, - Writable as DhCrateWritable, -}; -pub use std::io::Seek as StdIoSeek; diff --git a/src/primitive.rs b/src/primitive.rs new file mode 100644 index 0000000..83fa27a --- /dev/null +++ b/src/primitive.rs @@ -0,0 +1,82 @@ +use std::mem::size_of; + +// marker trait +pub trait Primitive { + fn from_ne_bytes(bytes: [u8; S]) -> Self; + fn from_le_bytes(bytes: [u8; S]) -> Self; + fn from_be_bytes(bytes: [u8; S]) -> Self; +} + +// trait implementation macro +macro_rules! impl_primitive { + ($type:ty, $type_upper:ident) => { + const $type_upper: usize = size_of::<$type>(); + + impl Primitive<$type, $type_upper> for $type { + fn from_ne_bytes(bytes: [u8; $type_upper]) -> $type { + <$type>::from_ne_bytes(bytes) + } + + fn from_le_bytes(bytes: [u8; $type_upper]) -> $type { + <$type>::from_le_bytes(bytes) + } + + fn from_be_bytes(bytes: [u8; $type_upper]) -> $type { + <$type>::from_be_bytes(bytes) + } + } + }; +} + +// unsigned integers +impl_primitive!(u8, U8); +impl_primitive!(u16, U16); +impl_primitive!(u32, U32); +impl_primitive!(u64, U64); +impl_primitive!(u128, U128); +impl_primitive!(usize, USIZE); + +// signed integers +impl_primitive!(i8, I8); +impl_primitive!(i16, I16); +impl_primitive!(i32, I32); +impl_primitive!(i64, I64); +impl_primitive!(i128, I128); +impl_primitive!(isize, ISIZE); + +// floating point numbers +impl_primitive!(f32, F32); +impl_primitive!(f64, F64); + +// other primitives (char is not handled as a primitive in dh!) +impl Primitive<[u8; S], S> for [u8; S] { + fn from_ne_bytes(bytes: [u8; S]) -> [u8; S] { + bytes + } + + fn from_le_bytes(bytes: [u8; S]) -> [u8; S] { + bytes + } + + fn from_be_bytes(bytes: [u8; S]) -> [u8; S] { + bytes + } +} +impl Primitive for bool { + fn from_ne_bytes(bytes: [u8; 1]) -> bool { + bytes[0] & 1 == 1 + } + + fn from_le_bytes(bytes: [u8; 1]) -> bool { + bytes[0] & 1 == 1 + } + + fn from_be_bytes(bytes: [u8; 1]) -> bool { + bytes[0] & 1 == 1 + } +} +impl Primitive<(), 0> for () { + fn from_ne_bytes(_: [u8; 0]) {} + fn from_le_bytes(_: [u8; 0]) {} + fn from_be_bytes(_: [u8; 0]) {} +} diff --git a/src/read.rs b/src/read.rs index a4904b8..2dd4f80 100644 --- a/src/read.rs +++ b/src/read.rs @@ -1,1966 +1 @@ -use crate::{limit_r, DataType, RLimited, Seekable, Source, Writable}; -use std::{ - cmp::min, - io::{ErrorKind, Read, Result}, - vec, -}; - -/// # **This function is only for variable length signed integers, not normal integers!!!** -fn unsigned_to_signed(num: u128, length: u8, size: u8) -> i128 { - let signed_max = (1 << (length * (8 * size - 1) - 1)) - 1; - - if num <= signed_max { - println!( - "pos size={} len={} unsigned=0x{:x} max=0x{:x}", - size, length, num, signed_max - ); - num as i128 - } else { - let signed_min = -(signed_max as i128) - 1; - println!( - "neg size={} len={} unsigned=0x{:x} max=0x{:x} min=0x{:x}", - size, length, num, signed_max, signed_min - ); - - signed_min + num as i128 + signed_min - } -} - -#[test] -fn test_unsigned_to_signed() { - assert_eq!(unsigned_to_signed(0, 1, 1), 0); - assert_eq!(unsigned_to_signed(0b0100_0000, 1, 1), -64); - assert_eq!(unsigned_to_signed(0b0100_0001, 1, 1), -63); - assert_eq!(unsigned_to_signed(0b0011_1111, 1, 1), 63); - - assert_eq!(unsigned_to_signed(0, 2, 1), 0); - assert_eq!(unsigned_to_signed(0b0010_0000_0000_0000, 2, 1), -8192); - assert_eq!(unsigned_to_signed(0b0010_0000_0000_0001, 2, 1), -8191); - assert_eq!(unsigned_to_signed(0b0001_1111_1111_1111, 2, 1), 8191); -} - -fn parse_vux(read_ux: &mut dyn FnMut(u8) -> Result, size: u8) -> Result<(u128, usize)> { - let mut result = 0; - let mut shift = 0u8; - let mut i = 0; - loop { - i += 1; - let bytes = read_ux(size)?; - if bytes & (1 << (size * 8 - 1)) == 0 { - result |= (bytes & !(1 << (size * 8 - 1))) << shift; - break; - } - result |= (bytes & !(1 << (size * 8 - 1))) << shift; - shift += size * 8 - 1; - } - Ok((result, i)) -} - -fn parse_vuxr(read_ux: &mut dyn FnMut(u8) -> Result, size: u8) -> Result<(u128, usize)> { - let mut result = 0; - let mut shift = 0u8; - let mut bytes = [0u128; 16]; - let mut i = 0; - loop { - let b = read_ux(size)?; - bytes[i] = b; - i += 1; - if b & (1 << (size * 8 - 1)) == 0 { - break; - } - } - bytes.reverse(); - let mut reached_data = false; - for byte in bytes.iter() { - if *byte == 0 && !reached_data { - continue; - } - reached_data = true; - result |= (*byte & !(1 << (size * 8 - 1))) << shift; - shift += size * 8 - 1; - } - Ok((result, i)) -} - -/// Provides methods to read data from a source. -/// -/// Although the trait can be implemented for any type that implements [`Read`] and [`Seekable`], -/// for most cases the [internal implementations](#implementors) are recommended. -pub trait Readable<'a>: Read + Seekable { - /// An internal method to get the reader as a trait object. - /// Yes, this is kinda nonsense, but Rust forces me into that. - /// - /// ### How you implement it - /// - /// ```ignore - /// fn as_trait(&mut self) -> &mut dyn Readable<'a> { - /// self - /// } - /// ``` - fn as_trait(&mut self) -> &mut dyn Readable<'a>; - - /// Borrows the read source. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0, 1, 2, 3, 4, 5, 6, 7]); - /// let source = reader.source(); - /// { - /// use dh::Source::*; - /// match source { - /// Vec(source) => assert_eq!(source, &mut vec![0, 1, 2, 3, 4, 5, 6, 7]), - /// _ => unreachable!(), - /// } - /// } - /// ``` - fn source(&mut self) -> Source; - - /// Closes the reader and can return the source if it was moved or references it. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![]); - /// // do something with the reader - /// reader.close().unwrap(); // if the reader goes out of scope, this happens automatically - /// ``` - fn close(self) -> Result>>; - - /// Limits the space the reader can read from. - /// - /// The reader will only be able to read from `pos` to `pos + length`. - /// - /// **Note:** The reader will automatically jump to the start of the limit here. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0, 1, 2, 3, 4, 5, 6, 7]); - /// let mut limited = reader.limit(2, 4).unwrap(); - /// - /// let size = limited.size().unwrap(); - /// assert_eq!(limited.read_bytes(size).unwrap(), vec![2, 3, 4, 5]); - /// ``` - fn limit(&'a mut self, pos: u64, length: u64) -> Result> { - limit_r(self.as_trait(), pos, length) - } - - /// Copies data from the current position to a target at a specific position. - /// - /// This executes the [`copy`][Readable::copy] method at `pos` and then returns to the original position. - fn copy_at( - &mut self, - pos: u64, - length: u64, - target: &mut dyn Writable<'a>, - buffer_size: u64, - ) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.copy(length, target, buffer_size); - self.to(pos_before)?; - result - } - - /// Copies data from the current position to a target at a specific position to a specific position. - /// - /// This executes the [`copy_to`][Readable::copy_to] method at `pos` and then returns to the original position. - fn copy_to_at( - &mut self, - pos: u64, - target_pos: u64, - length: u64, - target: &mut dyn Writable<'a>, - buffer_size: u64, - ) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.copy_to(target_pos, length, target, buffer_size); - self.to(pos_before)?; - result - } - - /// Reads bytes at a specific position. - /// - /// This executes the [`read_bytes`][Readable::read_bytes] method at `pos` and then returns to the original position. - fn read_bytes_at(&mut self, pos: u64, len: u64) -> Result> { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_bytes(len); - self.to(pos_before)?; - result - } - - /// Reads an UTF-8-encoded string at a specific position. - /// - /// This executes the [`read_utf8`][Readable::read_utf8] method at `pos` and then returns to the original position. - fn read_utf8_at(&mut self, pos: u64, len: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_utf8(len); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 8-bit integer at a specific position. - /// - /// This executes the [`read_u8`][Readable::read_u8] method at `pos` and then returns to the original position. - fn read_u8_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_u8(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 16-bit integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_u16le`][Readable::read_u16le] method at `pos` and then returns to the original position. - fn read_u16le_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_u16le(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 16-bit integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_u16be`][Readable::read_u16be] method at `pos` and then returns to the original position. - fn read_u16be_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_u16be(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 32-bit integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_u32le`][Readable::read_u32le] method at `pos` and then returns to the original position. - fn read_u32le_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_u32le(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 32-bit integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_u32be`][Readable::read_u32be] method at `pos` and then returns to the original position. - fn read_u32be_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_u32be(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 64-bit integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_u64le`][Readable::read_u64le] method at `pos` and then returns to the original position. - fn read_u64le_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_u64le(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 64-bit integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_u64be`][Readable::read_u64be] method at `pos` and then returns to the original position. - fn read_u64be_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_u64be(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 128-bit integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_u128le`][Readable::read_u128le] method at `pos` and then returns to the original position. - fn read_u128le_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_u128le(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 128-bit integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_u128be`][Readable::read_u128be] method at `pos` and then returns to the original position. - fn read_u128be_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_u128be(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 7-bit variable-length integer at a specific position. - /// - /// This executes the [`read_vu7`][Readable::read_vu7] method at `pos` and then returns to the original position. - fn read_vu7_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu7(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 7-bit variable-length integer in reversed byte order at a specific position. - /// - /// This executes the [`read_vu7r`][Readable::read_vu7r] method at `pos` and then returns to the original position. - fn read_vu7r_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu7r(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 15-bit variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_vu15le`][Readable::read_vu15le] method at `pos` and then returns to the original position. - fn read_vu15le_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu15le(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 15-bit variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_vu15be`][Readable::read_vu15be] method at `pos` and then returns to the original position. - fn read_vu15be_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu15be(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 15-bit variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`read_vu15ler`][Readable::read_vu15ler] method at `pos` and then returns to the original position. - fn read_vu15ler_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu15ler(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 15-bit variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`read_vu15ber`][Readable::read_vu15ber] method at `pos` and then returns to the original position. - fn read_vu15ber_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu15ber(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 31-bit variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_vu31le`][Readable::read_vu31le] method at `pos` and then returns to the original position. - fn read_vu31le_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu31le(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 31-bit variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_vu31be`][Readable::read_vu31be] method at `pos` and then returns to the original position. - fn read_vu31be_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu31be(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 31-bit variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`read_vu31ler`][Readable::read_vu31ler] method at `pos` and then returns to the original position. - fn read_vu31ler_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu31ler(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 31-bit variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`read_vu31ber`][Readable::read_vu31ber] method at `pos` and then returns to the original position. - fn read_vu31ber_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu31ber(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 63-bit variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_vu63le`][Readable::read_vu63le] method at `pos` and then returns to the original position. - fn read_vu63le_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu63le(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 63-bit variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_vu63be`][Readable::read_vu63be] method at `pos` and then returns to the original position. - fn read_vu63be_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu63be(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 63-bit variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`read_vu63ler`][Readable::read_vu63ler] method at `pos` and then returns to the original position. - fn read_vu63ler_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu63ler(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 63-bit variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`read_vu63ber`][Readable::read_vu63ber] method at `pos` and then returns to the original position. - fn read_vu63ber_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu63ber(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 127-bit variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_vu127le`][Readable::read_vu127le] method at `pos` and then returns to the original position. - fn read_vu127le_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu127le(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 127-bit variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_vu127be`][Readable::read_vu127be] method at `pos` and then returns to the original position. - fn read_vu127be_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu127be(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 127-bit variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`read_vu127ler`][Readable::read_vu127ler] method at `pos` and then returns to the original position. - fn read_vu127ler_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu127ler(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned 127-bit variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`read_vu127ber`][Readable::read_vu127ber] method at `pos` and then returns to the original position. - fn read_vu127ber_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vu127ber(); - self.to(pos_before)?; - result - } - - /// Reads an unsigned integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_uxle`][Readable::read_uxle] method at `pos` and then returns to the original position. - fn read_uxle_at(&mut self, pos: u64, size: u8) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_uxle(size); - self.to(pos_before)?; - result - } - - /// Reads an unsigned integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_uxbe`][Readable::read_uxbe] method at `pos` and then returns to the original position. - fn read_uxbe_at(&mut self, pos: u64, size: u8) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_uxbe(size); - self.to(pos_before)?; - result - } - - /// Reads an unsigned variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_vuxle`][Readable::read_vuxle] method at `pos` and then returns to the original position. - fn read_vuxle_at(&mut self, pos: u64, size: u8) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vuxle(size); - self.to(pos_before)?; - result - } - - /// Reads an unsigned variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_vuxbe`][Readable::read_vuxbe] method at `pos` and then returns to the original position. - fn read_vuxbe_at(&mut self, pos: u64, size: u8) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vuxbe(size); - self.to(pos_before)?; - result - } - - /// Reads an unsigned variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`read_vuxler`][Readable::read_vuxler] method at `pos` and then returns to the original position. - fn read_vuxler_at(&mut self, pos: u64, size: u8) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vuxler(size); - self.to(pos_before)?; - result - } - - /// Reads an unsigned variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`read_vuxber`][Readable::read_vuxber] method at `pos` and then returns to the original position. - fn read_vuxber_at(&mut self, pos: u64, size: u8) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vuxber(size); - self.to(pos_before)?; - result - } - - /// Reads a signed 8-bit integer at a specific position. - /// - /// This executes the [`read_i8`][Readable::read_i8] method at `pos` and then returns to the original position. - fn read_i8_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_i8(); - self.to(pos_before)?; - result - } - - /// Reads a signed 16-bit integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_i16le`][Readable::read_i16le] method at `pos` and then returns to the original position. - fn read_i16le_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_i16le(); - self.to(pos_before)?; - result - } - - /// Reads a signed 16-bit integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_i16be`][Readable::read_i16be] method at `pos` and then returns to the original position. - fn read_i16be_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_i16be(); - self.to(pos_before)?; - result - } - - /// Reads a signed 32-bit integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_i32le`][Readable::read_i32le] method at `pos` and then returns to the original position. - fn read_i32le_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_i32le(); - self.to(pos_before)?; - result - } - - /// Reads a signed 32-bit integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_i32be`][Readable::read_i32be] method at `pos` and then returns to the original position. - fn read_i32be_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_i32be(); - self.to(pos_before)?; - result - } - - /// Reads a signed 64-bit integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_i64le`][Readable::read_i64le] method at `pos` and then returns to the original position. - fn read_i64le_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_i64le(); - self.to(pos_before)?; - result - } - - /// Reads a signed 64-bit integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_i64be`][Readable::read_i64be] method at `pos` and then returns to the original position. - fn read_i64be_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_i64be(); - self.to(pos_before)?; - result - } - - /// Reads a signed 128-bit integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_i128le`][Readable::read_i128le] method at `pos` and then returns to the original position. - fn read_i128le_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_i128le(); - self.to(pos_before)?; - result - } - - /// Reads a signed 128-bit integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_i128be`][Readable::read_i128be] method at `pos` and then returns to the original position. - fn read_i128be_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_i128be(); - self.to(pos_before)?; - result - } - - /// Reads a signed 7-bit variable-length integer at a specific position. - /// - /// This executes the [`read_vi7`][Readable::read_vi7] method at `pos` and then returns to the original position. - fn read_vi7_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi7(); - self.to(pos_before)?; - result - } - - /// Reads a signed 7-bit variable-length integer in reversed byte order at a specific position. - /// - /// This executes the [`read_vi7r`][Readable::read_vi7r] method at `pos` and then returns to the original position. - fn read_vi7r_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi7r(); - self.to(pos_before)?; - result - } - - /// Reads a signed 15-bit variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_vi15le`][Readable::read_vi15le] method at `pos` and then returns to the original position. - fn read_vi15le_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi15le(); - self.to(pos_before)?; - result - } - - /// Reads a signed 15-bit variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_vi15be`][Readable::read_vi15be] method at `pos` and then returns to the original position. - fn read_vi15be_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi15be(); - self.to(pos_before)?; - result - } - - /// Reads a signed 15-bit variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`read_vi15ler`][Readable::read_vi15ler] method at `pos` and then returns to the original position. - fn read_vi15ler_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi15ler(); - self.to(pos_before)?; - result - } - - /// Reads a signed 15-bit variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`read_vi15ber`][Readable::read_vi15ber] method at `pos` and then returns to the original position. - fn read_vi15ber_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi15ber(); - self.to(pos_before)?; - result - } - - /// Reads a signed 31-bit variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_vi31le`][Readable::read_vi31le] method at `pos` and then returns to the original position. - fn read_vi31le_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi31le(); - self.to(pos_before)?; - result - } - - /// Reads a signed 31-bit variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_vi31be`][Readable::read_vi31be] method at `pos` and then returns to the original position. - fn read_vi31be_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi31be(); - self.to(pos_before)?; - result - } - - /// Reads a signed 31-bit variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`read_vi31ler`][Readable::read_vi31ler] method at `pos` and then returns to the original position. - fn read_vi31ler_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi31ler(); - self.to(pos_before)?; - result - } - - /// Reads a signed 31-bit variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`read_vi31ber`][Readable::read_vi31ber] method at `pos` and then returns to the original position. - fn read_vi31ber_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi31ber(); - self.to(pos_before)?; - result - } - - /// Reads a signed 63-bit variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_vi63le`][Readable::read_vi63le] method at `pos` and then returns to the original position. - fn read_vi63le_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi63le(); - self.to(pos_before)?; - result - } - - /// Reads a signed 63-bit variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_vi63be`][Readable::read_vi63be] method at `pos` and then returns to the original position. - fn read_vi63be_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi63be(); - self.to(pos_before)?; - result - } - - /// Reads a signed 63-bit variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`read_vi63ler`][Readable::read_vi63ler] method at `pos` and then returns to the original position. - fn read_vi63ler_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi63ler(); - self.to(pos_before)?; - result - } - - /// Reads a signed 63-bit variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`read_vi63ber`][Readable::read_vi63ber] method at `pos` and then returns to the original position. - fn read_vi63ber_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi63ber(); - self.to(pos_before)?; - result - } - - /// Reads a signed 127-bit variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_vi127le`][Readable::read_vi127le] method at `pos` and then returns to the original position. - fn read_vi127le_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi127le(); - self.to(pos_before)?; - result - } - - /// Reads a signed 127-bit variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_vi127be`][Readable::read_vi127be] method at `pos` and then returns to the original position. - fn read_vi127be_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi127be(); - self.to(pos_before)?; - result - } - - /// Reads a signed 127-bit variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`read_vi127ler`][Readable::read_vi127ler] method at `pos` and then returns to the original position. - fn read_vi127ler_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi127ler(); - self.to(pos_before)?; - result - } - - /// Reads a signed 127-bit variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`read_vi127ber`][Readable::read_vi127ber] method at `pos` and then returns to the original position. - fn read_vi127ber_at(&mut self, pos: u64) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vi127ber(); - self.to(pos_before)?; - result - } - - /// Reads a signed integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_ixle`][Readable::read_ixle] method at `pos` and then returns to the original position. - fn read_ixle_at(&mut self, pos: u64, size: u8) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_ixle(size); - self.to(pos_before)?; - result - } - - /// Reads a signed integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_ixbe`][Readable::read_ixbe] method at `pos` and then returns to the original position. - fn read_ixbe_at(&mut self, pos: u64, size: u8) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_ixbe(size); - self.to(pos_before)?; - result - } - - /// Reads a signed variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`read_vixle`][Readable::read_vixle] method at `pos` and then returns to the original position. - fn read_vixle_at(&mut self, pos: u64, size: u8) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vixle(size); - self.to(pos_before)?; - result - } - - /// Reads a signed variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`read_vixbe`][Readable::read_vixbe] method at `pos` and then returns to the original position. - fn read_vixbe_at(&mut self, pos: u64, size: u8) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vixbe(size); - self.to(pos_before)?; - result - } - - /// Reads a signed variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`read_vixler`][Readable::read_vixler] method at `pos` and then returns to the original position. - fn read_vixler_at(&mut self, pos: u64, size: u8) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vixler(size); - self.to(pos_before)?; - result - } - - /// Reads a signed variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`read_vixber`][Readable::read_vixber] method at `pos` and then returns to the original position. - fn read_vixber_at(&mut self, pos: u64, size: u8) -> Result { - let pos_before = self.stream_position()?; - self.to(pos)?; - let result = self.read_vixber(size); - self.to(pos_before)?; - result - } - - /// Copies data from the current position to a target. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut src = dh::data::read(vec![0, 1, 2, 3, 4, 5, 6, 7]); - /// let mut target = dh::data::write_new(8); - /// - /// src.copy(4, &mut target, 1024).unwrap(); - /// src.rewind().unwrap(); - /// src.copy(4, &mut target, 1024).unwrap(); - /// - /// let data = dh::data::close(target); - /// assert_eq!(data, vec![0, 1, 2, 3, 0, 1, 2, 3]); - /// ``` - fn copy(&mut self, length: u64, target: &mut dyn Writable<'a>, buffer_size: u64) -> Result<()> { - let mut buf = vec![0; buffer_size as usize]; - let mut remaining = length; - - while remaining > 0 { - let read = min(remaining, buffer_size); - if buffer_size > read { - buf.resize(read as usize, 0); - } - self.read_exact(&mut buf[..read as usize])?; - target.write_all(&buf[..read as usize])?; - remaining -= read; - } - Ok(()) - } - - /// Copies data from the current position to a target to a specific position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut src = dh::data::read(vec![0, 1, 2, 3, 4, 5, 6, 7]); - /// let mut target = dh::data::write_new(8); - /// - /// src.jump(1).unwrap(); - /// src.copy_to(2, 4, &mut target, 1024).unwrap(); - /// - /// let data = dh::data::close(target); - /// assert_eq!(data, vec![0, 0, 1, 2, 3, 4, 0, 0]); - /// ``` - fn copy_to( - &mut self, - target_pos: u64, - length: u64, - target: &mut dyn Writable<'a>, - buffer_size: u64, - ) -> Result<()> { - let target_pos_before = target.stream_position()?; - target.to(target_pos)?; - let result = self.copy(length, target, buffer_size); - target.to(target_pos_before)?; - result - } - - /// Reads bytes at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0, 1, 2, 3, 4, 5]); - /// reader.jump(2).unwrap(); - /// - /// let bytes = reader.read_bytes(3).unwrap(); - /// assert_eq!(bytes, vec![2, 3, 4]); - /// ``` - fn read_bytes(&mut self, length: u64) -> Result> { - let mut buf = vec![0; length as usize]; - self.read_exact(&mut buf)?; - Ok(buf) - } - - /// Reads an UTF-8-encoded string at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0x48, 0x65, 0x6c, 0x6c, 0x6f]); - /// - /// let string = reader.read_utf8(5).unwrap(); - /// assert_eq!(string, "Hello"); - /// ``` - fn read_utf8(&mut self, length: u64) -> Result { - let mut buf = vec![0; length as usize]; - self.read_exact(&mut buf)?; - Ok(match String::from_utf8(buf) { - Ok(str) => str, - Err(_) => return Err(ErrorKind::InvalidData.into()), - }) - } - - /// Reads an unsigned 8-bit integer at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0x48]); - /// - /// let byte = reader.read_u8().unwrap(); - /// assert_eq!(byte, 0x48); - /// ``` - fn read_u8(&mut self) -> Result { - Ok(self.read_uxle(1)? as u8) - } - - /// Reads an unsigned 16-bit integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0x01, 0x02]); - /// - /// let num = reader.read_u16le().unwrap(); - /// assert_eq!(num, 0x02_01); - /// ``` - fn read_u16le(&mut self) -> Result { - Ok(self.read_uxle(2)? as u16) - } - - /// Reads an unsigned 16-bit integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0x01, 0x02]); - /// - /// let num = reader.read_u16be().unwrap(); - /// assert_eq!(num, 0x01_02); - /// ``` - fn read_u16be(&mut self) -> Result { - Ok(self.read_uxbe(2)? as u16) - } - - /// Reads an unsigned 16-bit integer in little-endian or big-endian byte order at the current position. - /// - /// If `big_endian` is `true`, this executes the [`read_u16be`][Readable::read_u16be] method. - /// Otherwise, this executes the [`read_u16le`][Readable::read_u16le] method. - fn read_u16(&mut self, big_endian: bool) -> Result { - if big_endian { - self.read_u16be() - } else { - self.read_u16le() - } - } - - // TODO: add read methods without endianess for all other data types - - /// Reads an unsigned 32-bit integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0x01, 0x02, 0x03, 0x04]); - /// - /// let num = reader.read_u32le().unwrap(); - /// assert_eq!(num, 0x04_03_02_01); - /// ``` - fn read_u32le(&mut self) -> Result { - Ok(self.read_uxle(4)? as u32) - } - - /// Reads an unsigned 32-bit integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0x01, 0x02, 0x03, 0x04]); - /// - /// let num = reader.read_u32be().unwrap(); - /// assert_eq!(num, 0x01_02_03_04); - /// ``` - fn read_u32be(&mut self) -> Result { - Ok(self.read_uxbe(4)? as u32) - } - - /// Reads an unsigned 32-bit integer in little-endian or big-endian byte order at the current position. - /// - /// If `big_endian` is `true`, this executes the [`read_u32be`][Readable::read_u32be] method. - /// Otherwise, this executes the [`read_u32le`][Readable::read_u32le] method. - fn read_u32(&mut self, big_endian: bool) -> Result { - if big_endian { - self.read_u32be() - } else { - self.read_u32le() - } - } - - /// Reads an unsigned 64-bit integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]); - /// - /// let num = reader.read_u64le().unwrap(); - /// assert_eq!(num, 0x08_07_06_05_04_03_02_01); - /// ``` - fn read_u64le(&mut self) -> Result { - Ok(self.read_uxle(8)? as u64) - } - - /// Reads an unsigned 64-bit integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]); - /// - /// let num = reader.read_u64be().unwrap(); - /// assert_eq!(num, 0x01_02_03_04_05_06_07_08); - /// ``` - fn read_u64be(&mut self) -> Result { - Ok(self.read_uxbe(8)? as u64) - } - - /// Reads an unsigned 64-bit integer in little-endian or big-endian byte order at the current position. - /// - /// If `big_endian` is `true`, this executes the [`read_u64be`][Readable::read_u64be] method. - /// Otherwise, this executes the [`read_u64le`][Readable::read_u64le] method. - fn read_u64(&mut self, big_endian: bool) -> Result { - if big_endian { - self.read_u64be() - } else { - self.read_u64le() - } - } - - /// Reads an unsigned 128-bit integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10]); - /// - /// let num = reader.read_u128le().unwrap(); - /// - /// assert_eq!(num, 0x10_0f_0e_0d_0c_0b_0a_09_08_07_06_05_04_03_02_01); - /// ``` - fn read_u128le(&mut self) -> Result { - self.read_uxle(16) - } - - /// Reads an unsigned 128-bit integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10]); - /// - /// let num = reader.read_u128be().unwrap(); - /// - /// assert_eq!(num, 0x01_02_03_04_05_06_07_08_09_0a_0b_0c_0d_0e_0f_10); - /// ``` - fn read_u128be(&mut self) -> Result { - self.read_uxbe(16) - } - - /// Reads an unsigned 128-bit integer in little-endian or big-endian byte order at the current position. - /// - /// If `big_endian` is `true`, this executes the [`read_u128be`][Readable::read_u128be] method. - /// Otherwise, this executes the [`read_u128le`][Readable::read_u128le] method. - fn read_u128(&mut self, big_endian: bool) -> Result { - if big_endian { - self.read_u128be() - } else { - self.read_u128le() - } - } - - /// Reads an unsigned 7-bit variable-length integer at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b10010000, 0b01000001]); - /// - /// let num = reader.read_vu7().unwrap(); - /// assert_eq!(num, 0b1000001_0010000); - /// ``` - fn read_vu7(&mut self) -> Result { - self.read_vuxle(1) - } - - /// Reads an unsigned 7-bit variable-length integer in reversed byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b10010000, 0b01000001]); - /// - /// let num = reader.read_vu7r().unwrap(); - /// assert_eq!(num, 0b0010000_1000001); - /// ``` - fn read_vu7r(&mut self) -> Result { - self.read_vuxler(1) - } - - /// Reads an unsigned 15-bit variable-length integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b10101010, 0b11000001, 0b10101010, 0b01000001]); - /// - /// let num = reader.read_vu15le().unwrap(); - /// assert_eq!(num, 0b100000110101010_100000110101010); - /// ``` - fn read_vu15le(&mut self) -> Result { - self.read_vuxle(2) - } - - /// Reads an unsigned 15-bit variable-length integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b11000001, 0b10101010, 0b01000001, 0b10101010]); - /// - /// let num = reader.read_vu15be().unwrap(); - /// assert_eq!(num, 0b100000110101010_100000110101010); - /// ``` - fn read_vu15be(&mut self) -> Result { - self.read_vuxbe(2) - } - - /// Reads an unsigned 15-bit variable-length integer in reversed little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b10101010, 0b11001001, 0b10101010, 0b01000001]); - /// - /// let num = reader.read_vu15ler().unwrap(); - /// assert_eq!(num, 0b100100110101010_100000110101010); - /// ``` - fn read_vu15ler(&mut self) -> Result { - self.read_vuxler(2) - } - - /// Reads an unsigned 15-bit variable-length integer in reversed big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b11001001, 0b10101010, 0b01000001, 0b10101010]); - /// - /// let num = reader.read_vu15ber().unwrap(); - /// assert_eq!(num, 0b100100110101010_100000110101010); - /// ``` - fn read_vu15ber(&mut self) -> Result { - self.read_vuxber(2) - } - - /// Reads an unsigned 31-bit variable-length integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b10101010, 0b10000001, 0b10101010, 0b11000001, 0b10101010, 0b10000001, 0b10101010, 0b01000001]); - /// - /// let num = reader.read_vu31le().unwrap(); - /// assert_eq!(num, 0b1000001101010101000000110101010_1000001101010101000000110101010); - /// ``` - fn read_vu31le(&mut self) -> Result { - self.read_vuxle(4) - } - - /// Reads an unsigned 31-bit variable-length integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b11000001, 0b10101010, 0b10000001, 0b10101010, 0b01000001, 0b10101010, 0b10000001, 0b10101010]); - /// - /// let num = reader.read_vu31be().unwrap(); - /// assert_eq!(num, 0b1000001101010101000000110101010_1000001101010101000000110101010); - /// ``` - fn read_vu31be(&mut self) -> Result { - self.read_vuxbe(4) - } - - /// Reads an unsigned 31-bit variable-length integer in reversed little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b10101010, 0b10000001, 0b10101010, 0b11000001, 0b10101010, 0b10000001, 0b10101010, 0b01000001]); - /// - /// let num = reader.read_vu31ler().unwrap(); - /// assert_eq!(num, 0b1000001101010101000000110101010_1000001101010101000000110101010); - /// ``` - fn read_vu31ler(&mut self) -> Result { - self.read_vuxler(4) - } - - /// Reads an unsigned 31-bit variable-length integer in reversed big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b11000001, 0b10101010, 0b10000001, 0b10101010, 0b01000001, 0b10101010, 0b10000001, 0b10101010]); - /// - /// let num = reader.read_vu31ber().unwrap(); - /// assert_eq!(num, 0b1000001101010101000000110101010_1000001101010101000000110101010); - /// ``` - fn read_vu31ber(&mut self) -> Result { - self.read_vuxber(4) - } - - /// Reads an unsigned 63-bit variable-length integer in little-endian byte order at the current position. - /// - /// This works like [`read_vu31le`][Readable::read_vu31le] but with 63 bits. - fn read_vu63le(&mut self) -> Result { - self.read_vuxle(8) - } - - /// Reads an unsigned 63-bit variable-length integer in big-endian byte order at the current position. - /// - /// This works like [`read_vu31be`][Readable::read_vu31be] but with 63 bits. - fn read_vu63be(&mut self) -> Result { - self.read_vuxbe(8) - } - - /// Reads an unsigned 63-bit variable-length integer in reversed little-endian byte order at the current position. - /// - /// This works like [`read_vu31ler`][Readable::read_vu31ler] but with 63 bits. - fn read_vu63ler(&mut self) -> Result { - self.read_vuxler(8) - } - - /// Reads an unsigned 63-bit variable-length integer in reversed big-endian byte order at the current position. - /// - /// This works like [`read_vu31ber`][Readable::read_vu31ber] but with 63 bits. - fn read_vu63ber(&mut self) -> Result { - self.read_vuxber(8) - } - - /// Reads an unsigned 127-bit variable-length integer in little-endian byte order at the current position. - /// - /// This works like [`read_vu31le`][Readable::read_vu31le] but with 127 bits. - fn read_vu127le(&mut self) -> Result { - self.read_vuxle(16) - } - - /// Reads an unsigned 127-bit variable-length integer in big-endian byte order at the current position. - /// - /// This works like [`read_vu31be`][Readable::read_vu31be] but with 127 bits. - fn read_vu127be(&mut self) -> Result { - self.read_vuxbe(16) - } - - /// Reads an unsigned 127-bit variable-length integer in reversed little-endian byte order at the current position. - /// - /// This works like [`read_vu31ler`][Readable::read_vu31ler] but with 127 bits. - fn read_vu127ler(&mut self) -> Result { - self.read_vuxler(16) - } - - /// Reads an unsigned 127-bit variable-length integer in reversed big-endian byte order at the current position. - /// - /// This works like [`read_vu31ber`][Readable::read_vu31ber] but with 127 bits. - fn read_vu127ber(&mut self) -> Result { - self.read_vuxber(16) - } - - /// Reads an unsigned integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0x01, 0x02, 0x03]); - /// - /// let num = reader.read_uxle(3).unwrap(); - /// assert_eq!(num, 0x03_02_01); - /// ``` - fn read_uxle(&mut self, size: u8) -> Result { - let mut buffer = [0u8; 16]; - self.read_exact(&mut buffer[0..size as usize])?; - - let mut result = 0u128; - for (i, &byte) in buffer.iter().enumerate().take(size as usize) { - result |= (byte as u128) << (i * 8); - } - - Ok(result) - } - - /// Reads an unsigned integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0x01, 0x02, 0x03]); - /// - /// let num = reader.read_uxbe(3).unwrap(); - /// assert_eq!(num, 0x01_02_03); - /// ``` - fn read_uxbe(&mut self, size: u8) -> Result { - let mut buffer = [0u8; 16]; - self.read_exact(&mut buffer[0..size as usize])?; - - let mut result = 0u128; - for (i, &byte) in buffer.iter().enumerate().take(size as usize) { - result |= (byte as u128) << ((size - (i as u8) - 1) * 8); - } - - Ok(result) - } - - /// Reads an unsigned variable-length integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b10010000, 0b01000001]); - /// - /// let num = reader.read_vuxle(1).unwrap(); - /// assert_eq!(num, 0b1000001_0010000); - /// ``` - fn read_vuxle(&mut self, size: u8) -> Result { - Ok(parse_vux(&mut |s| self.read_uxle(s), size)?.0) - } - - /// Reads an unsigned variable-length integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b10010000, 0b01000001]); - /// - /// let num = reader.read_vuxbe(1).unwrap(); - /// assert_eq!(num, 0b1000001_0010000); - /// ``` - fn read_vuxbe(&mut self, size: u8) -> Result { - Ok(parse_vux(&mut |s| self.read_uxbe(s), size)?.0) - } - - /// Reads an unsigned variable-length integer in reversed little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b10010000, 0b01000001]); - /// - /// let num = reader.read_vuxler(1).unwrap(); - /// assert_eq!(num, 0b0010000_1000001); - /// ``` - fn read_vuxler(&mut self, size: u8) -> Result { - Ok(parse_vuxr(&mut |s| self.read_uxle(s), size)?.0) - } - - /// Reads an unsigned variable-length integer in reversed big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b10010000, 0b01000001]); - /// - /// let num = reader.read_vuxber(1).unwrap(); - /// assert_eq!(num, 0b0010000_1000001); - /// ``` - fn read_vuxber(&mut self, size: u8) -> Result { - Ok(parse_vuxr(&mut |s| self.read_uxbe(s), size)?.0) - } - - /// Reads a signed 8-bit integer at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(i8::MIN.to_le_bytes().to_vec()); - /// - /// let byte = reader.read_i8().unwrap(); - /// assert_eq!(byte, i8::MIN); - /// ``` - fn read_i8(&mut self) -> Result { - Ok(self.read_ixle(1)? as i8) - } - - /// Reads a signed 16-bit integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(i16::MIN.to_le_bytes().to_vec()); - /// - /// let num = reader.read_i16le().unwrap(); - /// assert_eq!(num, i16::MIN); - /// ``` - fn read_i16le(&mut self) -> Result { - Ok(self.read_ixle(2)? as i16) - } - - /// Reads a signed 16-bit integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(i16::MIN.to_be_bytes().to_vec()); - /// - /// let num = reader.read_i16be().unwrap(); - /// assert_eq!(num, i16::MIN); - /// ``` - fn read_i16be(&mut self) -> Result { - Ok(self.read_ixbe(2)? as i16) - } - - /// Reads a signed 32-bit integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(i32::MIN.to_le_bytes().to_vec()); - /// - /// let num = reader.read_i32le().unwrap(); - /// assert_eq!(num, i32::MIN); - /// ``` - fn read_i32le(&mut self) -> Result { - Ok(self.read_ixle(4)? as i32) - } - - /// Reads a signed 32-bit integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(i32::MIN.to_be_bytes().to_vec()); - /// - /// let num = reader.read_i32be().unwrap(); - /// assert_eq!(num, i32::MIN); - /// ``` - fn read_i32be(&mut self) -> Result { - Ok(self.read_ixbe(4)? as i32) - } - - /// Reads a signed 64-bit integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(i64::MIN.to_le_bytes().to_vec()); - /// - /// let num = reader.read_i64le().unwrap(); - /// assert_eq!(num, i64::MIN); - /// ``` - fn read_i64le(&mut self) -> Result { - Ok(self.read_ixle(8)? as i64) - } - - /// Reads a signed 64-bit integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(i64::MIN.to_be_bytes().to_vec()); - /// - /// let num = reader.read_i64be().unwrap(); - /// assert_eq!(num, i64::MIN); - /// ``` - fn read_i64be(&mut self) -> Result { - Ok(self.read_ixbe(8)? as i64) - } - - /// Reads a signed 128-bit integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(i128::MIN.to_le_bytes().to_vec()); - /// - /// let num = reader.read_i128le().unwrap(); - /// assert_eq!(num, i128::MIN); - /// ``` - fn read_i128le(&mut self) -> Result { - self.read_ixle(16) - } - - /// Reads a signed 128-bit integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(i128::MIN.to_be_bytes().to_vec()); - /// - /// let num = reader.read_i128be().unwrap(); - /// assert_eq!(num, i128::MIN); - /// ``` - fn read_i128be(&mut self) -> Result { - self.read_ixbe(16) - } - - /// Reads a signed 7-bit variable-length integer at the current position. - /// - /// This works like [`read_vu7`][Readable::read_vu7] but for signed integers. - fn read_vi7(&mut self) -> Result { - self.read_vixle(1) - } - - /// Reads a signed 7-bit variable-length integer in reversed byte order at the current position. - /// - /// This works like [`read_vu7r`][Readable::read_vu7r] but for signed integers. - fn read_vi7r(&mut self) -> Result { - self.read_vixler(1) - } - - /// Reads a signed 15-bit variable-length integer in little-endian byte order at the current position. - /// - /// This works like [`read_vu15le`][Readable::read_vu15le] but for signed integers. - fn read_vi15le(&mut self) -> Result { - self.read_vixle(2) - } - - /// Reads a signed 15-bit variable-length integer in big-endian byte order at the current position. - /// - /// This works like [`read_vu15be`][Readable::read_vu15be] but for signed integers. - fn read_vi15be(&mut self) -> Result { - self.read_vixbe(2) - } - - /// Reads a signed 15-bit variable-length integer in reversed little-endian byte order at the current position. - /// - /// This works like [`read_vu15ler`][Readable::read_vu15ler] but for signed integers. - fn read_vi15ler(&mut self) -> Result { - self.read_vixler(2) - } - - /// Reads a signed 15-bit variable-length integer in reversed big-endian byte order at the current position. - /// - /// This works like [`read_vu15ber`][Readable::read_vu15ber] but for signed integers. - fn read_vi15ber(&mut self) -> Result { - self.read_vixber(2) - } - - /// Reads a signed 31-bit variable-length integer in little-endian byte order at the current position. - /// - /// This works like [`read_vu31le`][Readable::read_vu31le] but for signed integers. - fn read_vi31le(&mut self) -> Result { - self.read_vixle(4) - } - - /// Reads a signed 31-bit variable-length integer in big-endian byte order at the current position. - /// - /// This works like [`read_vu31be`][Readable::read_vu31be] but for signed integers. - fn read_vi31be(&mut self) -> Result { - self.read_vixbe(4) - } - - /// Reads a signed 31-bit variable-length integer in reversed little-endian byte order at the current position. - /// - /// This works like [`read_vu31ler`][Readable::read_vu31ler] but for signed integers. - fn read_vi31ler(&mut self) -> Result { - self.read_vixler(4) - } - - /// Reads a signed 31-bit variable-length integer in reversed big-endian byte order at the current position. - /// - /// This works like [`read_vu31ber`][Readable::read_vu31ber] but for signed integers. - fn read_vi31ber(&mut self) -> Result { - self.read_vixber(4) - } - - /// Reads a signed 63-bit variable-length integer in little-endian byte order at the current position. - /// - /// This works like [`read_vu63le`][Readable::read_vu63le] but for signed integers. - fn read_vi63le(&mut self) -> Result { - self.read_vixle(8) - } - - /// Reads a signed 63-bit variable-length integer in big-endian byte order at the current position. - /// - /// This works like [`read_vu63be`][Readable::read_vu63be] but for signed integers. - fn read_vi63be(&mut self) -> Result { - self.read_vixbe(8) - } - - /// Reads a signed 63-bit variable-length integer in reversed little-endian byte order at the current position. - /// - /// This works like [`read_vu63ler`][Readable::read_vu63ler] but for signed integers. - fn read_vi63ler(&mut self) -> Result { - self.read_vixler(8) - } - - /// Reads a signed 63-bit variable-length integer in reversed big-endian byte order at the current position. - /// - /// This works like [`read_vu63ber`][Readable::read_vu63ber] but for signed integers. - fn read_vi63ber(&mut self) -> Result { - self.read_vixber(8) - } - - /// Reads a signed 127-bit variable-length integer in little-endian byte order at the current position. - /// - /// This works like [`read_vu127le`][Readable::read_vu127le] but for signed integers. - fn read_vi127le(&mut self) -> Result { - self.read_vixle(16) - } - - /// Reads a signed 127-bit variable-length integer in big-endian byte order at the current position. - /// - /// This works like [`read_vu127be`][Readable::read_vu127be] but for signed integers. - fn read_vi127be(&mut self) -> Result { - self.read_vixbe(16) - } - - /// Reads a signed 127-bit variable-length integer in reversed little-endian byte order at the current position. - /// - /// This works like [`read_vu127ler`][Readable::read_vu127ler] but for signed integers. - fn read_vi127ler(&mut self) -> Result { - self.read_vixler(16) - } - - /// Reads a signed 127-bit variable-length integer in reversed big-endian byte order at the current position. - /// - /// This works like [`read_vu127ber`][Readable::read_vu127ber] but for signed integers. - fn read_vi127ber(&mut self) -> Result { - self.read_vixber(16) - } - - /// Reads a signed integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(i8::MIN.to_le_bytes().to_vec()); - /// - /// let byte = reader.read_ixle(1).unwrap() as i8; - /// assert_eq!(byte, i8::MIN); - /// ``` - fn read_ixle(&mut self, size: u8) -> Result { - let mut buffer = [0u8; 16]; - self.read_exact(&mut buffer[0..size as usize])?; - - let mut result = 0i128; - for (i, &byte) in buffer.iter().enumerate().take(size as usize) { - result |= (byte as i128) << (i * 8); - } - - Ok(result) - } - - /// Reads a signed integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(i8::MIN.to_be_bytes().to_vec()); - /// - /// let byte = reader.read_ixbe(1).unwrap() as i8; - /// assert_eq!(byte, i8::MIN); - /// ``` - fn read_ixbe(&mut self, size: u8) -> Result { - let mut buffer = [0u8; 16]; - self.read_exact(&mut buffer[0..size as usize])?; - - let mut result = 0i128; - for (i, &byte) in buffer.iter().enumerate().take(size as usize) { - result |= (byte as i128) << ((size - (i as u8) - 1) * 8); - } - - Ok(result) - } - - /// Reads a signed variable-length integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b10000000, 0b01000000]); - /// - /// let num = reader.read_vixle(1).unwrap(); - /// assert_eq!(num, -8192); - /// ``` - fn read_vixle(&mut self, size: u8) -> Result { - let mut fun = |s: u8| self.read_uxle(s); - let result = parse_vux(&mut fun, size)?; - let unsigned = result.0; - let length = result.1 as u8; - - Ok(unsigned_to_signed(unsigned, length, size)) - } - - /// Reads a signed variable-length integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b01100000, 0b00000000]); - /// - /// let num = reader.read_vixbe(2).unwrap(); - /// assert_eq!(num, -8192); - /// ``` - fn read_vixbe(&mut self, size: u8) -> Result { - let mut fun = |s: u8| self.read_uxbe(s); - let result = parse_vux(&mut fun, size)?; - let unsigned = result.0; - let length = result.1 as u8; - - Ok(unsigned_to_signed(unsigned, length, size)) - } - - /// Reads a signed variable-length integer in reversed little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b00000000, 0b01100000]); - /// - /// let num = reader.read_vixler(2).unwrap(); - /// assert_eq!(num, -8192); - /// ``` - fn read_vixler(&mut self, size: u8) -> Result { - let mut fun = |s: u8| self.read_uxle(s); - let result = parse_vuxr(&mut fun, size)?; - let unsigned = result.0; - let length = result.1 as u8; - - Ok(unsigned_to_signed(unsigned, length, size)) - } - - /// Reads a signed variable-length integer in reversed big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0b01100000, 0b00000000]); - /// - /// let num = reader.read_vixber(2).unwrap(); - /// assert_eq!(num, -8192); - /// ``` - fn read_vixber(&mut self, size: u8) -> Result { - let mut fun = |s: u8| self.read_uxbe(s); - let result = parse_vuxr(&mut fun, size)?; - let unsigned = result.0; - let length = result.1 as u8; - - Ok(unsigned_to_signed(unsigned, length, size)) - } -} +pub(crate) mod val; diff --git a/src/read/val.rs b/src/read/val.rs new file mode 100644 index 0000000..df6a7f0 --- /dev/null +++ b/src/read/val.rs @@ -0,0 +1,98 @@ +use crate::{Primitive, Result}; +use std::io::Read; + +macro_rules! read_primitive { + ($fn_name:ident, $read_fn_name:ident) => { + /// Reads a primitive value from the reader using the specified byte order. + /// + /// It's recommended to use the typed wrappers like `read_u8` instead of this method for cleaner code. + fn $fn_name, U, const S: usize>(&mut self) -> Result { + let mut buf = [0; S]; + self.read_exact(&mut buf)?; + Ok(T::$read_fn_name(buf)) + } + }; +} + +macro_rules! read_primitive_typed { + ($fn_name:ident, $return_type:ty, $read_fn:ident) => { + /// Typed wrapper around `read_ne`, `read_le`, or `read_be`. + fn $fn_name(&mut self) -> Result<$return_type> { + self.$read_fn() + } + }; + + ($fn_name:ident, $return_type:ty, $read_fn:ident, $const:ident) => { + /// Typed wrapper around `read_ne`, `read_le`, or `read_be`. + fn $fn_name(&mut self) -> Result<$return_type> { + self.$read_fn::<$return_type, $return_type, $const>() + } + }; +} + +/// Extension trait for `Read` that provides methods for reading primitive values. +/// +/// **Note:** do not borrow this as `&mut dyn ReadVal`, as this would not compile. Use `&mut dyn Read` instead. +pub trait ReadVal: Read { + read_primitive!(read_ne, from_ne_bytes); + read_primitive!(read_le, from_le_bytes); + read_primitive!(read_be, from_be_bytes); + + read_primitive_typed!(read_u8, u8, read_ne); + + read_primitive_typed!(read_u16_ne, u16, read_ne); + read_primitive_typed!(read_u16_le, u16, read_le); + read_primitive_typed!(read_u16_be, u16, read_be); + + read_primitive_typed!(read_u32_ne, u32, read_ne); + read_primitive_typed!(read_u32_le, u32, read_le); + read_primitive_typed!(read_u32_be, u32, read_be); + + read_primitive_typed!(read_u64_ne, u64, read_ne); + read_primitive_typed!(read_u64_le, u64, read_le); + read_primitive_typed!(read_u64_be, u64, read_be); + + read_primitive_typed!(read_u128_ne, u128, read_ne); + read_primitive_typed!(read_u128_le, u128, read_le); + read_primitive_typed!(read_u128_be, u128, read_be); + + read_primitive_typed!(read_usize_ne, usize, read_ne); + read_primitive_typed!(read_usize_le, usize, read_le); + read_primitive_typed!(read_usize_be, usize, read_be); + + read_primitive_typed!(read_i8, i8, read_ne); + + read_primitive_typed!(read_i16_ne, i16, read_ne); + read_primitive_typed!(read_i16_le, i16, read_le); + read_primitive_typed!(read_i16_be, i16, read_be); + + read_primitive_typed!(read_i32_ne, i32, read_ne); + read_primitive_typed!(read_i32_le, i32, read_le); + read_primitive_typed!(read_i32_be, i32, read_be); + + read_primitive_typed!(read_i64_ne, i64, read_ne); + read_primitive_typed!(read_i64_le, i64, read_le); + read_primitive_typed!(read_i64_be, i64, read_be); + + read_primitive_typed!(read_i128_ne, i128, read_ne); + read_primitive_typed!(read_i128_le, i128, read_le); + read_primitive_typed!(read_i128_be, i128, read_be); + + read_primitive_typed!(read_isize_ne, isize, read_ne); + read_primitive_typed!(read_isize_le, isize, read_le); + read_primitive_typed!(read_isize_be, isize, read_be); + + read_primitive_typed!(read_f32_ne, f32, read_ne); + read_primitive_typed!(read_f32_le, f32, read_le); + read_primitive_typed!(read_f32_be, f32, read_be); + + read_primitive_typed!(read_f64_ne, f64, read_ne); + read_primitive_typed!(read_f64_le, f64, read_le); + read_primitive_typed!(read_f64_be, f64, read_be); + + read_primitive_typed!(read_u8_array, [u8; S], read_ne, S); + + read_primitive_typed!(read_bool, bool, read_ne); +} + +impl ReadVal for T {} diff --git a/src/rw.rs b/src/rw.rs deleted file mode 100644 index c97088e..0000000 --- a/src/rw.rs +++ /dev/null @@ -1,69 +0,0 @@ -use std::io::Result; - -use crate::{limit_rw, DataType, Readable, RwLimited, Source, Writable}; - -/// Provides methods to combine the [`Readable`] and [`Writable`] traits. -pub trait Rw<'a> -where - Self: Readable<'a> + Writable<'a>, -{ - /// An internal method to get the reader as a trait object. - /// Yes, this is kinda nonsense, but Rust forces me into that. - /// - /// ### How you implement it - /// - /// ```ignore - /// fn rw_as_trait(&mut self) -> &mut dyn Rw<'a> { - /// self - /// } - /// ``` - fn rw_as_trait(&mut self) -> &mut dyn Rw<'a>; - - /// Borrows the read/write source. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0, 1, 2, 3, 4, 5, 6, 7]); - /// let source = reader.source(); - /// { - /// use dh::Source::*; - /// match source { - /// Vec(source) => assert_eq!(source, &mut vec![0, 1, 2, 3, 4, 5, 6, 7]), - /// _ => unreachable!(), - /// } - /// } - /// ``` - fn rw_source(&mut self) -> Source; - - /// Closes the R/W stream and can return the target if it was moved or references it. - /// - /// Use this instead of [`Readable::close`] or [`Writable::close`] for cleaner code as you avoid the naming conflict. - fn rw_close(self) -> Result>>; - - /// Limits the R/W stream to a certain range. - /// - /// Using [`Readable::limit`] and [`Writable::limit`] would not - /// return [`RwLimited`] and would be limited to either reading or writing. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut data = vec![0, 1, 2, 3]; - /// let mut rw = dh::data::rw_ref(&mut data); - /// - /// let mut limited = rw.rw_limit(1, 2).unwrap(); - /// limited.to(1).unwrap(); - /// limited.write_u8(4).unwrap(); - /// - /// limited.rewind().unwrap(); - /// assert_eq!(limited.read_u16be().unwrap(), 0x0104); - /// ``` - fn rw_limit(&'a mut self, start: u64, length: u64) -> Result> { - limit_rw(self.rw_as_trait(), start, length) - } -} diff --git a/src/seek.rs b/src/seek.rs deleted file mode 100644 index f45542d..0000000 --- a/src/seek.rs +++ /dev/null @@ -1,97 +0,0 @@ -use std::io::{Result, Seek, SeekFrom}; - -/// Provides methods to seek a stream. -/// -/// This trait is automatically implemented for any type that implements [`Seek`], that -/// includes any type that implements [`Readable`][crate::Readable], -/// [`Writable`][crate::Writable] and [`Rw`][crate::Rw] as all these traits require [`Seek`] to be implemented. -pub trait Seekable: Seek { - /// Sets the stream position to the end. It is not recommended to read anything after this because it would result in an EOF error. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(2); - /// - /// writer.end().unwrap(); // sets the position to the end - /// assert_eq!(writer.pos().unwrap(), 2); - /// ``` - fn end(&mut self) -> Result { - self.seek(SeekFrom::End(0)) - } - - /// Sets the stream position to a specific position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(2); - /// - /// writer.to(1).unwrap(); // sets the position to the second byte - /// assert_eq!(writer.pos().unwrap(), 1); - /// ``` - fn to(&mut self, pos: u64) -> Result { - self.seek(SeekFrom::Start(pos)) - } - - /// Jumps a specific amount of bytes from the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(2); - /// - /// writer.to(1).unwrap(); // sets the position to the second byte - /// - /// writer.jump(1).unwrap(); // sets the position to the next byte - /// assert_eq!(writer.pos().unwrap(), 2); - /// - /// writer.jump(-1).unwrap(); // sets the position to the previous byte - /// assert_eq!(writer.pos().unwrap(), 1); - /// ``` - fn jump(&mut self, pos: i64) -> Result { - self.seek(SeekFrom::Current(pos)) - } - - /// Calculates the current size of the source. - /// Please call this method as less as possible because it moves to the end of the stream and back to the previous position. - /// If you need to know the size of the source, consider storing it in a variable. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(2); - /// - /// assert_eq!(writer.size().unwrap(), 2); - /// ``` - fn size(&mut self) -> Result { - let pos_before = self.stream_position()?; - let size = self.end(); - self.to(pos_before)?; - size - } - - /// Returns the current position of the stream. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(2); - /// - /// writer.write_u8(0x80).unwrap(); // reads the first byte - /// assert_eq!(writer.pos().unwrap(), 1); - /// ``` - fn pos(&mut self) -> Result { - self.stream_position() - } -} diff --git a/src/type.rs b/src/type.rs deleted file mode 100644 index a6db3d9..0000000 --- a/src/type.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::fs::File; - -/// A helper enum to allow getting the source data from a [`Vec`] reader and/or writer. -/// -/// **This data type is only intended for internal usage.** -pub enum DataType<'a> { - Vec(Vec), - Ref(&'a [u8]), - Mut(&'a mut [u8]), -} - -/// A helper enum to allow getting direct access on the data source. -/// -/// **This data type is only intended for internal usage.** -pub enum Source<'a> { - File(&'a mut File), - Vec(&'a mut Vec), - Ref(&'a [u8]), - Mut(&'a mut [u8]), -} diff --git a/src/write.rs b/src/write.rs deleted file mode 100644 index 2ea559b..0000000 --- a/src/write.rs +++ /dev/null @@ -1,1923 +0,0 @@ -use std::io::{Result, Write}; - -use crate::{limit_w, DataType, Seekable, Source, WLimited}; - -fn signed_to_unsigned(num: i128, size: u8) -> u128 { - if size == 16 { - // can't use 1 << 128 because it would overflow - return num as u128; - } - let mask = (1 << (size * 8)) - 1; - (num & mask) as u128 -} - -fn signed_to_unsigned_vi(num: i128, size: u8) -> u128 { - if size == 16 { - // can't use 1 << 128 because it would overflow - return num as u128; - } - let mask = (1 << (size * 8 - 1)) - 1; - (num & mask) as u128 -} - -fn serialize_vuxle(size: u8, num: u128, be: bool, rev: bool) -> Vec { - let mut num = num; - let mut buf = Vec::new(); - let shift = (8 * size) - 1; - let max_size = 1 << shift; - let mask = max_size - 1; - while num >= max_size { - buf.push(num & mask); - num >>= shift; - } - buf.push(num); - if rev { - buf.reverse(); - } - - let last_index = buf.len() - 1; - buf.iter_mut().take(last_index).for_each(|x| { - *x |= max_size; - }); - let buf = buf - .iter() - .flat_map(|&x| { - if be { - let mut bytes = x.to_be_bytes().to_vec(); - bytes.drain(0..(bytes.len() - size as usize)); - return bytes; - } - - let mut bytes = x.to_le_bytes().to_vec(); - bytes.truncate(size as usize); - bytes - }) - .collect::>(); - buf -} - -/// Provides methods to write data to a target. -/// -/// Although the trait can be implemented for any type that implements [`Write`] and [`Seekable`], -/// for most cases the [internal implementations](#implementors) are recommended. -pub trait Writable<'a> -where - Self: Write + Seekable, -{ - /// An internal method to get the reader as a trait object. - /// Yes, this is kinda nonsense, but Rust forces me into that. - /// - /// ### How you implement it - /// - /// ```ignore - /// fn as_trait(&mut self) -> &mut dyn Writable<'a> { - /// self - /// } - /// ``` - fn as_trait(&mut self) -> &mut dyn Writable<'a>; - - /// Borrows the write source. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::read(vec![0, 1, 2, 3, 4, 5, 6, 7]); - /// let source = reader.source(); - /// { - /// use dh::Source::*; - /// match source { - /// Vec(source) => assert_eq!(source, &mut vec![0, 1, 2, 3, 4, 5, 6, 7]), - /// _ => unreachable!(), - /// } - /// } - /// ``` - fn source(&mut self) -> Source; - - /// Closes the reader and can return the source if it was moved or references it. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut reader = dh::data::write(vec![]); - /// // do something with the writer - /// reader.close().unwrap(); // if the writer goes out of scope, this happens automatically - /// ``` - fn close(self) -> Result>>; - - /// Limits the space the writer can write to. - /// - /// The writer will only be able to write from `pos` to `pos + length`. - /// - /// **Note:** The writer will automatically jump to the start of the limit here. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write(vec![0, 1, 2, 3, 4, 5, 6, 7]); - /// let mut limited = writer.limit(2, 4).unwrap(); - /// - /// let size = limited.size().unwrap(); - /// limited.write_bytes(&vec![5, 4, 3, 2]).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, vec![0, 1, 5, 4, 3, 2, 6, 7]); - /// ``` - fn limit(&'a mut self, pos: u64, length: u64) -> Result> { - limit_w(self.as_trait(), pos, length) - } - - /// Writes bytes at a specific position. - /// - /// This executes the [`write_bytes`][Writable::write_bytes] method at `pos` and then returns to the original position. - fn write_bytes_at(&mut self, pos: u64, buf: &[u8]) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_bytes(buf)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an UTF-8-encoded string at a specific position. - /// - /// This executes the [`write_utf8`][Writable::write_utf8] method at `pos` and then returns to the original position. - fn write_utf8_at(&mut self, pos: u64, s: &str) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_utf8(s)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 8-bit integer at a specific position. - /// - /// This executes the [`write_u8`][Writable::write_u8] method at `pos` and then returns to the original position. - fn write_u8_at(&mut self, pos: u64, num: u8) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_u8(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 16-bit integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_u16le`][Writable::write_u16le] method at `pos` and then returns to the original position. - fn write_u16le_at(&mut self, pos: u64, num: u16) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_u16le(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 16-bit integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_u16be`][Writable::write_u16be] method at `pos` and then returns to the original position. - fn write_u16be_at(&mut self, pos: u64, num: u16) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_u16be(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 32-bit integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_u32le`][Writable::write_u32le] method at `pos` and then returns to the original position. - fn write_u32le_at(&mut self, pos: u64, num: u32) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_u32le(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 32-bit integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_u32be`][Writable::write_u32be] method at `pos` and then returns to the original position. - fn write_u32be_at(&mut self, pos: u64, num: u32) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_u32be(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 64-bit integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_u64le`][Writable::write_u64le] method at `pos` and then returns to the original position. - fn write_u64le_at(&mut self, pos: u64, num: u64) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_u64le(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 64-bit integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_u64be`][Writable::write_u64be] method at `pos` and then returns to the original position. - fn write_u64be_at(&mut self, pos: u64, num: u64) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_u64be(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 128-bit integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_u128le`][Writable::write_u128le] method at `pos` and then returns to the original position. - fn write_u128le_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_u128le(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 128-bit integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_u128be`][Writable::write_u128be] method at `pos` and then returns to the original position. - fn write_u128be_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_u128be(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 7-bit variable-length integer at a specific position. - /// - /// This executes the [`write_vu7`][Writable::write_vu7] method at `pos` and then returns to the original position. - fn write_vu7_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu7(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 7-bit variable-length integer in reversed byte order at a specific position. - /// - /// This executes the [`write_vu7r`][Writable::write_vu7r] method at `pos` and then returns to the original position. - fn write_vu7r_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu7r(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 15-bit variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_vu15le`][Writable::write_vu15le] method at `pos` and then returns to the original position. - fn write_vu15le_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu15le(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 15-bit variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_vu15be`][Writable::write_vu15be] method at `pos` and then returns to the original position. - fn write_vu15be_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu15be(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 15-bit variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`write_vu15ler`][Writable::write_vu15ler] method at `pos` and then returns to the original position. - fn write_vu15ler_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu15ler(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 15-bit variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`write_vu15ber`][Writable::write_vu15ber] method at `pos` and then returns to the original position. - fn write_vu15ber_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu15ber(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 31-bit variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_vu31le`][Writable::write_vu31le] method at `pos` and then returns to the original position. - fn write_vu31le_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu31le(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 31-bit variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_vu31be`][Writable::write_vu31be] method at `pos` and then returns to the original position. - fn write_vu31be_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu31be(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 31-bit variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`write_vu31ler`][Writable::write_vu31ler] method at `pos` and then returns to the original position. - fn write_vu31ler_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu31ler(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 31-bit variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`write_vu31ber`][Writable::write_vu31ber] method at `pos` and then returns to the original position. - fn write_vu31ber_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu31ber(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 63-bit variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_vu63le`][Writable::write_vu63le] method at `pos` and then returns to the original position. - fn write_vu63le_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu63le(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 63-bit variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_vu63be`][Writable::write_vu63be] method at `pos` and then returns to the original position. - fn write_vu63be_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu63be(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 63-bit variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`write_vu63ler`][Writable::write_vu63ler] method at `pos` and then returns to the original position. - fn write_vu63ler_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu63ler(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 63-bit variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`write_vu63ber`][Writable::write_vu63ber] method at `pos` and then returns to the original position. - fn write_vu63ber_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu63ber(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 127-bit variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_vu127le`][Writable::write_vu127le] method at `pos` and then returns to the original position. - fn write_vu127le_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu127le(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 127-bit variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_vu127be`][Writable::write_vu127be] method at `pos` and then returns to the original position. - fn write_vu127be_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu127be(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 127-bit variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`write_vu127ler`][Writable::write_vu127ler] method at `pos` and then returns to the original position. - fn write_vu127ler_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu127ler(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned 127-bit variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`write_vu127ber`][Writable::write_vu127ber] method at `pos` and then returns to the original position. - fn write_vu127ber_at(&mut self, pos: u64, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vu127ber(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_uxle`][Writable::write_uxle] method at `pos` and then returns to the original position. - fn write_uxle_at(&mut self, pos: u64, size: u8, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_uxle(size, num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_uxbe`][Writable::write_uxbe] method at `pos` and then returns to the original position. - fn write_uxbe_at(&mut self, pos: u64, size: u8, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_uxbe(size, num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_vuxle`][Writable::write_vuxle] method at `pos` and then returns to the original position. - fn write_vuxle_at(&mut self, pos: u64, size: u8, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vuxle(size, num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`write_vuxler`][Writable::write_vuxler] method at `pos` and then returns to the original position. - fn write_vuxbe_at(&mut self, pos: u64, size: u8, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vuxbe(size, num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`write_vuxler`][Writable::write_vuxler] method at `pos` and then returns to the original position. - fn write_vuxler_at(&mut self, pos: u64, size: u8, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vuxler(size, num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes an unsigned variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`write_vuxber`][Writable::write_vuxber] method at `pos` and then returns to the original position. - fn write_vuxber_at(&mut self, pos: u64, size: u8, num: u128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vuxber(size, num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 8-bit integer at a specific position. - /// - /// This executes the [`write_i8`][Writable::write_i8] method at `pos` and then returns to the original position. - fn write_i8_at(&mut self, pos: u64, num: i8) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_i8(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 16-bit integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_i16le`][Writable::write_i16le] method at `pos` and then returns to the original position. - fn write_i16le_at(&mut self, pos: u64, num: i16) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_i16le(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 16-bit integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_i16be`][Writable::write_i16be] method at `pos` and then returns to the original position. - fn write_i16be_at(&mut self, pos: u64, num: i16) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_i16be(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 32-bit integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_i32le`][Writable::write_i32le] method at `pos` and then returns to the original position. - fn write_i32le_at(&mut self, pos: u64, num: i32) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_i32le(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 32-bit integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_i32be`][Writable::write_i32be] method at `pos` and then returns to the original position. - fn write_i32be_at(&mut self, pos: u64, num: i32) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_i32be(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 64-bit integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_i64le`][Writable::write_i64le] method at `pos` and then returns to the original position. - fn write_i64le_at(&mut self, pos: u64, num: i64) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_i64le(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 64-bit integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_i64be`][Writable::write_i64be] method at `pos` and then returns to the original position. - fn write_i64be_at(&mut self, pos: u64, num: i64) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_i64be(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 128-bit integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_i128le`][Writable::write_i128le] method at `pos` and then returns to the original position. - fn write_i128le_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_i128le(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 128-bit integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_i128be`][Writable::write_i128be] method at `pos` and then returns to the original position. - fn write_i128be_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_i128be(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 7-bit variable-length integer at a specific position. - /// - /// This executes the [`write_vi7`][Writable::write_vi7] method at `pos` and then returns to the original position. - fn write_vi7_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi7(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 7-bit variable-length integer in reversed byte order at a specific position. - /// - /// This executes the [`write_vi7r`][Writable::write_vi7r] method at `pos` and then returns to the original position. - fn write_vi7r_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi7r(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 15-bit variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_vi15le`][Writable::write_vi15le] method at `pos` and then returns to the original position. - fn write_vi15le_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi15le(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 15-bit variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_vi15be`][Writable::write_vi15be] method at `pos` and then returns to the original position. - fn write_vi15be_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi15be(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 15-bit variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`write_vi15ler`][Writable::write_vi15ler] method at `pos` and then returns to the original position. - fn write_vi15ler_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi15ler(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 15-bit variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`write_vi15ber`][Writable::write_vi15ber] method at `pos` and then returns to the original position. - fn write_vi15ber_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi15ber(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 31-bit variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_vi31le`][Writable::write_vi31le] method at `pos` and then returns to the original position. - fn write_vi31le_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi31le(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 31-bit variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_vi31be`][Writable::write_vi31be] method at `pos` and then returns to the original position. - fn write_vi31be_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi31be(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 31-bit variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`write_vi31ler`][Writable::write_vi31ler] method at `pos` and then returns to the original position. - fn write_vi31ler_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi31ler(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 31-bit variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`write_vi31ber`][Writable::write_vi31ber] method at `pos` and then returns to the original position. - fn write_vi31ber_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi31ber(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 63-bit variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_vi63le`][Writable::write_vi63le] method at `pos` and then returns to the original position. - fn write_vi63le_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi63le(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 63-bit variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_vi63be`][Writable::write_vi63be] method at `pos` and then returns to the original position. - fn write_vi63be_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi63be(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 63-bit variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`write_vi63ler`][Writable::write_vi63ler] method at `pos` and then returns to the original position. - fn write_vi63ler_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi63ler(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 127-bit variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_vi127le`][Writable::write_vi127le] method at `pos` and then returns to the original position. - fn write_vi127le_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi127le(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 127-bit variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_vi127be`][Writable::write_vi127be] method at `pos` and then returns to the original position. - fn write_vi127be_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi127be(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 127-bit variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`write_vi127ler`][Writable::write_vi127ler] method at `pos` and then returns to the original position. - fn write_vi127ler_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi127ler(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed 127-bit variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`write_vi127ber`][Writable::write_vi127ber] method at `pos` and then returns to the original position. - fn write_vi127ber_at(&mut self, pos: u64, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vi127ber(num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_ixle`][Writable::write_ixle] method at `pos` and then returns to the original position. - fn write_ixle_at(&mut self, pos: u64, size: u8, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_ixle(size, num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_ixbe`][Writable::write_ixbe] method at `pos` and then returns to the original position. - fn write_ixbe_at(&mut self, pos: u64, size: u8, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_ixbe(size, num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed variable-length integer in little-endian byte order at a specific position. - /// - /// This executes the [`write_vixle`][Writable::write_vixle] method at `pos` and then returns to the original position. - fn write_vixle_at(&mut self, pos: u64, size: u8, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vixle(size, num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed variable-length integer in big-endian byte order at a specific position. - /// - /// This executes the [`write_vixbe`][Writable::write_vixbe] method at `pos` and then returns to the original position. - fn write_vixbe_at(&mut self, pos: u64, size: u8, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vixbe(size, num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed variable-length integer in reversed little-endian byte order at a specific position. - /// - /// This executes the [`write_vixler`][Writable::write_vixler] method at `pos` and then returns to the original position. - fn write_vixler_at(&mut self, pos: u64, size: u8, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vixler(size, num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes a signed variable-length integer in reversed big-endian byte order at a specific position. - /// - /// This executes the [`write_vixber`][Writable::write_vixber] method at `pos` and then returns to the original position. - fn write_vixber_at(&mut self, pos: u64, size: u8, num: i128) -> Result<()> { - let pos_before = self.stream_position()?; - self.to(pos)?; - self.write_vixber(size, num)?; - self.to(pos_before)?; - Ok(()) - } - - /// Writes bytes at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(5); - /// - /// writer.write_bytes(&[1, 2, 3, 4, 5]).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, vec![1, 2, 3, 4, 5]); - /// ``` - fn write_bytes(&mut self, vec: &[u8]) -> Result<()> { - self.write_all(vec) - } - - /// Writes an UTF-8-encoded string at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(5); - /// - /// writer.write_utf8("Hello").unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, vec![0x48, 0x65, 0x6c, 0x6c, 0x6f]); - /// ``` - fn write_utf8(&mut self, s: &str) -> Result<()> { - self.write_all(s.as_bytes()) - } - - /// Writes an unsigned 8-bit integer at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(1); - /// - /// writer.write_u8(0x48).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, vec![0x48]); - /// ``` - fn write_u8(&mut self, num: u8) -> Result<()> { - self.write_all(&[num]) - } - - /// Writes an unsigned 16-bit integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(2); - /// - /// writer.write_u16le(0x02_01).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, vec![0x01, 0x02]); - /// ``` - fn write_u16le(&mut self, num: u16) -> Result<()> { - self.write_all(&num.to_le_bytes()) - } - - /// Writes an unsigned 16-bit integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(2); - /// - /// writer.write_u16be(0x01_02).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, vec![0x01, 0x02]); - /// ``` - fn write_u16be(&mut self, num: u16) -> Result<()> { - self.write_all(&num.to_be_bytes()) - } - - /// Writes an unsigned 32-bit integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(4); - /// - /// writer.write_u32le(0x04_03_02_01).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, vec![0x01, 0x02, 0x03, 0x04]); - /// ``` - fn write_u32le(&mut self, num: u32) -> Result<()> { - self.write_all(&num.to_le_bytes()) - } - - /// Writes an unsigned 32-bit integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(4); - /// - /// writer.write_u32be(0x01_02_03_04).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, vec![0x01, 0x02, 0x03, 0x04]); - /// ``` - fn write_u32be(&mut self, num: u32) -> Result<()> { - self.write_all(&num.to_be_bytes()) - } - - /// Writes an unsigned 64-bit integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(8); - /// - /// writer.write_u64le(0x08_07_06_05_04_03_02_01).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]); - /// ``` - fn write_u64le(&mut self, num: u64) -> Result<()> { - self.write_all(&num.to_le_bytes()) - } - - /// Writes an unsigned 64-bit integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(8); - /// - /// writer.write_u64be(0x01_02_03_04_05_06_07_08).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]); - /// ``` - fn write_u64be(&mut self, num: u64) -> Result<()> { - self.write_all(&num.to_be_bytes()) - } - - /// Writes an unsigned 128-bit integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(16); - /// - /// writer.write_u128le(0x10_0f_0e_0d_0c_0b_0a_09_08_07_06_05_04_03_02_01).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10]); - /// ``` - fn write_u128le(&mut self, num: u128) -> Result<()> { - self.write_all(&num.to_le_bytes()) - } - - /// Writes an unsigned 128-bit integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(16); - /// - /// writer.write_u128be(0x01_02_03_04_05_06_07_08_09_0a_0b_0c_0d_0e_0f_10).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10]); - /// ``` - fn write_u128be(&mut self, num: u128) -> Result<()> { - self.write_all(&num.to_be_bytes()) - } - - /// Writes an unsigned 7-bit variable-length integer at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu7(0xff).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu7().unwrap(), 0xff); - /// ``` - fn write_vu7(&mut self, num: u128) -> Result<()> { - self.write_vuxle(1, num) - } - - /// Writes an unsigned 7-bit variable-length integer in reversed byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu7r(0xff).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu7r().unwrap(), 0xff); - /// ``` - fn write_vu7r(&mut self, num: u128) -> Result<()> { - self.write_vuxler(1, num) - } - - /// Writes an unsigned 15-bit variable-length integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu15le(0xff_ee).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu15le().unwrap(), 0xff_ee); - /// ``` - fn write_vu15le(&mut self, num: u128) -> Result<()> { - self.write_vuxle(2, num) - } - - /// Writes an unsigned 15-bit variable-length integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu15be(0xff_ee).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu15be().unwrap(), 0xff_ee); - /// ``` - fn write_vu15be(&mut self, num: u128) -> Result<()> { - self.write_vuxbe(2, num) - } - - /// Writes an unsigned 15-bit variable-length integer in reversed little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu15ler(0xff_ee).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu15ler().unwrap(), 0xff_ee); - /// ``` - fn write_vu15ler(&mut self, num: u128) -> Result<()> { - self.write_vuxler(2, num) - } - - /// Writes an unsigned 15-bit variable-length integer in reversed big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu15ber(0xff_ee).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu15ber().unwrap(), 0xff_ee); - /// ``` - fn write_vu15ber(&mut self, num: u128) -> Result<()> { - self.write_vuxber(2, num) - } - - /// Writes an unsigned 31-bit variable-length integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu31le(0xff_ee_dd_cc).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu31le().unwrap(), 0xff_ee_dd_cc); - /// ``` - fn write_vu31le(&mut self, num: u128) -> Result<()> { - self.write_vuxle(4, num) - } - - /// Writes an unsigned 31-bit variable-length integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu31be(0xff_ee_dd_cc).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu31be().unwrap(), 0xff_ee_dd_cc); - /// ``` - fn write_vu31be(&mut self, num: u128) -> Result<()> { - self.write_vuxbe(4, num) - } - - /// Writes an unsigned 31-bit variable-length integer in reversed little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu31ler(0xff_ee_dd_cc).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu31ler().unwrap(), 0xff_ee_dd_cc); - /// ``` - fn write_vu31ler(&mut self, num: u128) -> Result<()> { - self.write_vuxler(4, num) - } - - /// Writes an unsigned 31-bit variable-length integer in reversed big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu31ber(0xff_ee_dd_cc).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu31ber().unwrap(), 0xff_ee_dd_cc); - /// ``` - fn write_vu31ber(&mut self, num: u128) -> Result<()> { - self.write_vuxber(4, num) - } - - /// Writes an unsigned 63-bit variable-length integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu63le(0xff_ee_dd_cc_bb_aa_99_88).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu63le().unwrap(), 0xff_ee_dd_cc_bb_aa_99_88); - /// ``` - fn write_vu63le(&mut self, num: u128) -> Result<()> { - self.write_vuxle(8, num) - } - - /// Writes an unsigned 63-bit variable-length integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu63be(0xff_ee_dd_cc_bb_aa_99_88).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu63be().unwrap(), 0xff_ee_dd_cc_bb_aa_99_88); - /// ``` - fn write_vu63be(&mut self, num: u128) -> Result<()> { - self.write_vuxbe(8, num) - } - - /// Writes an unsigned 63-bit variable-length integer in reversed little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu63ler(0xff_ee_dd_cc_bb_aa_99_88).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu63ler().unwrap(), 0xff_ee_dd_cc_bb_aa_99_88); - /// ``` - fn write_vu63ler(&mut self, num: u128) -> Result<()> { - self.write_vuxler(8, num) - } - - /// Writes an unsigned 63-bit variable-length integer in reversed big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu63ber(0xff_ee_dd_cc_bb_aa_99_88).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu63ber().unwrap(), 0xff_ee_dd_cc_bb_aa_99_88); - /// ``` - fn write_vu63ber(&mut self, num: u128) -> Result<()> { - self.write_vuxber(8, num) - } - - /// Writes an unsigned 127-bit variable-length integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu127le(0xff_ee_dd_cc_bb_aa_99_88_77_66_55_44_33_22_11_00).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu127le().unwrap(), 0xff_ee_dd_cc_bb_aa_99_88_77_66_55_44_33_22_11_00); - /// ``` - fn write_vu127le(&mut self, num: u128) -> Result<()> { - self.write_vuxle(16, num) - } - - /// Writes an unsigned 127-bit variable-length integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu127be(0xff_ee_dd_cc_bb_aa_99_88_77_66_55_44_33_22_11_00).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu127be().unwrap(), 0xff_ee_dd_cc_bb_aa_99_88_77_66_55_44_33_22_11_00); - /// ``` - fn write_vu127be(&mut self, num: u128) -> Result<()> { - self.write_vuxbe(16, num) - } - - /// Writes an unsigned 127-bit variable-length integer in reversed little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu127ler(0xff_ee_dd_cc_bb_aa_99_88_77_66_55_44_33_22_11_00).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu127ler().unwrap(), 0xff_ee_dd_cc_bb_aa_99_88_77_66_55_44_33_22_11_00); - /// ``` - fn write_vu127ler(&mut self, num: u128) -> Result<()> { - self.write_vuxler(16, num) - } - - /// Writes an unsigned 127-bit variable-length integer in reversed big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vu127ber(0xff_ee_dd_cc_bb_aa_99_88_77_66_55_44_33_22_11_00).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vu127ber().unwrap(), 0xff_ee_dd_cc_bb_aa_99_88_77_66_55_44_33_22_11_00); - /// ``` - fn write_vu127ber(&mut self, num: u128) -> Result<()> { - self.write_vuxber(16, num) - } - - /// Writes an unsigned integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(3); - /// - /// writer.write_uxle(3, 0x01_02_03).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, vec![0x03, 0x02, 0x01]); - /// ``` - fn write_uxle(&mut self, size: u8, num: u128) -> Result<()> { - if num >= 1 << (size * 8) { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "number is too large for the given size", - )); - } - let mut num = num; - for _ in 0..size { - self.write_all(&[num as u8])?; - num >>= 8; - } - Ok(()) - } - - /// Writes an unsigned integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(3); - /// - /// writer.write_uxbe(3, 0x01_02_03).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, vec![0x01, 0x02, 0x03]); - /// ``` - fn write_uxbe(&mut self, size: u8, num: u128) -> Result<()> { - if num >= 1 << (size * 8) { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "number is too large for the given size", - )); - } - let mut num = num; - for _ in 0..size { - self.write_all(&[(num >> (8 * (size - 1))) as u8])?; - num <<= 8; - } - Ok(()) - } - - /// Writes an unsigned variable-length integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vuxle(3, 0xff_ee_dd).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vuxle(3).unwrap(), 0xff_ee_dd); - /// ``` - fn write_vuxle(&mut self, size: u8, num: u128) -> Result<()> { - let buf = serialize_vuxle(size, num, false, false); - self.write_all(&buf) - } - - /// Writes an unsigned variable-length integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vuxbe(3, 0xff_ee_dd).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vuxbe(3).unwrap(), 0xff_ee_dd); - /// ``` - fn write_vuxbe(&mut self, size: u8, num: u128) -> Result<()> { - let buf = serialize_vuxle(size, num, true, false); - self.write_all(&buf) - } - - /// Writes an unsigned variable-length integer in reversed little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vuxler(3, 0xff_ee_dd).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vuxler(3).unwrap(), 0xff_ee_dd); - /// ``` - fn write_vuxler(&mut self, size: u8, num: u128) -> Result<()> { - let buf = serialize_vuxle(size, num, false, true); - self.write_all(&buf) - } - - /// Writes an unsigned variable-length integer in reversed big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vuxber(3, 0xff_ee_dd).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vuxber(3).unwrap(), 0xff_ee_dd); - /// ``` - fn write_vuxber(&mut self, size: u8, num: u128) -> Result<()> { - let buf = serialize_vuxle(size, num, true, true); - self.write_all(&buf) - } - - /// Writes a signed 8-bit integer at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(1); - /// - /// writer.write_i8(i8::MIN).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, i8::MIN.to_le_bytes().to_vec()); - /// ``` - fn write_i8(&mut self, num: i8) -> Result<()> { - self.write_all(&num.to_le_bytes()) - } - - /// Writes a signed 16-bit integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(2); - /// - /// writer.write_i16le(i16::MIN).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, i16::MIN.to_le_bytes().to_vec()); - /// ``` - fn write_i16le(&mut self, num: i16) -> Result<()> { - self.write_all(&num.to_le_bytes()) - } - - /// Writes a signed 16-bit integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(2); - /// - /// writer.write_i16be(i16::MIN).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, i16::MIN.to_be_bytes().to_vec()); - /// ``` - fn write_i16be(&mut self, num: i16) -> Result<()> { - self.write_all(&num.to_be_bytes()) - } - - /// Writes a signed 32-bit integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(4); - /// - /// writer.write_i32le(i32::MIN).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, i32::MIN.to_le_bytes().to_vec()); - /// ``` - fn write_i32le(&mut self, num: i32) -> Result<()> { - self.write_all(&num.to_le_bytes()) - } - - /// Writes a signed 32-bit integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(4); - /// - /// writer.write_i32be(i32::MIN).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, i32::MIN.to_be_bytes().to_vec()); - /// ``` - fn write_i32be(&mut self, num: i32) -> Result<()> { - self.write_all(&num.to_be_bytes()) - } - - /// Writes a signed 64-bit integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(8); - /// - /// writer.write_i64le(i64::MIN).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, i64::MIN.to_le_bytes().to_vec()); - /// ``` - fn write_i64le(&mut self, num: i64) -> Result<()> { - self.write_all(&num.to_le_bytes()) - } - - /// Writes a signed 64-bit integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(8); - /// - /// writer.write_i64be(i64::MIN).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, i64::MIN.to_be_bytes().to_vec()); - /// ``` - fn write_i64be(&mut self, num: i64) -> Result<()> { - self.write_all(&num.to_be_bytes()) - } - - /// Writes a signed 128-bit integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(16); - /// - /// writer.write_i128le(i128::MIN).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, i128::MIN.to_le_bytes().to_vec()); - /// ``` - fn write_i128le(&mut self, num: i128) -> Result<()> { - self.write_all(&num.to_le_bytes()) - } - - /// Writes a signed 128-bit integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(16); - /// - /// writer.write_i128be(i128::MIN).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, i128::MIN.to_be_bytes().to_vec()); - /// ``` - fn write_i128be(&mut self, num: i128) -> Result<()> { - self.write_all(&num.to_be_bytes()) - } - - /// Writes a signed 7-bit variable-length integer at the current position. - /// - /// This works like [`write_vu7`][Writable::write_vu7] but for signed integers. - fn write_vi7(&mut self, num: i128) -> Result<()> { - self.write_vixle(1, num) - } - - /// Writes a signed 7-bit variable-length integer in reversed byte order at the current position. - /// - /// This works like [`write_vu7r`][Writable::write_vu7r] but for signed integers. - fn write_vi7r(&mut self, num: i128) -> Result<()> { - self.write_vixler(1, num) - } - - /// Writes a signed 15-bit variable-length integer in little-endian byte order at the current position. - /// - /// This works like [`write_vu15le`][Writable::write_vu15le] but for signed integers. - fn write_vi15le(&mut self, num: i128) -> Result<()> { - self.write_vixle(2, num) - } - - /// Writes a signed 15-bit variable-length integer in big-endian byte order at the current position. - /// - /// This works like [`write_vu15be`][Writable::write_vu15be] but for signed integers. - fn write_vi15be(&mut self, num: i128) -> Result<()> { - self.write_vixbe(2, num) - } - - /// Writes a signed 15-bit variable-length integer in reversed little-endian byte order at the current position. - /// - /// This works like [`write_vu15ler`][Writable::write_vu15ler] but for signed integers. - fn write_vi15ler(&mut self, num: i128) -> Result<()> { - self.write_vixler(2, num) - } - - /// Writes a signed 15-bit variable-length integer in reversed big-endian byte order at the current position. - /// - /// This works like [`write_vu15ber`][Writable::write_vu15ber] but for signed integers. - fn write_vi15ber(&mut self, num: i128) -> Result<()> { - self.write_vixber(2, num) - } - - /// Writes a signed 31-bit variable-length integer in little-endian byte order at the current position. - /// - /// This works like [`write_vu31le`][Writable::write_vu31le] but for signed integers. - fn write_vi31le(&mut self, num: i128) -> Result<()> { - self.write_vixle(4, num) - } - - /// Writes a signed 31-bit variable-length integer in big-endian byte order at the current position. - /// - /// This works like [`write_vu31be`][Writable::write_vu31be] but for signed integers. - fn write_vi31be(&mut self, num: i128) -> Result<()> { - self.write_vixbe(4, num) - } - - /// Writes a signed 31-bit variable-length integer in reversed little-endian byte order at the current position. - /// - /// This works like [`write_vu31ler`][Writable::write_vu31ler] but for signed integers. - fn write_vi31ler(&mut self, num: i128) -> Result<()> { - self.write_vixler(4, num) - } - - /// Writes a signed 31-bit variable-length integer in reversed big-endian byte order at the current position. - /// - /// This works like [`write_vu31ber`][Writable::write_vu31ber] but for signed integers. - fn write_vi31ber(&mut self, num: i128) -> Result<()> { - self.write_vixber(4, num) - } - - /// Writes a signed 63-bit variable-length integer in little-endian byte order at the current position. - /// - /// This works like [`write_vu63le`][Writable::write_vu63le] but for signed integers. - fn write_vi63le(&mut self, num: i128) -> Result<()> { - self.write_vixle(8, num) - } - - /// Writes a signed 63-bit variable-length integer in big-endian byte order at the current position. - /// - /// This works like [`write_vu63be`][Writable::write_vu63be] but for signed integers. - fn write_vi63be(&mut self, num: i128) -> Result<()> { - self.write_vixbe(8, num) - } - - /// Writes a signed 63-bit variable-length integer in reversed little-endian byte order at the current position. - /// - /// This works like [`write_vu63ler`][Writable::write_vu63ler] but for signed integers. - fn write_vi63ler(&mut self, num: i128) -> Result<()> { - self.write_vixler(8, num) - } - - /// Writes a signed 63-bit variable-length integer in reversed big-endian byte order at the current position. - /// - /// This works like [`write_vu63ber`][Writable::write_vu63ber] but for signed integers. - fn write_vi63ber(&mut self, num: i128) -> Result<()> { - self.write_vixber(8, num) - } - - /// Writes a signed 127-bit variable-length integer in little-endian byte order at the current position. - /// - /// This works like [`write_vu127le`][Writable::write_vu127le] but for signed integers. - fn write_vi127le(&mut self, num: i128) -> Result<()> { - self.write_vixle(16, num) - } - - /// Writes a signed 127-bit variable-length integer in big-endian byte order at the current position. - /// - /// This works like [`write_vu127be`][Writable::write_vu127be] but for signed integers. - fn write_vi127be(&mut self, num: i128) -> Result<()> { - self.write_vixbe(16, num) - } - - /// Writes a signed 127-bit variable-length integer in reversed little-endian byte order at the current position. - /// - /// This works like [`write_vu127ler`][Writable::write_vu127ler] but for signed integers. - fn write_vi127ler(&mut self, num: i128) -> Result<()> { - self.write_vixler(16, num) - } - - /// Writes a signed 127-bit variable-length integer in reversed big-endian byte order at the current position. - /// - /// This works like [`write_vu127ber`][Writable::write_vu127ber] but for signed integers. - fn write_vi127ber(&mut self, num: i128) -> Result<()> { - self.write_vixber(16, num) - } - - /// Writes a signed integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(3); - /// - /// writer.write_ixle(3, -0x01_02_03).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, vec![0xfd, 0xfd, 0xfe]); - /// ``` - fn write_ixle(&mut self, size: u8, num: i128) -> Result<()> { - self.write_uxle(size, signed_to_unsigned(num, size)) - } - - /// Writes a signed integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut writer = dh::data::write_new(3); - /// - /// writer.write_ixbe(3, -0x01_02_03).unwrap(); - /// - /// let data = dh::data::close(writer); - /// assert_eq!(data, vec![0xfe, 0xfd, 0xfd]); - /// ``` - fn write_ixbe(&mut self, size: u8, num: i128) -> Result<()> { - self.write_uxbe(size, signed_to_unsigned(num, size)) - } - - /// Writes a signed variable-length integer in little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vixle(3, -0x01_02_03).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vixle(3).unwrap(), -0x01_02_03); - /// ``` - fn write_vixle(&mut self, size: u8, num: i128) -> Result<()> { - self.write_vuxle(size, signed_to_unsigned_vi(num, size)) - } - - /// Writes a signed variable-length integer in big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vixbe(3, -0x01_02_03).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vixbe(3).unwrap(), -0x01_02_03); - /// ``` - fn write_vixbe(&mut self, size: u8, num: i128) -> Result<()> { - self.write_vuxbe(size, signed_to_unsigned_vi(num, size)) - } - - /// Writes a signed variable-length integer in reversed little-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vixler(3, -0x01_02_03).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vixler(3).unwrap(), -0x01_02_03); - /// ``` - fn write_vixler(&mut self, size: u8, num: i128) -> Result<()> { - self.write_vuxler(size, signed_to_unsigned_vi(num, size)) - } - - /// Writes a signed variable-length integer in reversed big-endian byte order at the current position. - /// - /// ### Example - /// - /// ```rust - /// use dh::recommended::*; - /// - /// let mut rw = dh::data::rw_empty(); - /// - /// rw.write_vixber(3, -0x01_02_03).unwrap(); - /// - /// rw.rewind(); - /// assert_eq!(rw.read_vixber(3).unwrap(), -0x01_02_03); - /// ``` - fn write_vixber(&mut self, size: u8, num: i128) -> Result<()> { - self.write_vuxber(size, signed_to_unsigned_vi(num, size)) - } -} diff --git a/tests/data.rs b/tests/data.rs deleted file mode 100644 index 73e0867..0000000 --- a/tests/data.rs +++ /dev/null @@ -1,113 +0,0 @@ -use dh::{data, recommended::*}; - -#[test] -fn r000() { - let data = "Hello, world!".as_bytes().to_vec(); - let cloned = data.clone(); - let mut reader = data::read(data); - - let size = reader.size().unwrap(); - assert_eq!(reader.read_utf8_at(0, size).unwrap(), "Hello, world!"); - - assert_eq!(data::close(reader), cloned); -} - -#[test] -fn r001() { - let data = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let mut reader = data::read(data); - - assert_eq!(reader.read_u8_at(0).unwrap(), 0); - assert_eq!(reader.read_u16le_at(6).unwrap(), 0x0706); - assert_eq!(reader.read_u64be().unwrap(), 0x0001020304050607); -} - -#[test] -fn w000() { - let data = "Hello, world!".as_bytes().to_vec(); - let mut writer = data::write(data); - - writer.write_utf8_at(7, "rust ").unwrap(); - - let data = data::close(writer); - assert_eq!(data, "Hello, rust !".as_bytes()); -} - -#[test] -fn w001() { - let data = "Hello, world!".as_bytes().to_vec(); - let mut writer = data::write(data); - - writer.write_utf8_at(7, "rust world!").unwrap(); - - let data = data::close(writer); - assert_eq!(data, "Hello, rust world!".as_bytes()); -} - -#[test] -fn w002() { - let mut writer = data::write_empty(); - - writer.write_utf8_at(0, "Hello, world!").unwrap(); - - let data = data::close(writer); - assert_eq!(data, "Hello, world!".as_bytes()); -} - -#[test] -fn w003() { - let mut writer = data::write_new(13); // better than w002 - - writer.write_utf8_at(0, "Hello, world!").unwrap(); - - let data = data::close(writer); - assert_eq!(data, "Hello, world!".as_bytes()); -} - -#[test] -fn w004() { - let buf = vec![1, 2, 3, 4, 5, 6, 7, 8]; - let mut reader = data::read_ref(&buf); - - let mut writer = data::write_new(8); - reader.copy(8, &mut writer, 8000).unwrap(); // even if the limit is 8000, it will copy only 8 bytes - - let new_buf = data::close(writer); - assert_eq!(new_buf, buf); -} - -#[test] -fn w005() { - let buf = vec![1, 2, 3, 4]; - let mut reader = data::read(buf); - - let mut writer = data::write_new(8); - reader.copy_to(4, 4, &mut writer, 4).unwrap(); - - let new_buf = data::close(writer); - assert_eq!(new_buf, vec![0, 0, 0, 0, 1, 2, 3, 4]); -} - -#[test] -fn w006() { - let buf = vec![1, 2, 3, 4, 5, 6, 7, 8]; - let mut reader = data::read(buf); - - let mut writer = data::write_new(8); - reader.copy_to_at(2, 2, 4, &mut writer, 4).unwrap(); - - let new_buf = data::close(writer); - assert_eq!(new_buf, vec![0, 0, 3, 4, 5, 6, 0, 0]); -} - -#[test] -fn rw000() { - let mut rw = data::rw_new(2); - - rw.write_u16be(0x1234).unwrap(); - rw.rewind().unwrap(); - assert_eq!(rw.read_u16be().unwrap(), 0x1234); - - let data = data::close(rw); - assert_eq!(data, vec![0x12, 0x34]); -} diff --git a/tests/data_ref.rs b/tests/data_ref.rs deleted file mode 100644 index 7c1b06b..0000000 --- a/tests/data_ref.rs +++ /dev/null @@ -1,63 +0,0 @@ -use dh::{data, recommended::*}; - -#[test] -fn r000() { - let data = "Hello, world!".as_bytes().to_vec(); - let data_ref = &data; - let mut reader = data::read_ref(&data); - - let size = reader.size().unwrap(); - assert_eq!(reader.read_utf8_at(0, size).unwrap(), "Hello, world!"); - - assert_eq!(data::close_ref(reader), data_ref); -} - -#[test] -fn r001() { - let data = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let data2 = { - let mut reader = data::read_ref(&data); - - assert_eq!(reader.read_u8_at(0).unwrap(), 0); - assert_eq!(reader.read_u16le_at(6).unwrap(), 0x0706); - assert_eq!(reader.read_u64be().unwrap(), 0x0001020304050607); - - data::close_ref(reader) - }; - assert_eq!(data2, &data); -} - -#[test] -fn w000() { - let mut data = "Hello, world!".as_bytes().to_vec(); - let mut writer = data::write_ref(&mut data); - - writer.write_utf8_at(7, "rust ").unwrap(); - - data::close_ref(writer); // close_mut would return the mutable reference - assert_eq!(data, "Hello, rust !".as_bytes()); -} - -#[test] -fn w001() { - let mut data = "Hello, world!".as_bytes().to_vec(); - let mut writer = data::write_ref(&mut data); - - writer.write_utf8_at(7, "rust ").unwrap(); - - writer.close().unwrap(); // recommended if the data is not used anymore - assert_eq!(data, "Hello, rust !".as_bytes()); -} - -#[test] -fn rw000() { - let mut data = vec![0u8; 2]; - let mut rw = data::rw_ref(&mut data); - - rw.write_u16be(0x1234).unwrap(); - rw.rewind().unwrap(); - assert_eq!(rw.read_u16be().unwrap(), 0x1234); - - rw.rw_close().unwrap(); - assert_eq!(data, vec![0x12, 0x34]); -} diff --git a/tests/file.rs b/tests/file.rs deleted file mode 100644 index e65920a..0000000 --- a/tests/file.rs +++ /dev/null @@ -1,114 +0,0 @@ -use dh::{file, recommended::*}; -use std::fs::remove_file; - -#[test] -fn r000() { - let path = "tests/samples/000"; - let mut reader = file::open_r(path).unwrap(); - let size = reader.size().unwrap(); - assert_eq!(reader.read_utf8_at(0, size).unwrap(), "Hello, world!"); - - assert_eq!(reader.read_u8_at(0).unwrap(), 0x48); - - assert_eq!(reader.read_u16le_at(0).unwrap(), 0x6548); - - assert_eq!(reader.read_u16be_at(0).unwrap(), 0x4865); - - assert_eq!(reader.read_u32le_at(0).unwrap(), 0x6c6c6548); - - assert_eq!(reader.read_u32be_at(0).unwrap(), 0x48656c6c); - - assert_eq!(reader.read_u64le_at(0).unwrap(), 0x77202c6f6c6c6548); - - assert_eq!(reader.read_u64be_at(0).unwrap(), 0x48656c6c6f2c2077); - - assert_eq!(reader.read_uxle_at(0, 3).unwrap(), 0x6c6548); - - assert_eq!(reader.read_uxle_at(0, 7).unwrap(), 0x202c6f6c6c6548); - - assert_eq!(reader.read_uxbe_at(0, 3).unwrap(), 0x48656c); - - assert_eq!(reader.read_uxbe_at(0, 7).unwrap(), 0x48656c6c6f2c20); -} - -#[test] -fn r001() { - let path = "tests/samples/001"; - let mut reader = file::open_r(path).unwrap(); - - assert_eq!(reader.read_vu7_at(0).unwrap(), 0b1101100_1100101_1001000); - - assert_eq!(reader.read_vu7r_at(0).unwrap(), 0b1001000_1100101_1101100); - - assert_eq!( - reader.read_vu15le_at(0).unwrap(), - 0b010110011001111_110110001101100_110010111001000 - ); - - assert_eq!( - reader.read_vu15be_at(0).unwrap(), - 0b110110011101100_100100011100101 - ); - - assert_eq!( - reader.read_vu15ler_at(0).unwrap(), - 0b110010111001000_110110001101100_010110011001111 - ); - - assert_eq!( - reader.read_vu15ber_at(0).unwrap(), - 0b100100011100101_110110011101100 - ); - - assert_eq!(reader.read_i8_at(0).unwrap(), -56); - - assert_eq!(reader.read_i16le_at(0).unwrap(), -6712); - - assert_eq!(reader.read_i16be_at(0).unwrap(), -14107); -} - -#[test] -fn w000() { - let path = "tests/samples/w000"; - let mut writer = file::open_w(path).unwrap(); - let str = String::from("Hello, world!"); - writer.write_utf8_at(0, &str).unwrap(); - writer.close().unwrap(); - - let mut reader = file::open_r(path).unwrap(); - let size = reader.size().unwrap(); - assert_eq!(reader.read_utf8_at(0, size).unwrap(), str); - reader.close().unwrap(); - - remove_file(path).unwrap(); -} - -#[test] -fn w001() { - let path = "tests/samples/w001"; - let mut writer = file::open_w(path).unwrap(); - writer.write_vu31le(0b1101100_1100101_1001000).unwrap(); - writer.write_vixler(3, 0b1101100_1100101_1001000).unwrap(); - writer.close().unwrap(); - - let mut reader = file::open_r(path).unwrap(); - assert_eq!(reader.read_vuxle(4).unwrap(), 0b1101100_1100101_1001000); - assert_eq!(reader.read_vixler(3).unwrap(), 0b1101100_1100101_1001000); - reader.close().unwrap(); - - remove_file(path).unwrap(); -} - -#[test] -fn rw000() { - let path = "tests/samples/rw000"; - let mut rw = file::open_rw(path).unwrap(); - let str = String::from("Hello, world!"); - - rw.write_utf8(&str).unwrap(); - rw.rewind().unwrap(); - assert_eq!(rw.read_utf8(str.len() as u64).unwrap(), str); - rw.rw_close().unwrap(); - - remove_file(path).unwrap(); -} diff --git a/tests/limited.rs b/tests/limited.rs deleted file mode 100644 index b58b8c0..0000000 --- a/tests/limited.rs +++ /dev/null @@ -1,93 +0,0 @@ -use dh::recommended::*; -use murmur3::murmur3_32; - -#[test] -fn r000() { - let data = "Hello, world!".as_bytes().to_vec(); - - let mut reader = dh::data::read(data); - - let mut limited = reader.limit(0, 5).unwrap(); - - assert_eq!(limited.size().unwrap(), 5); - - limited.to(6).unwrap_err(); - - limited.end().unwrap(); - assert_eq!(limited.pos().unwrap(), 5); - - reader.jump(2).unwrap(); - assert_eq!(reader.read_utf8(5).unwrap(), "world"); - - let mut limited = reader.limit(7, 5).unwrap(); - - limited.rewind().unwrap(); - assert_eq!(limited.pos().unwrap(), 0); - assert_eq!(limited.jump(1).unwrap(), 1); - assert_eq!(limited.jump(-1).unwrap(), 0); - assert_eq!(reader.pos().unwrap(), 7); -} - -#[test] -fn r001() { - let data = "Hello, world!".as_bytes().to_vec(); - - let mut reader = dh::data::read(data); - - let mut limited = reader.limit(0, 5).unwrap(); - - let size = limited.size().unwrap(); - assert_eq!(limited.read_utf8(size).unwrap(), "Hello"); - - let mut limited = reader.limit(7, 5).unwrap(); - limited.end().unwrap(); - - limited.read_u8().unwrap_err(); - - assert_eq!(reader.pos().unwrap(), 12); -} - -#[test] -fn r002() { - let data = "Hello, world!".as_bytes().to_vec(); - - let mut reader = dh::data::read(data); - - let mut limited = reader.limit(0, 5).unwrap(); - - let hash = murmur3_32(&mut limited, 0).unwrap(); - assert_eq!(hash, 316307400); - - let mut reader = limited.unlimit(); - reader.rewind().unwrap(); - let hash = murmur3_32(&mut reader, 0).unwrap(); - assert_eq!(hash, 3224780355); -} - -#[test] -fn w000() { - let mut data = "Hello, world!".as_bytes().to_vec(); - - let mut writer = dh::data::write_ref(&mut data); - - let mut limited = writer.limit(6, 6).unwrap(); - - limited.jump(1).unwrap(); - limited.write_utf8("rust ").unwrap(); - - assert_eq!(data, "Hello, rust !".as_bytes()); -} - -#[test] -fn rw000() { - let mut data = vec![0, 1, 2, 3, 4, 5, 6, 7]; - - let mut rw = dh::data::rw_ref(&mut data); - - let mut limited = rw.rw_limit(2, 4).unwrap(); - - assert_eq!(limited.read_u16be().unwrap(), 0x0203); - limited.write_u16be(0x0504).unwrap(); - - assert_eq!(data, vec![0, 1, 2, 3, 5, 4, 6, 7]); -} diff --git a/tests/read.rs b/tests/read.rs new file mode 100644 index 0000000..fdbddcd --- /dev/null +++ b/tests/read.rs @@ -0,0 +1,242 @@ +use dh::{ReadVal, Result}; +use std::io::{Cursor, Read}; + +#[test] +fn read_borrowing() { + let data = [0u8, 1, 2, 3]; + let mut cursor = Cursor::new(data); + + // this just needs to compile + let mut borrowed: &mut dyn Read = &mut cursor; + assert_eq!(borrowed.read_u8().unwrap(), 0); + assert_eq!(borrowed.read_u8().unwrap(), 1); + assert_eq!(cursor.read_u8().unwrap(), 2); + assert_eq!(cursor.read_u8().unwrap(), 3); +} + +#[test] +fn read_primitive() { + let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut cursor = Cursor::new(data); + + let val: u8 = cursor.read_ne().unwrap(); + assert_eq!(val, 0); + + let val: [u8; 3] = cursor.read_ne().unwrap(); + assert_eq!(val, [1, 2, 3]); + + let val: u16 = cursor.read_be().unwrap(); + assert_eq!(val, 0x04_05); + + let val: u16 = cursor.read_le().unwrap(); + assert_eq!(val, 0x07_06); + + // overflow + let val: Result = cursor.read_ne(); + assert!(val.is_err()); +} + +#[test] +fn read_u8() { + let data = [0u8, 1, 2, 3]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u8().unwrap(), 0); + assert_eq!(cursor.read_u8().unwrap(), 1); + assert_eq!(cursor.read_u8().unwrap(), 2); + assert_eq!(cursor.read_u8().unwrap(), 3); + + // overflow + let val = cursor.read_u8(); + assert!(val.is_err()); +} + +#[test] +fn read_u16_ne() { + let data = [0x12u8, 0x34, 0x56, 0x78]; + let mut cursor = Cursor::new(data); + + let parts = match cfg!(target_endian = "big") { + true => (0x1234, 0x5678), + false => (0x3412, 0x7856), + }; + + assert_eq!(cursor.read_u16_ne().unwrap(), parts.0); + assert_eq!(cursor.read_u16_ne().unwrap(), parts.1); + + // overflow + let val = cursor.read_u16_ne(); + assert!(val.is_err()); +} + +#[test] +fn read_u16_le() { + let data = [0x12u8, 0x34, 0x56, 0x78]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u16_le().unwrap(), 0x3412); + assert_eq!(cursor.read_u16_le().unwrap(), 0x7856); + + // overflow + let val = cursor.read_u16_le(); + assert!(val.is_err()); +} + +#[test] +fn read_u16_be() { + let data = [0x12u8, 0x34, 0x56, 0x78]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u16_be().unwrap(), 0x1234); + assert_eq!(cursor.read_u16_be().unwrap(), 0x5678); + + // overflow + let val = cursor.read_u16_be(); + assert!(val.is_err()); +} + +#[test] +fn read_u32_ne() { + let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; + let mut cursor = Cursor::new(data); + + let parts = match cfg!(target_endian = "big") { + true => (0x12345678, 0x9ABCDEF0), + false => (0x78563412, 0xF0DEBC9A), + }; + + assert_eq!(cursor.read_u32_ne().unwrap(), parts.0); + assert_eq!(cursor.read_u32_ne().unwrap(), parts.1); + + // overflow + let val = cursor.read_u32_ne(); + assert!(val.is_err()); +} + +#[test] +fn read_u32_le() { + let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u32_le().unwrap(), 0x78563412); + assert_eq!(cursor.read_u32_le().unwrap(), 0xF0DEBC9A); + + // overflow + let val = cursor.read_u32_le(); + assert!(val.is_err()); +} + +#[test] +fn read_u32_be() { + let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u32_be().unwrap(), 0x12345678); + assert_eq!(cursor.read_u32_be().unwrap(), 0x9ABCDEF0); + + // overflow + let val = cursor.read_u32_be(); + assert!(val.is_err()); +} + +#[test] +fn read_u64_ne() { + let data = [ + 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, + 0xEF, + ]; + let mut cursor = Cursor::new(data); + + let parts = match cfg!(target_endian = "big") { + true => (0x123456789ABCDEF0, 0x0123456789ABCDEF), + false => (0xF0DEBC9A78563412, 0xEFCDAB8967452301), + }; + + assert_eq!(cursor.read_u64_ne().unwrap(), parts.0); + assert_eq!(cursor.read_u64_ne().unwrap(), parts.1); + + // overflow + let val = cursor.read_u64_ne(); + assert!(val.is_err()); +} + +#[test] +fn read_u64_le() { + let data = [ + 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, + 0xEF, + ]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u64_le().unwrap(), 0xF0DEBC9A78563412); + assert_eq!(cursor.read_u64_le().unwrap(), 0xEFCDAB8967452301); + + // overflow + let val = cursor.read_u64_le(); + assert!(val.is_err()); +} + +#[test] +fn read_u64_be() { + let data = [ + 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, + 0xEF, + ]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u64_be().unwrap(), 0x123456789ABCDEF0); + assert_eq!(cursor.read_u64_be().unwrap(), 0x0123456789ABCDEF); + + // overflow + let val = cursor.read_u64_be(); + assert!(val.is_err()); +} + +#[test] +fn read_u128_ne() { + let data = [ + 1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ]; + let mut cursor = Cursor::new(data); + + let parts = match cfg!(target_endian = "big") { + true => ( + 0x01000000000000000000000000000000, + 0x01000000000000000000000000000000, + ), + false => ( + 0x00000000000000000000000000000001, + 0x00000000000000000000000000000001, + ), + }; + + assert_eq!(cursor.read_u128_ne().unwrap(), parts.0); + assert_eq!(cursor.read_u128_ne().unwrap(), parts.1); + + // overflow + let val = cursor.read_u128_ne(); + assert!(val.is_err()); +} + +#[test] +fn read_u128_le() { + let data = [ + 1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ]; + let mut cursor = Cursor::new(data); + + assert_eq!( + cursor.read_u128_le().unwrap(), + 0x00000000000000000000000000000001 + ); + assert_eq!( + cursor.read_u128_le().unwrap(), + 0x00000000000000000000000000000001 + ); + + // overflow + let val = cursor.read_u128_le(); + assert!(val.is_err()); +} diff --git a/tests/samples/000 b/tests/samples/000 deleted file mode 100644 index 5dd01c1..0000000 --- a/tests/samples/000 +++ /dev/null @@ -1 +0,0 @@ -Hello, world! \ No newline at end of file diff --git a/tests/samples/001 b/tests/samples/001 deleted file mode 100644 index e6285be..0000000 --- a/tests/samples/001 +++ /dev/null @@ -1 +0,0 @@ -ÈålìÏ, ÷oòìd! \ No newline at end of file From f0dcafede09664c826ee01c98d1a2551791a7587 Mon Sep 17 00:00:00 2001 From: Le0X8 <84378319+Le0X8@users.noreply.github.com> Date: Thu, 17 Apr 2025 12:33:00 +0200 Subject: [PATCH 2/7] feat: added dynamic types and an endianess enum --- Cargo.lock | 54 ---------------------------------------------- Cargo.toml | 4 ---- src/dynamic.rs | 19 ++++++++++++++++ src/lib.rs | 4 ++++ src/read/val.rs | 49 +++++++++++++++++++++++++++++++++++++++-- src/read/val_ne.rs | 0 src/types.rs | 6 ++++++ tests/read.rs | 34 +++++++++++++++++++++++++---- 8 files changed, 106 insertions(+), 64 deletions(-) create mode 100644 src/dynamic.rs create mode 100644 src/read/val_ne.rs create mode 100644 src/types.rs diff --git a/Cargo.lock b/Cargo.lock index 6886733..d1a7ee5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,60 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "casey" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e779867f62d81627d1438e0d3fb6ed7d7c9d64293ca6d87a1e88781b94ece1c" -dependencies = [ - "syn", -] - [[package]] name = "dh" version = "0.8.1" -dependencies = [ - "casey", - "murmur3", -] - -[[package]] -name = "murmur3" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9252111cf132ba0929b6f8e030cac2a24b507f3a4d6db6fb2896f27b354c714b" - -[[package]] -name = "proc-macro2" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "syn" -version = "2.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" diff --git a/Cargo.toml b/Cargo.toml index cc0a0ed..6ede54b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,3 @@ authors = [ "Leonard Lesinski <84378319+Le0X8@users.noreply.github.com>" ] readme = "README.md" keywords = [ "data", "files", "read", "write", "rw" ] categories = [ "data-structures", "encoding", "filesystem", "parsing" ] - -[dev-dependencies] -casey = "0.4.2" -murmur3 = "0.5.2" diff --git a/src/dynamic.rs b/src/dynamic.rs new file mode 100644 index 0000000..96e6d8e --- /dev/null +++ b/src/dynamic.rs @@ -0,0 +1,19 @@ +use crate::error::Result; +use std::io::{Error, ErrorKind::InvalidData}; + +// marker trait +pub trait Dynamic: Sized { + fn from_bytes(bytes: Vec) -> Result; +} + +impl Dynamic for Vec { + fn from_bytes(bytes: Vec) -> Result { + Ok(bytes) + } +} + +impl Dynamic for String { + fn from_bytes(bytes: Vec) -> Result { + String::from_utf8(bytes).map_err(|_| Error::new(InvalidData, "Invalid UTF-8")) + } +} diff --git a/src/lib.rs b/src/lib.rs index 725cd6f..c0730ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,11 @@ +mod dynamic; mod error; mod primitive; mod read; +mod types; +pub use dynamic::Dynamic; pub use error::{Error, Result}; pub use primitive::Primitive; pub use read::val::ReadVal; +pub use types::*; diff --git a/src/read/val.rs b/src/read/val.rs index df6a7f0..f789bb4 100644 --- a/src/read/val.rs +++ b/src/read/val.rs @@ -1,4 +1,4 @@ -use crate::{Primitive, Result}; +use crate::{Dynamic, Endianess, Primitive, Result}; use std::io::Read; macro_rules! read_primitive { @@ -22,6 +22,18 @@ macro_rules! read_primitive_typed { } }; + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `read_ne`, `read_le`, or `read_be`. + fn $fn_name(&mut self, endianess: Endianess) -> Result<$return_type> { + use Endianess::*; + match endianess { + Little => self.read_le(), + Big => self.read_be(), + Native => self.read_ne(), + } + } + }; + ($fn_name:ident, $return_type:ty, $read_fn:ident, $const:ident) => { /// Typed wrapper around `read_ne`, `read_le`, or `read_be`. fn $fn_name(&mut self) -> Result<$return_type> { @@ -30,7 +42,16 @@ macro_rules! read_primitive_typed { }; } -/// Extension trait for `Read` that provides methods for reading primitive values. +macro_rules! read_dynamic_typed { + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `read_dynamic`. + fn $fn_name(&mut self, len: usize) -> Result<$return_type> { + self.read_dynamic(len) + } + }; +} + +/// Extension trait for `Read` that provides methods for reading supported value types. /// /// **Note:** do not borrow this as `&mut dyn ReadVal`, as this would not compile. Use `&mut dyn Read` instead. pub trait ReadVal: Read { @@ -40,52 +61,64 @@ pub trait ReadVal: Read { read_primitive_typed!(read_u8, u8, read_ne); + read_primitive_typed!(read_u16, u16); read_primitive_typed!(read_u16_ne, u16, read_ne); read_primitive_typed!(read_u16_le, u16, read_le); read_primitive_typed!(read_u16_be, u16, read_be); + read_primitive_typed!(read_u32, u32); read_primitive_typed!(read_u32_ne, u32, read_ne); read_primitive_typed!(read_u32_le, u32, read_le); read_primitive_typed!(read_u32_be, u32, read_be); + read_primitive_typed!(read_u64, u64); read_primitive_typed!(read_u64_ne, u64, read_ne); read_primitive_typed!(read_u64_le, u64, read_le); read_primitive_typed!(read_u64_be, u64, read_be); + read_primitive_typed!(read_u128, u128); read_primitive_typed!(read_u128_ne, u128, read_ne); read_primitive_typed!(read_u128_le, u128, read_le); read_primitive_typed!(read_u128_be, u128, read_be); + read_primitive_typed!(read_usize, usize); read_primitive_typed!(read_usize_ne, usize, read_ne); read_primitive_typed!(read_usize_le, usize, read_le); read_primitive_typed!(read_usize_be, usize, read_be); read_primitive_typed!(read_i8, i8, read_ne); + read_primitive_typed!(read_i16, i16); read_primitive_typed!(read_i16_ne, i16, read_ne); read_primitive_typed!(read_i16_le, i16, read_le); read_primitive_typed!(read_i16_be, i16, read_be); + read_primitive_typed!(read_i32, i32); read_primitive_typed!(read_i32_ne, i32, read_ne); read_primitive_typed!(read_i32_le, i32, read_le); read_primitive_typed!(read_i32_be, i32, read_be); + read_primitive_typed!(read_i64, i64); read_primitive_typed!(read_i64_ne, i64, read_ne); read_primitive_typed!(read_i64_le, i64, read_le); read_primitive_typed!(read_i64_be, i64, read_be); + read_primitive_typed!(read_i128, i128); read_primitive_typed!(read_i128_ne, i128, read_ne); read_primitive_typed!(read_i128_le, i128, read_le); read_primitive_typed!(read_i128_be, i128, read_be); + read_primitive_typed!(read_isize, isize); read_primitive_typed!(read_isize_ne, isize, read_ne); read_primitive_typed!(read_isize_le, isize, read_le); read_primitive_typed!(read_isize_be, isize, read_be); + read_primitive_typed!(read_f32, f32); read_primitive_typed!(read_f32_ne, f32, read_ne); read_primitive_typed!(read_f32_le, f32, read_le); read_primitive_typed!(read_f32_be, f32, read_be); + read_primitive_typed!(read_f64, f64); read_primitive_typed!(read_f64_ne, f64, read_ne); read_primitive_typed!(read_f64_le, f64, read_le); read_primitive_typed!(read_f64_be, f64, read_be); @@ -93,6 +126,18 @@ pub trait ReadVal: Read { read_primitive_typed!(read_u8_array, [u8; S], read_ne, S); read_primitive_typed!(read_bool, bool, read_ne); + + /// Reads a dynamic value from the reader. + /// + /// It's recommended to use the typed wrappers like `read_vec` instead of this method for cleaner code. + fn read_dynamic(&mut self, len: usize) -> Result { + let mut buf = vec![0; len]; + self.read_exact(&mut buf)?; + T::from_bytes(buf) + } + + read_dynamic_typed!(read_vec, Vec); + read_dynamic_typed!(read_str, String); } impl ReadVal for T {} diff --git a/src/read/val_ne.rs b/src/read/val_ne.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/types.rs b/src/types.rs new file mode 100644 index 0000000..0b9b25e --- /dev/null +++ b/src/types.rs @@ -0,0 +1,6 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Endianess { + Little, + Big, + Native, +} diff --git a/tests/read.rs b/tests/read.rs index fdbddcd..c2762f0 100644 --- a/tests/read.rs +++ b/tests/read.rs @@ -1,4 +1,4 @@ -use dh::{ReadVal, Result}; +use dh::{Endianess, ReadVal, Result}; use std::io::{Cursor, Read}; #[test] @@ -74,11 +74,11 @@ fn read_u16_le() { let data = [0x12u8, 0x34, 0x56, 0x78]; let mut cursor = Cursor::new(data); - assert_eq!(cursor.read_u16_le().unwrap(), 0x3412); - assert_eq!(cursor.read_u16_le().unwrap(), 0x7856); + assert_eq!(cursor.read_u16(Endianess::Little).unwrap(), 0x3412); + assert_eq!(cursor.read_u16(Endianess::Little).unwrap(), 0x7856); // overflow - let val = cursor.read_u16_le(); + let val = cursor.read_u16(Endianess::Little); assert!(val.is_err()); } @@ -240,3 +240,29 @@ fn read_u128_le() { let val = cursor.read_u128_le(); assert!(val.is_err()); } + +#[test] +fn read_vec() { + let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut cursor = Cursor::new(data); + + let val: Vec = cursor.read_vec(4).unwrap(); + assert_eq!(val, vec![0, 1, 2, 3]); + + // overflow + let val: Result> = cursor.read_vec(10); + assert!(val.is_err()); +} + +#[test] +fn read_str() { + let data = [0x41u8, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]; + let mut cursor = Cursor::new(data); + + let val: String = cursor.read_str(4).unwrap(); + assert_eq!(val, String::from("ABCD")); + + // overflow + let val: Result = cursor.read_str(10); + assert!(val.is_err()); +} From fe6dc8bba0a9ef523c7c64fe53241f5b2fb8f553 Mon Sep 17 00:00:00 2001 From: Le0X8 <84378319+Le0X8@users.noreply.github.com> Date: Thu, 17 Apr 2025 13:15:54 +0200 Subject: [PATCH 3/7] feat: added endian-specific traits --- src/lib.rs | 2 +- src/read.rs | 4 + src/read/auto_impl.rs | 40 ++++++++++ src/read/val.rs | 41 ++-------- src/read/val_be.rs | 50 ++++++++++++ src/read/val_le.rs | 50 ++++++++++++ src/read/val_ne.rs | 50 ++++++++++++ tests/read_be.rs | 120 +++++++++++++++++++++++++++++ tests/read_le.rs | 142 ++++++++++++++++++++++++++++++++++ tests/read_ne.rs | 174 ++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 639 insertions(+), 34 deletions(-) create mode 100644 src/read/auto_impl.rs create mode 100644 src/read/val_be.rs create mode 100644 src/read/val_le.rs create mode 100644 tests/read_be.rs create mode 100644 tests/read_le.rs create mode 100644 tests/read_ne.rs diff --git a/src/lib.rs b/src/lib.rs index c0730ad..d86d629 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,5 +7,5 @@ mod types; pub use dynamic::Dynamic; pub use error::{Error, Result}; pub use primitive::Primitive; -pub use read::val::ReadVal; +pub use read::{val::ReadVal, val_be::ReadValBe, val_le::ReadValLe, val_ne::ReadValNe}; pub use types::*; diff --git a/src/read.rs b/src/read.rs index 2dd4f80..d4a030f 100644 --- a/src/read.rs +++ b/src/read.rs @@ -1 +1,5 @@ +pub(crate) mod auto_impl; pub(crate) mod val; +pub(crate) mod val_be; +pub(crate) mod val_le; +pub(crate) mod val_ne; diff --git a/src/read/auto_impl.rs b/src/read/auto_impl.rs new file mode 100644 index 0000000..feb217a --- /dev/null +++ b/src/read/auto_impl.rs @@ -0,0 +1,40 @@ +macro_rules! auto_impl { + () => { + read_primitive_typed!(read_u8, u8, read_ne); + + read_primitive_typed!(read_u16, u16); + read_primitive_typed!(read_u32, u32); + read_primitive_typed!(read_u64, u64); + read_primitive_typed!(read_u128, u128); + read_primitive_typed!(read_usize, usize); + + read_primitive_typed!(read_i8, i8, read_ne); + + read_primitive_typed!(read_i16, i16); + read_primitive_typed!(read_i32, i32); + read_primitive_typed!(read_i64, i64); + read_primitive_typed!(read_i128, i128); + read_primitive_typed!(read_isize, isize); + + read_primitive_typed!(read_f32, f32); + read_primitive_typed!(read_f64, f64); + + read_primitive_typed!(read_u8_array, [u8; S], read_ne, S); + + read_primitive_typed!(read_bool, bool, read_ne); + + /// Reads a dynamic value from the reader. + /// + /// It's recommended to use the typed wrappers like `read_vec` instead of this method for cleaner code. + fn read_dynamic(&mut self, len: usize) -> Result { + let mut buf = vec![0; len]; + self.read_exact(&mut buf)?; + T::from_bytes(buf) + } + + read_dynamic_typed!(read_vec, Vec); + read_dynamic_typed!(read_str, String); + }; +} + +pub(super) use auto_impl; diff --git a/src/read/val.rs b/src/read/val.rs index f789bb4..d167144 100644 --- a/src/read/val.rs +++ b/src/read/val.rs @@ -1,4 +1,5 @@ -use crate::{Dynamic, Endianess, Primitive, Result}; +use super::auto_impl::auto_impl; +use crate::{Endianess, Primitive, Result}; use std::io::Read; macro_rules! read_primitive { @@ -51,93 +52,67 @@ macro_rules! read_dynamic_typed { }; } +pub(super) use read_dynamic_typed; +pub(super) use read_primitive; +pub(super) use read_primitive_typed; + /// Extension trait for `Read` that provides methods for reading supported value types. /// /// **Note:** do not borrow this as `&mut dyn ReadVal`, as this would not compile. Use `&mut dyn Read` instead. pub trait ReadVal: Read { + auto_impl!(); + read_primitive!(read_ne, from_ne_bytes); read_primitive!(read_le, from_le_bytes); read_primitive!(read_be, from_be_bytes); - read_primitive_typed!(read_u8, u8, read_ne); - - read_primitive_typed!(read_u16, u16); read_primitive_typed!(read_u16_ne, u16, read_ne); read_primitive_typed!(read_u16_le, u16, read_le); read_primitive_typed!(read_u16_be, u16, read_be); - read_primitive_typed!(read_u32, u32); read_primitive_typed!(read_u32_ne, u32, read_ne); read_primitive_typed!(read_u32_le, u32, read_le); read_primitive_typed!(read_u32_be, u32, read_be); - read_primitive_typed!(read_u64, u64); read_primitive_typed!(read_u64_ne, u64, read_ne); read_primitive_typed!(read_u64_le, u64, read_le); read_primitive_typed!(read_u64_be, u64, read_be); - read_primitive_typed!(read_u128, u128); read_primitive_typed!(read_u128_ne, u128, read_ne); read_primitive_typed!(read_u128_le, u128, read_le); read_primitive_typed!(read_u128_be, u128, read_be); - read_primitive_typed!(read_usize, usize); read_primitive_typed!(read_usize_ne, usize, read_ne); read_primitive_typed!(read_usize_le, usize, read_le); read_primitive_typed!(read_usize_be, usize, read_be); - read_primitive_typed!(read_i8, i8, read_ne); - - read_primitive_typed!(read_i16, i16); read_primitive_typed!(read_i16_ne, i16, read_ne); read_primitive_typed!(read_i16_le, i16, read_le); read_primitive_typed!(read_i16_be, i16, read_be); - read_primitive_typed!(read_i32, i32); read_primitive_typed!(read_i32_ne, i32, read_ne); read_primitive_typed!(read_i32_le, i32, read_le); read_primitive_typed!(read_i32_be, i32, read_be); - read_primitive_typed!(read_i64, i64); read_primitive_typed!(read_i64_ne, i64, read_ne); read_primitive_typed!(read_i64_le, i64, read_le); read_primitive_typed!(read_i64_be, i64, read_be); - read_primitive_typed!(read_i128, i128); read_primitive_typed!(read_i128_ne, i128, read_ne); read_primitive_typed!(read_i128_le, i128, read_le); read_primitive_typed!(read_i128_be, i128, read_be); - read_primitive_typed!(read_isize, isize); read_primitive_typed!(read_isize_ne, isize, read_ne); read_primitive_typed!(read_isize_le, isize, read_le); read_primitive_typed!(read_isize_be, isize, read_be); - read_primitive_typed!(read_f32, f32); read_primitive_typed!(read_f32_ne, f32, read_ne); read_primitive_typed!(read_f32_le, f32, read_le); read_primitive_typed!(read_f32_be, f32, read_be); - read_primitive_typed!(read_f64, f64); read_primitive_typed!(read_f64_ne, f64, read_ne); read_primitive_typed!(read_f64_le, f64, read_le); read_primitive_typed!(read_f64_be, f64, read_be); - - read_primitive_typed!(read_u8_array, [u8; S], read_ne, S); - - read_primitive_typed!(read_bool, bool, read_ne); - - /// Reads a dynamic value from the reader. - /// - /// It's recommended to use the typed wrappers like `read_vec` instead of this method for cleaner code. - fn read_dynamic(&mut self, len: usize) -> Result { - let mut buf = vec![0; len]; - self.read_exact(&mut buf)?; - T::from_bytes(buf) - } - - read_dynamic_typed!(read_vec, Vec); - read_dynamic_typed!(read_str, String); } impl ReadVal for T {} diff --git a/src/read/val_be.rs b/src/read/val_be.rs new file mode 100644 index 0000000..02723d3 --- /dev/null +++ b/src/read/val_be.rs @@ -0,0 +1,50 @@ +use super::{auto_impl::auto_impl, val::read_dynamic_typed}; +use crate::{Primitive, Result}; +use std::io::Read; + +macro_rules! read_primitive { + ($fn_name:ident) => { + /// Reads a primitive value from the reader using the specified byte order. + /// + /// It's recommended to use the typed wrappers like `read_u8` instead of this method for cleaner code. + fn $fn_name, U, const S: usize>(&mut self) -> Result { + let mut buf = [0; S]; + self.read_exact(&mut buf)?; + Ok(T::from_be_bytes(buf)) + } + }; +} + +macro_rules! read_primitive_typed { + ($fn_name:ident, $return_type:ty, $_:ident) => { + /// Typed wrapper around `read_be`. + fn $fn_name(&mut self) -> Result<$return_type> { + self.read_be() + } + }; + + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `read_be`. + fn $fn_name(&mut self) -> Result<$return_type> { + self.read_be() + } + }; + + ($fn_name:ident, $return_type:ty, $_:ident, $const:ident) => { + /// Typed wrapper around `read_be`. + fn $fn_name(&mut self) -> Result<$return_type> { + self.read_be::<$return_type, $return_type, $const>() + } + }; +} + +/// Extension trait for `Read` that provides methods for reading supported value types in big endian order. +/// +/// **Note:** do not borrow this as `&mut dyn ReadValBe`, as this would not compile. Use `&mut dyn Read` instead. +pub trait ReadValBe: Read { + auto_impl!(); + + read_primitive!(read_be); +} + +impl ReadValBe for T {} diff --git a/src/read/val_le.rs b/src/read/val_le.rs new file mode 100644 index 0000000..ea85530 --- /dev/null +++ b/src/read/val_le.rs @@ -0,0 +1,50 @@ +use super::{auto_impl::auto_impl, val::read_dynamic_typed}; +use crate::{Primitive, Result}; +use std::io::Read; + +macro_rules! read_primitive { + ($fn_name:ident) => { + /// Reads a primitive value from the reader using the specified byte order. + /// + /// It's recommended to use the typed wrappers like `read_u8` instead of this method for cleaner code. + fn $fn_name, U, const S: usize>(&mut self) -> Result { + let mut buf = [0; S]; + self.read_exact(&mut buf)?; + Ok(T::from_le_bytes(buf)) + } + }; +} + +macro_rules! read_primitive_typed { + ($fn_name:ident, $return_type:ty, $_:ident) => { + /// Typed wrapper around `read_le`. + fn $fn_name(&mut self) -> Result<$return_type> { + self.read_le() + } + }; + + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `read_le`. + fn $fn_name(&mut self) -> Result<$return_type> { + self.read_le() + } + }; + + ($fn_name:ident, $return_type:ty, $_:ident, $const:ident) => { + /// Typed wrapper around `read_le`. + fn $fn_name(&mut self) -> Result<$return_type> { + self.read_le::<$return_type, $return_type, $const>() + } + }; +} + +/// Extension trait for `Read` that provides methods for reading supported value types in little endian order. +/// +/// **Note:** do not borrow this as `&mut dyn ReadValLe`, as this would not compile. Use `&mut dyn Read` instead. +pub trait ReadValLe: Read { + auto_impl!(); + + read_primitive!(read_le); +} + +impl ReadValLe for T {} diff --git a/src/read/val_ne.rs b/src/read/val_ne.rs index e69de29..15a2785 100644 --- a/src/read/val_ne.rs +++ b/src/read/val_ne.rs @@ -0,0 +1,50 @@ +use super::{auto_impl::auto_impl, val::read_dynamic_typed}; +use crate::{Primitive, Result}; +use std::io::Read; + +macro_rules! read_primitive { + ($fn_name:ident) => { + /// Reads a primitive value from the reader using the specified byte order. + /// + /// It's recommended to use the typed wrappers like `read_u8` instead of this method for cleaner code. + fn $fn_name, U, const S: usize>(&mut self) -> Result { + let mut buf = [0; S]; + self.read_exact(&mut buf)?; + Ok(T::from_ne_bytes(buf)) + } + }; +} + +macro_rules! read_primitive_typed { + ($fn_name:ident, $return_type:ty, $_:ident) => { + /// Typed wrapper around `read_ne`. + fn $fn_name(&mut self) -> Result<$return_type> { + self.read_ne() + } + }; + + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `read_ne`. + fn $fn_name(&mut self) -> Result<$return_type> { + self.read_ne() + } + }; + + ($fn_name:ident, $return_type:ty, $_:ident, $const:ident) => { + /// Typed wrapper around `read_ne`. + fn $fn_name(&mut self) -> Result<$return_type> { + self.read_ne::<$return_type, $return_type, $const>() + } + }; +} + +/// Extension trait for `Read` that provides methods for reading supported value types in native endian order. +/// +/// **Note:** do not borrow this as `&mut dyn ReadValNe`, as this would not compile. Use `&mut dyn Read` instead. +pub trait ReadValNe: Read { + auto_impl!(); + + read_primitive!(read_ne); +} + +impl ReadValNe for T {} diff --git a/tests/read_be.rs b/tests/read_be.rs new file mode 100644 index 0000000..0ae4625 --- /dev/null +++ b/tests/read_be.rs @@ -0,0 +1,120 @@ +use dh::{ReadValBe, Result}; +use std::io::{Cursor, Read}; + +#[test] +fn read_borrowing() { + let data = [0u8, 1, 2, 3]; + let mut cursor = Cursor::new(data); + + // this just needs to compile + let mut borrowed: &mut dyn Read = &mut cursor; + assert_eq!(borrowed.read_u8().unwrap(), 0); + assert_eq!(borrowed.read_u8().unwrap(), 1); + assert_eq!(cursor.read_u8().unwrap(), 2); + assert_eq!(cursor.read_u8().unwrap(), 3); +} + +#[test] +fn read_primitive() { + let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut cursor = Cursor::new(data); + + let val: u8 = cursor.read_be().unwrap(); + assert_eq!(val, 0); + + let val: [u8; 3] = cursor.read_be().unwrap(); + assert_eq!(val, [1, 2, 3]); + + let val: u16 = cursor.read_be().unwrap(); + assert_eq!(val, 0x04_05); + + let val: u16 = cursor.read_be().unwrap(); + assert_eq!(val, 0x06_07); + + // overflow + let val: Result = cursor.read_be(); + assert!(val.is_err()); +} + +#[test] +fn read_u8() { + let data = [0u8, 1, 2, 3]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u8().unwrap(), 0); + assert_eq!(cursor.read_u8().unwrap(), 1); + assert_eq!(cursor.read_u8().unwrap(), 2); + assert_eq!(cursor.read_u8().unwrap(), 3); + + // overflow + let val = cursor.read_u8(); + assert!(val.is_err()); +} + +#[test] +fn read_u16_be() { + let data = [0x12u8, 0x34, 0x56, 0x78]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u16().unwrap(), 0x1234); + assert_eq!(cursor.read_u16().unwrap(), 0x5678); + + // overflow + let val = cursor.read_u16(); + assert!(val.is_err()); +} + +#[test] +fn read_u32_be() { + let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u32().unwrap(), 0x12345678); + assert_eq!(cursor.read_u32().unwrap(), 0x9ABCDEF0); + + // overflow + let val = cursor.read_u32(); + assert!(val.is_err()); +} + +#[test] +fn read_u64_be() { + let data = [ + 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, + 0xEF, + ]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u64().unwrap(), 0x123456789ABCDEF0); + assert_eq!(cursor.read_u64().unwrap(), 0x0123456789ABCDEF); + + // overflow + let val = cursor.read_u64(); + assert!(val.is_err()); +} + +#[test] +fn read_vec() { + let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut cursor = Cursor::new(data); + + let val: Vec = cursor.read_vec(4).unwrap(); + assert_eq!(val, vec![0, 1, 2, 3]); + + // overflow + let val: Result> = cursor.read_vec(10); + assert!(val.is_err()); +} + +#[test] +fn read_str() { + let data = [0x41u8, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]; + let mut cursor = Cursor::new(data); + + let val: String = cursor.read_str(4).unwrap(); + assert_eq!(val, String::from("ABCD")); + + // overflow + let val: Result = cursor.read_str(10); + assert!(val.is_err()); +} diff --git a/tests/read_le.rs b/tests/read_le.rs new file mode 100644 index 0000000..0576ee0 --- /dev/null +++ b/tests/read_le.rs @@ -0,0 +1,142 @@ +use dh::{ReadValLe, Result}; +use std::io::{Cursor, Read}; + +#[test] +fn read_borrowing() { + let data = [0u8, 1, 2, 3]; + let mut cursor = Cursor::new(data); + + // this just needs to compile + let mut borrowed: &mut dyn Read = &mut cursor; + assert_eq!(borrowed.read_u8().unwrap(), 0); + assert_eq!(borrowed.read_u8().unwrap(), 1); + assert_eq!(cursor.read_u8().unwrap(), 2); + assert_eq!(cursor.read_u8().unwrap(), 3); +} + +#[test] +fn read_primitive() { + let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut cursor = Cursor::new(data); + + let val: u8 = cursor.read_le().unwrap(); + assert_eq!(val, 0); + + let val: [u8; 3] = cursor.read_le().unwrap(); + assert_eq!(val, [1, 2, 3]); + + let val: u16 = cursor.read_le().unwrap(); + assert_eq!(val, 0x05_04); + + let val: u16 = cursor.read_le().unwrap(); + assert_eq!(val, 0x07_06); + + // overflow + let val: Result = cursor.read_le(); + assert!(val.is_err()); +} + +#[test] +fn read_u8() { + let data = [0u8, 1, 2, 3]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u8().unwrap(), 0); + assert_eq!(cursor.read_u8().unwrap(), 1); + assert_eq!(cursor.read_u8().unwrap(), 2); + assert_eq!(cursor.read_u8().unwrap(), 3); + + // overflow + let val = cursor.read_u8(); + assert!(val.is_err()); +} + +#[test] +fn read_u16_le() { + let data = [0x12u8, 0x34, 0x56, 0x78]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u16().unwrap(), 0x3412); + assert_eq!(cursor.read_u16().unwrap(), 0x7856); + + // overflow + let val = cursor.read_u16(); + assert!(val.is_err()); +} + +#[test] +fn read_u32_le() { + let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u32().unwrap(), 0x78563412); + assert_eq!(cursor.read_u32().unwrap(), 0xF0DEBC9A); + + // overflow + let val = cursor.read_u32(); + assert!(val.is_err()); +} + +#[test] +fn read_u64_le() { + let data = [ + 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, + 0xEF, + ]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u64().unwrap(), 0xF0DEBC9A78563412); + assert_eq!(cursor.read_u64().unwrap(), 0xEFCDAB8967452301); + + // overflow + let val = cursor.read_u64(); + assert!(val.is_err()); +} + +#[test] +fn read_u128_le() { + let data = [ + 1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ]; + let mut cursor = Cursor::new(data); + + assert_eq!( + cursor.read_u128().unwrap(), + 0x00000000000000000000000000000001 + ); + assert_eq!( + cursor.read_u128().unwrap(), + 0x00000000000000000000000000000001 + ); + + // overflow + let val = cursor.read_u128(); + assert!(val.is_err()); +} + +#[test] +fn read_vec() { + let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut cursor = Cursor::new(data); + + let val: Vec = cursor.read_vec(4).unwrap(); + assert_eq!(val, vec![0, 1, 2, 3]); + + // overflow + let val: Result> = cursor.read_vec(10); + assert!(val.is_err()); +} + +#[test] +fn read_str() { + let data = [0x41u8, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]; + let mut cursor = Cursor::new(data); + + let val: String = cursor.read_str(4).unwrap(); + assert_eq!(val, String::from("ABCD")); + + // overflow + let val: Result = cursor.read_str(10); + assert!(val.is_err()); +} diff --git a/tests/read_ne.rs b/tests/read_ne.rs new file mode 100644 index 0000000..5ae0be6 --- /dev/null +++ b/tests/read_ne.rs @@ -0,0 +1,174 @@ +use dh::{ReadValNe, Result}; +use std::io::{Cursor, Read}; + +#[test] +fn read_borrowing() { + let data = [0u8, 1, 2, 3]; + let mut cursor = Cursor::new(data); + + // this just needs to compile + let mut borrowed: &mut dyn Read = &mut cursor; + assert_eq!(borrowed.read_u8().unwrap(), 0); + assert_eq!(borrowed.read_u8().unwrap(), 1); + assert_eq!(cursor.read_u8().unwrap(), 2); + assert_eq!(cursor.read_u8().unwrap(), 3); +} + +#[test] +fn read_primitive() { + let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut cursor = Cursor::new(data); + + let val: u8 = cursor.read_ne().unwrap(); + assert_eq!(val, 0); + + let val: [u8; 3] = cursor.read_ne().unwrap(); + assert_eq!(val, [1, 2, 3]); + + let val: u16 = cursor.read_ne().unwrap(); + assert_eq!( + val, + match cfg!(target_endian = "big") { + true => 0x04_05, + false => 0x05_04, + } + ); + + let val: u16 = cursor.read_ne().unwrap(); + assert_eq!( + val, + match cfg!(target_endian = "big") { + true => 0x06_07, + false => 0x07_06, + } + ); + + // overflow + let val: Result = cursor.read_ne(); + assert!(val.is_err()); +} + +#[test] +fn read_u8() { + let data = [0u8, 1, 2, 3]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u8().unwrap(), 0); + assert_eq!(cursor.read_u8().unwrap(), 1); + assert_eq!(cursor.read_u8().unwrap(), 2); + assert_eq!(cursor.read_u8().unwrap(), 3); + + // overflow + let val = cursor.read_u8(); + assert!(val.is_err()); +} + +#[test] +fn read_u16_ne() { + let data = [0x12u8, 0x34, 0x56, 0x78]; + let mut cursor = Cursor::new(data); + + let parts = match cfg!(target_endian = "big") { + true => (0x1234, 0x5678), + false => (0x3412, 0x7856), + }; + + assert_eq!(cursor.read_u16().unwrap(), parts.0); + assert_eq!(cursor.read_u16().unwrap(), parts.1); + + // overflow + let val = cursor.read_u16(); + assert!(val.is_err()); +} + +#[test] +fn read_u32_ne() { + let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; + let mut cursor = Cursor::new(data); + + let parts = match cfg!(target_endian = "big") { + true => (0x12345678, 0x9ABCDEF0), + false => (0x78563412, 0xF0DEBC9A), + }; + + assert_eq!(cursor.read_u32().unwrap(), parts.0); + assert_eq!(cursor.read_u32().unwrap(), parts.1); + + // overflow + let val = cursor.read_u32(); + assert!(val.is_err()); +} + +#[test] +fn read_u64_ne() { + let data = [ + 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, + 0xEF, + ]; + let mut cursor = Cursor::new(data); + + let parts = match cfg!(target_endian = "big") { + true => (0x123456789ABCDEF0, 0x0123456789ABCDEF), + false => (0xF0DEBC9A78563412, 0xEFCDAB8967452301), + }; + + assert_eq!(cursor.read_u64().unwrap(), parts.0); + assert_eq!(cursor.read_u64().unwrap(), parts.1); + + // overflow + let val = cursor.read_u64(); + assert!(val.is_err()); +} + +#[test] +fn read_u128_ne() { + let data = [ + 1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ]; + let mut cursor = Cursor::new(data); + + let parts = match cfg!(target_endian = "big") { + true => ( + 0x01000000000000000000000000000000, + 0x01000000000000000000000000000000, + ), + false => ( + 0x00000000000000000000000000000001, + 0x00000000000000000000000000000001, + ), + }; + + assert_eq!(cursor.read_u128().unwrap(), parts.0); + assert_eq!(cursor.read_u128().unwrap(), parts.1); + + // overflow + let val = cursor.read_u128(); + assert!(val.is_err()); +} + +#[test] +fn read_vec() { + let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut cursor = Cursor::new(data); + + let val: Vec = cursor.read_vec(4).unwrap(); + assert_eq!(val, vec![0, 1, 2, 3]); + + // overflow + let val: Result> = cursor.read_vec(10); + assert!(val.is_err()); +} + +#[test] +fn read_str() { + let data = [0x41u8, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]; + let mut cursor = Cursor::new(data); + + let val: String = cursor.read_str(4).unwrap(); + assert_eq!(val, String::from("ABCD")); + + // overflow + let val: Result = cursor.read_str(10); + assert!(val.is_err()); +} From 64a1ca338026f17c203cbe60369b1e3f56543e68 Mon Sep 17 00:00:00 2001 From: Le0X8 <84378319+Le0X8@users.noreply.github.com> Date: Thu, 17 Apr 2025 21:12:20 +0200 Subject: [PATCH 4/7] feat: added "force" reader variants --- Cargo.lock | 2 +- Cargo.toml | 8 +- src/lib.rs | 6 +- src/read.rs | 4 + src/read/auto_impl.rs | 72 +++++++++++++- src/read/force.rs | 76 +++++++++++++++ src/read/force_be.rs | 68 +++++++++++++ src/read/force_le.rs | 68 +++++++++++++ src/read/force_ne.rs | 68 +++++++++++++ src/read/val.rs | 55 +---------- src/read/val_be.rs | 5 +- src/read/val_le.rs | 5 +- src/read/val_ne.rs | 5 +- tests/read.rs | 2 +- tests/read_be.rs | 2 +- tests/read_force.rs | 217 +++++++++++++++++++++++++++++++++++++++++ tests/read_force_be.rs | 1 + tests/read_force_le.rs | 119 ++++++++++++++++++++++ tests/read_force_ne.rs | 1 + tests/read_le.rs | 2 +- tests/read_ne.rs | 2 +- 21 files changed, 718 insertions(+), 70 deletions(-) create mode 100644 src/read/force.rs create mode 100644 src/read/force_be.rs create mode 100644 src/read/force_le.rs create mode 100644 src/read/force_ne.rs create mode 100644 tests/read_force.rs create mode 100644 tests/read_force_be.rs create mode 100644 tests/read_force_le.rs create mode 100644 tests/read_force_ne.rs diff --git a/Cargo.lock b/Cargo.lock index d1a7ee5..a4e0ab4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,4 +4,4 @@ version = 4 [[package]] name = "dh" -version = "0.8.1" +version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index 6ede54b..a62be25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "dh" -version = "0.8.1" -edition = "2021" +version = "0.9.0" +edition = "2024" description = "Data handling in Rust, made easy." license = "MIT" repository = "https://github.com/Le0X8/dh" documentation = "https://docs.rs/dh" authors = [ "Leonard Lesinski <84378319+Le0X8@users.noreply.github.com>" ] readme = "README.md" -keywords = [ "data", "files", "read", "write", "rw" ] -categories = [ "data-structures", "encoding", "filesystem", "parsing" ] +keywords = [ "data", "read", "write", "rw" ] +categories = [ "data-structures", "encoding", "parsing" ] diff --git a/src/lib.rs b/src/lib.rs index d86d629..a9978f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,5 +7,9 @@ mod types; pub use dynamic::Dynamic; pub use error::{Error, Result}; pub use primitive::Primitive; -pub use read::{val::ReadVal, val_be::ReadValBe, val_le::ReadValLe, val_ne::ReadValNe}; +pub use read::{ + force::ForceReadVal, force_be::ForceReadValBe, force_le::ForceReadValLe, + force_ne::ForceReadValNe, val::ReadVal, val_be::ReadValBe, val_le::ReadValLe, + val_ne::ReadValNe, +}; pub use types::*; diff --git a/src/read.rs b/src/read.rs index d4a030f..4918183 100644 --- a/src/read.rs +++ b/src/read.rs @@ -1,4 +1,8 @@ pub(crate) mod auto_impl; +pub(crate) mod force; +pub(crate) mod force_be; +pub(crate) mod force_le; +pub(crate) mod force_ne; pub(crate) mod val; pub(crate) mod val_be; pub(crate) mod val_le; diff --git a/src/read/auto_impl.rs b/src/read/auto_impl.rs index feb217a..6da8e43 100644 --- a/src/read/auto_impl.rs +++ b/src/read/auto_impl.rs @@ -1,4 +1,4 @@ -macro_rules! auto_impl { +macro_rules! auto_impl_nofns { () => { read_primitive_typed!(read_u8, u8, read_ne); @@ -23,6 +23,71 @@ macro_rules! auto_impl { read_primitive_typed!(read_bool, bool, read_ne); + read_dynamic_typed!(read_vec, Vec); + read_dynamic_typed!(read_str, String); + }; +} + +macro_rules! auto_impl_all { + () => { + read_primitive!(read_ne, from_ne_bytes); + read_primitive!(read_le, from_le_bytes); + read_primitive!(read_be, from_be_bytes); + + read_primitive_typed!(read_u16_ne, u16, read_ne); + read_primitive_typed!(read_u16_le, u16, read_le); + read_primitive_typed!(read_u16_be, u16, read_be); + + read_primitive_typed!(read_u32_ne, u32, read_ne); + read_primitive_typed!(read_u32_le, u32, read_le); + read_primitive_typed!(read_u32_be, u32, read_be); + + read_primitive_typed!(read_u64_ne, u64, read_ne); + read_primitive_typed!(read_u64_le, u64, read_le); + read_primitive_typed!(read_u64_be, u64, read_be); + + read_primitive_typed!(read_u128_ne, u128, read_ne); + read_primitive_typed!(read_u128_le, u128, read_le); + read_primitive_typed!(read_u128_be, u128, read_be); + + read_primitive_typed!(read_usize_ne, usize, read_ne); + read_primitive_typed!(read_usize_le, usize, read_le); + read_primitive_typed!(read_usize_be, usize, read_be); + + read_primitive_typed!(read_i16_ne, i16, read_ne); + read_primitive_typed!(read_i16_le, i16, read_le); + read_primitive_typed!(read_i16_be, i16, read_be); + + read_primitive_typed!(read_i32_ne, i32, read_ne); + read_primitive_typed!(read_i32_le, i32, read_le); + read_primitive_typed!(read_i32_be, i32, read_be); + + read_primitive_typed!(read_i64_ne, i64, read_ne); + read_primitive_typed!(read_i64_le, i64, read_le); + read_primitive_typed!(read_i64_be, i64, read_be); + + read_primitive_typed!(read_i128_ne, i128, read_ne); + read_primitive_typed!(read_i128_le, i128, read_le); + read_primitive_typed!(read_i128_be, i128, read_be); + + read_primitive_typed!(read_isize_ne, isize, read_ne); + read_primitive_typed!(read_isize_le, isize, read_le); + read_primitive_typed!(read_isize_be, isize, read_be); + + read_primitive_typed!(read_f32_ne, f32, read_ne); + read_primitive_typed!(read_f32_le, f32, read_le); + read_primitive_typed!(read_f32_be, f32, read_be); + + read_primitive_typed!(read_f64_ne, f64, read_ne); + read_primitive_typed!(read_f64_le, f64, read_le); + read_primitive_typed!(read_f64_be, f64, read_be); + }; +} + +macro_rules! auto_impl { + () => { + auto_impl_nofns!(); + /// Reads a dynamic value from the reader. /// /// It's recommended to use the typed wrappers like `read_vec` instead of this method for cleaner code. @@ -31,10 +96,9 @@ macro_rules! auto_impl { self.read_exact(&mut buf)?; T::from_bytes(buf) } - - read_dynamic_typed!(read_vec, Vec); - read_dynamic_typed!(read_str, String); }; } pub(super) use auto_impl; +pub(super) use auto_impl_all; +pub(super) use auto_impl_nofns; diff --git a/src/read/force.rs b/src/read/force.rs new file mode 100644 index 0000000..c8a8683 --- /dev/null +++ b/src/read/force.rs @@ -0,0 +1,76 @@ +use super::auto_impl::{auto_impl_all, auto_impl_nofns}; +use crate::{Dynamic, Endianess, Primitive}; +use std::io::Read; + +macro_rules! read_primitive { + ($fn_name:ident, $read_fn_name:ident) => { + /// Reads a primitive value from the reader using the specified byte order. + /// + /// It's recommended to use the typed wrappers like `read_u8` instead of this method for cleaner code. + fn $fn_name, U, const S: usize>(&mut self) -> T { + let mut buf = [0; S]; + self.read_exact(&mut buf).unwrap(); + T::$read_fn_name(buf) + } + }; +} + +macro_rules! read_primitive_typed { + ($fn_name:ident, $return_type:ty, $read_fn:ident) => { + /// Typed wrapper around `read_ne`, `read_le`, or `read_be`. + fn $fn_name(&mut self) -> $return_type { + self.$read_fn() + } + }; + + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `read_ne`, `read_le`, or `read_be`. + fn $fn_name(&mut self, endianess: Endianess) -> $return_type { + use Endianess::*; + match endianess { + Little => self.read_le(), + Big => self.read_be(), + Native => self.read_ne(), + } + } + }; + + ($fn_name:ident, $return_type:ty, $read_fn:ident, $const:ident) => { + /// Typed wrapper around `read_ne`, `read_le`, or `read_be`. + fn $fn_name(&mut self) -> $return_type { + self.$read_fn::<$return_type, $return_type, $const>() + } + }; +} + +macro_rules! read_dynamic_typed { + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `read_dynamic`. + fn $fn_name(&mut self, len: usize) -> $return_type { + self.read_dynamic(len) + } + }; +} + +pub(super) use read_dynamic_typed; +pub(super) use read_primitive; +pub(super) use read_primitive_typed; + +/// Extension trait for `Read` that provides methods for reading supported value types without the `Result` return type, triggering a panic on error. +/// +/// **Note:** do not borrow this as `&mut dyn ForceReadVal`, as this would not compile. Use `&mut dyn Read` instead. +pub trait ForceReadVal: Read { + auto_impl_nofns!(); + auto_impl_all!(); + + /// Reads a dynamic value from the reader. + /// + /// It's recommended to use the typed wrappers like `read_vec` instead of this method for cleaner code. + fn read_dynamic(&mut self, len: usize) -> T { + let mut buf = vec![0; len]; + self.read_exact(&mut buf).unwrap(); + T::from_bytes(buf).unwrap() + } +} + +impl ForceReadVal for T {} diff --git a/src/read/force_be.rs b/src/read/force_be.rs new file mode 100644 index 0000000..8e7b7e3 --- /dev/null +++ b/src/read/force_be.rs @@ -0,0 +1,68 @@ +use super::auto_impl::auto_impl_nofns; +use crate::{Dynamic, Primitive}; +use std::io::Read; + +macro_rules! read_primitive { + ($fn_name:ident) => { + /// Reads a primitive value from the reader using the specified byte order. + /// + /// It's recommended to use the typed wrappers like `read_u8` instead of this method for cleaner code. + fn $fn_name, U, const S: usize>(&mut self) -> T { + let mut buf = [0; S]; + self.read_exact(&mut buf).unwrap(); + T::from_be_bytes(buf) + } + }; +} + +macro_rules! read_primitive_typed { + ($fn_name:ident, $return_type:ty, $_:ident) => { + /// Typed wrapper around `read_be`. + fn $fn_name(&mut self) -> $return_type { + self.read_be() + } + }; + + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `read_be`. + fn $fn_name(&mut self) -> $return_type { + self.read_be() + } + }; + + ($fn_name:ident, $return_type:ty, $_:ident, $const:ident) => { + /// Typed wrapper around `read_be`. + fn $fn_name(&mut self) -> $return_type { + self.read_be::<$return_type, $return_type, $const>() + } + }; +} + +macro_rules! read_dynamic_typed { + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `read_dynamic`. + fn $fn_name(&mut self, len: usize) -> $return_type { + self.read_dynamic(len) + } + }; +} + +/// Extension trait for `Read` that provides methods for reading supported value types in big endian order without the `Result` return type, triggering a panic on error. +/// +/// **Note:** do not borrow this as `&mut dyn ForceReadValBe`, as this would not compile. Use `&mut dyn Read` instead. +pub trait ForceReadValBe: Read { + auto_impl_nofns!(); + + read_primitive!(read_be); + + /// Reads a dynamic value from the reader. + /// + /// It's recommended to use the typed wrappers like `read_vec` instead of this method for cleaner code. + fn read_dynamic(&mut self, len: usize) -> T { + let mut buf = vec![0; len]; + self.read_exact(&mut buf).unwrap(); + T::from_bytes(buf).unwrap() + } +} + +impl ForceReadValBe for T {} diff --git a/src/read/force_le.rs b/src/read/force_le.rs new file mode 100644 index 0000000..5535156 --- /dev/null +++ b/src/read/force_le.rs @@ -0,0 +1,68 @@ +use super::auto_impl::auto_impl_nofns; +use crate::{Dynamic, Primitive}; +use std::io::Read; + +macro_rules! read_primitive { + ($fn_name:ident) => { + /// Reads a primitive value from the reader using the specified byte order. + /// + /// It's recommended to use the typed wrappers like `read_u8` instead of this method for cleaner code. + fn $fn_name, U, const S: usize>(&mut self) -> T { + let mut buf = [0; S]; + self.read_exact(&mut buf).unwrap(); + T::from_le_bytes(buf) + } + }; +} + +macro_rules! read_primitive_typed { + ($fn_name:ident, $return_type:ty, $_:ident) => { + /// Typed wrapper around `read_le`. + fn $fn_name(&mut self) -> $return_type { + self.read_le() + } + }; + + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `read_le`. + fn $fn_name(&mut self) -> $return_type { + self.read_le() + } + }; + + ($fn_name:ident, $return_type:ty, $_:ident, $const:ident) => { + /// Typed wrapper around `read_le`. + fn $fn_name(&mut self) -> $return_type { + self.read_le::<$return_type, $return_type, $const>() + } + }; +} + +macro_rules! read_dynamic_typed { + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `read_dynamic`. + fn $fn_name(&mut self, len: usize) -> $return_type { + self.read_dynamic(len) + } + }; +} + +/// Extension trait for `Read` that provides methods for reading supported value types in little endian order without the `Result` return type, triggering a panic on error. +/// +/// **Note:** do not borrow this as `&mut dyn ForceReadValLe`, as this would not compile. Use `&mut dyn Read` instead. +pub trait ForceReadValLe: Read { + auto_impl_nofns!(); + + read_primitive!(read_le); + + /// Reads a dynamic value from the reader. + /// + /// It's recommended to use the typed wrappers like `read_vec` instead of this method for cleaner code. + fn read_dynamic(&mut self, len: usize) -> T { + let mut buf = vec![0; len]; + self.read_exact(&mut buf).unwrap(); + T::from_bytes(buf).unwrap() + } +} + +impl ForceReadValLe for T {} diff --git a/src/read/force_ne.rs b/src/read/force_ne.rs new file mode 100644 index 0000000..8cdc190 --- /dev/null +++ b/src/read/force_ne.rs @@ -0,0 +1,68 @@ +use super::auto_impl::auto_impl_nofns; +use crate::{Dynamic, Primitive}; +use std::io::Read; + +macro_rules! read_primitive { + ($fn_name:ident) => { + /// Reads a primitive value from the reader using the specified byte order. + /// + /// It's recommended to use the typed wrappers like `read_u8` instead of this method for cleaner code. + fn $fn_name, U, const S: usize>(&mut self) -> T { + let mut buf = [0; S]; + self.read_exact(&mut buf).unwrap(); + T::from_ne_bytes(buf) + } + }; +} + +macro_rules! read_primitive_typed { + ($fn_name:ident, $return_type:ty, $_:ident) => { + /// Typed wrapper around `read_ne`. + fn $fn_name(&mut self) -> $return_type { + self.read_ne() + } + }; + + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `read_ne`. + fn $fn_name(&mut self) -> $return_type { + self.read_ne() + } + }; + + ($fn_name:ident, $return_type:ty, $_:ident, $const:ident) => { + /// Typed wrapper around `read_ne`. + fn $fn_name(&mut self) -> $return_type { + self.read_ne::<$return_type, $return_type, $const>() + } + }; +} + +macro_rules! read_dynamic_typed { + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `read_dynamic`. + fn $fn_name(&mut self, len: usize) -> $return_type { + self.read_dynamic(len) + } + }; +} + +/// Extension trait for `Read` that provides methods for reading supported value types in native endian order without the `Result` return type, triggering a panic on error. +/// +/// **Note:** do not borrow this as `&mut dyn ForceReadValNe`, as this would not compile. Use `&mut dyn Read` instead. +pub trait ForceReadValNe: Read { + auto_impl_nofns!(); + + read_primitive!(read_ne); + + /// Reads a dynamic value from the reader. + /// + /// It's recommended to use the typed wrappers like `read_vec` instead of this method for cleaner code. + fn read_dynamic(&mut self, len: usize) -> T { + let mut buf = vec![0; len]; + self.read_exact(&mut buf).unwrap(); + T::from_bytes(buf).unwrap() + } +} + +impl ForceReadValNe for T {} diff --git a/src/read/val.rs b/src/read/val.rs index d167144..f2768d9 100644 --- a/src/read/val.rs +++ b/src/read/val.rs @@ -1,4 +1,4 @@ -use super::auto_impl::auto_impl; +use super::auto_impl::{auto_impl, auto_impl_all, auto_impl_nofns}; use crate::{Endianess, Primitive, Result}; use std::io::Read; @@ -61,58 +61,7 @@ pub(super) use read_primitive_typed; /// **Note:** do not borrow this as `&mut dyn ReadVal`, as this would not compile. Use `&mut dyn Read` instead. pub trait ReadVal: Read { auto_impl!(); - - read_primitive!(read_ne, from_ne_bytes); - read_primitive!(read_le, from_le_bytes); - read_primitive!(read_be, from_be_bytes); - - read_primitive_typed!(read_u16_ne, u16, read_ne); - read_primitive_typed!(read_u16_le, u16, read_le); - read_primitive_typed!(read_u16_be, u16, read_be); - - read_primitive_typed!(read_u32_ne, u32, read_ne); - read_primitive_typed!(read_u32_le, u32, read_le); - read_primitive_typed!(read_u32_be, u32, read_be); - - read_primitive_typed!(read_u64_ne, u64, read_ne); - read_primitive_typed!(read_u64_le, u64, read_le); - read_primitive_typed!(read_u64_be, u64, read_be); - - read_primitive_typed!(read_u128_ne, u128, read_ne); - read_primitive_typed!(read_u128_le, u128, read_le); - read_primitive_typed!(read_u128_be, u128, read_be); - - read_primitive_typed!(read_usize_ne, usize, read_ne); - read_primitive_typed!(read_usize_le, usize, read_le); - read_primitive_typed!(read_usize_be, usize, read_be); - - read_primitive_typed!(read_i16_ne, i16, read_ne); - read_primitive_typed!(read_i16_le, i16, read_le); - read_primitive_typed!(read_i16_be, i16, read_be); - - read_primitive_typed!(read_i32_ne, i32, read_ne); - read_primitive_typed!(read_i32_le, i32, read_le); - read_primitive_typed!(read_i32_be, i32, read_be); - - read_primitive_typed!(read_i64_ne, i64, read_ne); - read_primitive_typed!(read_i64_le, i64, read_le); - read_primitive_typed!(read_i64_be, i64, read_be); - - read_primitive_typed!(read_i128_ne, i128, read_ne); - read_primitive_typed!(read_i128_le, i128, read_le); - read_primitive_typed!(read_i128_be, i128, read_be); - - read_primitive_typed!(read_isize_ne, isize, read_ne); - read_primitive_typed!(read_isize_le, isize, read_le); - read_primitive_typed!(read_isize_be, isize, read_be); - - read_primitive_typed!(read_f32_ne, f32, read_ne); - read_primitive_typed!(read_f32_le, f32, read_le); - read_primitive_typed!(read_f32_be, f32, read_be); - - read_primitive_typed!(read_f64_ne, f64, read_ne); - read_primitive_typed!(read_f64_le, f64, read_le); - read_primitive_typed!(read_f64_be, f64, read_be); + auto_impl_all!(); } impl ReadVal for T {} diff --git a/src/read/val_be.rs b/src/read/val_be.rs index 02723d3..f1ec154 100644 --- a/src/read/val_be.rs +++ b/src/read/val_be.rs @@ -1,4 +1,7 @@ -use super::{auto_impl::auto_impl, val::read_dynamic_typed}; +use super::{ + auto_impl::{auto_impl, auto_impl_nofns}, + val::read_dynamic_typed, +}; use crate::{Primitive, Result}; use std::io::Read; diff --git a/src/read/val_le.rs b/src/read/val_le.rs index ea85530..8a32e02 100644 --- a/src/read/val_le.rs +++ b/src/read/val_le.rs @@ -1,4 +1,7 @@ -use super::{auto_impl::auto_impl, val::read_dynamic_typed}; +use super::{ + auto_impl::{auto_impl, auto_impl_nofns}, + val::read_dynamic_typed, +}; use crate::{Primitive, Result}; use std::io::Read; diff --git a/src/read/val_ne.rs b/src/read/val_ne.rs index 15a2785..48bc528 100644 --- a/src/read/val_ne.rs +++ b/src/read/val_ne.rs @@ -1,4 +1,7 @@ -use super::{auto_impl::auto_impl, val::read_dynamic_typed}; +use super::{ + auto_impl::{auto_impl, auto_impl_nofns}, + val::read_dynamic_typed, +}; use crate::{Primitive, Result}; use std::io::Read; diff --git a/tests/read.rs b/tests/read.rs index c2762f0..937f97c 100644 --- a/tests/read.rs +++ b/tests/read.rs @@ -259,7 +259,7 @@ fn read_str() { let data = [0x41u8, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]; let mut cursor = Cursor::new(data); - let val: String = cursor.read_str(4).unwrap(); + let val = cursor.read_str(4).unwrap(); assert_eq!(val, String::from("ABCD")); // overflow diff --git a/tests/read_be.rs b/tests/read_be.rs index 0ae4625..bd292b6 100644 --- a/tests/read_be.rs +++ b/tests/read_be.rs @@ -111,7 +111,7 @@ fn read_str() { let data = [0x41u8, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]; let mut cursor = Cursor::new(data); - let val: String = cursor.read_str(4).unwrap(); + let val = cursor.read_str(4).unwrap(); assert_eq!(val, String::from("ABCD")); // overflow diff --git a/tests/read_force.rs b/tests/read_force.rs new file mode 100644 index 0000000..656dd9b --- /dev/null +++ b/tests/read_force.rs @@ -0,0 +1,217 @@ +use dh::{Endianess, ForceReadVal}; +use std::io::{Cursor, Read}; + +#[test] +fn read_borrowing() { + let data = [0u8, 1, 2, 3]; + let mut cursor = Cursor::new(data); + + // this just needs to compile + let mut borrowed: &mut dyn Read = &mut cursor; + assert_eq!(borrowed.read_u8(), 0); + assert_eq!(borrowed.read_u8(), 1); + assert_eq!(cursor.read_u8(), 2); + assert_eq!(cursor.read_u8(), 3); +} + +#[test] +fn read_primitive() { + let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut cursor = Cursor::new(data); + + let val: u8 = cursor.read_ne(); + assert_eq!(val, 0); + + let val: [u8; 3] = cursor.read_ne(); + assert_eq!(val, [1, 2, 3]); + + let val: u16 = cursor.read_be(); + assert_eq!(val, 0x04_05); + + let val: u16 = cursor.read_le(); + assert_eq!(val, 0x07_06); +} + +#[test] +fn read_u8() { + let data = [0u8, 1, 2, 3]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u8(), 0); + assert_eq!(cursor.read_u8(), 1); + assert_eq!(cursor.read_u8(), 2); + assert_eq!(cursor.read_u8(), 3); +} + +#[test] +#[should_panic] +fn read_u8_panic() { + let data = [0u8, 1, 2, 3]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u8(), 0); + assert_eq!(cursor.read_u8(), 1); + assert_eq!(cursor.read_u8(), 2); + assert_eq!(cursor.read_u8(), 3); + + // overflow + cursor.read_u8(); +} + +#[test] +fn read_u16_ne() { + let data = [0x12u8, 0x34, 0x56, 0x78]; + let mut cursor = Cursor::new(data); + + let parts = match cfg!(target_endian = "big") { + true => (0x1234, 0x5678), + false => (0x3412, 0x7856), + }; + + assert_eq!(cursor.read_u16_ne(), parts.0); + assert_eq!(cursor.read_u16_ne(), parts.1); +} + +#[test] +fn read_u16_le() { + let data = [0x12u8, 0x34, 0x56, 0x78]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u16(Endianess::Little), 0x3412); + assert_eq!(cursor.read_u16(Endianess::Little), 0x7856); +} + +#[test] +fn read_u16_be() { + let data = [0x12u8, 0x34, 0x56, 0x78]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u16_be(), 0x1234); + assert_eq!(cursor.read_u16_be(), 0x5678); +} + +#[test] +fn read_u32_ne() { + let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; + let mut cursor = Cursor::new(data); + + let parts = match cfg!(target_endian = "big") { + true => (0x12345678, 0x9ABCDEF0), + false => (0x78563412, 0xF0DEBC9A), + }; + + assert_eq!(cursor.read_u32_ne(), parts.0); + assert_eq!(cursor.read_u32_ne(), parts.1); +} + +#[test] +fn read_u32_le() { + let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u32_le(), 0x78563412); + assert_eq!(cursor.read_u32_le(), 0xF0DEBC9A); +} + +#[test] +fn read_u32_be() { + let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u32_be(), 0x12345678); + assert_eq!(cursor.read_u32_be(), 0x9ABCDEF0); +} + +#[test] +fn read_u64_ne() { + let data = [ + 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, + 0xEF, + ]; + let mut cursor = Cursor::new(data); + + let parts = match cfg!(target_endian = "big") { + true => (0x123456789ABCDEF0, 0x0123456789ABCDEF), + false => (0xF0DEBC9A78563412, 0xEFCDAB8967452301), + }; + + assert_eq!(cursor.read_u64_ne(), parts.0); + assert_eq!(cursor.read_u64_ne(), parts.1); +} + +#[test] +fn read_u64_le() { + let data = [ + 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, + 0xEF, + ]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u64_le(), 0xF0DEBC9A78563412); + assert_eq!(cursor.read_u64_le(), 0xEFCDAB8967452301); +} + +#[test] +fn read_u64_be() { + let data = [ + 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, + 0xEF, + ]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u64_be(), 0x123456789ABCDEF0); + assert_eq!(cursor.read_u64_be(), 0x0123456789ABCDEF); +} + +#[test] +fn read_u128_ne() { + let data = [ + 1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ]; + let mut cursor = Cursor::new(data); + + let parts = match cfg!(target_endian = "big") { + true => ( + 0x01000000000000000000000000000000, + 0x01000000000000000000000000000000, + ), + false => ( + 0x00000000000000000000000000000001, + 0x00000000000000000000000000000001, + ), + }; + + assert_eq!(cursor.read_u128_ne(), parts.0); + assert_eq!(cursor.read_u128_ne(), parts.1); +} + +#[test] +fn read_u128_le() { + let data = [ + 1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u128_le(), 0x00000000000000000000000000000001); + assert_eq!(cursor.read_u128_le(), 0x00000000000000000000000000000001); +} + +#[test] +fn read_vec() { + let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut cursor = Cursor::new(data); + + let val: Vec = cursor.read_vec(4); + assert_eq!(val, vec![0, 1, 2, 3]); +} + +#[test] +fn read_str() { + let data = [0x41u8, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]; + let mut cursor = Cursor::new(data); + + let val = cursor.read_str(4); + assert_eq!(val, String::from("ABCD")); +} diff --git a/tests/read_force_be.rs b/tests/read_force_be.rs new file mode 100644 index 0000000..b70f86f --- /dev/null +++ b/tests/read_force_be.rs @@ -0,0 +1 @@ +// TODO: add tests diff --git a/tests/read_force_le.rs b/tests/read_force_le.rs new file mode 100644 index 0000000..a1514e4 --- /dev/null +++ b/tests/read_force_le.rs @@ -0,0 +1,119 @@ +use dh::ForceReadValLe; +use std::io::{Cursor, Read}; + +#[test] +fn read_borrowing() { + let data = [0u8, 1, 2, 3]; + let mut cursor = Cursor::new(data); + + // this just needs to compile + let mut borrowed: &mut dyn Read = &mut cursor; + assert_eq!(borrowed.read_u8(), 0); + assert_eq!(borrowed.read_u8(), 1); + assert_eq!(cursor.read_u8(), 2); + assert_eq!(cursor.read_u8(), 3); +} + +#[test] +fn read_primitive() { + let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut cursor = Cursor::new(data); + + let val: u8 = cursor.read_le(); + assert_eq!(val, 0); + + let val: [u8; 3] = cursor.read_le(); + assert_eq!(val, [1, 2, 3]); + + let val: u16 = cursor.read_le(); + assert_eq!(val, 0x05_04); + + let val: u16 = cursor.read_le(); + assert_eq!(val, 0x07_06); +} + +#[test] +fn read_u8() { + let data = [0u8, 1, 2, 3]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u8(), 0); + assert_eq!(cursor.read_u8(), 1); + assert_eq!(cursor.read_u8(), 2); + assert_eq!(cursor.read_u8(), 3); +} + +#[test] +#[should_panic] +fn read_u8_panic() { + let data = [0u8, 1, 2, 3]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u8(), 0); + assert_eq!(cursor.read_u8(), 1); + assert_eq!(cursor.read_u8(), 2); + assert_eq!(cursor.read_u8(), 3); + + // overflow + cursor.read_u8(); +} + +#[test] +fn read_u16_le() { + let data = [0x12u8, 0x34, 0x56, 0x78]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u16(), 0x3412); + assert_eq!(cursor.read_u16(), 0x7856); +} + +#[test] +fn read_u32_le() { + let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u32(), 0x78563412); + assert_eq!(cursor.read_u32(), 0xF0DEBC9A); +} + +#[test] +fn read_u64_le() { + let data = [ + 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, + 0xEF, + ]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u64(), 0xF0DEBC9A78563412); + assert_eq!(cursor.read_u64(), 0xEFCDAB8967452301); +} + +#[test] +fn read_u128_le() { + let data = [ + 1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u128(), 0x00000000000000000000000000000001); + assert_eq!(cursor.read_u128(), 0x00000000000000000000000000000001); +} + +#[test] +fn read_vec() { + let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut cursor = Cursor::new(data); + + let val: Vec = cursor.read_vec(4); + assert_eq!(val, vec![0, 1, 2, 3]); +} + +#[test] +fn read_str() { + let data = [0x41u8, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]; + let mut cursor = Cursor::new(data); + + let val = cursor.read_str(4); + assert_eq!(val, String::from("ABCD")); +} diff --git a/tests/read_force_ne.rs b/tests/read_force_ne.rs new file mode 100644 index 0000000..b70f86f --- /dev/null +++ b/tests/read_force_ne.rs @@ -0,0 +1 @@ +// TODO: add tests diff --git a/tests/read_le.rs b/tests/read_le.rs index 0576ee0..7379d28 100644 --- a/tests/read_le.rs +++ b/tests/read_le.rs @@ -133,7 +133,7 @@ fn read_str() { let data = [0x41u8, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]; let mut cursor = Cursor::new(data); - let val: String = cursor.read_str(4).unwrap(); + let val = cursor.read_str(4).unwrap(); assert_eq!(val, String::from("ABCD")); // overflow diff --git a/tests/read_ne.rs b/tests/read_ne.rs index 5ae0be6..2a46bf7 100644 --- a/tests/read_ne.rs +++ b/tests/read_ne.rs @@ -165,7 +165,7 @@ fn read_str() { let data = [0x41u8, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]; let mut cursor = Cursor::new(data); - let val: String = cursor.read_str(4).unwrap(); + let val = cursor.read_str(4).unwrap(); assert_eq!(val, String::from("ABCD")); // overflow From 7d8d59a8a9d4f8ea025476158d6c9e8af6e20dc0 Mon Sep 17 00:00:00 2001 From: Le0X8 <84378319+Le0X8@users.noreply.github.com> Date: Sun, 13 Jul 2025 18:58:00 +0200 Subject: [PATCH 5/7] added ReadAt trait, removed unneccessary traits --- src/lib.rs | 6 +- src/read.rs | 9 +- src/read/at.rs | 157 +++++++++++++++++++++++ src/read/auto_impl.rs | 104 ---------------- src/read/force.rs | 76 ------------ src/read/force_be.rs | 68 ---------- src/read/force_le.rs | 68 ---------- src/read/force_ne.rs | 68 ---------- src/read/val.rs | 89 ++++++++++++- src/read/val_be.rs | 53 -------- src/read/val_le.rs | 53 -------- src/read/val_ne.rs | 53 -------- src/types.rs | 6 + tests/read_at.rs | 275 +++++++++++++++++++++++++++++++++++++++++ tests/read_be.rs | 120 ------------------ tests/read_force.rs | 217 -------------------------------- tests/read_force_be.rs | 1 - tests/read_force_le.rs | 119 ------------------ tests/read_force_ne.rs | 1 - tests/read_le.rs | 142 --------------------- tests/read_ne.rs | 174 -------------------------- 21 files changed, 526 insertions(+), 1333 deletions(-) create mode 100644 src/read/at.rs delete mode 100644 src/read/auto_impl.rs delete mode 100644 src/read/force.rs delete mode 100644 src/read/force_be.rs delete mode 100644 src/read/force_le.rs delete mode 100644 src/read/force_ne.rs delete mode 100644 src/read/val_be.rs delete mode 100644 src/read/val_le.rs delete mode 100644 src/read/val_ne.rs create mode 100644 tests/read_at.rs delete mode 100644 tests/read_be.rs delete mode 100644 tests/read_force.rs delete mode 100644 tests/read_force_be.rs delete mode 100644 tests/read_force_le.rs delete mode 100644 tests/read_force_ne.rs delete mode 100644 tests/read_le.rs delete mode 100644 tests/read_ne.rs diff --git a/src/lib.rs b/src/lib.rs index a9978f9..acc7d61 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,9 +7,5 @@ mod types; pub use dynamic::Dynamic; pub use error::{Error, Result}; pub use primitive::Primitive; -pub use read::{ - force::ForceReadVal, force_be::ForceReadValBe, force_le::ForceReadValLe, - force_ne::ForceReadValNe, val::ReadVal, val_be::ReadValBe, val_le::ReadValLe, - val_ne::ReadValNe, -}; +pub use read::{at::ReadValAt, val::ReadVal}; pub use types::*; diff --git a/src/read.rs b/src/read.rs index 4918183..af2c080 100644 --- a/src/read.rs +++ b/src/read.rs @@ -1,9 +1,2 @@ -pub(crate) mod auto_impl; -pub(crate) mod force; -pub(crate) mod force_be; -pub(crate) mod force_le; -pub(crate) mod force_ne; +pub(crate) mod at; pub(crate) mod val; -pub(crate) mod val_be; -pub(crate) mod val_le; -pub(crate) mod val_ne; diff --git a/src/read/at.rs b/src/read/at.rs new file mode 100644 index 0000000..6063d6a --- /dev/null +++ b/src/read/at.rs @@ -0,0 +1,157 @@ +use crate::{Endianess, Primitive, Result}; +use std::io::{Read, Seek, SeekFrom::Start as SeekPos}; + +macro_rules! read_primitive { + ($fn_name:ident, $read_fn_name:ident) => { + /// Reads a primitive value from the reader using the specified byte order. + /// + /// It's recommended to use the typed wrappers like `read_u8_at` instead of this method for cleaner code. + fn $fn_name, U, const S: usize>(&mut self, pos: usize) -> Result { + let mut buf = [0; S]; + let pos_before = self.stream_position()?; + self.seek(SeekPos(pos as u64))?; + self.read_exact(&mut buf)?; + self.seek(SeekPos(pos_before))?; + Ok(T::$read_fn_name(buf)) + } + }; +} + +macro_rules! read_primitive_typed { + ($fn_name:ident, $return_type:ty, $read_fn:ident) => { + /// Typed wrapper around `read_ne_at`, `read_le_at`, or `read_be_at`. + fn $fn_name(&mut self, pos: usize) -> Result<$return_type> { + self.$read_fn(pos) + } + }; + + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `read_ne_at`, `read_le_at`, or `read_be_at`. + fn $fn_name(&mut self, pos: usize, endianess: Endianess) -> Result<$return_type> { + use Endianess::*; + match endianess { + Little => self.read_le_at(pos), + Big => self.read_be_at(pos), + Native => self.read_ne_at(pos), + } + } + }; + + ($fn_name:ident, $return_type:ty, $read_fn:ident, $const:ident) => { + /// Typed wrapper around `read_ne_at`, `read_le_at`, or `read_be_at`. + fn $fn_name(&mut self, pos: usize) -> Result<$return_type> { + self.$read_fn::<$return_type, $return_type, $const>(pos) + } + }; +} + +macro_rules! read_dynamic_typed { + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `read_dynamic_at`. + fn $fn_name(&mut self, pos: usize, len: usize) -> Result<$return_type> { + let pos_before = self.stream_position()?; + self.seek(SeekPos(pos as u64))?; + let result = self.read_dynamic(len); + self.seek(SeekPos(pos_before))?; + result + } + }; +} + +pub(super) use read_dynamic_typed; +pub(super) use read_primitive; +pub(super) use read_primitive_typed; + +/// Extension trait for `Read` that provides methods for reading supported value types. +/// +/// **Note:** do not borrow this as `&mut dyn ReadValAt`, as this would not compile. Use `&mut dyn dh::ReadSeek` instead. +pub trait ReadValAt: Read + Seek { + read_primitive_typed!(read_u8_at, u8, read_ne_at); + + read_primitive_typed!(read_u16_at, u16); + read_primitive_typed!(read_u32_at, u32); + read_primitive_typed!(read_u64_at, u64); + read_primitive_typed!(read_u128_at, u128); + read_primitive_typed!(read_usize_at, usize); + + read_primitive_typed!(read_i8_at, i8, read_ne_at); + + read_primitive_typed!(read_i16_at, i16); + read_primitive_typed!(read_i32_at, i32); + read_primitive_typed!(read_i64_at, i64); + read_primitive_typed!(read_i128_at, i128); + read_primitive_typed!(read_isize_at, isize); + + read_primitive_typed!(read_f32_at, f32); + read_primitive_typed!(read_f64_at, f64); + + read_primitive_typed!(read_u8_array_at, [u8; S], read_ne_at, S); + + read_primitive_typed!(read_bool_at, bool, read_ne_at); + + read_dynamic_typed!(read_vec_at, Vec); + read_dynamic_typed!(read_str_at, String); + + read_primitive!(read_ne_at, from_ne_bytes); + read_primitive!(read_le_at, from_le_bytes); + read_primitive!(read_be_at, from_be_bytes); + + read_primitive_typed!(read_u16_ne_at, u16, read_ne_at); + read_primitive_typed!(read_u16_le_at, u16, read_le_at); + read_primitive_typed!(read_u16_be_at, u16, read_be_at); + + read_primitive_typed!(read_u32_ne_at, u32, read_ne_at); + read_primitive_typed!(read_u32_le_at, u32, read_le_at); + read_primitive_typed!(read_u32_be_at, u32, read_be_at); + + read_primitive_typed!(read_u64_ne_at, u64, read_ne_at); + read_primitive_typed!(read_u64_le_at, u64, read_le_at); + read_primitive_typed!(read_u64_be_at, u64, read_be_at); + + read_primitive_typed!(read_u128_ne_at, u128, read_ne_at); + read_primitive_typed!(read_u128_le_at, u128, read_le_at); + read_primitive_typed!(read_u128_be_at, u128, read_be_at); + + read_primitive_typed!(read_usize_ne_at, usize, read_ne_at); + read_primitive_typed!(read_usize_le_at, usize, read_le_at); + read_primitive_typed!(read_usize_be_at, usize, read_be_at); + + read_primitive_typed!(read_i16_ne_at, i16, read_ne_at); + read_primitive_typed!(read_i16_le_at, i16, read_le_at); + read_primitive_typed!(read_i16_be_at, i16, read_be_at); + + read_primitive_typed!(read_i32_ne_at, i32, read_ne_at); + read_primitive_typed!(read_i32_le_at, i32, read_le_at); + read_primitive_typed!(read_i32_be_at, i32, read_be_at); + + read_primitive_typed!(read_i64_ne_at, i64, read_ne_at); + read_primitive_typed!(read_i64_le_at, i64, read_le_at); + read_primitive_typed!(read_i64_be_at, i64, read_be_at); + + read_primitive_typed!(read_i128_ne_at, i128, read_ne_at); + read_primitive_typed!(read_i128_le_at, i128, read_le_at); + read_primitive_typed!(read_i128_be_at, i128, read_be_at); + + read_primitive_typed!(read_isize_ne_at, isize, read_ne_at); + read_primitive_typed!(read_isize_le_at, isize, read_le_at); + read_primitive_typed!(read_isize_be_at, isize, read_be_at); + + read_primitive_typed!(read_f32_ne_at, f32, read_ne_at); + read_primitive_typed!(read_f32_le_at, f32, read_le_at); + read_primitive_typed!(read_f32_be_at, f32, read_be_at); + + read_primitive_typed!(read_f64_ne_at, f64, read_ne_at); + read_primitive_typed!(read_f64_le_at, f64, read_le_at); + read_primitive_typed!(read_f64_be_at, f64, read_be_at); + + /// Reads a dynamic value from the reader. + /// + /// It's recommended to use the typed wrappers like `read_vec` instead of this method for cleaner code. + fn read_dynamic(&mut self, len: usize) -> Result { + let mut buf = vec![0; len]; + self.read_exact(&mut buf)?; + T::from_bytes(buf) + } +} + +impl ReadValAt for T {} diff --git a/src/read/auto_impl.rs b/src/read/auto_impl.rs deleted file mode 100644 index 6da8e43..0000000 --- a/src/read/auto_impl.rs +++ /dev/null @@ -1,104 +0,0 @@ -macro_rules! auto_impl_nofns { - () => { - read_primitive_typed!(read_u8, u8, read_ne); - - read_primitive_typed!(read_u16, u16); - read_primitive_typed!(read_u32, u32); - read_primitive_typed!(read_u64, u64); - read_primitive_typed!(read_u128, u128); - read_primitive_typed!(read_usize, usize); - - read_primitive_typed!(read_i8, i8, read_ne); - - read_primitive_typed!(read_i16, i16); - read_primitive_typed!(read_i32, i32); - read_primitive_typed!(read_i64, i64); - read_primitive_typed!(read_i128, i128); - read_primitive_typed!(read_isize, isize); - - read_primitive_typed!(read_f32, f32); - read_primitive_typed!(read_f64, f64); - - read_primitive_typed!(read_u8_array, [u8; S], read_ne, S); - - read_primitive_typed!(read_bool, bool, read_ne); - - read_dynamic_typed!(read_vec, Vec); - read_dynamic_typed!(read_str, String); - }; -} - -macro_rules! auto_impl_all { - () => { - read_primitive!(read_ne, from_ne_bytes); - read_primitive!(read_le, from_le_bytes); - read_primitive!(read_be, from_be_bytes); - - read_primitive_typed!(read_u16_ne, u16, read_ne); - read_primitive_typed!(read_u16_le, u16, read_le); - read_primitive_typed!(read_u16_be, u16, read_be); - - read_primitive_typed!(read_u32_ne, u32, read_ne); - read_primitive_typed!(read_u32_le, u32, read_le); - read_primitive_typed!(read_u32_be, u32, read_be); - - read_primitive_typed!(read_u64_ne, u64, read_ne); - read_primitive_typed!(read_u64_le, u64, read_le); - read_primitive_typed!(read_u64_be, u64, read_be); - - read_primitive_typed!(read_u128_ne, u128, read_ne); - read_primitive_typed!(read_u128_le, u128, read_le); - read_primitive_typed!(read_u128_be, u128, read_be); - - read_primitive_typed!(read_usize_ne, usize, read_ne); - read_primitive_typed!(read_usize_le, usize, read_le); - read_primitive_typed!(read_usize_be, usize, read_be); - - read_primitive_typed!(read_i16_ne, i16, read_ne); - read_primitive_typed!(read_i16_le, i16, read_le); - read_primitive_typed!(read_i16_be, i16, read_be); - - read_primitive_typed!(read_i32_ne, i32, read_ne); - read_primitive_typed!(read_i32_le, i32, read_le); - read_primitive_typed!(read_i32_be, i32, read_be); - - read_primitive_typed!(read_i64_ne, i64, read_ne); - read_primitive_typed!(read_i64_le, i64, read_le); - read_primitive_typed!(read_i64_be, i64, read_be); - - read_primitive_typed!(read_i128_ne, i128, read_ne); - read_primitive_typed!(read_i128_le, i128, read_le); - read_primitive_typed!(read_i128_be, i128, read_be); - - read_primitive_typed!(read_isize_ne, isize, read_ne); - read_primitive_typed!(read_isize_le, isize, read_le); - read_primitive_typed!(read_isize_be, isize, read_be); - - read_primitive_typed!(read_f32_ne, f32, read_ne); - read_primitive_typed!(read_f32_le, f32, read_le); - read_primitive_typed!(read_f32_be, f32, read_be); - - read_primitive_typed!(read_f64_ne, f64, read_ne); - read_primitive_typed!(read_f64_le, f64, read_le); - read_primitive_typed!(read_f64_be, f64, read_be); - }; -} - -macro_rules! auto_impl { - () => { - auto_impl_nofns!(); - - /// Reads a dynamic value from the reader. - /// - /// It's recommended to use the typed wrappers like `read_vec` instead of this method for cleaner code. - fn read_dynamic(&mut self, len: usize) -> Result { - let mut buf = vec![0; len]; - self.read_exact(&mut buf)?; - T::from_bytes(buf) - } - }; -} - -pub(super) use auto_impl; -pub(super) use auto_impl_all; -pub(super) use auto_impl_nofns; diff --git a/src/read/force.rs b/src/read/force.rs deleted file mode 100644 index c8a8683..0000000 --- a/src/read/force.rs +++ /dev/null @@ -1,76 +0,0 @@ -use super::auto_impl::{auto_impl_all, auto_impl_nofns}; -use crate::{Dynamic, Endianess, Primitive}; -use std::io::Read; - -macro_rules! read_primitive { - ($fn_name:ident, $read_fn_name:ident) => { - /// Reads a primitive value from the reader using the specified byte order. - /// - /// It's recommended to use the typed wrappers like `read_u8` instead of this method for cleaner code. - fn $fn_name, U, const S: usize>(&mut self) -> T { - let mut buf = [0; S]; - self.read_exact(&mut buf).unwrap(); - T::$read_fn_name(buf) - } - }; -} - -macro_rules! read_primitive_typed { - ($fn_name:ident, $return_type:ty, $read_fn:ident) => { - /// Typed wrapper around `read_ne`, `read_le`, or `read_be`. - fn $fn_name(&mut self) -> $return_type { - self.$read_fn() - } - }; - - ($fn_name:ident, $return_type:ty) => { - /// Typed wrapper around `read_ne`, `read_le`, or `read_be`. - fn $fn_name(&mut self, endianess: Endianess) -> $return_type { - use Endianess::*; - match endianess { - Little => self.read_le(), - Big => self.read_be(), - Native => self.read_ne(), - } - } - }; - - ($fn_name:ident, $return_type:ty, $read_fn:ident, $const:ident) => { - /// Typed wrapper around `read_ne`, `read_le`, or `read_be`. - fn $fn_name(&mut self) -> $return_type { - self.$read_fn::<$return_type, $return_type, $const>() - } - }; -} - -macro_rules! read_dynamic_typed { - ($fn_name:ident, $return_type:ty) => { - /// Typed wrapper around `read_dynamic`. - fn $fn_name(&mut self, len: usize) -> $return_type { - self.read_dynamic(len) - } - }; -} - -pub(super) use read_dynamic_typed; -pub(super) use read_primitive; -pub(super) use read_primitive_typed; - -/// Extension trait for `Read` that provides methods for reading supported value types without the `Result` return type, triggering a panic on error. -/// -/// **Note:** do not borrow this as `&mut dyn ForceReadVal`, as this would not compile. Use `&mut dyn Read` instead. -pub trait ForceReadVal: Read { - auto_impl_nofns!(); - auto_impl_all!(); - - /// Reads a dynamic value from the reader. - /// - /// It's recommended to use the typed wrappers like `read_vec` instead of this method for cleaner code. - fn read_dynamic(&mut self, len: usize) -> T { - let mut buf = vec![0; len]; - self.read_exact(&mut buf).unwrap(); - T::from_bytes(buf).unwrap() - } -} - -impl ForceReadVal for T {} diff --git a/src/read/force_be.rs b/src/read/force_be.rs deleted file mode 100644 index 8e7b7e3..0000000 --- a/src/read/force_be.rs +++ /dev/null @@ -1,68 +0,0 @@ -use super::auto_impl::auto_impl_nofns; -use crate::{Dynamic, Primitive}; -use std::io::Read; - -macro_rules! read_primitive { - ($fn_name:ident) => { - /// Reads a primitive value from the reader using the specified byte order. - /// - /// It's recommended to use the typed wrappers like `read_u8` instead of this method for cleaner code. - fn $fn_name, U, const S: usize>(&mut self) -> T { - let mut buf = [0; S]; - self.read_exact(&mut buf).unwrap(); - T::from_be_bytes(buf) - } - }; -} - -macro_rules! read_primitive_typed { - ($fn_name:ident, $return_type:ty, $_:ident) => { - /// Typed wrapper around `read_be`. - fn $fn_name(&mut self) -> $return_type { - self.read_be() - } - }; - - ($fn_name:ident, $return_type:ty) => { - /// Typed wrapper around `read_be`. - fn $fn_name(&mut self) -> $return_type { - self.read_be() - } - }; - - ($fn_name:ident, $return_type:ty, $_:ident, $const:ident) => { - /// Typed wrapper around `read_be`. - fn $fn_name(&mut self) -> $return_type { - self.read_be::<$return_type, $return_type, $const>() - } - }; -} - -macro_rules! read_dynamic_typed { - ($fn_name:ident, $return_type:ty) => { - /// Typed wrapper around `read_dynamic`. - fn $fn_name(&mut self, len: usize) -> $return_type { - self.read_dynamic(len) - } - }; -} - -/// Extension trait for `Read` that provides methods for reading supported value types in big endian order without the `Result` return type, triggering a panic on error. -/// -/// **Note:** do not borrow this as `&mut dyn ForceReadValBe`, as this would not compile. Use `&mut dyn Read` instead. -pub trait ForceReadValBe: Read { - auto_impl_nofns!(); - - read_primitive!(read_be); - - /// Reads a dynamic value from the reader. - /// - /// It's recommended to use the typed wrappers like `read_vec` instead of this method for cleaner code. - fn read_dynamic(&mut self, len: usize) -> T { - let mut buf = vec![0; len]; - self.read_exact(&mut buf).unwrap(); - T::from_bytes(buf).unwrap() - } -} - -impl ForceReadValBe for T {} diff --git a/src/read/force_le.rs b/src/read/force_le.rs deleted file mode 100644 index 5535156..0000000 --- a/src/read/force_le.rs +++ /dev/null @@ -1,68 +0,0 @@ -use super::auto_impl::auto_impl_nofns; -use crate::{Dynamic, Primitive}; -use std::io::Read; - -macro_rules! read_primitive { - ($fn_name:ident) => { - /// Reads a primitive value from the reader using the specified byte order. - /// - /// It's recommended to use the typed wrappers like `read_u8` instead of this method for cleaner code. - fn $fn_name, U, const S: usize>(&mut self) -> T { - let mut buf = [0; S]; - self.read_exact(&mut buf).unwrap(); - T::from_le_bytes(buf) - } - }; -} - -macro_rules! read_primitive_typed { - ($fn_name:ident, $return_type:ty, $_:ident) => { - /// Typed wrapper around `read_le`. - fn $fn_name(&mut self) -> $return_type { - self.read_le() - } - }; - - ($fn_name:ident, $return_type:ty) => { - /// Typed wrapper around `read_le`. - fn $fn_name(&mut self) -> $return_type { - self.read_le() - } - }; - - ($fn_name:ident, $return_type:ty, $_:ident, $const:ident) => { - /// Typed wrapper around `read_le`. - fn $fn_name(&mut self) -> $return_type { - self.read_le::<$return_type, $return_type, $const>() - } - }; -} - -macro_rules! read_dynamic_typed { - ($fn_name:ident, $return_type:ty) => { - /// Typed wrapper around `read_dynamic`. - fn $fn_name(&mut self, len: usize) -> $return_type { - self.read_dynamic(len) - } - }; -} - -/// Extension trait for `Read` that provides methods for reading supported value types in little endian order without the `Result` return type, triggering a panic on error. -/// -/// **Note:** do not borrow this as `&mut dyn ForceReadValLe`, as this would not compile. Use `&mut dyn Read` instead. -pub trait ForceReadValLe: Read { - auto_impl_nofns!(); - - read_primitive!(read_le); - - /// Reads a dynamic value from the reader. - /// - /// It's recommended to use the typed wrappers like `read_vec` instead of this method for cleaner code. - fn read_dynamic(&mut self, len: usize) -> T { - let mut buf = vec![0; len]; - self.read_exact(&mut buf).unwrap(); - T::from_bytes(buf).unwrap() - } -} - -impl ForceReadValLe for T {} diff --git a/src/read/force_ne.rs b/src/read/force_ne.rs deleted file mode 100644 index 8cdc190..0000000 --- a/src/read/force_ne.rs +++ /dev/null @@ -1,68 +0,0 @@ -use super::auto_impl::auto_impl_nofns; -use crate::{Dynamic, Primitive}; -use std::io::Read; - -macro_rules! read_primitive { - ($fn_name:ident) => { - /// Reads a primitive value from the reader using the specified byte order. - /// - /// It's recommended to use the typed wrappers like `read_u8` instead of this method for cleaner code. - fn $fn_name, U, const S: usize>(&mut self) -> T { - let mut buf = [0; S]; - self.read_exact(&mut buf).unwrap(); - T::from_ne_bytes(buf) - } - }; -} - -macro_rules! read_primitive_typed { - ($fn_name:ident, $return_type:ty, $_:ident) => { - /// Typed wrapper around `read_ne`. - fn $fn_name(&mut self) -> $return_type { - self.read_ne() - } - }; - - ($fn_name:ident, $return_type:ty) => { - /// Typed wrapper around `read_ne`. - fn $fn_name(&mut self) -> $return_type { - self.read_ne() - } - }; - - ($fn_name:ident, $return_type:ty, $_:ident, $const:ident) => { - /// Typed wrapper around `read_ne`. - fn $fn_name(&mut self) -> $return_type { - self.read_ne::<$return_type, $return_type, $const>() - } - }; -} - -macro_rules! read_dynamic_typed { - ($fn_name:ident, $return_type:ty) => { - /// Typed wrapper around `read_dynamic`. - fn $fn_name(&mut self, len: usize) -> $return_type { - self.read_dynamic(len) - } - }; -} - -/// Extension trait for `Read` that provides methods for reading supported value types in native endian order without the `Result` return type, triggering a panic on error. -/// -/// **Note:** do not borrow this as `&mut dyn ForceReadValNe`, as this would not compile. Use `&mut dyn Read` instead. -pub trait ForceReadValNe: Read { - auto_impl_nofns!(); - - read_primitive!(read_ne); - - /// Reads a dynamic value from the reader. - /// - /// It's recommended to use the typed wrappers like `read_vec` instead of this method for cleaner code. - fn read_dynamic(&mut self, len: usize) -> T { - let mut buf = vec![0; len]; - self.read_exact(&mut buf).unwrap(); - T::from_bytes(buf).unwrap() - } -} - -impl ForceReadValNe for T {} diff --git a/src/read/val.rs b/src/read/val.rs index f2768d9..8f53501 100644 --- a/src/read/val.rs +++ b/src/read/val.rs @@ -1,4 +1,3 @@ -use super::auto_impl::{auto_impl, auto_impl_all, auto_impl_nofns}; use crate::{Endianess, Primitive, Result}; use std::io::Read; @@ -60,8 +59,92 @@ pub(super) use read_primitive_typed; /// /// **Note:** do not borrow this as `&mut dyn ReadVal`, as this would not compile. Use `&mut dyn Read` instead. pub trait ReadVal: Read { - auto_impl!(); - auto_impl_all!(); + read_primitive_typed!(read_u8, u8, read_ne); + + read_primitive_typed!(read_u16, u16); + read_primitive_typed!(read_u32, u32); + read_primitive_typed!(read_u64, u64); + read_primitive_typed!(read_u128, u128); + read_primitive_typed!(read_usize, usize); + + read_primitive_typed!(read_i8, i8, read_ne); + + read_primitive_typed!(read_i16, i16); + read_primitive_typed!(read_i32, i32); + read_primitive_typed!(read_i64, i64); + read_primitive_typed!(read_i128, i128); + read_primitive_typed!(read_isize, isize); + + read_primitive_typed!(read_f32, f32); + read_primitive_typed!(read_f64, f64); + + read_primitive_typed!(read_u8_array, [u8; S], read_ne, S); + + read_primitive_typed!(read_bool, bool, read_ne); + + read_dynamic_typed!(read_vec, Vec); + read_dynamic_typed!(read_str, String); + + read_primitive!(read_ne, from_ne_bytes); + read_primitive!(read_le, from_le_bytes); + read_primitive!(read_be, from_be_bytes); + + read_primitive_typed!(read_u16_ne, u16, read_ne); + read_primitive_typed!(read_u16_le, u16, read_le); + read_primitive_typed!(read_u16_be, u16, read_be); + + read_primitive_typed!(read_u32_ne, u32, read_ne); + read_primitive_typed!(read_u32_le, u32, read_le); + read_primitive_typed!(read_u32_be, u32, read_be); + + read_primitive_typed!(read_u64_ne, u64, read_ne); + read_primitive_typed!(read_u64_le, u64, read_le); + read_primitive_typed!(read_u64_be, u64, read_be); + + read_primitive_typed!(read_u128_ne, u128, read_ne); + read_primitive_typed!(read_u128_le, u128, read_le); + read_primitive_typed!(read_u128_be, u128, read_be); + + read_primitive_typed!(read_usize_ne, usize, read_ne); + read_primitive_typed!(read_usize_le, usize, read_le); + read_primitive_typed!(read_usize_be, usize, read_be); + + read_primitive_typed!(read_i16_ne, i16, read_ne); + read_primitive_typed!(read_i16_le, i16, read_le); + read_primitive_typed!(read_i16_be, i16, read_be); + + read_primitive_typed!(read_i32_ne, i32, read_ne); + read_primitive_typed!(read_i32_le, i32, read_le); + read_primitive_typed!(read_i32_be, i32, read_be); + + read_primitive_typed!(read_i64_ne, i64, read_ne); + read_primitive_typed!(read_i64_le, i64, read_le); + read_primitive_typed!(read_i64_be, i64, read_be); + + read_primitive_typed!(read_i128_ne, i128, read_ne); + read_primitive_typed!(read_i128_le, i128, read_le); + read_primitive_typed!(read_i128_be, i128, read_be); + + read_primitive_typed!(read_isize_ne, isize, read_ne); + read_primitive_typed!(read_isize_le, isize, read_le); + read_primitive_typed!(read_isize_be, isize, read_be); + + read_primitive_typed!(read_f32_ne, f32, read_ne); + read_primitive_typed!(read_f32_le, f32, read_le); + read_primitive_typed!(read_f32_be, f32, read_be); + + read_primitive_typed!(read_f64_ne, f64, read_ne); + read_primitive_typed!(read_f64_le, f64, read_le); + read_primitive_typed!(read_f64_be, f64, read_be); + + /// Reads a dynamic value from the reader. + /// + /// It's recommended to use the typed wrappers like `read_vec` instead of this method for cleaner code. + fn read_dynamic(&mut self, len: usize) -> Result { + let mut buf = vec![0; len]; + self.read_exact(&mut buf)?; + T::from_bytes(buf) + } } impl ReadVal for T {} diff --git a/src/read/val_be.rs b/src/read/val_be.rs deleted file mode 100644 index f1ec154..0000000 --- a/src/read/val_be.rs +++ /dev/null @@ -1,53 +0,0 @@ -use super::{ - auto_impl::{auto_impl, auto_impl_nofns}, - val::read_dynamic_typed, -}; -use crate::{Primitive, Result}; -use std::io::Read; - -macro_rules! read_primitive { - ($fn_name:ident) => { - /// Reads a primitive value from the reader using the specified byte order. - /// - /// It's recommended to use the typed wrappers like `read_u8` instead of this method for cleaner code. - fn $fn_name, U, const S: usize>(&mut self) -> Result { - let mut buf = [0; S]; - self.read_exact(&mut buf)?; - Ok(T::from_be_bytes(buf)) - } - }; -} - -macro_rules! read_primitive_typed { - ($fn_name:ident, $return_type:ty, $_:ident) => { - /// Typed wrapper around `read_be`. - fn $fn_name(&mut self) -> Result<$return_type> { - self.read_be() - } - }; - - ($fn_name:ident, $return_type:ty) => { - /// Typed wrapper around `read_be`. - fn $fn_name(&mut self) -> Result<$return_type> { - self.read_be() - } - }; - - ($fn_name:ident, $return_type:ty, $_:ident, $const:ident) => { - /// Typed wrapper around `read_be`. - fn $fn_name(&mut self) -> Result<$return_type> { - self.read_be::<$return_type, $return_type, $const>() - } - }; -} - -/// Extension trait for `Read` that provides methods for reading supported value types in big endian order. -/// -/// **Note:** do not borrow this as `&mut dyn ReadValBe`, as this would not compile. Use `&mut dyn Read` instead. -pub trait ReadValBe: Read { - auto_impl!(); - - read_primitive!(read_be); -} - -impl ReadValBe for T {} diff --git a/src/read/val_le.rs b/src/read/val_le.rs deleted file mode 100644 index 8a32e02..0000000 --- a/src/read/val_le.rs +++ /dev/null @@ -1,53 +0,0 @@ -use super::{ - auto_impl::{auto_impl, auto_impl_nofns}, - val::read_dynamic_typed, -}; -use crate::{Primitive, Result}; -use std::io::Read; - -macro_rules! read_primitive { - ($fn_name:ident) => { - /// Reads a primitive value from the reader using the specified byte order. - /// - /// It's recommended to use the typed wrappers like `read_u8` instead of this method for cleaner code. - fn $fn_name, U, const S: usize>(&mut self) -> Result { - let mut buf = [0; S]; - self.read_exact(&mut buf)?; - Ok(T::from_le_bytes(buf)) - } - }; -} - -macro_rules! read_primitive_typed { - ($fn_name:ident, $return_type:ty, $_:ident) => { - /// Typed wrapper around `read_le`. - fn $fn_name(&mut self) -> Result<$return_type> { - self.read_le() - } - }; - - ($fn_name:ident, $return_type:ty) => { - /// Typed wrapper around `read_le`. - fn $fn_name(&mut self) -> Result<$return_type> { - self.read_le() - } - }; - - ($fn_name:ident, $return_type:ty, $_:ident, $const:ident) => { - /// Typed wrapper around `read_le`. - fn $fn_name(&mut self) -> Result<$return_type> { - self.read_le::<$return_type, $return_type, $const>() - } - }; -} - -/// Extension trait for `Read` that provides methods for reading supported value types in little endian order. -/// -/// **Note:** do not borrow this as `&mut dyn ReadValLe`, as this would not compile. Use `&mut dyn Read` instead. -pub trait ReadValLe: Read { - auto_impl!(); - - read_primitive!(read_le); -} - -impl ReadValLe for T {} diff --git a/src/read/val_ne.rs b/src/read/val_ne.rs deleted file mode 100644 index 48bc528..0000000 --- a/src/read/val_ne.rs +++ /dev/null @@ -1,53 +0,0 @@ -use super::{ - auto_impl::{auto_impl, auto_impl_nofns}, - val::read_dynamic_typed, -}; -use crate::{Primitive, Result}; -use std::io::Read; - -macro_rules! read_primitive { - ($fn_name:ident) => { - /// Reads a primitive value from the reader using the specified byte order. - /// - /// It's recommended to use the typed wrappers like `read_u8` instead of this method for cleaner code. - fn $fn_name, U, const S: usize>(&mut self) -> Result { - let mut buf = [0; S]; - self.read_exact(&mut buf)?; - Ok(T::from_ne_bytes(buf)) - } - }; -} - -macro_rules! read_primitive_typed { - ($fn_name:ident, $return_type:ty, $_:ident) => { - /// Typed wrapper around `read_ne`. - fn $fn_name(&mut self) -> Result<$return_type> { - self.read_ne() - } - }; - - ($fn_name:ident, $return_type:ty) => { - /// Typed wrapper around `read_ne`. - fn $fn_name(&mut self) -> Result<$return_type> { - self.read_ne() - } - }; - - ($fn_name:ident, $return_type:ty, $_:ident, $const:ident) => { - /// Typed wrapper around `read_ne`. - fn $fn_name(&mut self) -> Result<$return_type> { - self.read_ne::<$return_type, $return_type, $const>() - } - }; -} - -/// Extension trait for `Read` that provides methods for reading supported value types in native endian order. -/// -/// **Note:** do not borrow this as `&mut dyn ReadValNe`, as this would not compile. Use `&mut dyn Read` instead. -pub trait ReadValNe: Read { - auto_impl!(); - - read_primitive!(read_ne); -} - -impl ReadValNe for T {} diff --git a/src/types.rs b/src/types.rs index 0b9b25e..5a15267 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,6 +1,12 @@ +use std::io::{Read, Seek}; + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Endianess { Little, Big, Native, } + +/// Because you can't do `dyn Read + Seek` in Rust, this trait is used to combine both traits. +pub trait ReadSeek: Read + Seek {} +impl ReadSeek for T {} diff --git a/tests/read_at.rs b/tests/read_at.rs new file mode 100644 index 0000000..b6c7fed --- /dev/null +++ b/tests/read_at.rs @@ -0,0 +1,275 @@ +use dh::{Endianess, ReadSeek, ReadVal, ReadValAt, Result}; +use std::io::Cursor; + +#[test] +fn read_at_borrowing() { + let data = [0u8, 1, 2, 3]; + let mut cursor = Cursor::new(data); + + // this just needs to compile + let mut borrowed: &mut dyn ReadSeek = &mut cursor; + assert_eq!(borrowed.read_u8().unwrap(), 0); + assert_eq!(borrowed.read_u8().unwrap(), 1); + assert_eq!(cursor.read_u8_at(2).unwrap(), 2); + assert_eq!(cursor.read_u8_at(3).unwrap(), 3); +} + +#[test] +fn read_at_primitive() { + let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut cursor = Cursor::new(data); + + let val: u8 = cursor.read_ne_at(0).unwrap(); + assert_eq!(val, 0); + + let val: [u8; 3] = cursor.read_ne().unwrap(); + assert_eq!(val, [0, 1, 2]); + + let val: u16 = cursor.read_be_at(4).unwrap(); + assert_eq!(val, 0x04_05); + + let val: u16 = cursor.read_le().unwrap(); + assert_eq!(val, 0x04_03); + + // position out of bounds + let val: Result = cursor.read_ne_at(8); + assert!(val.is_err()); + + // position out of bounds + cursor.set_position(8); + let val: Result = cursor.read_ne(); + assert!(val.is_err()); +} + +#[test] +fn read_at_u8() { + let data = [0u8, 1, 2, 3]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u8_at(2).unwrap(), 2); + assert_eq!(cursor.read_u8_at(3).unwrap(), 3); + assert_eq!(cursor.read_u8().unwrap(), 0); + assert_eq!(cursor.read_u8().unwrap(), 1); + assert_eq!(cursor.read_u8().unwrap(), 2); + assert_eq!(cursor.read_u8().unwrap(), 3); + + // overflow + let val = cursor.read_u8(); + assert!(val.is_err()); +} + +#[test] +fn read_at_u16_ne() { + let data = [0x12u8, 0x34, 0x56, 0x78]; + let mut cursor = Cursor::new(data); + + let parts = match cfg!(target_endian = "big") { + true => (0x1234, 0x5678), + false => (0x3412, 0x7856), + }; + + assert_eq!(cursor.read_u16_ne().unwrap(), parts.0); + assert_eq!(cursor.read_u16_ne().unwrap(), parts.1); + + // overflow + let val = cursor.read_u16_ne(); + assert!(val.is_err()); +} + +#[test] +fn read_at_u16_le() { + let data = [0x12u8, 0x34, 0x56, 0x78]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u16(Endianess::Little).unwrap(), 0x3412); + assert_eq!(cursor.read_u16(Endianess::Little).unwrap(), 0x7856); + + // overflow + let val = cursor.read_u16(Endianess::Little); + assert!(val.is_err()); +} + +#[test] +fn read_at_u16_be() { + let data = [0x12u8, 0x34, 0x56, 0x78]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u16_be().unwrap(), 0x1234); + assert_eq!(cursor.read_u16_be().unwrap(), 0x5678); + + // overflow + let val = cursor.read_u16_be(); + assert!(val.is_err()); +} + +#[test] +fn read_at_u32_ne() { + let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; + let mut cursor = Cursor::new(data); + + let parts = match cfg!(target_endian = "big") { + true => (0x12345678, 0x9ABCDEF0), + false => (0x78563412, 0xF0DEBC9A), + }; + + assert_eq!(cursor.read_u32_ne().unwrap(), parts.0); + assert_eq!(cursor.read_u32_ne().unwrap(), parts.1); + + // overflow + let val = cursor.read_u32_ne(); + assert!(val.is_err()); +} + +#[test] +fn read_at_u32_le() { + let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u32_le().unwrap(), 0x78563412); + assert_eq!(cursor.read_u32_le().unwrap(), 0xF0DEBC9A); + + // overflow + let val = cursor.read_u32_le(); + assert!(val.is_err()); +} + +#[test] +fn read_at_u32_be() { + let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u32_be().unwrap(), 0x12345678); + assert_eq!(cursor.read_u32_be().unwrap(), 0x9ABCDEF0); + + // overflow + let val = cursor.read_u32_be(); + assert!(val.is_err()); +} + +#[test] +fn read_at_u64_ne() { + let data = [ + 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, + 0xEF, + ]; + let mut cursor = Cursor::new(data); + + let parts = match cfg!(target_endian = "big") { + true => (0x123456789ABCDEF0, 0x0123456789ABCDEF), + false => (0xF0DEBC9A78563412, 0xEFCDAB8967452301), + }; + + assert_eq!(cursor.read_u64_ne().unwrap(), parts.0); + assert_eq!(cursor.read_u64_ne().unwrap(), parts.1); + + // overflow + let val = cursor.read_u64_ne(); + assert!(val.is_err()); +} + +#[test] +fn read_at_u64_le() { + let data = [ + 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, + 0xEF, + ]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u64_le().unwrap(), 0xF0DEBC9A78563412); + assert_eq!(cursor.read_u64_le().unwrap(), 0xEFCDAB8967452301); + + // overflow + let val = cursor.read_u64_le(); + assert!(val.is_err()); +} + +#[test] +fn read_at_u64_be() { + let data = [ + 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, + 0xEF, + ]; + let mut cursor = Cursor::new(data); + + assert_eq!(cursor.read_u64_be().unwrap(), 0x123456789ABCDEF0); + assert_eq!(cursor.read_u64_be().unwrap(), 0x0123456789ABCDEF); + + // overflow + let val = cursor.read_u64_be(); + assert!(val.is_err()); +} + +#[test] +fn read_at_u128_ne() { + let data = [ + 1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ]; + let mut cursor = Cursor::new(data); + + let parts = match cfg!(target_endian = "big") { + true => ( + 0x01000000000000000000000000000000, + 0x01000000000000000000000000000000, + ), + false => ( + 0x00000000000000000000000000000001, + 0x00000000000000000000000000000001, + ), + }; + + assert_eq!(cursor.read_u128_ne().unwrap(), parts.0); + assert_eq!(cursor.read_u128_ne().unwrap(), parts.1); + + // overflow + let val = cursor.read_u128_ne(); + assert!(val.is_err()); +} + +#[test] +fn read_at_u128_le() { + let data = [ + 1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ]; + let mut cursor = Cursor::new(data); + + assert_eq!( + cursor.read_u128_le().unwrap(), + 0x00000000000000000000000000000001 + ); + assert_eq!( + cursor.read_u128_le().unwrap(), + 0x00000000000000000000000000000001 + ); + + // overflow + let val = cursor.read_u128_le(); + assert!(val.is_err()); +} + +#[test] +fn read_at_vec() { + let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut cursor = Cursor::new(data); + + let val: Vec = cursor.read_vec(4).unwrap(); + assert_eq!(val, vec![0, 1, 2, 3]); + + // overflow + let val: Result> = cursor.read_vec(10); + assert!(val.is_err()); +} + +#[test] +fn read_at_str() { + let data = [0x41u8, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]; + let mut cursor = Cursor::new(data); + + let val = cursor.read_str(4).unwrap(); + assert_eq!(val, String::from("ABCD")); + + // overflow + let val: Result = cursor.read_str(10); + assert!(val.is_err()); +} diff --git a/tests/read_be.rs b/tests/read_be.rs deleted file mode 100644 index bd292b6..0000000 --- a/tests/read_be.rs +++ /dev/null @@ -1,120 +0,0 @@ -use dh::{ReadValBe, Result}; -use std::io::{Cursor, Read}; - -#[test] -fn read_borrowing() { - let data = [0u8, 1, 2, 3]; - let mut cursor = Cursor::new(data); - - // this just needs to compile - let mut borrowed: &mut dyn Read = &mut cursor; - assert_eq!(borrowed.read_u8().unwrap(), 0); - assert_eq!(borrowed.read_u8().unwrap(), 1); - assert_eq!(cursor.read_u8().unwrap(), 2); - assert_eq!(cursor.read_u8().unwrap(), 3); -} - -#[test] -fn read_primitive() { - let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; - let mut cursor = Cursor::new(data); - - let val: u8 = cursor.read_be().unwrap(); - assert_eq!(val, 0); - - let val: [u8; 3] = cursor.read_be().unwrap(); - assert_eq!(val, [1, 2, 3]); - - let val: u16 = cursor.read_be().unwrap(); - assert_eq!(val, 0x04_05); - - let val: u16 = cursor.read_be().unwrap(); - assert_eq!(val, 0x06_07); - - // overflow - let val: Result = cursor.read_be(); - assert!(val.is_err()); -} - -#[test] -fn read_u8() { - let data = [0u8, 1, 2, 3]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u8().unwrap(), 0); - assert_eq!(cursor.read_u8().unwrap(), 1); - assert_eq!(cursor.read_u8().unwrap(), 2); - assert_eq!(cursor.read_u8().unwrap(), 3); - - // overflow - let val = cursor.read_u8(); - assert!(val.is_err()); -} - -#[test] -fn read_u16_be() { - let data = [0x12u8, 0x34, 0x56, 0x78]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u16().unwrap(), 0x1234); - assert_eq!(cursor.read_u16().unwrap(), 0x5678); - - // overflow - let val = cursor.read_u16(); - assert!(val.is_err()); -} - -#[test] -fn read_u32_be() { - let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u32().unwrap(), 0x12345678); - assert_eq!(cursor.read_u32().unwrap(), 0x9ABCDEF0); - - // overflow - let val = cursor.read_u32(); - assert!(val.is_err()); -} - -#[test] -fn read_u64_be() { - let data = [ - 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, - 0xEF, - ]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u64().unwrap(), 0x123456789ABCDEF0); - assert_eq!(cursor.read_u64().unwrap(), 0x0123456789ABCDEF); - - // overflow - let val = cursor.read_u64(); - assert!(val.is_err()); -} - -#[test] -fn read_vec() { - let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; - let mut cursor = Cursor::new(data); - - let val: Vec = cursor.read_vec(4).unwrap(); - assert_eq!(val, vec![0, 1, 2, 3]); - - // overflow - let val: Result> = cursor.read_vec(10); - assert!(val.is_err()); -} - -#[test] -fn read_str() { - let data = [0x41u8, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]; - let mut cursor = Cursor::new(data); - - let val = cursor.read_str(4).unwrap(); - assert_eq!(val, String::from("ABCD")); - - // overflow - let val: Result = cursor.read_str(10); - assert!(val.is_err()); -} diff --git a/tests/read_force.rs b/tests/read_force.rs deleted file mode 100644 index 656dd9b..0000000 --- a/tests/read_force.rs +++ /dev/null @@ -1,217 +0,0 @@ -use dh::{Endianess, ForceReadVal}; -use std::io::{Cursor, Read}; - -#[test] -fn read_borrowing() { - let data = [0u8, 1, 2, 3]; - let mut cursor = Cursor::new(data); - - // this just needs to compile - let mut borrowed: &mut dyn Read = &mut cursor; - assert_eq!(borrowed.read_u8(), 0); - assert_eq!(borrowed.read_u8(), 1); - assert_eq!(cursor.read_u8(), 2); - assert_eq!(cursor.read_u8(), 3); -} - -#[test] -fn read_primitive() { - let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; - let mut cursor = Cursor::new(data); - - let val: u8 = cursor.read_ne(); - assert_eq!(val, 0); - - let val: [u8; 3] = cursor.read_ne(); - assert_eq!(val, [1, 2, 3]); - - let val: u16 = cursor.read_be(); - assert_eq!(val, 0x04_05); - - let val: u16 = cursor.read_le(); - assert_eq!(val, 0x07_06); -} - -#[test] -fn read_u8() { - let data = [0u8, 1, 2, 3]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u8(), 0); - assert_eq!(cursor.read_u8(), 1); - assert_eq!(cursor.read_u8(), 2); - assert_eq!(cursor.read_u8(), 3); -} - -#[test] -#[should_panic] -fn read_u8_panic() { - let data = [0u8, 1, 2, 3]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u8(), 0); - assert_eq!(cursor.read_u8(), 1); - assert_eq!(cursor.read_u8(), 2); - assert_eq!(cursor.read_u8(), 3); - - // overflow - cursor.read_u8(); -} - -#[test] -fn read_u16_ne() { - let data = [0x12u8, 0x34, 0x56, 0x78]; - let mut cursor = Cursor::new(data); - - let parts = match cfg!(target_endian = "big") { - true => (0x1234, 0x5678), - false => (0x3412, 0x7856), - }; - - assert_eq!(cursor.read_u16_ne(), parts.0); - assert_eq!(cursor.read_u16_ne(), parts.1); -} - -#[test] -fn read_u16_le() { - let data = [0x12u8, 0x34, 0x56, 0x78]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u16(Endianess::Little), 0x3412); - assert_eq!(cursor.read_u16(Endianess::Little), 0x7856); -} - -#[test] -fn read_u16_be() { - let data = [0x12u8, 0x34, 0x56, 0x78]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u16_be(), 0x1234); - assert_eq!(cursor.read_u16_be(), 0x5678); -} - -#[test] -fn read_u32_ne() { - let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; - let mut cursor = Cursor::new(data); - - let parts = match cfg!(target_endian = "big") { - true => (0x12345678, 0x9ABCDEF0), - false => (0x78563412, 0xF0DEBC9A), - }; - - assert_eq!(cursor.read_u32_ne(), parts.0); - assert_eq!(cursor.read_u32_ne(), parts.1); -} - -#[test] -fn read_u32_le() { - let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u32_le(), 0x78563412); - assert_eq!(cursor.read_u32_le(), 0xF0DEBC9A); -} - -#[test] -fn read_u32_be() { - let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u32_be(), 0x12345678); - assert_eq!(cursor.read_u32_be(), 0x9ABCDEF0); -} - -#[test] -fn read_u64_ne() { - let data = [ - 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, - 0xEF, - ]; - let mut cursor = Cursor::new(data); - - let parts = match cfg!(target_endian = "big") { - true => (0x123456789ABCDEF0, 0x0123456789ABCDEF), - false => (0xF0DEBC9A78563412, 0xEFCDAB8967452301), - }; - - assert_eq!(cursor.read_u64_ne(), parts.0); - assert_eq!(cursor.read_u64_ne(), parts.1); -} - -#[test] -fn read_u64_le() { - let data = [ - 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, - 0xEF, - ]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u64_le(), 0xF0DEBC9A78563412); - assert_eq!(cursor.read_u64_le(), 0xEFCDAB8967452301); -} - -#[test] -fn read_u64_be() { - let data = [ - 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, - 0xEF, - ]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u64_be(), 0x123456789ABCDEF0); - assert_eq!(cursor.read_u64_be(), 0x0123456789ABCDEF); -} - -#[test] -fn read_u128_ne() { - let data = [ - 1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, - ]; - let mut cursor = Cursor::new(data); - - let parts = match cfg!(target_endian = "big") { - true => ( - 0x01000000000000000000000000000000, - 0x01000000000000000000000000000000, - ), - false => ( - 0x00000000000000000000000000000001, - 0x00000000000000000000000000000001, - ), - }; - - assert_eq!(cursor.read_u128_ne(), parts.0); - assert_eq!(cursor.read_u128_ne(), parts.1); -} - -#[test] -fn read_u128_le() { - let data = [ - 1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, - ]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u128_le(), 0x00000000000000000000000000000001); - assert_eq!(cursor.read_u128_le(), 0x00000000000000000000000000000001); -} - -#[test] -fn read_vec() { - let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; - let mut cursor = Cursor::new(data); - - let val: Vec = cursor.read_vec(4); - assert_eq!(val, vec![0, 1, 2, 3]); -} - -#[test] -fn read_str() { - let data = [0x41u8, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]; - let mut cursor = Cursor::new(data); - - let val = cursor.read_str(4); - assert_eq!(val, String::from("ABCD")); -} diff --git a/tests/read_force_be.rs b/tests/read_force_be.rs deleted file mode 100644 index b70f86f..0000000 --- a/tests/read_force_be.rs +++ /dev/null @@ -1 +0,0 @@ -// TODO: add tests diff --git a/tests/read_force_le.rs b/tests/read_force_le.rs deleted file mode 100644 index a1514e4..0000000 --- a/tests/read_force_le.rs +++ /dev/null @@ -1,119 +0,0 @@ -use dh::ForceReadValLe; -use std::io::{Cursor, Read}; - -#[test] -fn read_borrowing() { - let data = [0u8, 1, 2, 3]; - let mut cursor = Cursor::new(data); - - // this just needs to compile - let mut borrowed: &mut dyn Read = &mut cursor; - assert_eq!(borrowed.read_u8(), 0); - assert_eq!(borrowed.read_u8(), 1); - assert_eq!(cursor.read_u8(), 2); - assert_eq!(cursor.read_u8(), 3); -} - -#[test] -fn read_primitive() { - let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; - let mut cursor = Cursor::new(data); - - let val: u8 = cursor.read_le(); - assert_eq!(val, 0); - - let val: [u8; 3] = cursor.read_le(); - assert_eq!(val, [1, 2, 3]); - - let val: u16 = cursor.read_le(); - assert_eq!(val, 0x05_04); - - let val: u16 = cursor.read_le(); - assert_eq!(val, 0x07_06); -} - -#[test] -fn read_u8() { - let data = [0u8, 1, 2, 3]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u8(), 0); - assert_eq!(cursor.read_u8(), 1); - assert_eq!(cursor.read_u8(), 2); - assert_eq!(cursor.read_u8(), 3); -} - -#[test] -#[should_panic] -fn read_u8_panic() { - let data = [0u8, 1, 2, 3]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u8(), 0); - assert_eq!(cursor.read_u8(), 1); - assert_eq!(cursor.read_u8(), 2); - assert_eq!(cursor.read_u8(), 3); - - // overflow - cursor.read_u8(); -} - -#[test] -fn read_u16_le() { - let data = [0x12u8, 0x34, 0x56, 0x78]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u16(), 0x3412); - assert_eq!(cursor.read_u16(), 0x7856); -} - -#[test] -fn read_u32_le() { - let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u32(), 0x78563412); - assert_eq!(cursor.read_u32(), 0xF0DEBC9A); -} - -#[test] -fn read_u64_le() { - let data = [ - 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, - 0xEF, - ]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u64(), 0xF0DEBC9A78563412); - assert_eq!(cursor.read_u64(), 0xEFCDAB8967452301); -} - -#[test] -fn read_u128_le() { - let data = [ - 1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, - ]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u128(), 0x00000000000000000000000000000001); - assert_eq!(cursor.read_u128(), 0x00000000000000000000000000000001); -} - -#[test] -fn read_vec() { - let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; - let mut cursor = Cursor::new(data); - - let val: Vec = cursor.read_vec(4); - assert_eq!(val, vec![0, 1, 2, 3]); -} - -#[test] -fn read_str() { - let data = [0x41u8, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]; - let mut cursor = Cursor::new(data); - - let val = cursor.read_str(4); - assert_eq!(val, String::from("ABCD")); -} diff --git a/tests/read_force_ne.rs b/tests/read_force_ne.rs deleted file mode 100644 index b70f86f..0000000 --- a/tests/read_force_ne.rs +++ /dev/null @@ -1 +0,0 @@ -// TODO: add tests diff --git a/tests/read_le.rs b/tests/read_le.rs deleted file mode 100644 index 7379d28..0000000 --- a/tests/read_le.rs +++ /dev/null @@ -1,142 +0,0 @@ -use dh::{ReadValLe, Result}; -use std::io::{Cursor, Read}; - -#[test] -fn read_borrowing() { - let data = [0u8, 1, 2, 3]; - let mut cursor = Cursor::new(data); - - // this just needs to compile - let mut borrowed: &mut dyn Read = &mut cursor; - assert_eq!(borrowed.read_u8().unwrap(), 0); - assert_eq!(borrowed.read_u8().unwrap(), 1); - assert_eq!(cursor.read_u8().unwrap(), 2); - assert_eq!(cursor.read_u8().unwrap(), 3); -} - -#[test] -fn read_primitive() { - let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; - let mut cursor = Cursor::new(data); - - let val: u8 = cursor.read_le().unwrap(); - assert_eq!(val, 0); - - let val: [u8; 3] = cursor.read_le().unwrap(); - assert_eq!(val, [1, 2, 3]); - - let val: u16 = cursor.read_le().unwrap(); - assert_eq!(val, 0x05_04); - - let val: u16 = cursor.read_le().unwrap(); - assert_eq!(val, 0x07_06); - - // overflow - let val: Result = cursor.read_le(); - assert!(val.is_err()); -} - -#[test] -fn read_u8() { - let data = [0u8, 1, 2, 3]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u8().unwrap(), 0); - assert_eq!(cursor.read_u8().unwrap(), 1); - assert_eq!(cursor.read_u8().unwrap(), 2); - assert_eq!(cursor.read_u8().unwrap(), 3); - - // overflow - let val = cursor.read_u8(); - assert!(val.is_err()); -} - -#[test] -fn read_u16_le() { - let data = [0x12u8, 0x34, 0x56, 0x78]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u16().unwrap(), 0x3412); - assert_eq!(cursor.read_u16().unwrap(), 0x7856); - - // overflow - let val = cursor.read_u16(); - assert!(val.is_err()); -} - -#[test] -fn read_u32_le() { - let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u32().unwrap(), 0x78563412); - assert_eq!(cursor.read_u32().unwrap(), 0xF0DEBC9A); - - // overflow - let val = cursor.read_u32(); - assert!(val.is_err()); -} - -#[test] -fn read_u64_le() { - let data = [ - 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, - 0xEF, - ]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u64().unwrap(), 0xF0DEBC9A78563412); - assert_eq!(cursor.read_u64().unwrap(), 0xEFCDAB8967452301); - - // overflow - let val = cursor.read_u64(); - assert!(val.is_err()); -} - -#[test] -fn read_u128_le() { - let data = [ - 1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, - ]; - let mut cursor = Cursor::new(data); - - assert_eq!( - cursor.read_u128().unwrap(), - 0x00000000000000000000000000000001 - ); - assert_eq!( - cursor.read_u128().unwrap(), - 0x00000000000000000000000000000001 - ); - - // overflow - let val = cursor.read_u128(); - assert!(val.is_err()); -} - -#[test] -fn read_vec() { - let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; - let mut cursor = Cursor::new(data); - - let val: Vec = cursor.read_vec(4).unwrap(); - assert_eq!(val, vec![0, 1, 2, 3]); - - // overflow - let val: Result> = cursor.read_vec(10); - assert!(val.is_err()); -} - -#[test] -fn read_str() { - let data = [0x41u8, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]; - let mut cursor = Cursor::new(data); - - let val = cursor.read_str(4).unwrap(); - assert_eq!(val, String::from("ABCD")); - - // overflow - let val: Result = cursor.read_str(10); - assert!(val.is_err()); -} diff --git a/tests/read_ne.rs b/tests/read_ne.rs deleted file mode 100644 index 2a46bf7..0000000 --- a/tests/read_ne.rs +++ /dev/null @@ -1,174 +0,0 @@ -use dh::{ReadValNe, Result}; -use std::io::{Cursor, Read}; - -#[test] -fn read_borrowing() { - let data = [0u8, 1, 2, 3]; - let mut cursor = Cursor::new(data); - - // this just needs to compile - let mut borrowed: &mut dyn Read = &mut cursor; - assert_eq!(borrowed.read_u8().unwrap(), 0); - assert_eq!(borrowed.read_u8().unwrap(), 1); - assert_eq!(cursor.read_u8().unwrap(), 2); - assert_eq!(cursor.read_u8().unwrap(), 3); -} - -#[test] -fn read_primitive() { - let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; - let mut cursor = Cursor::new(data); - - let val: u8 = cursor.read_ne().unwrap(); - assert_eq!(val, 0); - - let val: [u8; 3] = cursor.read_ne().unwrap(); - assert_eq!(val, [1, 2, 3]); - - let val: u16 = cursor.read_ne().unwrap(); - assert_eq!( - val, - match cfg!(target_endian = "big") { - true => 0x04_05, - false => 0x05_04, - } - ); - - let val: u16 = cursor.read_ne().unwrap(); - assert_eq!( - val, - match cfg!(target_endian = "big") { - true => 0x06_07, - false => 0x07_06, - } - ); - - // overflow - let val: Result = cursor.read_ne(); - assert!(val.is_err()); -} - -#[test] -fn read_u8() { - let data = [0u8, 1, 2, 3]; - let mut cursor = Cursor::new(data); - - assert_eq!(cursor.read_u8().unwrap(), 0); - assert_eq!(cursor.read_u8().unwrap(), 1); - assert_eq!(cursor.read_u8().unwrap(), 2); - assert_eq!(cursor.read_u8().unwrap(), 3); - - // overflow - let val = cursor.read_u8(); - assert!(val.is_err()); -} - -#[test] -fn read_u16_ne() { - let data = [0x12u8, 0x34, 0x56, 0x78]; - let mut cursor = Cursor::new(data); - - let parts = match cfg!(target_endian = "big") { - true => (0x1234, 0x5678), - false => (0x3412, 0x7856), - }; - - assert_eq!(cursor.read_u16().unwrap(), parts.0); - assert_eq!(cursor.read_u16().unwrap(), parts.1); - - // overflow - let val = cursor.read_u16(); - assert!(val.is_err()); -} - -#[test] -fn read_u32_ne() { - let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; - let mut cursor = Cursor::new(data); - - let parts = match cfg!(target_endian = "big") { - true => (0x12345678, 0x9ABCDEF0), - false => (0x78563412, 0xF0DEBC9A), - }; - - assert_eq!(cursor.read_u32().unwrap(), parts.0); - assert_eq!(cursor.read_u32().unwrap(), parts.1); - - // overflow - let val = cursor.read_u32(); - assert!(val.is_err()); -} - -#[test] -fn read_u64_ne() { - let data = [ - 0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, - 0xEF, - ]; - let mut cursor = Cursor::new(data); - - let parts = match cfg!(target_endian = "big") { - true => (0x123456789ABCDEF0, 0x0123456789ABCDEF), - false => (0xF0DEBC9A78563412, 0xEFCDAB8967452301), - }; - - assert_eq!(cursor.read_u64().unwrap(), parts.0); - assert_eq!(cursor.read_u64().unwrap(), parts.1); - - // overflow - let val = cursor.read_u64(); - assert!(val.is_err()); -} - -#[test] -fn read_u128_ne() { - let data = [ - 1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, - ]; - let mut cursor = Cursor::new(data); - - let parts = match cfg!(target_endian = "big") { - true => ( - 0x01000000000000000000000000000000, - 0x01000000000000000000000000000000, - ), - false => ( - 0x00000000000000000000000000000001, - 0x00000000000000000000000000000001, - ), - }; - - assert_eq!(cursor.read_u128().unwrap(), parts.0); - assert_eq!(cursor.read_u128().unwrap(), parts.1); - - // overflow - let val = cursor.read_u128(); - assert!(val.is_err()); -} - -#[test] -fn read_vec() { - let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; - let mut cursor = Cursor::new(data); - - let val: Vec = cursor.read_vec(4).unwrap(); - assert_eq!(val, vec![0, 1, 2, 3]); - - // overflow - let val: Result> = cursor.read_vec(10); - assert!(val.is_err()); -} - -#[test] -fn read_str() { - let data = [0x41u8, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]; - let mut cursor = Cursor::new(data); - - let val = cursor.read_str(4).unwrap(); - assert_eq!(val, String::from("ABCD")); - - // overflow - let val: Result = cursor.read_str(10); - assert!(val.is_err()); -} From 535f4091e21e79cdda9a35a1c41a859b7eac8db3 Mon Sep 17 00:00:00 2001 From: Le0X8 <84378319+Le0X8@users.noreply.github.com> Date: Mon, 18 Aug 2025 16:09:24 +0200 Subject: [PATCH 6/7] feat: added write methods --- src/dynamic.rs | 8 ++ src/lib.rs | 2 + src/primitive.rs | 50 ++++++++ src/read/at.rs | 8 +- src/types.rs | 6 +- src/write.rs | 2 + src/write/at.rs | 160 ++++++++++++++++++++++++ src/write/val.rs | 146 ++++++++++++++++++++++ tests/write.rs | 300 +++++++++++++++++++++++++++++++++++++++++++++ tests/write_at.rs | 301 ++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 978 insertions(+), 5 deletions(-) create mode 100644 src/write.rs create mode 100644 src/write/at.rs create mode 100644 src/write/val.rs create mode 100644 tests/write.rs create mode 100644 tests/write_at.rs diff --git a/src/dynamic.rs b/src/dynamic.rs index 96e6d8e..9d81ede 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -4,16 +4,24 @@ use std::io::{Error, ErrorKind::InvalidData}; // marker trait pub trait Dynamic: Sized { fn from_bytes(bytes: Vec) -> Result; + #[allow(clippy::wrong_self_convention)] + fn into_bytes(&self) -> Result<&[u8]>; } impl Dynamic for Vec { fn from_bytes(bytes: Vec) -> Result { Ok(bytes) } + fn into_bytes(&self) -> Result<&[u8]> { + Ok(self) + } } impl Dynamic for String { fn from_bytes(bytes: Vec) -> Result { String::from_utf8(bytes).map_err(|_| Error::new(InvalidData, "Invalid UTF-8")) } + fn into_bytes(&self) -> Result<&[u8]> { + Ok(self.as_bytes()) + } } diff --git a/src/lib.rs b/src/lib.rs index acc7d61..2742e99 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,9 +3,11 @@ mod error; mod primitive; mod read; mod types; +mod write; pub use dynamic::Dynamic; pub use error::{Error, Result}; pub use primitive::Primitive; pub use read::{at::ReadValAt, val::ReadVal}; pub use types::*; +pub use write::{at::WriteValAt, val::WriteVal}; diff --git a/src/primitive.rs b/src/primitive.rs index 83fa27a..4b50528 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -5,6 +5,10 @@ pub trait Primitive { fn from_ne_bytes(bytes: [u8; S]) -> Self; fn from_le_bytes(bytes: [u8; S]) -> Self; fn from_be_bytes(bytes: [u8; S]) -> Self; + + fn to_ne_bytes(self) -> [u8; S]; + fn to_le_bytes(self) -> [u8; S]; + fn to_be_bytes(self) -> [u8; S]; } // trait implementation macro @@ -24,6 +28,18 @@ macro_rules! impl_primitive { fn from_be_bytes(bytes: [u8; $type_upper]) -> $type { <$type>::from_be_bytes(bytes) } + + fn to_ne_bytes(self) -> [u8; $type_upper] { + self.to_ne_bytes() + } + + fn to_le_bytes(self) -> [u8; $type_upper] { + self.to_le_bytes() + } + + fn to_be_bytes(self) -> [u8; $type_upper] { + self.to_be_bytes() + } } }; } @@ -61,6 +77,18 @@ impl Primitive<[u8; S], S> for [u8; S] { fn from_be_bytes(bytes: [u8; S]) -> [u8; S] { bytes } + + fn to_ne_bytes(self) -> [u8; S] { + self + } + + fn to_le_bytes(self) -> [u8; S] { + self + } + + fn to_be_bytes(self) -> [u8; S] { + self + } } impl Primitive for bool { fn from_ne_bytes(bytes: [u8; 1]) -> bool { @@ -74,9 +102,31 @@ impl Primitive for bool { fn from_be_bytes(bytes: [u8; 1]) -> bool { bytes[0] & 1 == 1 } + + fn to_ne_bytes(self) -> [u8; 1] { + [if self { 1 } else { 0 }] + } + + fn to_le_bytes(self) -> [u8; 1] { + [if self { 1 } else { 0 }] + } + + fn to_be_bytes(self) -> [u8; 1] { + [if self { 1 } else { 0 }] + } } impl Primitive<(), 0> for () { fn from_ne_bytes(_: [u8; 0]) {} fn from_le_bytes(_: [u8; 0]) {} fn from_be_bytes(_: [u8; 0]) {} + + fn to_ne_bytes(self) -> [u8; 0] { + [] + } + fn to_le_bytes(self) -> [u8; 0] { + [] + } + fn to_be_bytes(self) -> [u8; 0] { + [] + } } diff --git a/src/read/at.rs b/src/read/at.rs index 6063d6a..baf22d7 100644 --- a/src/read/at.rs +++ b/src/read/at.rs @@ -51,7 +51,7 @@ macro_rules! read_dynamic_typed { fn $fn_name(&mut self, pos: usize, len: usize) -> Result<$return_type> { let pos_before = self.stream_position()?; self.seek(SeekPos(pos as u64))?; - let result = self.read_dynamic(len); + let result = self.read_dynamic_at(len); self.seek(SeekPos(pos_before))?; result } @@ -62,7 +62,7 @@ pub(super) use read_dynamic_typed; pub(super) use read_primitive; pub(super) use read_primitive_typed; -/// Extension trait for `Read` that provides methods for reading supported value types. +/// Extension trait for `Read + Seek` that provides methods for reading supported value types. /// /// **Note:** do not borrow this as `&mut dyn ReadValAt`, as this would not compile. Use `&mut dyn dh::ReadSeek` instead. pub trait ReadValAt: Read + Seek { @@ -146,8 +146,8 @@ pub trait ReadValAt: Read + Seek { /// Reads a dynamic value from the reader. /// - /// It's recommended to use the typed wrappers like `read_vec` instead of this method for cleaner code. - fn read_dynamic(&mut self, len: usize) -> Result { + /// It's recommended to use the typed wrappers like `read_vec_at` instead of this method for cleaner code. + fn read_dynamic_at(&mut self, len: usize) -> Result { let mut buf = vec![0; len]; self.read_exact(&mut buf)?; T::from_bytes(buf) diff --git a/src/types.rs b/src/types.rs index 5a15267..dceae7b 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,4 +1,4 @@ -use std::io::{Read, Seek}; +use std::io::{Read, Seek, Write}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Endianess { @@ -10,3 +10,7 @@ pub enum Endianess { /// Because you can't do `dyn Read + Seek` in Rust, this trait is used to combine both traits. pub trait ReadSeek: Read + Seek {} impl ReadSeek for T {} + +/// Because you can't do `dyn Read + Write` in Rust, this trait is used to combine both traits. +pub trait WriteSeek: Write + Seek {} +impl WriteSeek for T {} diff --git a/src/write.rs b/src/write.rs new file mode 100644 index 0000000..af2c080 --- /dev/null +++ b/src/write.rs @@ -0,0 +1,2 @@ +pub(crate) mod at; +pub(crate) mod val; diff --git a/src/write/at.rs b/src/write/at.rs new file mode 100644 index 0000000..fb9e8b6 --- /dev/null +++ b/src/write/at.rs @@ -0,0 +1,160 @@ +use crate::{Endianess, Primitive, Result}; +use std::io::{Seek, SeekFrom::Start as SeekPos, Write}; + +macro_rules! write_primitive { + ($fn_name:ident, $write_fn_name:ident) => { + /// Writes a primitive value to the writer using the specified byte order. + /// + /// It's recommended to use the typed wrappers like `write_u8_at` instead of this method for cleaner code. + fn $fn_name, U, const S: usize>( + &mut self, + pos: usize, + data: T, + ) -> Result<()> { + let pos_before = self.stream_position()?; + self.seek(SeekPos(pos as u64))?; + + let response = self.write_all(&data.$write_fn_name()); + + self.seek(SeekPos(pos_before))?; + response + } + }; +} + +macro_rules! write_primitive_typed { + ($fn_name:ident, $return_type:ty, $write_fn:ident) => { + /// Typed wrapper around `write_ne_at`, `write_le_at`, or `write_be_at`. + fn $fn_name(&mut self, pos: usize, data: $return_type) -> Result<()> { + self.$write_fn(pos, data) + } + }; + + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `write_ne_at`, `write_le_at`, or `write_be_at`. + fn $fn_name(&mut self, pos: usize, endianess: Endianess, data: $return_type) -> Result<()> { + use Endianess::*; + match endianess { + Little => self.write_le_at(pos, data), + Big => self.write_be_at(pos, data), + Native => self.write_ne_at(pos, data), + } + } + }; + + ($fn_name:ident, $return_type:ty, $write_fn:ident, $const:ident) => { + /// Typed wrapper around `write_ne_at`, `write_le_at`, or `write_be_at`. + fn $fn_name(&mut self, pos: usize, data: $return_type) -> Result<()> { + self.$write_fn::<$return_type, $return_type, $const>(pos, data) + } + }; +} + +macro_rules! write_dynamic_typed { + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `write_dynamic_at`. + fn $fn_name(&mut self, pos: usize, data: $return_type) -> Result<()> { + let pos_before = self.stream_position()?; + self.seek(SeekPos(pos as u64))?; + let response = self.write_dynamic_at(data); + self.seek(SeekPos(pos_before))?; + response + } + }; +} + +pub(super) use write_dynamic_typed; +pub(super) use write_primitive; +pub(super) use write_primitive_typed; + +/// Extension trait for `Write + Seek` that provides methods for writeing supported value types. +/// +/// **Note:** do not borrow this as `&mut dyn WriteValAt`, as this would not compile. Use `&mut dyn dh::WriteSeek` instead. +pub trait WriteValAt: Write + Seek { + write_primitive_typed!(write_u8_at, u8, write_ne_at); + + write_primitive_typed!(write_u16_at, u16); + write_primitive_typed!(write_u32_at, u32); + write_primitive_typed!(write_u64_at, u64); + write_primitive_typed!(write_u128_at, u128); + write_primitive_typed!(write_usize_at, usize); + + write_primitive_typed!(write_i8_at, i8, write_ne_at); + + write_primitive_typed!(write_i16_at, i16); + write_primitive_typed!(write_i32_at, i32); + write_primitive_typed!(write_i64_at, i64); + write_primitive_typed!(write_i128_at, i128); + write_primitive_typed!(write_isize_at, isize); + + write_primitive_typed!(write_f32_at, f32); + write_primitive_typed!(write_f64_at, f64); + + write_primitive_typed!(write_u8_array_at, [u8; S], write_ne_at, S); + + write_primitive_typed!(write_bool_at, bool, write_ne_at); + + write_dynamic_typed!(write_vec_at, Vec); + write_dynamic_typed!(write_str_at, String); + + write_primitive!(write_ne_at, to_ne_bytes); + write_primitive!(write_le_at, to_le_bytes); + write_primitive!(write_be_at, to_be_bytes); + + write_primitive_typed!(write_u16_ne_at, u16, write_ne_at); + write_primitive_typed!(write_u16_le_at, u16, write_le_at); + write_primitive_typed!(write_u16_be_at, u16, write_be_at); + + write_primitive_typed!(write_u32_ne_at, u32, write_ne_at); + write_primitive_typed!(write_u32_le_at, u32, write_le_at); + write_primitive_typed!(write_u32_be_at, u32, write_be_at); + + write_primitive_typed!(write_u64_ne_at, u64, write_ne_at); + write_primitive_typed!(write_u64_le_at, u64, write_le_at); + write_primitive_typed!(write_u64_be_at, u64, write_be_at); + + write_primitive_typed!(write_u128_ne_at, u128, write_ne_at); + write_primitive_typed!(write_u128_le_at, u128, write_le_at); + write_primitive_typed!(write_u128_be_at, u128, write_be_at); + + write_primitive_typed!(write_usize_ne_at, usize, write_ne_at); + write_primitive_typed!(write_usize_le_at, usize, write_le_at); + write_primitive_typed!(write_usize_be_at, usize, write_be_at); + + write_primitive_typed!(write_i16_ne_at, i16, write_ne_at); + write_primitive_typed!(write_i16_le_at, i16, write_le_at); + write_primitive_typed!(write_i16_be_at, i16, write_be_at); + + write_primitive_typed!(write_i32_ne_at, i32, write_ne_at); + write_primitive_typed!(write_i32_le_at, i32, write_le_at); + write_primitive_typed!(write_i32_be_at, i32, write_be_at); + + write_primitive_typed!(write_i64_ne_at, i64, write_ne_at); + write_primitive_typed!(write_i64_le_at, i64, write_le_at); + write_primitive_typed!(write_i64_be_at, i64, write_be_at); + + write_primitive_typed!(write_i128_ne_at, i128, write_ne_at); + write_primitive_typed!(write_i128_le_at, i128, write_le_at); + write_primitive_typed!(write_i128_be_at, i128, write_be_at); + + write_primitive_typed!(write_isize_ne_at, isize, write_ne_at); + write_primitive_typed!(write_isize_le_at, isize, write_le_at); + write_primitive_typed!(write_isize_be_at, isize, write_be_at); + + write_primitive_typed!(write_f32_ne_at, f32, write_ne_at); + write_primitive_typed!(write_f32_le_at, f32, write_le_at); + write_primitive_typed!(write_f32_be_at, f32, write_be_at); + + write_primitive_typed!(write_f64_ne_at, f64, write_ne_at); + write_primitive_typed!(write_f64_le_at, f64, write_le_at); + write_primitive_typed!(write_f64_be_at, f64, write_be_at); + + /// Writes a dynamic value to the writeer. + /// + /// It's recommended to use the typed wrappers like `write_vec_at` instead of this method for cleaner code. + fn write_dynamic_at(&mut self, data: T) -> Result<()> { + self.write_all(data.into_bytes()?) + } +} + +impl WriteValAt for T {} diff --git a/src/write/val.rs b/src/write/val.rs new file mode 100644 index 0000000..c2e0ba4 --- /dev/null +++ b/src/write/val.rs @@ -0,0 +1,146 @@ +use crate::{Endianess, Primitive, Result}; +use std::io::Write; + +macro_rules! write_primitive { + ($fn_name:ident, $write_fn_name:ident) => { + /// Writes a primitive value to the writer using the specified byte order. + /// + /// It's recommended to use the typed wrappers like `write_u8` instead of this method for cleaner code. + fn $fn_name, U, const S: usize>(&mut self, data: T) -> Result<()> { + self.write_all(&data.$write_fn_name()) + } + }; +} + +macro_rules! write_primitive_typed { + ($fn_name:ident, $return_type:ty, $write_fn:ident) => { + /// Typed wrapper around `write_ne`, `write_le`, or `write_be`. + fn $fn_name(&mut self, data: $return_type) -> Result<()> { + self.$write_fn(data) + } + }; + + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `write_ne`, `write_le`, or `write_be`. + fn $fn_name(&mut self, endianess: Endianess, data: $return_type) -> Result<()> { + use Endianess::*; + match endianess { + Little => self.write_le(data), + Big => self.write_be(data), + Native => self.write_ne(data), + } + } + }; + + ($fn_name:ident, $return_type:ty, $write_fn:ident, $const:ident) => { + /// Typed wrapper around `write_ne`, `write_le`, or `write_be`. + fn $fn_name(&mut self, data: $return_type) -> Result<()> { + self.$write_fn::<$return_type, $return_type, $const>(data) + } + }; +} + +macro_rules! write_dynamic_typed { + ($fn_name:ident, $return_type:ty) => { + /// Typed wrapper around `write_dynamic`. + fn $fn_name(&mut self, data: $return_type) -> Result<()> { + self.write_dynamic(data) + } + }; +} + +pub(super) use write_dynamic_typed; +pub(super) use write_primitive; +pub(super) use write_primitive_typed; + +/// Extension trait for `Write` that provides methods for writeing supported value types. +/// +/// **Note:** do not borrow this as `&mut dyn WriteVal`, as this would not compile. Use `&mut dyn Write` instead. +pub trait WriteVal: Write { + write_primitive_typed!(write_u8, u8, write_ne); + + write_primitive_typed!(write_u16, u16); + write_primitive_typed!(write_u32, u32); + write_primitive_typed!(write_u64, u64); + write_primitive_typed!(write_u128, u128); + write_primitive_typed!(write_usize, usize); + + write_primitive_typed!(write_i8, i8, write_ne); + + write_primitive_typed!(write_i16, i16); + write_primitive_typed!(write_i32, i32); + write_primitive_typed!(write_i64, i64); + write_primitive_typed!(write_i128, i128); + write_primitive_typed!(write_isize, isize); + + write_primitive_typed!(write_f32, f32); + write_primitive_typed!(write_f64, f64); + + write_primitive_typed!(write_u8_array, [u8; S], write_ne, S); + + write_primitive_typed!(write_bool, bool, write_ne); + + write_dynamic_typed!(write_vec, Vec); + write_dynamic_typed!(write_str, String); + + write_primitive!(write_ne, to_ne_bytes); + write_primitive!(write_le, to_le_bytes); + write_primitive!(write_be, to_be_bytes); + + write_primitive_typed!(write_u16_ne, u16, write_ne); + write_primitive_typed!(write_u16_le, u16, write_le); + write_primitive_typed!(write_u16_be, u16, write_be); + + write_primitive_typed!(write_u32_ne, u32, write_ne); + write_primitive_typed!(write_u32_le, u32, write_le); + write_primitive_typed!(write_u32_be, u32, write_be); + + write_primitive_typed!(write_u64_ne, u64, write_ne); + write_primitive_typed!(write_u64_le, u64, write_le); + write_primitive_typed!(write_u64_be, u64, write_be); + + write_primitive_typed!(write_u128_ne, u128, write_ne); + write_primitive_typed!(write_u128_le, u128, write_le); + write_primitive_typed!(write_u128_be, u128, write_be); + + write_primitive_typed!(write_usize_ne, usize, write_ne); + write_primitive_typed!(write_usize_le, usize, write_le); + write_primitive_typed!(write_usize_be, usize, write_be); + + write_primitive_typed!(write_i16_ne, i16, write_ne); + write_primitive_typed!(write_i16_le, i16, write_le); + write_primitive_typed!(write_i16_be, i16, write_be); + + write_primitive_typed!(write_i32_ne, i32, write_ne); + write_primitive_typed!(write_i32_le, i32, write_le); + write_primitive_typed!(write_i32_be, i32, write_be); + + write_primitive_typed!(write_i64_ne, i64, write_ne); + write_primitive_typed!(write_i64_le, i64, write_le); + write_primitive_typed!(write_i64_be, i64, write_be); + + write_primitive_typed!(write_i128_ne, i128, write_ne); + write_primitive_typed!(write_i128_le, i128, write_le); + write_primitive_typed!(write_i128_be, i128, write_be); + + write_primitive_typed!(write_isize_ne, isize, write_ne); + write_primitive_typed!(write_isize_le, isize, write_le); + write_primitive_typed!(write_isize_be, isize, write_be); + + write_primitive_typed!(write_f32_ne, f32, write_ne); + write_primitive_typed!(write_f32_le, f32, write_le); + write_primitive_typed!(write_f32_be, f32, write_be); + + write_primitive_typed!(write_f64_ne, f64, write_ne); + write_primitive_typed!(write_f64_le, f64, write_le); + write_primitive_typed!(write_f64_be, f64, write_be); + + /// Writes a dynamic value to the writeer. + /// + /// It's recommended to use the typed wrappers like `write_vec` instead of this method for cleaner code. + fn write_dynamic(&mut self, data: T) -> Result<()> { + self.write_all(data.into_bytes()?) + } +} + +impl WriteVal for T {} diff --git a/tests/write.rs b/tests/write.rs new file mode 100644 index 0000000..c3431d3 --- /dev/null +++ b/tests/write.rs @@ -0,0 +1,300 @@ +use dh::{Endianess::Little, WriteVal}; +use std::io::{Cursor, Write}; + +#[test] +fn write_borrowing() { + let mut cursor = Cursor::new([0u8; 4]); + + // this just needs to compile + let mut borrowed: &mut dyn Write = &mut cursor; + + borrowed.write_u8(0).unwrap(); + borrowed.write_u8(1).unwrap(); + borrowed.write_u8(2).unwrap(); + borrowed.write_u8(3).unwrap(); + + assert_eq!(cursor.get_ref(), &[0, 1, 2, 3]); +} + +#[test] +fn write_primitive() { + let mut cursor = Cursor::new([0u8; 8]); + + cursor.write_ne(0u8).unwrap(); + cursor.write_ne([1u8, 2, 3]).unwrap(); + cursor.write_be(0x04_05u16).unwrap(); + cursor.write_le(0x07_06u16).unwrap(); + + assert_eq!(cursor.get_ref(), &[0, 1, 2, 3, 4, 5, 6, 7]); + + // overflow + let val = cursor.write_ne(0u8); + assert!(val.is_err()); +} + +#[test] +fn write_u8() { + let mut cursor = Cursor::new([0u8; 4]); + + cursor.write_u8(0).unwrap(); + cursor.write_u8(1).unwrap(); + cursor.write_u8(2).unwrap(); + cursor.write_u8(3).unwrap(); + + assert_eq!(cursor.get_ref(), &[0, 1, 2, 3]); + + // overflow + let val = cursor.write_u8(0); + assert!(val.is_err()); +} + +#[test] +fn write_u16_ne() { + let mut cursor = Cursor::new([0u8; 4]); + + let parts = match cfg!(target_endian = "big") { + true => (0x1234, 0x5678), + false => (0x3412, 0x7856), + }; + + cursor.write_u16_ne(parts.0).unwrap(); + cursor.write_u16_ne(parts.1).unwrap(); + + assert_eq!(cursor.get_ref(), &[0x12, 0x34, 0x56, 0x78]); + + // overflow + let val = cursor.write_u16_ne(0); + assert!(val.is_err()); +} + +#[test] +fn write_u16_le() { + let mut cursor = Cursor::new([0u8; 4]); + + cursor.write_u16(Little, 0x3412).unwrap(); + cursor.write_u16(Little, 0x7856).unwrap(); + + assert_eq!(cursor.get_ref(), &[0x12, 0x34, 0x56, 0x78]); + + // overflow + let val = cursor.write_u16_le(0); + assert!(val.is_err()); +} + +#[test] +fn write_u16_be() { + let mut cursor = Cursor::new([0u8; 4]); + + cursor.write_u16_be(0x1234).unwrap(); + cursor.write_u16_be(0x5678).unwrap(); + + assert_eq!(cursor.get_ref(), &[0x12, 0x34, 0x56, 0x78]); + + // overflow + let val = cursor.write_u16_be(0); + assert!(val.is_err()); +} + +#[test] +fn write_u32_ne() { + let mut cursor = Cursor::new([0u8; 8]); + + let parts = match cfg!(target_endian = "big") { + true => (0x12345678, 0x9ABCDEF0), + false => (0x78563412, 0xF0DEBC9A), + }; + + cursor.write_u32_ne(parts.0).unwrap(); + cursor.write_u32_ne(parts.1).unwrap(); + + assert_eq!( + cursor.get_ref(), + &[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0] + ); + + // overflow + let val = cursor.write_u32_ne(0); + assert!(val.is_err()); +} + +#[test] +fn write_u32_le() { + let mut cursor = Cursor::new([0u8; 8]); + + cursor.write_u32_le(0x78563412).unwrap(); + cursor.write_u32_le(0xF0DEBC9A).unwrap(); + + assert_eq!( + cursor.get_ref(), + &[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0] + ); + + // overflow + let val = cursor.write_u32_le(0); + assert!(val.is_err()); +} + +#[test] +fn write_u32_be() { + let mut cursor = Cursor::new([0u8; 8]); + + cursor.write_u32_be(0x12345678).unwrap(); + cursor.write_u32_be(0x9ABCDEF0).unwrap(); + + assert_eq!( + cursor.get_ref(), + &[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0] + ); + + // overflow + let val = cursor.write_u32_be(0); + assert!(val.is_err()); +} + +#[test] +fn write_u64_ne() { + let mut cursor = Cursor::new([0u8; 16]); + + let parts = match cfg!(target_endian = "big") { + true => (0x123456789ABCDEF0, 0x0123456789ABCDEF), + false => (0xF0DEBC9A78563412, 0xEFCDAB8967452301), + }; + + cursor.write_u64_ne(parts.0).unwrap(); + cursor.write_u64_ne(parts.1).unwrap(); + + assert_eq!( + cursor.get_ref(), + &[ + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, + 0xCD, 0xEF + ] + ); + + // overflow + let val = cursor.write_u64_ne(0); + assert!(val.is_err()); +} + +#[test] +fn write_u64_le() { + let mut cursor = Cursor::new([0u8; 16]); + + cursor.write_u64_le(0xF0DEBC9A78563412).unwrap(); + cursor.write_u64_le(0xEFCDAB8967452301).unwrap(); + + assert_eq!( + cursor.get_ref(), + &[ + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, + 0xCD, 0xEF, + ] + ); + + // overflow + let val = cursor.write_u64_le(0); + assert!(val.is_err()); +} + +#[test] +fn write_u64_be() { + let mut cursor = Cursor::new([0u8; 16]); + + cursor.write_u64_be(0x123456789ABCDEF0).unwrap(); + cursor.write_u64_be(0x0123456789ABCDEF).unwrap(); + + assert_eq!( + cursor.get_ref(), + &[ + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, + 0xCD, 0xEF, + ] + ); + + // overflow + let val = cursor.write_u64_be(0); + assert!(val.is_err()); +} + +#[test] +fn write_u128_ne() { + let mut cursor = Cursor::new([0u8; 32]); + + let parts = match cfg!(target_endian = "big") { + true => ( + 0x01000000000000000000000000000000, + 0x01000000000000000000000000000000, + ), + false => ( + 0x00000000000000000000000000000001, + 0x00000000000000000000000000000001, + ), + }; + + cursor.write_u128_ne(parts.0).unwrap(); + cursor.write_u128_ne(parts.1).unwrap(); + + assert_eq!( + cursor.get_ref(), + &[ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ] + ); + + // overflow + let val = cursor.write_u128_ne(0); + assert!(val.is_err()); +} + +#[test] +fn write_u128_le() { + let mut cursor = Cursor::new([0u8; 32]); + + cursor + .write_u128_le(0x00000000000000000000000000000001) + .unwrap(); + cursor + .write_u128_le(0x00000000000000000000000000000001) + .unwrap(); + + assert_eq!( + cursor.get_ref(), + &[ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ] + ); + + // overflow + let val = cursor.write_u128_le(0); + assert!(val.is_err()); +} + +// TODO: Implement write_u128_be for all + +#[test] +fn write_vec() { + let mut cursor = Cursor::new([0u8; 8]); + + cursor.write_vec(vec![0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); + + assert_eq!(cursor.get_ref(), &[0, 1, 2, 3, 4, 5, 6, 7]); + + // overflow + let val = cursor.write_vec(vec![0]); + assert!(val.is_err()); +} + +#[test] +fn write_str() { + let mut cursor = Cursor::new([0u8; 8]); + + cursor.write_str("ABCDEFGH".to_string()).unwrap(); + + assert_eq!(cursor.get_ref(), b"ABCDEFGH"); + + // overflow + let val = cursor.write_str("A".to_string()); + assert!(val.is_err()); +} diff --git a/tests/write_at.rs b/tests/write_at.rs new file mode 100644 index 0000000..923ff68 --- /dev/null +++ b/tests/write_at.rs @@ -0,0 +1,301 @@ +use dh::{Endianess::Little, WriteSeek, WriteVal, WriteValAt}; +use std::io::Cursor; + +#[test] +fn write_at_borrowing() { + let mut cursor = Cursor::new([0u8; 4]); + + // this just needs to compile + let mut borrowed: &mut dyn WriteSeek = &mut cursor; + + borrowed.write_u8(0).unwrap(); + borrowed.write_u8(1).unwrap(); + borrowed.write_u8_at(2, 2).unwrap(); + borrowed.write_u8_at(3, 3).unwrap(); + + assert_eq!(cursor.get_ref(), &[0, 1, 2, 3]); +} + +#[test] +fn write_at_primitive() { + let mut cursor = Cursor::new([0u8; 8]); + + cursor.write_ne_at(0, 0u8).unwrap(); + cursor.write_ne([0u8, 1, 2]).unwrap(); + cursor.write_be(3u8).unwrap(); + cursor.write_be_at(4, 0x04_05u16).unwrap(); + cursor.write_le_at(6, 0x07_06u16).unwrap(); + + assert_eq!(cursor.get_ref(), &[0, 1, 2, 3, 4, 5, 6, 7]); + + // overflow + let val = cursor.write_ne_at(8, 0u8); + assert!(val.is_err()); +} + +#[test] +fn write_at_u8() { + let mut cursor = Cursor::new([0u8; 4]); + + cursor.write_u8(0).unwrap(); + cursor.write_u8(1).unwrap(); + cursor.write_u8(2).unwrap(); + cursor.write_u8(3).unwrap(); + + assert_eq!(cursor.get_ref(), &[0, 1, 2, 3]); + + // overflow + let val = cursor.write_u8(0); + assert!(val.is_err()); +} + +#[test] +fn write_at_u16_ne() { + let mut cursor = Cursor::new([0u8; 4]); + + let parts = match cfg!(target_endian = "big") { + true => (0x1234, 0x5678), + false => (0x3412, 0x7856), + }; + + cursor.write_u16_ne(parts.0).unwrap(); + cursor.write_u16_ne(parts.1).unwrap(); + + assert_eq!(cursor.get_ref(), &[0x12, 0x34, 0x56, 0x78]); + + // overflow + let val = cursor.write_u16_ne(0); + assert!(val.is_err()); +} + +#[test] +fn write_at_u16_le() { + let mut cursor = Cursor::new([0u8; 4]); + + cursor.write_u16(Little, 0x3412).unwrap(); + cursor.write_u16(Little, 0x7856).unwrap(); + + assert_eq!(cursor.get_ref(), &[0x12, 0x34, 0x56, 0x78]); + + // overflow + let val = cursor.write_u16_le(0); + assert!(val.is_err()); +} + +#[test] +fn write_at_u16_be() { + let mut cursor = Cursor::new([0u8; 4]); + + cursor.write_u16_be(0x1234).unwrap(); + cursor.write_u16_be(0x5678).unwrap(); + + assert_eq!(cursor.get_ref(), &[0x12, 0x34, 0x56, 0x78]); + + // overflow + let val = cursor.write_u16_be(0); + assert!(val.is_err()); +} + +#[test] +fn write_at_u32_ne() { + let mut cursor = Cursor::new([0u8; 8]); + + let parts = match cfg!(target_endian = "big") { + true => (0x12345678, 0x9ABCDEF0), + false => (0x78563412, 0xF0DEBC9A), + }; + + cursor.write_u32_ne(parts.0).unwrap(); + cursor.write_u32_ne(parts.1).unwrap(); + + assert_eq!( + cursor.get_ref(), + &[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0] + ); + + // overflow + let val = cursor.write_u32_ne(0); + assert!(val.is_err()); +} + +#[test] +fn write_at_u32_le() { + let mut cursor = Cursor::new([0u8; 8]); + + cursor.write_u32_le(0x78563412).unwrap(); + cursor.write_u32_le(0xF0DEBC9A).unwrap(); + + assert_eq!( + cursor.get_ref(), + &[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0] + ); + + // overflow + let val = cursor.write_u32_le(0); + assert!(val.is_err()); +} + +#[test] +fn write_at_u32_be() { + let mut cursor = Cursor::new([0u8; 8]); + + cursor.write_u32_be(0x12345678).unwrap(); + cursor.write_u32_be(0x9ABCDEF0).unwrap(); + + assert_eq!( + cursor.get_ref(), + &[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0] + ); + + // overflow + let val = cursor.write_u32_be(0); + assert!(val.is_err()); +} + +#[test] +fn write_at_u64_ne() { + let mut cursor = Cursor::new([0u8; 16]); + + let parts = match cfg!(target_endian = "big") { + true => (0x123456789ABCDEF0, 0x0123456789ABCDEF), + false => (0xF0DEBC9A78563412, 0xEFCDAB8967452301), + }; + + cursor.write_u64_ne(parts.0).unwrap(); + cursor.write_u64_ne(parts.1).unwrap(); + + assert_eq!( + cursor.get_ref(), + &[ + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, + 0xCD, 0xEF + ] + ); + + // overflow + let val = cursor.write_u64_ne(0); + assert!(val.is_err()); +} + +#[test] +fn write_at_u64_le() { + let mut cursor = Cursor::new([0u8; 16]); + + cursor.write_u64_le(0xF0DEBC9A78563412).unwrap(); + cursor.write_u64_le(0xEFCDAB8967452301).unwrap(); + + assert_eq!( + cursor.get_ref(), + &[ + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, + 0xCD, 0xEF, + ] + ); + + // overflow + let val = cursor.write_u64_le(0); + assert!(val.is_err()); +} + +#[test] +fn write_at_u64_be() { + let mut cursor = Cursor::new([0u8; 16]); + + cursor.write_u64_be(0x123456789ABCDEF0).unwrap(); + cursor.write_u64_be(0x0123456789ABCDEF).unwrap(); + + assert_eq!( + cursor.get_ref(), + &[ + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, + 0xCD, 0xEF, + ] + ); + + // overflow + let val = cursor.write_u64_be(0); + assert!(val.is_err()); +} + +#[test] +fn write_at_u128_ne() { + let mut cursor = Cursor::new([0u8; 32]); + + let parts = match cfg!(target_endian = "big") { + true => ( + 0x01000000000000000000000000000000, + 0x01000000000000000000000000000000, + ), + false => ( + 0x00000000000000000000000000000001, + 0x00000000000000000000000000000001, + ), + }; + + cursor.write_u128_ne(parts.0).unwrap(); + cursor.write_u128_ne(parts.1).unwrap(); + + assert_eq!( + cursor.get_ref(), + &[ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ] + ); + + // overflow + let val = cursor.write_u128_ne(0); + assert!(val.is_err()); +} + +#[test] +fn write_at_u128_le() { + let mut cursor = Cursor::new([0u8; 32]); + + cursor + .write_u128_le(0x00000000000000000000000000000001) + .unwrap(); + cursor + .write_u128_le(0x00000000000000000000000000000001) + .unwrap(); + + assert_eq!( + cursor.get_ref(), + &[ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ] + ); + + // overflow + let val = cursor.write_u128_le(0); + assert!(val.is_err()); +} + +// TODO: Implement write_u128_be for all + +#[test] +fn write_at_vec() { + let mut cursor = Cursor::new([0u8; 8]); + + cursor.write_vec(vec![0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); + + assert_eq!(cursor.get_ref(), &[0, 1, 2, 3, 4, 5, 6, 7]); + + // overflow + let val = cursor.write_vec(vec![0]); + assert!(val.is_err()); +} + +#[test] +fn write_at_str() { + let mut cursor = Cursor::new([0u8; 8]); + + cursor.write_str("ABCDEFGH".to_string()).unwrap(); + + assert_eq!(cursor.get_ref(), b"ABCDEFGH"); + + // overflow + let val = cursor.write_str("A".to_string()); + assert!(val.is_err()); +} From 4caf81d525120529bf86590c8c2c28d86667c7f0 Mon Sep 17 00:00:00 2001 From: Le0X8 <84378319+Le0X8@users.noreply.github.com> Date: Mon, 18 Aug 2025 16:49:27 +0200 Subject: [PATCH 7/7] feat: added copying, ready for v0.9 :) --- README.md | 107 +----------------------------------------------- src/read/at.rs | 61 ++++++++++++++++++++++++++- src/read/val.rs | 55 ++++++++++++++++++++++++- tests/copy.rs | 82 +++++++++++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+), 109 deletions(-) create mode 100644 tests/copy.rs diff --git a/README.md b/README.md index 1b85d70..6c31b48 100644 --- a/README.md +++ b/README.md @@ -10,23 +10,19 @@

- Data handling in Rust, made easy. + Binary data handling in Rust, made easy.

## Features - Read and write files in streams -- Support for a lot of data types (including custom length integers) - Read and write u8 vectors - std::io::Read and std::io::Write implementations for `ReadVal` and `WriteVal` (happens automatically as they extend these traits) -- Copying data from `ReadVal` to `WriteVal` -- Partial read & write access with `limit` +- Copying data from `ReadVal` to `Write` (chunked and all at once if you want) - Floating point number support ### Planned features -- Zero-cost cloning -- Zero-cost subarray clones - Reading and writing of data that does not fill a whole byte