Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: Add different modes of reading a string #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
Techassi wants to merge 2 commits into main
base: main
Choose a base branch
Loading
from feat/read-string
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 3 additions & 13 deletions Cargo.toml
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
[workspace]
members = [".", "crates/*"]
members = ["crates/*"]

[package]
name = "binbuf"
version = "0.0.1"
[workspace.package]
authors = ["Techassi <git@techassi.dev>"]
categories = ["encoding", "parsing", "network-programming"]
description = "binbuf is a small library to work with binary (network) data"
Expand All @@ -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"
15 changes: 15 additions & 0 deletions crates/binbuf-core/Cargo.toml
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -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
File renamed without changes.
File renamed without changes.
135 changes: 103 additions & 32 deletions src/read.rs → crates/binbuf-core/src/read.rs
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::{borrow::Cow, io::BufRead};

use binbuf_macros::from_buffer_and_readable_impl;
use snafu::{ensure, OptionExt, Snafu};

Expand Down Expand Up @@ -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));
Expand All @@ -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(())
Expand All @@ -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);
Expand All @@ -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));
Expand All @@ -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(()));
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
Expand All @@ -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));
Expand All @@ -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));
Expand All @@ -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.
Expand Down Expand Up @@ -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<u8>) -> 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<Cow<'_, [u8]>> {
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
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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<u8>),
Terminated {
max_length: Option<u8>,
terminator: u8,
},
}

impl ReadStringOption {
pub fn sized(max_length: Option<u8>) -> Self {
Self::Sized(max_length)
}

pub fn terminated(terminator: u8, max_length: Option<u8>) -> Self {
Self::Terminated {
max_length,
terminator,
}
}
}
Loading

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