1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! Tools for reading 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 [`BitBuffer`]
//! ,wrap it into a [`BitStream`] and then read from the stream.
//!
//! Once you have a BitStream, there are 2 different approaches of reading data
//!
//! - read primitives, Strings and byte arrays, using [`read_bool`], [`read_int`], [`read_float`], [`read_bytes`] and [`read_string`]
//! - read any type implementing the  [`BitRead`] or [`BitReadSized`] traits using [`read`] and [`read_sized`]
//!   - [`BitRead`] is for types that can be read without requiring any size info (e.g. null-terminal strings, floats, whole integers, etc)
//!   - [`BitReadSized`] is for types that require external sizing information to be read (fixed length strings, arbitrary length integers
//!
//! The [`BitRead`] and [`BitReadSized`] traits can be used with `#[derive]` if all fields implement [`BitRead`] or [`BitReadSized`].
//!
//! # Examples
//!
//! ```
//! # use bitstream_reader::Result;
//! use bitstream_reader::{BitBuffer, LittleEndian, BitStream, BitRead};
//!
//! #[derive(BitRead)]
//! struct ComplexType {
//!     first: u8,
//!     #[size = 15]
//!     second: u16,
//!     third: bool,
//! }
//!
//! # fn main() -> Result<()> {
//! let bytes = vec![
//!     0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
//!     0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111
//! ];
//! let buffer = BitBuffer::new(bytes, LittleEndian);
//! let mut stream = BitStream::new(buffer);
//! let value: u8 = stream.read_int(7)?;
//! let complex: ComplexType = stream.read()?;
//! #
//! #     Ok(())
//! # }
//! ```
//!
//! [`BitBuffer`]: struct.BitBuffer.html
//! [`BitStream`]: struct.BitStream.html
//! [`read_bool`]: struct.BitStream.html#method.read_bool
//! [`read_int`]: struct.BitStream.html#method.read_int
//! [`read_float`]: struct.BitStream.html#method.read_float
//! [`read_bytes`]: struct.BitStream.html#method.read_bytes
//! [`read_string`]: struct.BitStream.html#method.read_string
//! [`read`]: struct.BitStream.html#method.read
//! [`read_sized`]: struct.BitStream.html#method.read_sized
//! [`BitRead`]: trait.BitRead.html
//! [`BitReadSized`]: trait.BitReadSized.html

#![warn(missing_docs)]

use std::error::Error;
use std::fmt;
use std::fmt::Display;
pub use std::string::FromUtf8Error;

pub use bitstream_reader_derive::{BitRead, BitReadSized, BitSize, BitSizeSized};
pub use buffer::BitBuffer;
pub use endianness::*;
pub use read::{BitRead, BitReadSized, BitSize, BitSizeSized, LazyBitRead, LazyBitReadSized};
pub use stream::BitStream;

mod buffer;
mod endianness;
mod is_signed;
mod read;
mod stream;
mod unchecked_primitive;

/// Errors that can be returned when trying to read from a buffer
#[derive(Debug)]
pub enum ReadError {
    /// Too many bits requested to fit in the requested data type
    TooManyBits {
        /// The number of bits requested to read
        requested: usize,
        /// The number of bits that fit in the requested data type
        max: usize,
    },
    /// Not enough data in the buffer to read all requested bits
    NotEnoughData {
        /// The number of bits requested to read
        requested: usize,
        /// the number of bits left in the buffer
        bits_left: usize,
    },
    /// The requested position is outside the bounds of the stream or buffer
    IndexOutOfBounds {
        /// The requested position
        pos: usize,
        /// the number of bits in the buffer
        size: usize,
    },
    /// Unmatched discriminant found while trying to read an enum
    UnmatchedDiscriminant {
        /// The read discriminant
        discriminant: usize,
        /// The name of the enum that is trying to be read
        enum_name: String,
    },
    /// The read slice of bytes are not valid utf8
    Utf8Error(FromUtf8Error),
}

impl Display for ReadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ReadError::TooManyBits { requested, max } =>
                write!(f, "Too many bits requested to fit in the requested data type, requested to read {} bits while only {} fit in the datatype", requested, max),
            ReadError::NotEnoughData { requested, bits_left } =>
                write!(f, "Not enough data in the buffer to read all requested bits, requested to read {} bits while only {} bits are left", requested, bits_left),
            ReadError::IndexOutOfBounds { pos, size } =>
                write!(f, "The requested position is outside the bounds of the stream, requested position {} while the stream or buffer is only {} bits long", pos, size),
            ReadError::UnmatchedDiscriminant { discriminant, enum_name } =>
                write!(f, "Unmatched discriminant '{}' found while trying to read enum '{}'", discriminant, enum_name),
            ReadError::Utf8Error(err) => err.fmt(f)
        }
    }
}

impl From<FromUtf8Error> for ReadError {
    fn from(err: FromUtf8Error) -> ReadError {
        ReadError::Utf8Error(err)
    }
}

impl Error for ReadError {
    fn cause(&self) -> Option<&Error> {
        match self {
            ReadError::Utf8Error(err) => Some(err),
            _ => None,
        }
    }
}

/// Either the read bits in the requested format or a [`ReadError`](enum.ReadError.html)
pub type Result<T> = std::result::Result<T, ReadError>;

/// Get the number of bits required to read a type from stream
#[inline(always)]
pub fn bit_size_of<T: BitSize>() -> usize {
    T::bit_size()
}

/// Get the number of bits required to read a type from stream
#[inline(always)]
pub fn bit_size_of_sized<T: BitSizeSized>(size: usize) -> usize {
    T::bit_size(size)
}