pkbuffer 0.7.0

Buffer objects made for arbitrary casting and addressing!
Documentation
//! [PKBuffer](https://github.com/frank2/pkbuffer) is a library for reading and writing data to byte buffers
//! using safe byte-copy operations. It creates an interface for reading and writing primitive types
//! and byte sequences to an arbitrary buffer of bytes.
//!
//! For example:
//! ```rust
//! use pkbuffer::{Buffer, VecBuffer};
//!
//! let mut buffer = VecBuffer::with_initial_size(4);
//! buffer.write_val::<u32>(0, &0x07060504).unwrap();
//!
//! assert_eq!(buffer, [4,5,6,7]);
//! ```
//!
//! Buffer objects are derived from the [`Buffer`](Buffer) trait. This trait
//! provides methods for reading, writing, searching, and manipulating byte buffers.
//!
//! Buffer objects comes in two forms: *pointer form* ([`PtrBuffer`](PtrBuffer)) and
//! *allocated form* ([`VecBuffer`](VecBuffer)). Each of these structures come
//! in handy for different reasons. [`PtrBuffer`](PtrBuffer) is useful on unowned data
//! such as arbitrary locations in memory, whereas [`VecBuffer`](VecBuffer)'s
//! utility comes from being able to manipulate the underlying owned data.
//!
//! [`VecBuffer`](VecBuffer)s are handy for creating a brand-new buffer of objects.
//!
//! ```rust
//! use pkbuffer::{Buffer, VecBuffer};
//!
//! let mut buffer = VecBuffer::new();
//! buffer.append_val::<u8>(&0x1);
//! buffer.append_val::<u16>(&0x0302);
//! buffer.append_val::<u32>(&0x07060504);
//! assert_eq!(buffer, [1,2,3,4,5,6,7]);
//! ```
//!
//! ## Safety
//!
//! All type reads and writes use safe byte-copy operations via `read_val<T>` and
//! `write_val<T>`, which work correctly regardless of alignment on all platforms.
//! No unsafe pointer casting is used.

#[cfg(test)]
mod tests;

mod buffer;
pub use buffer::*;

mod ptr;
pub use ptr::*;

mod vec;
pub use vec::*;

/// Errors produced by the library.
#[derive(Debug)]
pub enum Error {
    /// An error produced by [`std::io::Error`](std::io::Error).
    IoError(std::io::Error),
    /// The operation went out of bounds.
    ///
    /// The first arg represents the current boundary, the second arg
    /// represents the out-of-bounds argument.
    OutOfBounds(usize,usize),
    /// The operation produced an invalid pointer. Argument is the pointer
    /// in question.
    InvalidPointer(*const u8),
    /// The sizes didn't match. The first arg represents the expected size,
    /// the second arg represents the received size.
    SizeMismatch(usize,usize),
    /// The search term would match everything.
    SearchMatchesEverything,
    /// The offset is not properly aligned for the requested type.
    AlignmentMismatch(usize, usize),
}
impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            Self::IoError(io) => write!(f, "i/o error: {}", io.to_string()),
            Self::OutOfBounds(expected,got) => write!(f, "out of bounds: boundary is {:#x}, got {:#x} instead", expected, got),
            Self::InvalidPointer(ptr) => write!(f, "invalid pointer: {:p}", ptr),
            Self::SizeMismatch(expected,got) => write!(f, "size mismatch: the two types differed in size, expected {}, got {}", expected, got),
            Self::SearchMatchesEverything => write!(f, "the search would match everything in the binary"),
            Self::AlignmentMismatch(offset, align) => write!(f, "alignment mismatch: offset {:#x} is not aligned for type with alignment {:#x}", offset, align),
        }
    }
}
impl std::error::Error for Error {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::IoError(ref e) => Some(e),
            _ => None,
        }
    }
}
impl std::convert::From<std::io::Error> for Error {
    fn from(io_err: std::io::Error) -> Self {
        Self::IoError(io_err)
    }
}
unsafe impl Send for Error {}
unsafe impl Sync for Error {}