mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-03 16:44:06 +02:00
doc updates
This commit is contained in:
parent
ac3c7ab32a
commit
1ace766dda
3 changed files with 183 additions and 24 deletions
61
src/lib.rs
61
src/lib.rs
|
|
@ -1,6 +1,6 @@
|
||||||
//! Tools for reading data types of arbitrary bit length and might not be byte-aligned in the source data
|
//! Tools for reading and writing data types of arbitrary bit length and might not be byte-aligned in the source data
|
||||||
//!
|
//!
|
||||||
//! The main way of handling with the binary data is to first create a [`BitReadBuffer`]
|
//! The main way of reading the binary data is to first create a [`BitReadBuffer`]
|
||||||
//! ,wrap it into a [`BitReadStream`] and then read from the stream.
|
//! ,wrap it into a [`BitReadStream`] and then read from the stream.
|
||||||
//!
|
//!
|
||||||
//! Once you have a BitStream, there are 2 different approaches of reading data
|
//! Once you have a BitStream, there are 2 different approaches of reading data
|
||||||
|
|
@ -12,13 +12,22 @@
|
||||||
//!
|
//!
|
||||||
//! The [`BitRead`] and [`BitReadSized`] traits can be used with `#[derive]` if all fields implement [`BitRead`] or [`BitReadSized`].
|
//! The [`BitRead`] and [`BitReadSized`] traits can be used with `#[derive]` if all fields implement [`BitRead`] or [`BitReadSized`].
|
||||||
//!
|
//!
|
||||||
|
//! For writing the data you wrap the output `Vec` into a [`BitWriteStream`] which can then be used in a manner similar to the [`BitReadStream`]
|
||||||
|
//!
|
||||||
|
//! - write primitives, Strings and byte arrays, using [`write_bool`], [`write_int`], [`write_float`], [`write_bytes`] and [`write_string`]
|
||||||
|
//! - write any type implementing the [`BitWrite`] or [`BitWriteSized`] traits using [`write`] and [`write_sized`]
|
||||||
|
//! - [`BitWrite`] is for types that can be written without requiring any size info (e.g. null-terminal strings, floats, whole integers, etc)
|
||||||
|
//! - [`BitWriteSized`] is for types that require external sizing information to be written (fixed length strings, arbitrary length integers
|
||||||
|
//!
|
||||||
|
//! Just like the read counterparts, [`BitWrite`] and [`BitWriteSized`] traits can be used with `#[derive]` if all fields implement [`BitWrite`] or [`BitWriteSized`].
|
||||||
|
//!
|
||||||
//! # Examples
|
//! # Examples
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # use bitbuffer::Result;
|
//! # use bitbuffer::Result;
|
||||||
//! use bitbuffer::{BitReadBuffer, LittleEndian, BitReadStream, BitRead};
|
//! use bitbuffer::{BitReadBuffer, LittleEndian, BitReadStream, BitRead, BitWrite, BitWriteStream};
|
||||||
//!
|
//!
|
||||||
//! #[derive(BitRead)]
|
//! #[derive(BitRead, BitWrite)]
|
||||||
//! struct ComplexType {
|
//! struct ComplexType {
|
||||||
//! first: u8,
|
//! first: u8,
|
||||||
//! #[size = 15]
|
//! #[size = 15]
|
||||||
|
|
@ -35,22 +44,34 @@
|
||||||
//! let mut stream = BitReadStream::new(buffer);
|
//! let mut stream = BitReadStream::new(buffer);
|
||||||
//! let value: u8 = stream.read_int(7)?;
|
//! let value: u8 = stream.read_int(7)?;
|
||||||
//! let complex: ComplexType = stream.read()?;
|
//! let complex: ComplexType = stream.read()?;
|
||||||
|
//!
|
||||||
|
//! let mut write_bytes = vec![];
|
||||||
|
//! let mut write_stream = BitWriteStream::new(&mut write_bytes, LittleEndian);
|
||||||
|
//! write_stream.write_int(12, 7)?;
|
||||||
|
//! write_stream.write(&ComplexType {
|
||||||
|
//! first: 55,
|
||||||
|
//! second: 12,
|
||||||
|
//! third: true
|
||||||
|
//! })?;
|
||||||
//! #
|
//! #
|
||||||
//! # Ok(())
|
//! # Ok(())
|
||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! [`BitReadBuffer`]: struct.BitReadBuffer.html
|
//! [`read_bool`]: BitReadStream::read_bool
|
||||||
//! [`BitReadStream`]: struct.BitReadStream.html
|
//! [`read_int`]: BitReadStream::read_int
|
||||||
//! [`read_bool`]: struct.BitStream.html#method.read_bool
|
//! [`read_float`]: BitReadStream::read_float
|
||||||
//! [`read_int`]: struct.BitStream.html#method.read_int
|
//! [`read_bytes`]: BitReadStream::read_bytes
|
||||||
//! [`read_float`]: struct.BitStream.html#method.read_float
|
//! [`read_string`]: BitReadStream::read_string
|
||||||
//! [`read_bytes`]: struct.BitStream.html#method.read_bytes
|
//! [`read`]: BitReadStream::read
|
||||||
//! [`read_string`]: struct.BitStream.html#method.read_string
|
//! [`read_sized`]: BitReadStream::read_sized
|
||||||
//! [`read`]: struct.BitStream.html#method.read
|
//! [`write_bool`]: BitWriteStream::write_bool
|
||||||
//! [`read_sized`]: struct.BitStream.html#method.read_sized
|
//! [`write_int`]: BitWriteStream::write_int
|
||||||
//! [`BitRead`]: trait.BitRead.html
|
//! [`write_float`]: BitWriteStream::write_float
|
||||||
//! [`BitReadSized`]: trait.BitReadSized.html
|
//! [`write_bytes`]: BitWriteStream::write_bytes
|
||||||
|
//! [`write_string`]: BitWriteStream::write_string
|
||||||
|
//! [`write`]: BitWriteStream::write
|
||||||
|
//! [`write_sized`]: BitWriteStream::write_sized
|
||||||
|
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
|
@ -75,7 +96,7 @@ mod write;
|
||||||
mod writebuffer;
|
mod writebuffer;
|
||||||
mod writestream;
|
mod writestream;
|
||||||
|
|
||||||
/// Errors that can be returned when trying to read from a buffer
|
/// Errors that can be returned when trying to read from or write to a buffer
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum BitError {
|
pub enum BitError {
|
||||||
/// Too many bits requested to fit in the requested data type
|
/// Too many bits requested to fit in the requested data type
|
||||||
|
|
@ -149,16 +170,20 @@ impl From<FromUtf8Error> for BitError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Either the read bits in the requested format or a [`ReadError`](enum.ReadError.html)
|
/// Either the read bits in the requested format or a [`BitError`]
|
||||||
pub type Result<T> = std::result::Result<T, BitError>;
|
pub type Result<T> = std::result::Result<T, BitError>;
|
||||||
|
|
||||||
/// Get the number of bits required to read a type from stream
|
/// Get the number of bits required to read a type from stream
|
||||||
|
///
|
||||||
|
/// If the number of bits needed can not be determined beforehand `None` is returned
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn bit_size_of<'a, T: BitRead<'a, LittleEndian>>() -> Option<usize> {
|
pub fn bit_size_of<'a, T: BitRead<'a, LittleEndian>>() -> Option<usize> {
|
||||||
T::bit_size()
|
T::bit_size()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the number of bits required to read a type from stream
|
/// Get the number of bits required to read a type from stream given an input size
|
||||||
|
///
|
||||||
|
/// If the number of bits needed can not be determined beforehand `None` is returned
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn bit_size_of_sized<'a, T: BitReadSized<'a, LittleEndian>>(size: usize) -> Option<usize> {
|
pub fn bit_size_of_sized<'a, T: BitReadSized<'a, LittleEndian>>(size: usize) -> Option<usize> {
|
||||||
T::bit_size_sized(size)
|
T::bit_size_sized(size)
|
||||||
|
|
|
||||||
10
src/read.rs
10
src/read.rs
|
|
@ -87,9 +87,8 @@ use std::sync::Arc;
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`BitReadSized`]: trait.BitReadSized.html
|
/// [read_sized]: BitReadStream::read_sized
|
||||||
/// [read_sized]: struct.BitStream.html#method.read_sized
|
/// [read]: BitReadStream::read
|
||||||
/// [read]: struct.BitStream.html#method.read
|
|
||||||
pub trait BitRead<'a, E: Endianness>: Sized {
|
pub trait BitRead<'a, E: Endianness>: Sized {
|
||||||
/// Read the type from stream
|
/// Read the type from stream
|
||||||
fn read(stream: &mut BitReadStream<'a, E>) -> Result<Self>;
|
fn read(stream: &mut BitReadStream<'a, E>) -> Result<Self>;
|
||||||
|
|
@ -454,9 +453,8 @@ impl<'a, E: Endianness, T: BitRead<'a, E>, const N: usize> BitRead<'a, E> for [T
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`BitRead`]: trait.BitRead.html
|
/// [read_sized]: BitReadStream::read_sized
|
||||||
/// [read_sized]: struct.BitStream.html#method.read_sized
|
/// [read]: BitReadStream::read
|
||||||
/// [read]: struct.BitStream.html#method.read
|
|
||||||
pub trait BitReadSized<'a, E: Endianness>: Sized {
|
pub trait BitReadSized<'a, E: Endianness>: Sized {
|
||||||
/// Read the type from stream
|
/// Read the type from stream
|
||||||
fn read(stream: &mut BitReadStream<'a, E>, size: usize) -> Result<Self>;
|
fn read(stream: &mut BitReadStream<'a, E>, size: usize) -> Result<Self>;
|
||||||
|
|
|
||||||
136
src/write.rs
136
src/write.rs
|
|
@ -4,6 +4,81 @@ use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Trait for types that can be written to a stream without requiring the size to be configured
|
/// Trait for types that can be written to a stream without requiring the size to be configured
|
||||||
|
///
|
||||||
|
/// The `BitWrite` trait can be used with `#[derive]` on structs and enums
|
||||||
|
///
|
||||||
|
/// # Structs
|
||||||
|
///
|
||||||
|
/// The implementation can be derived for a struct as long as every field in the struct implements `BitWrite` or [`BitWriteSized`]
|
||||||
|
///
|
||||||
|
/// The struct is written field by field in the order they are defined in, if the size for a field is set [`stream.write_sized()`][write_sized]
|
||||||
|
/// will be used, otherwise [`write_read()`][write] will be used.
|
||||||
|
///
|
||||||
|
/// The size for a field can be set using 3 different methods
|
||||||
|
/// - set the size as an integer using the `size` attribute,
|
||||||
|
/// - use a previously defined field as the size using the `size` attribute
|
||||||
|
///
|
||||||
|
/// ## Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bitbuffer::BitWrite;
|
||||||
|
/// #
|
||||||
|
/// #[derive(BitWrite)]
|
||||||
|
/// struct TestStruct {
|
||||||
|
/// foo: u8,
|
||||||
|
/// str: String,
|
||||||
|
/// #[size = 2] // when `size` is set, the attributed will be read using `read_sized`
|
||||||
|
/// truncated: String,
|
||||||
|
/// bar: u16,
|
||||||
|
/// float: f32,
|
||||||
|
/// #[size = 3]
|
||||||
|
/// asd: u8,
|
||||||
|
/// #[size = "asd"] // use a previously defined field as size
|
||||||
|
/// previous_field: u8,
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Enums
|
||||||
|
///
|
||||||
|
/// The implementation can be derived for an enum as long as every variant of the enum either has no field, or an unnamed field that implements `BitWrite` or [`BitWriteSized`]
|
||||||
|
///
|
||||||
|
/// The enum is written by first writing a set number of bits as the discriminant of the enum, then the variant written.
|
||||||
|
///
|
||||||
|
/// For details about setting the input size for fields implementing [`BitWriteSized`] see the block about size in the `Structs` section above.
|
||||||
|
///
|
||||||
|
/// The discriminant for the variants defaults to incrementing by one for every field, starting with `0`.
|
||||||
|
/// You can overwrite the discriminant for a field, which will also change the discriminant for every following field.
|
||||||
|
///
|
||||||
|
/// ## Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bitbuffer::BitWrite;
|
||||||
|
/// #
|
||||||
|
/// #[derive(BitWrite)]
|
||||||
|
/// #[discriminant_bits = 2]
|
||||||
|
/// enum TestBareEnum {
|
||||||
|
/// Foo,
|
||||||
|
/// Bar,
|
||||||
|
/// Asd = 3, // manually set the discriminant value for a field
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bitbuffer::BitWrite;
|
||||||
|
/// #
|
||||||
|
/// #[derive(BitWrite)]
|
||||||
|
/// #[discriminant_bits = 2]
|
||||||
|
/// enum TestUnnamedFieldEnum {
|
||||||
|
/// #[size = 5]
|
||||||
|
/// Foo(i8),
|
||||||
|
/// Bar(bool),
|
||||||
|
/// #[discriminant = 3] // since rust only allows setting the discriminant on field-less enums, you can use an attribute instead
|
||||||
|
/// Asd(u8),
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [write_sized]: BitWriteStream::write_sized
|
||||||
|
/// [write]: BitWriteStream::write
|
||||||
pub trait BitWrite<E: Endianness> {
|
pub trait BitWrite<E: Endianness> {
|
||||||
/// Write the type to stream
|
/// Write the type to stream
|
||||||
fn write(&self, stream: &mut BitWriteStream<E>) -> Result<()>;
|
fn write(&self, stream: &mut BitWriteStream<E>) -> Result<()>;
|
||||||
|
|
@ -121,6 +196,67 @@ impl_write_tuple!(0: T1, 1: T2, 2: T3);
|
||||||
impl_write_tuple!(0: T1, 1: T2, 2: T3, 3: T4);
|
impl_write_tuple!(0: T1, 1: T2, 2: T3, 3: T4);
|
||||||
|
|
||||||
/// Trait for types that can be written to a stream, requiring the size to be configured
|
/// Trait for types that can be written to a stream, requiring the size to be configured
|
||||||
|
///
|
||||||
|
/// The meaning of the set sized depends on the type being written (e.g, number of bits for integers,
|
||||||
|
/// number of bytes for strings, number of items for Vec's, etc)
|
||||||
|
///
|
||||||
|
/// The `BitReadSized` trait can be used with `#[derive]` on structs
|
||||||
|
///
|
||||||
|
/// The implementation can be derived for a struct as long as every field in the struct implements [`BitWrite`] or `BitWriteSized`
|
||||||
|
///
|
||||||
|
/// The struct is written field by field in the order they are defined in, if the size for a field is set [`stream.write_sized()`][write_sized]
|
||||||
|
/// will be used, otherwise [`stream.write()`][write] will be used.
|
||||||
|
///
|
||||||
|
/// The size for a field can be set using 4 different methods
|
||||||
|
/// - set the size as an integer using the `size` attribute,
|
||||||
|
/// - use a previously defined field as the size using the `size` attribute
|
||||||
|
/// - based on the input size by setting `size` attribute to `"input_size"`
|
||||||
|
///
|
||||||
|
/// ## Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bitbuffer::BitWriteSized;
|
||||||
|
/// #
|
||||||
|
/// #[derive(BitWriteSized, PartialEq, Debug)]
|
||||||
|
/// struct TestStructSized {
|
||||||
|
/// foo: u8,
|
||||||
|
/// #[size = "input_size"]
|
||||||
|
/// string: String,
|
||||||
|
/// #[size = "input_size"]
|
||||||
|
/// int: u8,
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Enums
|
||||||
|
///
|
||||||
|
/// The implementation can be derived for an enum as long as every variant of the enum either has no field, or an unnamed field that implements [`BitWrite`] or `BitWriteSized`
|
||||||
|
///
|
||||||
|
/// The enum is written by first writing a set number of bits as the discriminant of the enum, then the variant is written.
|
||||||
|
///
|
||||||
|
/// For details about setting the input size for fields implementing `BitWriteSized` see the block about size in the `Structs` section above.
|
||||||
|
///
|
||||||
|
/// The discriminant for the variants defaults to incrementing by one for every field, starting with `0`.
|
||||||
|
/// You can overwrite the discriminant for a field, which will also change the discriminant for every following field.
|
||||||
|
///
|
||||||
|
/// ## Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bitbuffer::BitWriteSized;
|
||||||
|
/// #
|
||||||
|
/// #[derive(BitWriteSized)]
|
||||||
|
/// #[discriminant_bits = 2]
|
||||||
|
/// enum TestUnnamedFieldEnum {
|
||||||
|
/// #[size = 5]
|
||||||
|
/// Foo(i8),
|
||||||
|
/// Bar(bool),
|
||||||
|
/// #[discriminant = 3] // since rust only allows setting the discriminant on field-less enums, you can use an attribute instead
|
||||||
|
/// #[size = "input_size"]
|
||||||
|
/// Asd(u8),
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [write_sized]: BitReadStream::write_sized
|
||||||
|
/// [write]: BitReadStream::write
|
||||||
pub trait BitWriteSized<E: Endianness> {
|
pub trait BitWriteSized<E: Endianness> {
|
||||||
/// Write the type to stream
|
/// Write the type to stream
|
||||||
fn write_sized(&self, stream: &mut BitWriteStream<E>, len: usize) -> Result<()>;
|
fn write_sized(&self, stream: &mut BitWriteStream<E>, len: usize) -> Result<()>;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue