Expand description
§octs
Finally, a good byte manipulation library.
This crate builds on top of the types defined by bytes
by replacing its panicking get
and
put
functions with fallible, non-panicking read
and write
functions via octs::Read
and
octs::Write
.
§Features
-
Based on
bytes
- which provides useful types for byte manipulation, and allows cheaply cloning byte allocations via reference counting. Great for writing zero-copy networking code. -
Panicking functions were a mistake - in networking, you can’t trust your inputs. So why should it ever be possible to panic on malformed input?? All functions in
octs
which can fail return aResult
. -
Your types are first-class citizens - instead of
get_u16
,put_f32
, etc., just use oneread
andwrite
function for all types. This means you can implementDecode
and be able toread
it from any buffer, and likewise forEncode
andwrite
. -
Dedicated varints - one of the staples of networking primitives is implemented here, without needing any extensions. Just
read
orwrite
aVarInt
as you would any other value. -
Zero unsafe - I’m not smart enough to write unsafe code.
-
#![no_std]
- just likebytes
, but it still requiresalloc
.
§Examples
§Writing
use octs::{Read, Write, VarInt};
fn write_packet(
mut buf: octs::BytesMut,
// ^^^^^^^^^^^^^^
// | re-exports the core `bytes` types
packet_id: u16,
timestamp: u64,
payload: &[u8],
) -> Result<(), octs::BufTooShort> {
// ^^^^^^^^^^^^^^^^^
// | the main error type
buf.write(packet_id)?;
// ^^^^^
// | one `write` function for all your types
buf.write(timestamp)?;
// +---------------^
// | just use ? for errors
// | no panics
buf.write(VarInt(payload.len()))?;
// ^^^^^^^
// | inbuilt support for varints
// | using the Protocol Buffers spec
buf.write_from(payload)?;
// ^^^^^^^^^^
// | copy from an existing buffer
Ok(())
}
§Reading
use core::num::NonZeroU8;
use octs::{Bytes, BufError, Decode, Read, BufTooShortOr, VarInt};
#[derive(Debug)]
struct Fragment {
num_frags: NonZeroU8,
payload: Bytes,
}
#[derive(Debug)]
enum FragmentError {
InvalidNumFrags,
PayloadTooLarge,
}
impl Decode for Fragment {
// ^^^^^^
// | implement this trait to be able to `read`
// | this value from a buffer
type Error = FragmentError;
fn decode(mut buf: impl Read) -> Result<Self, BufTooShortOr<Self::Error>> {
let num_frags = buf
.read::<NonZeroU8>()
.map_err(|e| e.map_or(|_| FragmentError::InvalidNumFrags))?;
// +--------------^^^^^^^
// | map the `InvalidValue` error of reading
// | a `NonZeroU8` to your own error value
let VarInt(payload_len) = buf
.read::<VarInt<usize>>()
.map_err(|e| e.map_or(|_| FragmentError::PayloadTooLarge))?;
let payload = buf.read_next(payload_len)?;
// +-------------^^^^^^^^^^
// | read the next `payload_len` bytes directly into `Bytes`
// | if `buf` is also a `Bytes`, this is zero-copy!
Ok(Self {
num_frags,
payload
})
}
}
§Inspirations
bytes
- core byte manipulation primitives, such as the possibly-non-contiguousbytes::Buf
trait, and the cheaply-cloneablebytes::Bytes
type.octets
- general API style, and having varints be a core part of the APIsafer-bytes
- making a good version of thebytes
APIinteger-encoding
- implementations of varint encode/decode
Re-exports§
pub use bytes;
Modules§
- chunks
- Allows splitting a byte buffer into non-overlapping chunks of bytes.
- prim
- Implementations of
Decode
andEncode
for primitive types. - test
- Utilities for testing trait implementations.
Structs§
- BufToo
Short - Performed an operation on a
Read
orWrite
which required more bytes available than were actually available. - Bytes
- A cheaply cloneable and sliceable chunk of contiguous memory.
- Bytes
Mut - A unique reference to a contiguous slice of memory.
- VarInt
- Integer which is encoded in a variable amount of bytes.
- VarInt
TooLarge - Attempted to read a
VarInt
from a buffer, but the resulting integer would have been too large to fit into thisVarInt
.
Enums§
- BufToo
Short Or - Error which may represent either a
BufTooShort
or some other user-specified error type.
Traits§
- Buf
- Read bytes from a buffer.
- BufError
- Marker trait for an error type which can be used as the
E
parameter inBufTooShortOr
. - BufMut
- A trait for values that provide sequential write access to bytes.
- Decode
- Allows reading a value of this type from a
Read
. - Encode
- Allows writing a value of this type into a
Write
. - Encode
Len - Gets how many bytes it takes to encode a value of this type.
- Fixed
Encode Len - Defines exactly how many bytes it will take to encode a value of this type.
- Fixed
Encode LenHint - Provides hints on how many bytes it may take to encode a value of this type.
- Read
- Allows reading bytes from a buffer.
- Write
- Allows writing bytes into a buffer.