#![doc = include_str!("../README.md")]
#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs)]
pub mod error;
mod primitives;
#[cfg(feature = "packbytes-derive")]
pub use packbytes_derive::{FromBytes, ToBytes, TryFromBytes};
use core::convert::Infallible;
use core::ops;
mod private {
pub trait ByteArray {}
impl<const N: usize> ByteArray for [u8; N] {}
}
pub trait ByteArray:
private::ByteArray
+ ops::IndexMut<usize, Output = u8>
+ ops::IndexMut<ops::Range<usize>, Output = [u8]>
+ AsRef<[u8]>
+ AsMut<[u8]>
{
const SIZE: usize;
fn zeroed() -> Self;
}
impl<const N: usize> ByteArray for [u8; N] {
const SIZE: usize = N;
fn zeroed() -> Self {
[0; N]
}
}
pub trait FromBytes: Sized {
type Bytes: ByteArray;
const PREFERS_LE: bool = true;
fn from_le_bytes(bytes: Self::Bytes) -> Self;
fn from_be_bytes(bytes: Self::Bytes) -> Self;
#[inline]
fn from_bytes(bytes: Self::Bytes) -> Self {
if Self::PREFERS_LE {
Self::from_le_bytes(bytes)
} else {
Self::from_be_bytes(bytes)
}
}
#[inline]
fn from_ne_bytes(bytes: Self::Bytes) -> Self {
if cfg!(target_endian = "little") {
Self::from_le_bytes(bytes)
} else {
Self::from_be_bytes(bytes)
}
}
#[cfg(feature = "std")]
#[inline]
fn read_packed<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
let mut bytes = Self::Bytes::zeroed();
reader.read_exact(bytes.as_mut())?;
Ok(Self::from_bytes(bytes))
}
}
pub trait TryFromBytes: Sized {
type Bytes: ByteArray;
type Error;
const PREFERS_LE: bool = true;
fn try_from_le_bytes(bytes: Self::Bytes) -> Result<Self, Self::Error>;
fn try_from_be_bytes(bytes: Self::Bytes) -> Result<Self, Self::Error>;
#[inline]
fn try_from_bytes(bytes: Self::Bytes) -> Result<Self, Self::Error> {
if Self::PREFERS_LE {
Self::try_from_le_bytes(bytes)
} else {
Self::try_from_be_bytes(bytes)
}
}
#[inline]
fn try_from_ne_bytes(bytes: Self::Bytes) -> Result<Self, Self::Error> {
if cfg!(target_endian = "little") {
Self::try_from_le_bytes(bytes)
} else {
Self::try_from_be_bytes(bytes)
}
}
}
pub trait ToBytes: Sized {
type Bytes: ByteArray;
const PREFERS_LE: bool = true;
fn to_le_bytes(self) -> Self::Bytes;
fn to_be_bytes(self) -> Self::Bytes;
#[inline]
fn to_bytes(self) -> Self::Bytes {
if Self::PREFERS_LE {
self.to_le_bytes()
} else {
self.to_be_bytes()
}
}
#[inline]
fn to_ne_bytes(self) -> Self::Bytes {
if cfg!(target_endian = "little") {
self.to_le_bytes()
} else {
self.to_be_bytes()
}
}
#[cfg(feature = "std")]
#[inline]
fn write_packed<W: std::io::Write>(self, writer: &mut W) -> std::io::Result<()> {
writer.write_all(self.to_bytes().as_ref())
}
}
impl<B: ByteArray, T: FromBytes<Bytes = B>> TryFromBytes for T {
type Bytes = B;
type Error = Infallible;
#[inline]
fn try_from_le_bytes(bytes: B) -> Result<Self, Self::Error> {
Ok(Self::from_le_bytes(bytes))
}
#[inline]
fn try_from_be_bytes(bytes: B) -> Result<Self, Self::Error> {
Ok(Self::from_be_bytes(bytes))
}
}
impl<const N: usize> FromBytes for [u8; N] {
type Bytes = Self;
#[inline]
fn from_le_bytes(bytes: Self::Bytes) -> Self {
bytes
}
#[inline]
fn from_be_bytes(bytes: Self::Bytes) -> Self {
bytes
}
}
impl<const N: usize> ToBytes for [u8; N] {
type Bytes = Self;
#[inline]
fn to_le_bytes(self) -> Self::Bytes {
self
}
#[inline]
fn to_be_bytes(self) -> Self::Bytes {
self
}
}