use crate::ctx::{Endian, Len};
use crate::{Decode, Encode, Error};
#[doc(inline)]
pub use crate::magic_bytes;
macro_rules! endian_wrappers {
($($(#[$attr:meta])* $name:ident: $endian:expr,)*) => {$(
$(#[$attr])*
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct $name<T>(pub T);
impl<T> Encode<()> for $name<T>
where
T: Encode<Endian>,
{
fn encode<W>(&self, _ctx: (), writer: &mut W) -> Result<(), Error>
where
W: std::io::Write,
{
self.0.encode($endian, writer)
}
}
impl<T> Decode<()> for $name<T>
where
T: Decode<Endian>,
{
fn decode<R>(_ctx: (), reader: &mut R) -> Result<Self, Error>
where
R: std::io::Read,
{
T::decode($endian, reader).map(Self)
}
}
impl<T> From<T> for $name<T> {
fn from(value: T) -> Self {
Self(value)
}
}
impl<T> $name<T> {
pub fn into_inner(self) -> T {
self.0
}
}
)*}
}
endian_wrappers! {
LittleEndian: Endian::Little,
BigEndian: Endian::Big,
}
pub mod utf8 {
use crate::{Decode, Encode, Error};
#[allow(missing_docs)]
pub fn encode<S, Ctx, W>(string: &S, ctx: Ctx, writer: &mut W) -> Result<(), Error>
where
S: AsRef<str>,
[u8]: Encode<Ctx>,
W: std::io::Write,
{
string.as_ref().as_bytes().encode(ctx, writer)
}
#[allow(missing_docs)]
pub fn decode<Ctx, R>(ctx: Ctx, reader: &mut R) -> Result<String, Error>
where
Vec<u8>: Decode<Ctx>,
R: std::io::Read,
{
let bytes: Vec<u8> = Decode::decode(ctx, reader)?;
let string = String::from_utf8(bytes)?;
Ok(string)
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Utf8(pub String);
impl Encode<Len> for Utf8 {
fn encode<W>(&self, ctx: Len, writer: &mut W) -> Result<(), Error>
where
W: std::io::Write,
{
utf8::encode(&self.0, ctx, writer)
}
}
impl Encode<()> for Utf8 {
fn encode<W>(&self, _ctx: (), writer: &mut W) -> Result<(), Error>
where
W: std::io::Write,
{
utf8::encode(&self.0, ((),), writer)
}
}
impl Decode<Len> for Utf8 {
fn decode<R>(ctx: Len, reader: &mut R) -> Result<Self, Error>
where
R: std::io::Read,
{
utf8::decode(ctx, reader).map(Self)
}
}
impl From<String> for Utf8 {
fn from(value: String) -> Self {
Self(value)
}
}
impl From<&str> for Utf8 {
fn from(value: &str) -> Self {
value.to_string().into()
}
}
impl From<Utf8> for String {
fn from(wrapper: Utf8) -> Self {
wrapper.0
}
}
pub mod zero_one {
use crate::{Decode, Encode, Error};
#[allow(missing_docs)]
pub fn encode<W>(b: &bool, _ctx: (), writer: &mut W) -> Result<(), Error>
where
W: std::io::Write,
{
let byte: u8 = match b {
false => 0,
true => 1,
};
byte.encode((), writer)
}
#[allow(missing_docs)]
pub fn decode<R>(_ctx: (), reader: &mut R) -> Result<bool, Error>
where
R: std::io::Read,
{
let byte: u8 = Decode::decode((), reader)?;
match byte {
0 => Ok(false),
1 => Ok(true),
_ => Err(Error::new(format!(
"invalid byte value for boolean: expected 0 or 1, got {:?}",
byte
))),
}
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ZeroOne(pub bool);
impl Encode<()> for ZeroOne {
fn encode<W>(&self, _ctx: (), writer: &mut W) -> Result<(), Error>
where
W: std::io::Write,
{
zero_one::encode(&self.0, (), writer)
}
}
impl Decode<()> for ZeroOne {
fn decode<R>(_ctx: (), reader: &mut R) -> Result<Self, Error>
where
R: std::io::Read,
{
zero_one::decode((), reader).map(Self)
}
}
impl From<bool> for ZeroOne {
fn from(value: bool) -> Self {
Self(value)
}
}
impl From<ZeroOne> for bool {
fn from(wrapper: ZeroOne) -> Self {
wrapper.0
}
}