diff --git a/Cargo.toml b/Cargo.toml index c0cce3c..f144d53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,7 @@ [workspace] -members = [".", "crates/*"] +members = ["crates/*"] -[package] -name = "binbuf" -version = "0.0.1" +[workspace.package] authors = ["Techassi "] categories = ["encoding", "parsing", "network-programming"] description = "binbuf is a small library to work with binary (network) data" @@ -15,13 +13,5 @@ repository = "https://github.com/Techassi/binbuf" homepage = "https://github.com/Techassi/binbuf" exclude = ["tests/**/*", ".github/*", ".vscode/*", ".gitignore", "docs/**/*"] -[features] -full = ["derive", "macros"] -derive = [] -macros = [] - -[dependencies] -binbuf-derive = { path = "crates/binbuf-derive", version = "0.0.1" } -binbuf-macros = { path = "crates/binbuf-macros", version = "0.0.1" } - +[workspace.dependencies] snafu = "0.7.5" diff --git a/crates/binbuf-core/Cargo.toml b/crates/binbuf-core/Cargo.toml new file mode 100644 index 0000000..95a1070 --- /dev/null +++ b/crates/binbuf-core/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "binbuf" +version = "0.1.0" +edition.workspace = true + +[features] +full = ["derive", "macros"] +derive = [] +macros = [] + +[dependencies] +binbuf-derive = { path = "../binbuf-derive", version = "0.0.1" } +binbuf-macros = { path = "../binbuf-macros", version = "0.0.1" } + +snafu.workspace = true diff --git a/src/impls.rs b/crates/binbuf-core/src/impls.rs similarity index 100% rename from src/impls.rs rename to crates/binbuf-core/src/impls.rs diff --git a/src/lib.rs b/crates/binbuf-core/src/lib.rs similarity index 100% rename from src/lib.rs rename to crates/binbuf-core/src/lib.rs diff --git a/src/read.rs b/crates/binbuf-core/src/read.rs similarity index 76% rename from src/read.rs rename to crates/binbuf-core/src/read.rs index 4c7cdd3..10760ac 100644 --- a/src/read.rs +++ b/crates/binbuf-core/src/read.rs @@ -1,3 +1,5 @@ +use std::{borrow::Cow, io::BufRead}; + use binbuf_macros::from_buffer_and_readable_impl; use snafu::{ensure, OptionExt, Snafu}; @@ -60,15 +62,15 @@ impl<'a> Reader<'a> { } } - /// Read a single byte from the front of the buffer. If the buffer is + /// Read a single byte from the front of the reader. If the reader is /// empty, an error is returned. /// /// ### Example /// /// ``` - /// use binbuf::read::{Buffer, Error}; + /// use binbuf::read::{Reader, Error}; /// - /// let mut b = Buffer::new(&[69, 88]); + /// let mut b = Reader::new(&[69, 88]); /// /// assert_eq!(b.pop(), Ok(69)); /// assert_eq!(b.pop(), Ok(88)); @@ -83,8 +85,8 @@ impl<'a> Reader<'a> { BufferTooShortSnafu.fail() } - /// Pop off a byte from the front of the buffer without returning the byte. - /// This is rarely useful other than in combination with [`ReadBuffer::peek()`]. + /// Pop off a byte from the front of the reader without returning the byte. + /// This is rarely useful other than in combination with [`Reader::peek()`]. pub fn skip(&mut self) -> Result<()> { self.pop()?; Ok(()) @@ -94,9 +96,9 @@ impl<'a> Reader<'a> { self.rest = self.buf; } - /// Pop off `n` bytes from the front of the buffer but do not return the + /// Pop off `n` bytes from the front of the reader but do not return the /// popped off bytes. This is rarely useful other than in combination with - /// `peekn()`. + /// [`Reader::peekn()`]. pub fn skipn(&mut self, n: usize) -> Result<()> { // Ensure the buffer is long enough to skip n bytes. ensure!(n <= self.len(), BufferTooShortSnafu); @@ -111,15 +113,15 @@ impl<'a> Reader<'a> { Ok(()) } - /// Peek the next byte of the buffer. If the buffer is empty + /// Peek the next byte of the reader. If the reader is empty /// [`None`] is returned. /// /// ### Example /// /// ``` - /// use binbuf::read::Buffer; + /// use binbuf::Reader; /// - /// let mut b = Buffer::new(&[69]); + /// let mut b = Reader::new(&[69]); /// /// assert_eq!(b.peek(), Some(69)); /// assert_eq!(b.pop(), Ok(69)); @@ -129,15 +131,15 @@ impl<'a> Reader<'a> { self.rest.first().copied() } - /// Peek the next `n` bytes of the buffer. If the buffer is empty + /// Peek the next `n` bytes of the reader. If the reader is empty /// [`None`] is returned. /// /// ### Example /// /// ``` - /// use binbuf::read::Buffer; + /// use binbuf::Reader; /// - /// let mut b = Buffer::new(&[69, 88]); + /// let mut b = Reader::new(&[69, 88]); /// /// assert_eq!(b.peekn::<2>(), Some([69, 88])); /// assert_eq!(b.skipn(2), Ok(())); @@ -156,7 +158,7 @@ impl<'a> Reader<'a> { /// Jumps back to offset `index`. Jumping beyond the current offset is not /// permitted and returns [`Error::InvalidJump`]. pub fn jump_to(&mut self, index: usize) -> Result<()> { - // Ensure we don't jump to ann index larger than the currennt offset. + // Ensure we don't jump to an index larger than the current offset. ensure!( index <= self.offset(), InvalidJumpSnafu { @@ -201,9 +203,9 @@ impl<'a> Reader<'a> { /// ### Example /// /// ``` - /// use binbuf::read::Buffer; + /// use binbuf::Reader; /// - /// let mut b = Buffer::new(&[69, 88]); + /// let mut b = Reader::new(&[69, 88]); /// /// assert_eq!(b.pop(), Ok(69)); /// assert_eq!(b.offset(), 1); @@ -212,14 +214,14 @@ impl<'a> Reader<'a> { self.buf.len() - self.rest.len() } - /// Returns the length of the remaining buffer. + /// Returns the length of the reader (in remaining bytes). /// /// ### Example /// /// ``` - /// use binbuf::read::Buffer; + /// use binbuf::Reader; /// - /// let mut b = Buffer::new(&[69, 88]); + /// let mut b = Reader::new(&[69, 88]); /// /// assert_eq!(b.len(), 2); /// assert_eq!(b.pop(), Ok(69)); @@ -229,14 +231,14 @@ impl<'a> Reader<'a> { self.rest.len() } - /// Returns if the buffer is empty. + /// Returns if the reader is empty. /// /// ### Example /// /// ``` - /// use binbuf::read::Buffer; + /// use binbuf::Reader; /// - /// let mut b = Buffer::new(&[69]); + /// let mut b = Reader::new(&[69]); /// /// assert_eq!(b.is_empty(), false); /// assert_eq!(b.pop(), Ok(69)); @@ -246,6 +248,7 @@ impl<'a> Reader<'a> { self.rest.is_empty() } + // TODO (@Techassi): Update doc comment /// Read a character string with an optional maximum length of `max_len`. /// A character string is composed of one byte indicating the number of /// bytes the string is made of. The string bytes then follow. @@ -282,15 +285,62 @@ impl<'a> Reader<'a> { /// assert_eq!(b.read_char_string(Some(3)), Err(Error::MaxLengthOverflow)); /// assert_eq!(b.len(), 8); /// ``` - pub fn read_char_string(&mut self, max_len: Option) -> Result<&[u8]> { - let len = self.peek().context(BufferTooShortSnafu)? as usize; + pub fn read_char_string(&mut self) -> Result<&[u8]> { + self.read_char_string_with_max_len(u8::MAX) + } - if let Some(max_len) = max_len { - ensure!(len <= max_len.into(), MaxLengthOverflowSnafu); - } + pub fn read_char_string_with_max_len(&mut self, max_len: u8) -> Result<&[u8]> { + let len = self.peek().context(BufferTooShortSnafu)?; + ensure!(len <= max_len, MaxLengthOverflowSnafu); self.skip()?; - self.read_slice(len) + self.read_slice(len as usize) + } + + pub fn read_string(&mut self, option: ReadStringOption) -> Result> { + match option { + ReadStringOption::Sized(max_length) => match max_length { + Some(max_length) => { + let len = self.peek().context(BufferTooShortSnafu)?; + ensure!(len <= max_length, MaxLengthOverflowSnafu); + + self.skip()?; + Ok(Cow::Borrowed(self.read_slice(len as usize)?)) + } + None => { + let len = self.peek().context(BufferTooShortSnafu)?; + self.skip()?; + Ok(Cow::Borrowed(self.read_slice(len as usize)?)) + } + }, + ReadStringOption::Terminated { + max_length, + terminator, + } => match max_length { + Some(max_length) => { + let mut bytes = Vec::with_capacity(max_length as usize); + + loop { + ensure!(bytes.len() < max_length as usize, MaxLengthOverflowSnafu); + let b = self.pop()?; + + if b == terminator { + break; + } + + bytes.push(b); + } + + Ok(Cow::Owned(bytes)) + } + None => { + let mut bytes = Vec::new(); + let _ = self.rest.read_until(terminator, &mut bytes); + + Ok(Cow::Owned(bytes)) + } + }, + } } /// Read a slice of bytes with the length `nbytes` from the buffer. If the @@ -300,10 +350,10 @@ impl<'a> Reader<'a> { /// ### Example /// /// ``` - /// use binbuf::read::Buffer; + /// use binbuf::Reader; /// /// let d = &[69, 88, 65, 77, 80, 76, 69, 33]; - /// let mut b = Buffer::new(d); + /// let mut b = Reader::new(d); /// /// assert_eq!(b.read_slice(4), Ok(&[69, 88, 65, 77])); /// assert_eq!(b.len(), 4); @@ -322,10 +372,10 @@ impl<'a> Reader<'a> { /// ### Example /// /// ``` - /// use binbuf::read::Buffer; + /// use binbuf::Reader; /// /// let d = &[69, 88, 65, 77, 80, 76, 69, 33]; - /// let mut b = Buffer::new(d); + /// let mut b = Reader::new(d); /// /// assert_eq!(b.read_vec(4), Ok(vec![69, 88, 65, 77])); /// assert_eq!(b.len(), 4); @@ -471,3 +521,24 @@ from_buffer_and_readable_impl!(u32, 4); from_buffer_and_readable_impl!(u64, 8); from_buffer_and_readable_impl!(u128, 16); from_buffer_and_readable_impl!(usize, (usize::BITS / 8) as usize); + +pub enum ReadStringOption { + Sized(Option), + Terminated { + max_length: Option, + terminator: u8, + }, +} + +impl ReadStringOption { + pub fn sized(max_length: Option) -> Self { + Self::Sized(max_length) + } + + pub fn terminated(terminator: u8, max_length: Option) -> Self { + Self::Terminated { + max_length, + terminator, + } + } +} diff --git a/src/write.rs b/crates/binbuf-core/src/write.rs similarity index 80% rename from src/write.rs rename to crates/binbuf-core/src/write.rs index 5460524..778e3ba 100644 --- a/src/write.rs +++ b/crates/binbuf-core/src/write.rs @@ -31,14 +31,14 @@ pub struct Writer { } impl Writer { - /// Creates a new empty [`Buffer`] backed by a `Vec`. + /// Creates a new empty [`Writer`] backed by a [`Vec`]. /// /// ### Example /// /// ``` - /// use binbuf::write::Buffer; + /// use binbuf::Writer; /// - /// let mut b = Buffer::new(); + /// let mut b = Writer::new(); /// 17752u16.write::(&mut b).unwrap(); /// /// assert_eq!(b.len(), 2); @@ -48,16 +48,16 @@ impl Writer { Self::default() } - /// Creates a new [`Buffer`] backed by a `Vec` with the provided bytes + /// Creates a new [`Writer`] backed by a [`Vec`] with the provided bytes /// already in the buffer. Possible parameters are: `Vec`, `&[u8]`, and /// `[u8]`. /// /// ### Example /// /// ``` - /// use binbuf::write::Buffer; + /// use binbuf::Writer; /// - /// let mut b = Buffer::new_with([69, 88]); + /// let mut b = Writer::new_with([69, 88]); /// assert_eq!(b.bytes(), &[69, 88]); /// ``` pub fn new_with>(b: T) -> Self { @@ -71,14 +71,14 @@ impl Writer { buf } - /// Adds a new byte to the end of the [`Buffer`]. + /// Adds a new byte to the end of the [`Writer`]. /// /// ### Example /// /// ``` - /// use binbuf::write::Buffer; + /// use binbuf::Writer; /// - /// let mut b = Buffer::new(); + /// let mut b = Writer::new(); /// b.push(69); /// /// assert_eq!(b.len(), 1); @@ -92,14 +92,14 @@ impl Writer { } } - /// Clears the [`Buffer`], removing all bytes. + /// Clears the [`Writer`], removing all bytes. /// /// ### Example /// /// ``` - /// use binbuf::write::Buffer; + /// use binbuf::Writer; /// - /// let mut b = Buffer::new_with([69, 88]); + /// let mut b = Writer::new_with([69, 88]); /// b.clear(); /// /// assert_eq!(b.len(), 0); @@ -108,28 +108,28 @@ impl Writer { self.buf.clear() } - /// Returns the length of the [`Buffer`]. + /// Returns the length of the [`Writer`]. /// /// ### Example /// /// ``` - /// use binbuf::write::Buffer; + /// use binbuf::Writer; /// - /// let mut b = Buffer::new_with([69, 88]); + /// let mut b = Writer::new_with([69, 88]); /// assert_eq!(b.len(), 2); /// ``` pub fn len(&self) -> usize { self.buf.len() } - /// Returns if the [`Buffer`] is empty. + /// Returns if the [`Writer`] is empty. /// /// ### Example /// /// ``` - /// use binbuf::write::Buffer; + /// use binbuf::Writer; /// - /// let mut b = Buffer::new(); + /// let mut b = Writer::new(); /// assert_eq!(b.is_empty(), true); /// /// b.push(69); @@ -139,15 +139,15 @@ impl Writer { self.buf.is_empty() } - /// Writes multiple bytes of data to the [`Buffer`]. Possible + /// Writes multiple bytes of data to the [`Writer`]. Possible /// parameters are: `Vec`, `&[u8]`, and `[u8]`. /// /// ### Example /// /// ``` - /// use binbuf::write::Buffer; + /// use binbuf::Writer; /// - /// let mut b = Buffer::new(); + /// let mut b = Writer::new(); /// b.write(vec![69, 88, 65]); /// /// assert_eq!(b.len(), 3); @@ -166,7 +166,8 @@ impl Writer { len } - /// Writes a character string to the [`Buffer`]. This will first write the + // TODO (@Techassi): Update doc comment + /// Writes a character string to the [`Writer`]. This will first write the /// length of the string as a sequence of bytes which is followed by the /// actual string contents. /// @@ -176,19 +177,17 @@ impl Writer { /// returns [`Error::MaxLengthOverflow`]. /// /// It is possible to write character strings, which exceeds the length of - /// [`u8::MAX`][u8max]. Most network protocols however only allow character - /// strings with a max size of [`u8::MAX`][u8max] at most. DNS being one + /// [`u8::MAX`]. Most network protocols however only allow character + /// strings with a max size of [`u8::MAX`] at most. DNS being one /// prominent example. The length label is currently **only** writen using /// big endian byte order. /// - /// [u8max]: https://doc.rust-lang.org/std/primitive.u8.html#associatedconstant.MAX - /// /// ### Example /// /// ``` - /// use binbuf::write::Buffer; + /// use binbuf::Writer; /// - /// let mut b = Buffer::new(); + /// let mut b = Writer::new(); /// b.write_char_string(&[88, 65, 77, 80], None).unwrap(); /// /// assert_eq!(b.len(), 5); @@ -224,12 +223,12 @@ impl Writer { n } - /// Returns the content of [`WriteBuffer`] as a slice of bytes. + /// Returns the content of [`Writer`] as a slice of bytes. pub fn bytes(&self) -> &[u8] { self.buf.as_slice() } - /// Returns the content [`WriteBuffer`] as an owned vector of bytes. + /// Returns the content of [`Writer`] as an owned vector of bytes. pub fn owned_bytes(&self) -> Vec { self.buf.clone() } diff --git a/tests/lib.rs b/crates/binbuf-core/tests/lib.rs similarity index 100% rename from tests/lib.rs rename to crates/binbuf-core/tests/lib.rs diff --git a/tests/read/mod.rs b/crates/binbuf-core/tests/read/mod.rs similarity index 97% rename from tests/read/mod.rs rename to crates/binbuf-core/tests/read/mod.rs index efc9a23..4b7aba4 100644 --- a/tests/read/mod.rs +++ b/crates/binbuf-core/tests/read/mod.rs @@ -8,6 +8,8 @@ mod read_derive_struct; mod read_impl; mod read_multi; +mod read_string; + #[test] fn test_read_u8() { let data = &[69, 88, 65, 77, 80, 76, 69, 33]; @@ -70,7 +72,7 @@ fn test_read_char_string() { let b = &[8, 69, 88, 65, 77, 80, 76, 69, 33]; let mut b = Reader::new(b); - match b.read_char_string(None) { + match b.read_char_string() { Ok(n) => assert_eq!(n, &[69, 88, 65, 77, 80, 76, 69, 33]), Err(err) => panic!("{}", err), } diff --git a/tests/read/read_buffer.rs b/crates/binbuf-core/tests/read/read_buffer.rs similarity index 100% rename from tests/read/read_buffer.rs rename to crates/binbuf-core/tests/read/read_buffer.rs diff --git a/tests/read/read_derive_enum.rs b/crates/binbuf-core/tests/read/read_derive_enum.rs similarity index 100% rename from tests/read/read_derive_enum.rs rename to crates/binbuf-core/tests/read/read_derive_enum.rs diff --git a/tests/read/read_derive_struct.rs b/crates/binbuf-core/tests/read/read_derive_struct.rs similarity index 100% rename from tests/read/read_derive_struct.rs rename to crates/binbuf-core/tests/read/read_derive_struct.rs diff --git a/tests/read/read_impl.rs b/crates/binbuf-core/tests/read/read_impl.rs similarity index 100% rename from tests/read/read_impl.rs rename to crates/binbuf-core/tests/read/read_impl.rs diff --git a/tests/read/read_multi.rs b/crates/binbuf-core/tests/read/read_multi.rs similarity index 100% rename from tests/read/read_multi.rs rename to crates/binbuf-core/tests/read/read_multi.rs diff --git a/crates/binbuf-core/tests/read/read_string.rs b/crates/binbuf-core/tests/read/read_string.rs new file mode 100644 index 0000000..77c3b4c --- /dev/null +++ b/crates/binbuf-core/tests/read/read_string.rs @@ -0,0 +1,22 @@ +use binbuf::{ + read::{Error, ReadStringOption}, + Reader, +}; + +#[test] +fn read_string_sized() { + let b = &[8, 69, 88, 65, 77, 80, 76, 69, 33]; + let mut r = Reader::new(b); + + let s = r.read_string(ReadStringOption::sized(None)).unwrap(); + assert_eq!(*s, [69, 88, 65, 77, 80, 76, 69, 33]); +} + +#[test] +fn read_string_sized_max_length() { + let b = &[8, 69, 88, 65, 77, 80, 76, 69, 33]; + let mut r = Reader::new(b); + + let e = r.read_string(ReadStringOption::sized(Some(5))).unwrap_err(); + assert_eq!(e, Error::MaxLengthOverflow); +} diff --git a/tests/write/mod.rs b/crates/binbuf-core/tests/write/mod.rs similarity index 100% rename from tests/write/mod.rs rename to crates/binbuf-core/tests/write/mod.rs diff --git a/tests/write/write_buffer.rs b/crates/binbuf-core/tests/write/write_buffer.rs similarity index 100% rename from tests/write/write_buffer.rs rename to crates/binbuf-core/tests/write/write_buffer.rs diff --git a/tests/write/write_derive.rs b/crates/binbuf-core/tests/write/write_derive.rs similarity index 100% rename from tests/write/write_derive.rs rename to crates/binbuf-core/tests/write/write_derive.rs diff --git a/tests/write/write_impl.rs b/crates/binbuf-core/tests/write/write_impl.rs similarity index 100% rename from tests/write/write_impl.rs rename to crates/binbuf-core/tests/write/write_impl.rs diff --git a/tests/write/write_macro.rs b/crates/binbuf-core/tests/write/write_macro.rs similarity index 100% rename from tests/write/write_macro.rs rename to crates/binbuf-core/tests/write/write_macro.rs diff --git a/tests/write/write_multi.rs b/crates/binbuf-core/tests/write/write_multi.rs similarity index 100% rename from tests/write/write_multi.rs rename to crates/binbuf-core/tests/write/write_multi.rs diff --git a/tests/write/write_span.rs b/crates/binbuf-core/tests/write/write_span.rs similarity index 100% rename from tests/write/write_span.rs rename to crates/binbuf-core/tests/write/write_span.rs diff --git a/crates/binbuf-derive/Cargo.toml b/crates/binbuf-derive/Cargo.toml index 50c5016..b09d19a 100644 --- a/crates/binbuf-derive/Cargo.toml +++ b/crates/binbuf-derive/Cargo.toml @@ -1,15 +1,15 @@ [package] name = "binbuf-derive" version = "0.0.1" -authors = ["Techassi "] -categories = ["encoding", "parsing", "network-programming"] -description = "Automatically implement binbuf traits with derive macros" documentation = "https://docs.rs/binbuf_derive" -edition = "2021" -keywords = ["binary", "numbers", "network"] -license = "MIT" -repository = "https://github.com/Techassi/binbuf" -homepage = "https://github.com/Techassi/binbuf" +authors.workspace = true +categories.workspace = true +description.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true [lib] proc-macro = true diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..d93669a --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1 @@ +toolchain.channel = "1.79.0"

AltStyle によって変換されたページ (->オリジナル) /