#![cfg_attr(feature = "unstable", feature(doc_cfg))]
#![cfg_attr(feature = "unstable", feature(never_type))]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "alloc")]
extern crate alloc;
use core::any::Any;
use core::fmt::Debug;
use core::hash::Hash;
use core::mem::replace;
use parse_display::Display;
#[cfg(feature = "derive")]
#[cfg_attr(feature = "unstable", doc(cfg(feature = "derive")))]
pub use ender_derive::{Decode, Encode};
pub use error::*;
pub use opaque::*;
pub use convenience::*;
use crate::io::{BorrowRead, Read, Seek, SeekFrom, SizeLimit, SizeTrack, Write, Zero};
#[cfg(test)]
mod test;
mod error;
pub mod facade;
mod impls;
pub mod io;
mod opaque;
#[cfg(feature = "serde")]
mod serde;
mod source;
mod windows1252;
mod convenience;
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default, Display)]
pub enum Endianness {
LittleEndian,
#[default]
BigEndian,
}
impl Endianness {
#[inline]
pub const fn native() -> Self {
#[cfg(target_endian = "little")]
{
Self::LittleEndian
}
#[cfg(target_endian = "big")]
{
Self::BigEndian
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default, Display)]
#[non_exhaustive]
pub enum NumEncoding {
#[default]
Fixed,
Leb128,
ProtobufWasteful,
ProtobufZigzag,
}
impl NumEncoding {
#[inline]
pub const fn borrowable(&self) -> bool {
match self {
NumEncoding::Fixed => true,
_ => false,
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Debug, Default, Display)]
pub enum BitWidth {
#[display("8Bit")]
Bit8,
#[display("16Bit")]
Bit16,
#[display("32Bit")]
Bit32,
#[display("64Bit")]
#[default]
Bit64,
#[display("128Bit")]
Bit128,
}
impl BitWidth {
#[inline]
pub const fn native() -> Self {
#[cfg(target_pointer_width = "64")]
{
Self::Bit64
}
#[cfg(target_pointer_width = "32")]
{
Self::Bit32
}
#[cfg(target_pointer_width = "16")]
{
Self::Bit16
}
}
#[inline]
pub const fn bits(&self) -> usize {
match self {
BitWidth::Bit8 => 8,
BitWidth::Bit16 => 16,
BitWidth::Bit32 => 32,
BitWidth::Bit64 => 64,
BitWidth::Bit128 => 128,
}
}
#[inline]
pub const fn bytes(&self) -> usize {
match self {
BitWidth::Bit8 => 1,
BitWidth::Bit16 => 2,
BitWidth::Bit32 => 4,
BitWidth::Bit64 => 8,
BitWidth::Bit128 => 16,
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default, Display)]
pub enum StrLen {
#[default]
LengthPrefixed,
NullTerminated,
#[display("NullTerminatedFixed({0})")]
NullTerminatedFixed(usize),
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default, Display)]
#[non_exhaustive]
pub enum StrEncoding {
Ascii,
#[default]
Utf8,
Utf16,
Utf32,
Windows1252,
}
impl StrEncoding {
#[inline]
pub const fn bytes(&self) -> usize {
match self {
StrEncoding::Ascii => 1,
StrEncoding::Utf8 => 1,
StrEncoding::Utf16 => 2,
StrEncoding::Utf32 => 4,
StrEncoding::Windows1252 => 1,
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)]
#[display("endianness = {endianness}, encoding = {num_encoding}")]
pub struct NumRepr {
pub endianness: Endianness,
pub num_encoding: NumEncoding,
}
impl NumRepr {
#[inline]
pub const fn new() -> Self {
Self {
endianness: Endianness::LittleEndian,
num_encoding: NumEncoding::Fixed,
}
}
#[inline]
pub const fn endianness(mut self, endiannes: Endianness) -> Self {
self.endianness = endiannes;
self
}
#[inline]
pub const fn num_encoding(mut self, num_encoding: NumEncoding) -> Self {
self.num_encoding = num_encoding;
self
}
}
impl Default for NumRepr {
#[inline]
fn default() -> Self {
Self::new()
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)]
#[display("endianness = {endianness} , encoding = {num_encoding}, bit_width = {width}, max_size = {max_size}")]
pub struct SizeRepr {
pub endianness: Endianness,
pub num_encoding: NumEncoding,
pub width: BitWidth,
pub max_size: usize,
}
impl SizeRepr {
#[inline]
pub const fn new() -> Self {
Self {
endianness: Endianness::LittleEndian,
num_encoding: NumEncoding::Fixed,
width: BitWidth::Bit64,
max_size: usize::MAX,
}
}
#[inline]
pub const fn endianness(mut self, endiannes: Endianness) -> Self {
self.endianness = endiannes;
self
}
#[inline]
pub const fn num_encoding(mut self, num_encoding: NumEncoding) -> Self {
self.num_encoding = num_encoding;
self
}
#[inline]
pub const fn bit_width(mut self, bit_width: BitWidth) -> Self {
self.width = bit_width;
self
}
#[inline]
pub const fn max_size(mut self, max_size: usize) -> Self {
self.max_size = max_size;
self
}
}
impl Default for SizeRepr {
#[inline]
fn default() -> Self {
Self::new()
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)]
#[display("endianness = {endianness} , encoding = {num_encoding}, bit_width = {width}")]
pub struct VariantRepr {
pub endianness: Endianness,
pub num_encoding: NumEncoding,
pub width: BitWidth,
}
impl VariantRepr {
#[inline]
pub const fn new() -> Self {
Self {
endianness: Endianness::LittleEndian,
num_encoding: NumEncoding::Fixed,
width: BitWidth::Bit32,
}
}
#[inline]
pub const fn endianness(mut self, endiannes: Endianness) -> Self {
self.endianness = endiannes;
self
}
#[inline]
pub const fn num_encoding(mut self, num_encoding: NumEncoding) -> Self {
self.num_encoding = num_encoding;
self
}
#[inline]
pub const fn bit_width(mut self, bit_width: BitWidth) -> Self {
self.width = bit_width;
self
}
}
impl Default for VariantRepr {
#[inline]
fn default() -> Self {
Self::new()
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)]
#[display("encoding = {encoding}, endianness = {endianness}, len = {len}")]
pub struct StringRepr {
pub encoding: StrEncoding,
pub endianness: Endianness,
pub len: StrLen,
}
impl StringRepr {
#[inline]
pub const fn new() -> Self {
Self {
encoding: StrEncoding::Utf8,
endianness: Endianness::LittleEndian,
len: StrLen::LengthPrefixed,
}
}
#[inline]
pub const fn str_encoding(mut self, str_encoding: StrEncoding) -> Self {
self.encoding = str_encoding;
self
}
#[inline]
pub const fn endianness(mut self, endiannes: Endianness) -> Self {
self.endianness = endiannes;
self
}
#[inline]
pub const fn len_encoding(mut self, len_encoding: StrLen) -> Self {
self.len = len_encoding;
self
}
}
impl Default for StringRepr {
#[inline]
fn default() -> Self {
Self::new()
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)]
#[display("num_repr = ({num_repr}), size_repr = ({size_repr}), variant_repr = ({variant_repr}), string_repr = ({string_repr})")]
pub struct BinSettings {
pub num_repr: NumRepr,
pub size_repr: SizeRepr,
pub variant_repr: VariantRepr,
pub string_repr: StringRepr,
}
impl BinSettings {
#[inline]
pub const fn new() -> Self {
Self {
num_repr: NumRepr::new(),
size_repr: SizeRepr::new(),
variant_repr: VariantRepr::new(),
string_repr: StringRepr::new(),
}
}
#[inline]
pub const fn num_repr(mut self, num_repr: NumRepr) -> Self {
self.num_repr = num_repr;
self
}
#[inline]
pub const fn size_repr(mut self, size_repr: SizeRepr) -> Self {
self.size_repr = size_repr;
self
}
#[inline]
pub const fn variant_repr(mut self, variant_repr: VariantRepr) -> Self {
self.variant_repr = variant_repr;
self
}
#[inline]
pub const fn string_repr(mut self, string_repr: StringRepr) -> Self {
self.string_repr = string_repr;
self
}
}
impl Default for BinSettings {
#[inline]
fn default() -> Self {
Self::new()
}
}
#[derive(Copy, Clone, Debug, Default)]
#[non_exhaustive]
pub struct Context<'a> {
pub user: Option<&'a dyn Any>,
pub settings: BinSettings,
pub bool_flatten: Option<bool>,
pub variant_flatten: Option<Opaque>,
pub size_flatten: Option<usize>,
}
impl<'a> Context<'a> {
#[inline]
pub const fn new() -> Self {
Self {
user: None,
settings: BinSettings::new(),
bool_flatten: None,
variant_flatten: None,
size_flatten: None,
}
}
#[inline]
pub const fn settings(mut self, settings: BinSettings) -> Self {
self.settings = settings;
self
}
#[inline]
pub const fn user_data<'b>(self, data: &'b dyn Any) -> Context<'b> {
let this = Context {
user: Some(data),
settings: self.settings,
bool_flatten: self.bool_flatten,
variant_flatten: self.variant_flatten,
size_flatten: self.size_flatten,
};
this
}
#[inline]
pub const fn bool_flatten(mut self, value: bool) -> Self {
self.bool_flatten = Some(value);
self
}
#[inline]
pub const fn variant_flatten(mut self, value: Opaque) -> Self
{
self.variant_flatten = Some(value);
self
}
#[inline]
pub const fn size_flatten(mut self, value: usize) -> Self {
self.size_flatten = Some(value);
self
}
#[inline]
pub fn with_settings(settings: BinSettings) -> Self {
Self {
user: None,
settings,
bool_flatten: None,
variant_flatten: None,
size_flatten: None,
}
}
#[inline]
pub fn with_user_data(settings: BinSettings, data: &'a dyn Any) -> Self {
Self {
user: Some(data),
settings,
bool_flatten: None,
variant_flatten: None,
size_flatten: None,
}
}
#[inline]
pub fn reset(&mut self, options: BinSettings) {
self.settings = options;
self.bool_flatten = None;
self.variant_flatten = None;
self.size_flatten = None;
}
#[inline]
pub fn consume_bool_flatten(&mut self) -> Option<bool> {
replace(&mut self.bool_flatten, None)
}
#[inline]
pub fn consume_variant_flatten(&mut self) -> Option<Opaque> {
replace(&mut self.variant_flatten, None)
}
#[inline]
pub fn consume_size_flatten(&mut self) -> Option<usize> {
replace(&mut self.size_flatten, None)
}
}
#[derive(Clone)]
#[non_exhaustive]
pub struct Encoder<'a, T> {
pub stream: T,
pub ctxt: Context<'a>,
#[cfg(feature = "debug")]
pub stack: source::Stack,
}
macro_rules! debug_fn {
($fn_name:ident, $variant_name:ident ( $ty:ty )) => {
#[inline]
pub fn $fn_name<F, R>(&mut self, f: F, s: $ty) -> EncodingResult<R>
where
F: FnOnce(&mut Encoder<T>) -> EncodingResult<R>,
{
#[cfg(feature = "debug")]
{
#[cfg(feature = "alloc")]
{
self.stack.frames.push(source::Frame::$variant_name(s));
let r = f(self)?;
self.stack.frames.pop();
Ok(r)
}
#[cfg(not(feature = "alloc"))]
{
let last_frame = self.stack.last_frame;
self.stack.last_frame = source::Frame::$variant_name(s);
let r = f(self)?;
self.stack.last_frame = last_frame;
Ok(r)
}
}
#[cfg(not(feature = "debug"))]
{
let _ = s;
f(self)
}
}
};
}
impl<'a, T> Encoder<'a, T> {
#[inline]
pub fn new(stream: T, ctxt: Context<'a>) -> Self {
Self {
stream,
ctxt,
#[cfg(feature = "debug")]
stack: source::Stack::new(),
}
}
#[inline]
pub fn swap_stream(&mut self, new: T) -> T {
replace(&mut self.stream, new)
}
#[inline]
pub fn user_data<U: Any>(&self) -> EncodingResult<&U> {
self.ctxt
.user
.ok_or(val_error!("User-data requested, but none is present"))
.and_then(|x| {
x.downcast_ref().ok_or(val_error!(
"User-data doesnt match the requested concrete type of {}",
core::any::type_name::<U>()
))
})
}
debug_fn!(with_item, Item(&'static str));
debug_fn!(with_variant, Variant(&'static str));
debug_fn!(with_field, Field(&'static str));
debug_fn!(with_index, Index(usize));
}
impl<T: Write> Encoder<'_, T> {
#[inline]
pub fn encode_value<V: Encode<T>>(&mut self, value: V) -> EncodingResult<()> {
value.encode(self)
}
}
impl<T: Read> Encoder<'_, T> {
#[inline]
pub fn decode_value<V: Decode<T>>(&mut self) -> EncodingResult<V> {
V::decode(self)
}
}
impl<'a, T> Encoder<'a, T> {
#[inline]
pub fn finish(self) -> (T, Context<'a>) {
(self.stream, self.ctxt)
}
}
macro_rules! make_write_fns {
(
type $uty:ty {
pub u_write: $u_write:ident,
pub u_write_direct: $u_write_direct:ident,
priv uleb128_encode: $uleb128_encode:ident
$(,)?
},
type $ity:ty {
pub i_write: $i_write:ident,
pub i_write_direct: $i_write_direct:ident,
priv leb128_encode: $leb128_encode:ident
$(,)?
}$(,)?
) => {
#[doc = "Encodes a `"]
#[doc = stringify!($uty)]
#[doc = "` to the underlying stream using ULEB-128 encoding"]
#[inline]
fn $uleb128_encode(&mut self, value: $uty) -> EncodingResult<()> {
let mut shifted = value;
let mut more = true;
while more {
let mut byte: u8 = shifted as u8 & 0b01111111;
shifted >>= 7;
if shifted != 0 {
byte |= 0b10000000;
} else {
more = false;
}
self.write_byte(byte)?;
}
Ok(())
}
#[doc = "Encodes a `"]
#[doc = stringify!($uty)]
#[doc = "` to the underlying stream, according to the endianness and numerical encoding in the encoder's state"]
#[inline]
pub fn $u_write(&mut self, value: $uty) -> EncodingResult<()> {
self.$u_write_direct(value, self.ctxt.settings.num_repr.num_encoding, self.ctxt.settings.num_repr.endianness)
}
#[doc = "Encodes a `"]
#[doc = stringify!($uty)]
#[doc = "` to the underlying stream, according to the endianness and numerical passed as parameters"]
#[inline]
pub fn $u_write_direct(&mut self, value: $uty, num_encoding: NumEncoding, endianness: Endianness) -> EncodingResult<()> {
match num_encoding {
NumEncoding::Fixed => {
let bytes: [u8; core::mem::size_of::<$uty>()] = match endianness {
Endianness::BigEndian => value.to_be_bytes(),
Endianness::LittleEndian => value.to_le_bytes()
};
self.stream.write(&bytes)?;
},
NumEncoding::Leb128 | NumEncoding::ProtobufWasteful | NumEncoding::ProtobufZigzag => {
self.$uleb128_encode(value)?;
}
}
Ok(())
}
#[doc = "Encodes a `"]
#[doc = stringify!($ity)]
#[doc = "` to the underlying stream using LEB-128 encoding"]
#[inline]
fn $leb128_encode(&mut self, value: $ity) -> EncodingResult<()> {
let mut shifted = value;
let mut more = true;
while more {
let mut byte = shifted as u8 & 0b0111_1111;
shifted >>= 7;
let neg = (byte & 0b0100_0000) != 0;
if (neg && shifted != -1) || (!neg && shifted != 0) {
byte |= 0b1000_0000;
} else {
more = false;
}
self.write_byte(byte)?;
}
Ok(())
}
#[doc = "Encodes a `"]
#[doc = stringify!($ity)]
#[doc = "` to the underlying stream, according to the endianness and numerical encoding in the encoder's state"]
#[inline]
pub fn $i_write(&mut self, value: $ity) -> EncodingResult<()> {
self.$i_write_direct(value, self.ctxt.settings.num_repr.num_encoding, self.ctxt.settings.num_repr.endianness)
}
#[doc = "Encodes a `"]
#[doc = stringify!($ity)]
#[doc = "` to the underlying stream, according to the endianness and numerical encoding passed as parameters"]
#[inline]
pub fn $i_write_direct(&mut self, value: $ity, num_encoding: NumEncoding, endianness: Endianness) -> EncodingResult<()> {
match num_encoding {
NumEncoding::Fixed => {
let bytes: [u8; core::mem::size_of::<$ity>()] = match endianness {
Endianness::BigEndian => value.to_be_bytes(),
Endianness::LittleEndian => value.to_le_bytes()
};
self.stream.write(&bytes)?;
},
NumEncoding::Leb128 => {
self.$leb128_encode(value)?;
},
NumEncoding::ProtobufWasteful => {
let unsigned = <$uty>::from_ne_bytes(value.to_ne_bytes());
self.$uleb128_encode(unsigned)?;
}
NumEncoding::ProtobufZigzag => {
let shifted = (value << 1) ^ (value >> (<$ity>::BITS - 1));
let unsigned = <$uty>::from_ne_bytes(shifted.to_ne_bytes());
self.$uleb128_encode(unsigned)?;
}
}
Ok(())
}
};
}
impl<T: Write> Encoder<'_, T> {
make_write_fns! {
type u8 {
pub u_write: write_u8,
pub u_write_direct: write_u8_with,
priv uleb128_encode: uleb128_encode_u8,
},
type i8 {
pub i_write: write_i8,
pub i_write_direct: write_i8_with,
priv leb128_encode: leb128_encode_i8,
},
}
make_write_fns! {
type u16 {
pub u_write: write_u16,
pub u_write_direct: write_u16_with,
priv uleb128_encode: uleb128_encode_u16,
},
type i16 {
pub i_write: write_i16,
pub i_write_direct: write_i16_with,
priv leb128_encode: leb128_encode_i16,
},
}
make_write_fns! {
type u32 {
pub u_write: write_u32,
pub u_write_direct: write_u32_with,
priv uleb128_encode: uleb128_encode_u32,
},
type i32 {
pub i_write: write_i32,
pub i_write_direct: write_i32_with,
priv leb128_encode: leb128_encode_i32,
},
}
make_write_fns! {
type u64 {
pub u_write: write_u64,
pub u_write_direct: write_u64_with,
priv uleb128_encode: uleb128_encode_u64,
},
type i64 {
pub i_write: write_i64,
pub i_write_direct: write_i64_with,
priv leb128_encode: leb128_encode_i64,
},
}
make_write_fns! {
type u128 {
pub u_write: write_u128,
pub u_write_direct: write_u128_with,
priv uleb128_encode: uleb128_encode_u128,
},
type i128 {
pub i_write: write_i128,
pub i_write_direct: write_i128_with,
priv leb128_encode: leb128_encode_i128,
},
}
#[inline]
pub fn write_usize(&mut self, value: usize) -> EncodingResult<()> {
if let Some(size) = self.ctxt.consume_size_flatten() {
if size != value {
return Err(EncodingError::FlattenError(FlattenError::LenMismatch {
expected: size,
got: value,
}));
}
Ok(())
} else {
if value > self.ctxt.settings.size_repr.max_size {
return Err(EncodingError::MaxSizeExceeded {
max: self.ctxt.settings.size_repr.max_size,
requested: value,
});
}
let encoding = self.ctxt.settings.size_repr.num_encoding;
let endianness = self.ctxt.settings.size_repr.endianness;
let opaque = Opaque::from(value);
match self.ctxt.settings.size_repr.width {
BitWidth::Bit8 => self.write_u8_with(opaque.try_into()?, encoding, endianness),
BitWidth::Bit16 => self.write_u16_with(opaque.try_into()?, encoding, endianness),
BitWidth::Bit32 => self.write_u32_with(opaque.try_into()?, encoding, endianness),
BitWidth::Bit64 => self.write_u64_with(opaque.try_into()?, encoding, endianness),
BitWidth::Bit128 => self.write_u128_with(opaque.try_into()?, encoding, endianness),
}
}
}
#[inline]
pub fn write_isize(&mut self, value: isize) -> EncodingResult<()> {
let encoding = self.ctxt.settings.size_repr.num_encoding;
let endianness = self.ctxt.settings.size_repr.endianness;
let opaque = Opaque::from(value);
match self.ctxt.settings.size_repr.width {
BitWidth::Bit8 => self.write_i8_with(opaque.try_into()?, encoding, endianness),
BitWidth::Bit16 => self.write_i16_with(opaque.try_into()?, encoding, endianness),
BitWidth::Bit32 => self.write_i32_with(opaque.try_into()?, encoding, endianness),
BitWidth::Bit64 => self.write_i64_with(opaque.try_into()?, encoding, endianness),
BitWidth::Bit128 => self.write_i128_with(opaque.try_into()?, encoding, endianness),
}
}
#[inline]
#[allow(private_bounds)]
pub fn write_uvariant<V>(&mut self, value: V) -> EncodingResult<()>
where
Opaque: From<V>,
V: Sign<Sign = Unsigned>,
{
let value = Opaque::from(value);
if let Some(variant) = self.ctxt.consume_variant_flatten() {
if value != variant {
return Err(FlattenError::VariantMismatch {
expected: variant,
got: value,
}
.into());
}
Ok(())
} else {
let width = self.ctxt.settings.variant_repr.width;
let encoding = self.ctxt.settings.variant_repr.num_encoding;
let endianness = self.ctxt.settings.variant_repr.endianness;
match width {
BitWidth::Bit8 => self.write_u8_with(value.try_into()?, encoding, endianness),
BitWidth::Bit16 => self.write_u16_with(value.try_into()?, encoding, endianness),
BitWidth::Bit32 => self.write_u32_with(value.try_into()?, encoding, endianness),
BitWidth::Bit64 => self.write_u64_with(value.try_into()?, encoding, endianness),
BitWidth::Bit128 => self.write_u128_with(value.try_into()?, encoding, endianness),
}
}
}
#[inline]
#[allow(private_bounds)]
pub fn write_ivariant<V>(&mut self, value: V) -> EncodingResult<()>
where
Opaque: From<V>,
V: Sign<Sign = Signed>,
{
let value = Opaque::from(value);
if let Some(variant) = self.ctxt.consume_variant_flatten() {
if value != variant {
return Err(FlattenError::VariantMismatch {
expected: variant,
got: value,
}
.into());
}
Ok(())
} else {
let width = self.ctxt.settings.variant_repr.width;
let encoding = self.ctxt.settings.variant_repr.num_encoding;
let endianness = self.ctxt.settings.variant_repr.endianness;
match width {
BitWidth::Bit8 => self.write_i8_with(value.try_into()?, encoding, endianness),
BitWidth::Bit16 => self.write_i16_with(value.try_into()?, encoding, endianness),
BitWidth::Bit32 => self.write_i32_with(value.try_into()?, encoding, endianness),
BitWidth::Bit64 => self.write_i64_with(value.try_into()?, encoding, endianness),
BitWidth::Bit128 => self.write_i128_with(value.try_into()?, encoding, endianness),
}
}
}
#[inline]
pub fn write_bool(&mut self, value: bool) -> EncodingResult<()> {
if let Some(boolean) = self.ctxt.consume_bool_flatten() {
if boolean != value {
return Err(FlattenError::BoolMismatch {
expected: boolean,
got: value,
}
.into());
}
Ok(())
} else {
self.write_byte(if value { 1 } else { 0 })
}
}
#[inline]
pub fn write_char(&mut self, value: char) -> EncodingResult<()> {
self.write_char_with(
value,
self.ctxt.settings.string_repr.encoding,
self.ctxt.settings.string_repr.endianness
)
}
#[inline]
pub fn write_char_with(&mut self, value: char, encoding: StrEncoding, endianness: Endianness) -> EncodingResult<()> {
match encoding {
StrEncoding::Ascii => {
if !value.is_ascii() {
return Err(StringError::InvalidChar.into());
}
self.write_byte(value as u8)?;
}
StrEncoding::Utf8 => {
let mut buf = [0u8; 4];
let len = value.encode_utf8(&mut buf).len();
self.write_bytes(&buf[..len])?;
}
StrEncoding::Utf16 => {
let mut buf = [0u16; 2];
let len = value.encode_utf16(&mut buf).len();
for block in buf[..len].iter() {
self.write_u16_with(*block, NumEncoding::Fixed, endianness)?;
}
}
StrEncoding::Utf32 => {
self.write_u32_with(value as u32, NumEncoding::Fixed, endianness)?;
}
StrEncoding::Windows1252 => {
let encoded = windows1252::dec_to_enc(value);
if let Some(encoded) = encoded {
self.write_byte(encoded)?;
} else {
return Err(StringError::InvalidChar.into());
}
}
}
Ok(())
}
#[inline]
pub fn write_f32(&mut self, value: f32) -> EncodingResult<()> {
self.write_u32_with(
value.to_bits(),
NumEncoding::Fixed,
self.ctxt.settings.num_repr.endianness,
)
}
#[inline]
pub fn write_f64(&mut self, value: f64) -> EncodingResult<()> {
self.write_u64_with(
value.to_bits(),
NumEncoding::Fixed,
self.ctxt.settings.num_repr.endianness,
)
}
#[inline]
pub fn write_str<S>(&mut self, string: S) -> EncodingResult<()>
where
S: IntoIterator<Item = char, IntoIter: Clone>,
{
self.write_str_with(
string,
self.ctxt.settings.string_repr.encoding,
self.ctxt.settings.string_repr.endianness,
self.ctxt.settings.string_repr.len
)
}
pub fn write_str_with<S>(&mut self, string: S, encoding: StrEncoding, endianness: Endianness, len_encoding: StrLen) -> EncodingResult<()>
where
S: IntoIterator<Item = char, IntoIter: Clone>,
{
let chars = string.into_iter();
match len_encoding {
StrLen::LengthPrefixed => {
let mut sz_encoder = Encoder::new(SizeTrack::new(Zero), self.ctxt);
for ch in chars.clone() {
sz_encoder.write_char_with(ch, encoding, endianness)?;
}
let size = sz_encoder.finish().0.size_written();
self.write_usize(size)?;
for ch in chars {
self.write_char_with(ch, encoding, endianness)?;
}
}
StrLen::NullTerminated => {
for ch in chars {
self.write_char_with(ch, encoding, endianness)?;
}
self.write_char_with('\0', encoding, endianness)?;
}
StrLen::NullTerminatedFixed(max) => {
let mut capped = Encoder::new(SizeLimit::new(&mut self.stream, max, 0), self.ctxt);
for ch in chars {
match capped.write_char_with(ch, encoding, endianness) {
Err(EncodingError::UnexpectedEnd) => {
Err(EncodingError::StringError(StringError::TooLong))
}
any => any,
}?;
}
for _ in 0..capped.stream.remaining_writable() {
self.write_byte(0)?;
}
}
}
Ok(())
}
#[inline]
pub fn write_byte(&mut self, byte: u8) -> EncodingResult<()> {
self.stream.write(&[byte])
}
#[inline]
pub fn write_bytes(&mut self, bytes: &[u8]) -> EncodingResult<()> {
self.stream.write(bytes)
}
}
macro_rules! make_read_fns {
(
type $uty:ty {
pub u_read: $u_read:ident,
pub u_read_direct: $u_read_direct:ident,
priv uleb128_decode: $uleb128_decode:ident
$(,)?
},
type $ity:ty {
pub i_read: $i_read:ident,
pub i_read_direct: $i_read_direct:ident,
priv leb128_decode: $leb128_decode:ident
$(,)?
}
$(,)?
) => {
#[doc = "Decodes a `"]
#[doc = stringify!($uty)]
#[doc = "` from the underlying stream using ULEB-128 decoding"]
#[inline]
fn $uleb128_decode(&mut self) -> EncodingResult<$uty> {
let mut result: $uty = 0;
let mut shift: u8 = 0;
loop {
if shift >= <$uty>::BITS as u8 {
return Err(EncodingError::VarIntError);
}
let byte = self.read_byte()?;
result |= (byte & 0b0111_1111) as $uty << shift;
shift += 7;
if (byte & 0b1000_0000) == 0 {
break;
}
}
Ok(result)
}
#[doc = "Decodes a `"]
#[doc = stringify!($uty)]
#[doc = "` from the underlying stream, according to the endianness and numerical encoding in the encoder's state"]
#[inline]
pub fn $u_read(&mut self) -> EncodingResult<$uty> {
self.$u_read_direct(self.ctxt.settings.num_repr.num_encoding, self.ctxt.settings.num_repr.endianness)
}
#[doc = "Decodes a `"]
#[doc = stringify!($uty)]
#[doc = "` from the underlying stream, according to the endianness and numerical passed as parameters"]
#[inline]
pub fn $u_read_direct(&mut self, num_encoding: NumEncoding, endianness: Endianness) -> EncodingResult<$uty> {
Ok(match num_encoding {
NumEncoding::Fixed => {
let mut bytes: [u8; core::mem::size_of::<$uty>()] = [0u8; core::mem::size_of::<$uty>()];
self.stream.read(&mut bytes)?;
match endianness {
Endianness::BigEndian => <$uty>::from_be_bytes(bytes),
Endianness::LittleEndian => <$uty>::from_le_bytes(bytes)
}
}
NumEncoding::Leb128 | NumEncoding::ProtobufWasteful | NumEncoding::ProtobufZigzag => {
self.$uleb128_decode()?
}
})
}
#[doc = "Decodes a `"]
#[doc = stringify!($ity)]
#[doc = "` from the underlying stream using LEB-128 decoding"]
#[inline]
fn $leb128_decode(&mut self) -> EncodingResult<$ity> {
let mut result: $ity = 0;
let mut byte;
let mut shift: u8 = 0;
loop {
if shift >= <$ity>::BITS as u8 {
return Err(EncodingError::VarIntError);
}
byte = self.read_byte()?;
result |= (byte & 0b0111_1111) as $ity << shift;
shift += 7;
if (byte & 0b1000_0000) == 0 {
break;
}
}
if shift < <$ity>::BITS as u8 && (byte & 0b0100_0000) != 0 {
result |= (!0 << shift);
}
Ok(result)
}
#[doc = "Decodes a `"]
#[doc = stringify!($ity)]
#[doc = "` from the underlying stream, according to the endianness and numerical encoding in the encoder's context"]
#[inline]
pub fn $i_read(&mut self) -> EncodingResult<$ity> {
self.$i_read_direct(self.ctxt.settings.num_repr.num_encoding, self.ctxt.settings.num_repr.endianness)
}
#[doc = "Decodes a `"]
#[doc = stringify!($ity)]
#[doc = "` from the underlying stream, according to the endianness and numerical encoding passed as parameters"]
#[inline]
pub fn $i_read_direct(&mut self, num_encoding: NumEncoding, endianness: Endianness) -> EncodingResult<$ity> {
Ok(match num_encoding {
NumEncoding::Fixed => {
let mut bytes: [u8; core::mem::size_of::<$ity>()] = [0u8; core::mem::size_of::<$ity>()];
self.stream.read(&mut bytes)?;
match endianness {
Endianness::BigEndian => <$ity>::from_be_bytes(bytes),
Endianness::LittleEndian => <$ity>::from_le_bytes(bytes)
}
}
NumEncoding::Leb128 => {
self.$leb128_decode()?
}
NumEncoding::ProtobufWasteful => {
let unsigned = self.$uleb128_decode()?;
<$ity>::from_ne_bytes(unsigned.to_ne_bytes())
}
NumEncoding::ProtobufZigzag => {
let unsigned = self.$uleb128_decode()?;
let neg = (unsigned & 1) != 0;
let transformed = if neg {
!(unsigned >> 1)
} else {
unsigned >> 1
};
<$ity>::from_ne_bytes(transformed.to_ne_bytes())
}
})
}
};
}
impl<'user, T: Read> Encoder<'user, T> {
make_read_fns! {
type u8 {
pub u_read: read_u8,
pub u_read_direct: read_u8_with,
priv uleb128_decode: uleb128_decode_u8,
},
type i8 {
pub i_read: read_i8,
pub i_read_direct: read_i8_with,
priv leb128_decode: leb128_decode_i8,
},
}
make_read_fns! {
type u16 {
pub u_read: read_u16,
pub u_read_direct: read_u16_with,
priv uleb128_decode: uleb128_decode_u16,
},
type i16 {
pub i_read: read_i16,
pub i_read_direct: read_i16_with,
priv leb128_decode: leb128_decode_i16,
},
}
make_read_fns! {
type u32 {
pub u_read: read_u32,
pub u_read_direct: read_u32_with,
priv uleb128_decode: uleb128_decode_u32,
},
type i32 {
pub i_read: read_i32,
pub i_read_direct: read_i32_with,
priv leb128_decode: leb128_decode_i32,
},
}
make_read_fns! {
type u64 {
pub u_read: read_u64,
pub u_read_direct: read_u64_with,
priv uleb128_decode: uleb128_decode_u64,
},
type i64 {
pub i_read: read_i64,
pub i_read_direct: read_i64_with,
priv leb128_decode: leb128_decode_i64,
},
}
make_read_fns! {
type u128 {
pub u_read: read_u128,
pub u_read_direct: read_u128_with,
priv uleb128_decode: uleb128_decode_u128,
},
type i128 {
pub i_read: read_i128,
pub i_read_direct: read_i128_with,
priv leb128_decode: leb128_decode_i128,
},
}
#[inline]
pub fn read_usize(&mut self) -> EncodingResult<usize> {
if let Some(size) = self.ctxt.consume_size_flatten() {
Ok(size)
} else {
let encoding = self.ctxt.settings.size_repr.num_encoding;
let endianness = self.ctxt.settings.size_repr.endianness;
let value = match self.ctxt.settings.size_repr.width {
BitWidth::Bit8 => Opaque::from(self.read_u8_with(encoding, endianness)?),
BitWidth::Bit16 => Opaque::from(self.read_u16_with(encoding, endianness)?),
BitWidth::Bit32 => Opaque::from(self.read_u32_with(encoding, endianness)?),
BitWidth::Bit64 => Opaque::from(self.read_u64_with(encoding, endianness)?),
BitWidth::Bit128 => Opaque::from(self.read_u128_with(encoding, endianness)?),
}
.try_into()?;
if value > self.ctxt.settings.size_repr.max_size {
return Err(EncodingError::MaxSizeExceeded {
max: self.ctxt.settings.size_repr.max_size,
requested: value,
});
}
Ok(value)
}
}
#[inline]
pub fn read_isize(&mut self) -> EncodingResult<isize> {
let encoding = self.ctxt.settings.size_repr.num_encoding;
let endianness = self.ctxt.settings.size_repr.endianness;
match self.ctxt.settings.size_repr.width {
BitWidth::Bit8 => Opaque::from(self.read_i8_with(encoding, endianness)?),
BitWidth::Bit16 => Opaque::from(self.read_i16_with(encoding, endianness)?),
BitWidth::Bit32 => Opaque::from(self.read_i32_with(encoding, endianness)?),
BitWidth::Bit64 => Opaque::from(self.read_i64_with(encoding, endianness)?),
BitWidth::Bit128 => Opaque::from(self.read_i128_with(encoding, endianness)?),
}
.try_into()
}
#[inline]
#[allow(private_bounds)]
pub fn read_uvariant<V>(&mut self) -> EncodingResult<V>
where
V: Sign<Sign = Unsigned>,
Opaque: TryInto<V, Error = EncodingError>,
{
if let Some(variant) = self.ctxt.consume_variant_flatten() {
variant.try_into()
} else {
let width = self.ctxt.settings.variant_repr.width;
let encoding = self.ctxt.settings.variant_repr.num_encoding;
let endianness = self.ctxt.settings.variant_repr.endianness;
match width {
BitWidth::Bit8 => Opaque::from(self.read_u8_with(encoding, endianness)?),
BitWidth::Bit16 => Opaque::from(self.read_u16_with(encoding, endianness)?),
BitWidth::Bit32 => Opaque::from(self.read_u32_with(encoding, endianness)?),
BitWidth::Bit64 => Opaque::from(self.read_u64_with(encoding, endianness)?),
BitWidth::Bit128 => Opaque::from(self.read_u128_with(encoding, endianness)?),
}
.try_into()
}
}
#[inline]
#[allow(private_bounds)]
pub fn read_ivariant<V>(&mut self) -> EncodingResult<V>
where
V: Sign<Sign = Signed>,
Opaque: TryInto<V, Error = EncodingError>,
{
if let Some(variant) = self.ctxt.consume_variant_flatten() {
variant.try_into()
} else {
let width = self.ctxt.settings.variant_repr.width;
let encoding = self.ctxt.settings.variant_repr.num_encoding;
let endianness = self.ctxt.settings.variant_repr.endianness;
match width {
BitWidth::Bit8 => Opaque::from(self.read_i8_with(encoding, endianness)?),
BitWidth::Bit16 => Opaque::from(self.read_i16_with(encoding, endianness)?),
BitWidth::Bit32 => Opaque::from(self.read_i32_with(encoding, endianness)?),
BitWidth::Bit64 => Opaque::from(self.read_i64_with(encoding, endianness)?),
BitWidth::Bit128 => Opaque::from(self.read_i128_with(encoding, endianness)?),
}
.try_into()
}
}
#[inline]
pub fn read_bool(&mut self) -> EncodingResult<bool> {
if let Some(boolean) = self.ctxt.consume_bool_flatten() {
Ok(boolean)
} else {
match self.read_byte()? {
0 => Ok(false),
1 => Ok(true),
_ => Err(EncodingError::InvalidBool),
}
}
}
#[inline]
pub fn read_char(&mut self) -> EncodingResult<char> {
self.read_char_with(
self.ctxt.settings.string_repr.encoding,
self.ctxt.settings.string_repr.endianness
)
}
#[inline]
fn read_char_with(&mut self, encoding: StrEncoding, endianness: Endianness) -> EncodingResult<char> {
match encoding {
StrEncoding::Ascii => {
let ch = self.read_byte()?;
if !ch.is_ascii() {
return Err(StringError::InvalidChar.into());
}
let ch = char::from_u32(ch as u32);
Ok(ch.unwrap())
}
StrEncoding::Utf8 => {
let mut buf = self.read_byte()?;
let (add, rshift) = if buf.leading_ones() == 0 {
(0usize, 1u32)
} else {
let leading = buf.leading_ones();
if leading == 1 || leading > 4 {
return Err(StringError::InvalidChar.into());
}
(leading as usize - 1, leading + 1)
};
let mut ch: u32 = ((u8::MAX >> rshift) & buf) as u32;
let mut shift = 0;
for _ in 0..add {
buf = self.read_byte()?;
if buf.leading_ones() != 1 {
return Err(StringError::InvalidChar.into());
}
shift += 6;
ch = (ch << shift) | ((buf & 0b0011_1111) as u32);
}
Ok(char::from_u32(ch).ok_or(
EncodingError::StringError(StringError::InvalidChar),
)?)
}
StrEncoding::Utf16 => {
let buf = self.read_u16_with(NumEncoding::Fixed, endianness)?;
let ch;
if 0xD800 <= buf && buf <= 0xDBFF {
let high_surrogate = buf;
let low_surrogate = self.read_u16_with(NumEncoding::Fixed, endianness)?;
if !(0xDC00 <= low_surrogate && low_surrogate <= 0xDFFF) {
return Err(StringError::InvalidChar.into());
}
const LOW_TEN_BITS: u16 = 0b0000_0011_1111_1111;
let high_bits = ((high_surrogate - 0xD800) & LOW_TEN_BITS) as u32;
let low_bits = ((low_surrogate - 0xDC00) & LOW_TEN_BITS) as u32;
ch = (high_bits << 10) | low_bits;
} else if 0xDC00 <= buf && buf <= 0xDFFF {
return Err(StringError::InvalidChar.into());
} else {
ch = buf as u32;
}
Ok(char::from_u32(ch).ok_or(
EncodingError::StringError(StringError::InvalidChar),
)?)
}
StrEncoding::Utf32 => {
let buf = self.read_u32_with(NumEncoding::Fixed, endianness)?;
Ok(char::from_u32(buf).ok_or(
EncodingError::StringError(StringError::InvalidChar),
)?)
}
StrEncoding::Windows1252 => {
let buf = self.read_byte()?;
if let Some(ch) = windows1252::enc_to_dec(buf) {
Ok(ch)
} else {
Err(EncodingError::StringError(StringError::InvalidChar))
}
}
}
}
#[inline]
pub fn read_f32(&mut self) -> EncodingResult<f32> {
Ok(f32::from_bits(self.read_u32_with(
NumEncoding::Fixed,
self.ctxt.settings.num_repr.endianness,
)?))
}
#[inline]
pub fn read_f64(&mut self) -> EncodingResult<f64> {
Ok(f64::from_bits(self.read_u64_with(
NumEncoding::Fixed,
self.ctxt.settings.num_repr.endianness,
)?))
}
#[inline]
pub fn read_str<S>(&mut self) -> EncodingResult<S>
where
S: FromIterator<char>,
{
self.read_str_iter()?.into_iter().collect()
}
#[inline]
pub fn read_str_with<S>(&mut self, encoding: StrEncoding, endianness: Endianness, len_encoding: StrLen) -> EncodingResult<S>
where
S: FromIterator<char>
{
self.read_str_iter_with(encoding, endianness, len_encoding)?.into_iter().collect()
}
#[inline]
pub fn read_str_iter<'a>(&'a mut self) -> EncodingResult<impl IntoIterator<Item = EncodingResult<char>> + use<'a, 'user, T>>
{
self.read_str_iter_with(
self.ctxt.settings.string_repr.encoding,
self.ctxt.settings.string_repr.endianness,
self.ctxt.settings.string_repr.len
)
}
#[inline]
pub fn read_str_iter_with<'a>(&'a mut self, encoding: StrEncoding, endianness: Endianness, len_encoding: StrLen) -> EncodingResult<impl IntoIterator<Item = EncodingResult<char>> + use<'a, 'user, T>>
{
struct LenPrefixCharIter<'iter, 'user, T: Read> {
encoder: Encoder<'user, SizeLimit<&'iter mut T>>,
encoding: StrEncoding,
endianness: Endianness,
}
impl<T: Read> Iterator for LenPrefixCharIter<'_, '_, T> {
type Item = EncodingResult<char>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.encoder.stream.remaining_readable() == 0 {
return None;
};
Some(self.encoder.read_char_with(self.encoding, self.endianness))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.encoder.stream.remaining_readable()))
}
}
struct NullTermCharIter<'iter, 'user, T: Read> {
encoder: &'iter mut Encoder<'user, T>,
encoding: StrEncoding,
endianness: Endianness,
}
impl<T: Read> Iterator for NullTermCharIter<'_, '_, T> {
type Item = EncodingResult<char>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match self.encoder.read_char_with(self.encoding, self.endianness) {
Ok('\0') => {
None }
Ok(x) => {
Some(Ok(x)) }
Err(x) => {
Some(Err(x)) }
}
}
}
struct NullTermFixedLengthCharIter<'iter, 'user, T: Read> {
encoder: Encoder<'user, SizeLimit<&'iter mut T>>,
encoding: StrEncoding,
endianness: Endianness
}
impl<T: Read> Iterator for NullTermFixedLengthCharIter<'_, '_, T> {
type Item = EncodingResult<char>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.encoder.stream.remaining_readable() == 0 {
return None;
}
match self.encoder.read_char_with(self.encoding, self.endianness) {
Ok('\0') => {
for _ in 0..self.encoder.stream.remaining_readable() {
let z = match self.encoder.read_byte() {
Ok(z) => z,
Err(err) => return Some(Err(err)),
};
if z != 0 {
return Some(Err(EncodingError::StringError(
StringError::MissingNull,
)));
}
}
None }
Ok(x) => {
Some(Ok(x)) }
Err(x) => {
Some(Err(x)) }
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.encoder.stream.remaining_readable()))
}
}
enum IteratorDecider<'iter, 'user, T: Read> {
LenPrefix(LenPrefixCharIter<'iter, 'user, T>),
NullTerm(NullTermCharIter<'iter, 'user, T>),
NullTermFixedLength(NullTermFixedLengthCharIter<'iter, 'user, T>)
}
impl<T: Read> Iterator for IteratorDecider<'_, '_, T> {
type Item = EncodingResult<char>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match self {
IteratorDecider::LenPrefix(x) => x.next(),
IteratorDecider::NullTerm(x) => x.next(),
IteratorDecider::NullTermFixedLength(x) => x.next(),
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
match self {
IteratorDecider::LenPrefix(x) => x.size_hint(),
IteratorDecider::NullTerm(x) => x.size_hint(),
IteratorDecider::NullTermFixedLength(x) => x.size_hint(),
}
}
}
match len_encoding {
StrLen::LengthPrefixed => {
let length = self.read_usize()?;
let iter = LenPrefixCharIter {
encoder: Encoder::new(SizeLimit::new(&mut self.stream, 0, length), self.ctxt),
encoding,
endianness
};
Ok(IteratorDecider::LenPrefix(iter))
}
StrLen::NullTerminated => {
let iter = NullTermCharIter {
encoder: self,
encoding,
endianness
};
Ok(IteratorDecider::NullTerm(iter))
}
StrLen::NullTerminatedFixed(max) => {
let iter = NullTermFixedLengthCharIter {
encoder: Encoder::new(SizeLimit::new(&mut self.stream, 0, max), self.ctxt),
encoding,
endianness
};
Ok(IteratorDecider::NullTermFixedLength(iter))
}
}
}
#[inline]
pub fn read_byte(&mut self) -> EncodingResult<u8> {
let mut buf = [0u8; 1];
self.stream.read(&mut buf)?;
Ok(buf[0])
}
#[inline]
pub fn read_bytes(&mut self, buf: &mut [u8]) -> EncodingResult<()> {
self.stream.read(buf)
}
}
macro_rules! make_borrow_slice_fn {
($name:ident -> $ty:ty) => {
#[doc = "Borrows a `"]
#[doc = stringify!($ty)]
#[doc = "` slice of `length` length from the encoder, checking"]
#[doc = "that the [`Endianness`] and alignment match those of the system"]
#[doc = "and that the [`NumEncoding`] is [`borrowable`][`NumEncoding::borrowable`]"]
#[inline]
pub fn $name(
&mut self,
length: usize,
num_encoding: NumEncoding,
endianness: Endianness,
) -> EncodingResult<&'data [$ty]> {
if !num_encoding.borrowable() {
return Err(EncodingError::BorrowError(
BorrowError::NonBorrowableNumEncoding { num_encoding },
));
}
if endianness != Endianness::native() {
return Err(EncodingError::BorrowError(
BorrowError::EndiannessMismatch {
found: endianness,
system: Endianness::native(),
},
));
}
const BYTES: usize = core::mem::size_of::<$ty>();
let u8_slice: &[u8] = self.stream.borrow_read(length * BYTES)?;
let conv: &[$ty] = bytemuck::try_cast_slice(u8_slice)
.map_err(|_| EncodingError::BorrowError(BorrowError::AlignmentMismatch))?;
Ok(conv)
}
};
}
impl<'data, T: BorrowRead<'data>> Encoder<'_, T> {
#[inline]
pub fn peek_bytes(&self, len: usize) -> EncodingResult<&'data [u8]> {
self.stream.peek(len)
}
#[inline]
pub fn borrow_byte_slice(&mut self, len: usize) -> EncodingResult<&'data [u8]> {
self.stream.borrow_read(len)
}
#[inline]
pub fn borrow_u8_slice(
&mut self,
len: usize,
num_encoding: NumEncoding,
) -> EncodingResult<&'data [u8]> {
if !num_encoding.borrowable() {
return Err(EncodingError::BorrowError(
BorrowError::NonBorrowableNumEncoding { num_encoding },
));
}
self.stream.borrow_read(len)
}
make_borrow_slice_fn!(borrow_u16_slice -> u16);
make_borrow_slice_fn!(borrow_u32_slice -> u32);
make_borrow_slice_fn!(borrow_u64_slice -> u64);
make_borrow_slice_fn!(borrow_u128_slice -> u128);
#[inline]
pub fn borrow_i8_slice(
&mut self,
len: usize,
num_encoding: NumEncoding,
) -> EncodingResult<&'data [i8]> {
if !num_encoding.borrowable() {
return Err(EncodingError::BorrowError(
BorrowError::NonBorrowableNumEncoding { num_encoding },
));
}
let u8_slice: &[u8] = self.stream.borrow_read(len)?;
Ok(bytemuck::try_cast_slice(u8_slice).map_err(|_| BorrowError::AlignmentMismatch)?)
}
make_borrow_slice_fn!(borrow_i16_slice -> i16);
make_borrow_slice_fn!(borrow_i32_slice -> i32);
make_borrow_slice_fn!(borrow_i64_slice -> i64);
make_borrow_slice_fn!(borrow_i128_slice -> i128);
make_borrow_slice_fn!(borrow_f32_slice -> f32);
make_borrow_slice_fn!(borrow_f64_slice -> f64);
#[inline]
pub fn borrow_usize_slice(
&mut self,
len: usize,
num_encoding: NumEncoding,
endianness: Endianness,
bit_width: BitWidth,
) -> EncodingResult<&'data [usize]> {
if !num_encoding.borrowable() {
return Err(EncodingError::BorrowError(
BorrowError::NonBorrowableNumEncoding { num_encoding },
));
}
if endianness != Endianness::native() {
return Err(EncodingError::BorrowError(
BorrowError::EndiannessMismatch {
found: endianness,
system: Endianness::native(),
},
));
}
if bit_width != BitWidth::native() {
return Err(EncodingError::BorrowError(BorrowError::BitWidthMismatch {
found: bit_width,
system: BitWidth::native(),
}));
}
let u8_slice = self.stream.borrow_read(bit_width.bytes() * len)?;
let conv: &[usize] = bytemuck::try_cast_slice(u8_slice)
.map_err(|_| EncodingError::BorrowError(BorrowError::AlignmentMismatch))?;
for &elem in conv {
let max = self.ctxt.settings.size_repr.max_size;
if elem > max {
return Err(EncodingError::MaxSizeExceeded {
requested: elem,
max,
});
}
}
Ok(conv)
}
#[inline]
pub fn borrow_isize_slice(
&mut self,
len: usize,
num_encoding: NumEncoding,
endianness: Endianness,
bit_width: BitWidth,
) -> EncodingResult<&'data [isize]> {
if !num_encoding.borrowable() {
return Err(EncodingError::BorrowError(
BorrowError::NonBorrowableNumEncoding { num_encoding },
));
}
if endianness != Endianness::native() {
return Err(EncodingError::BorrowError(
BorrowError::EndiannessMismatch {
found: endianness,
system: Endianness::native(),
},
));
}
if bit_width != BitWidth::native() {
return Err(EncodingError::BorrowError(BorrowError::BitWidthMismatch {
found: bit_width,
system: BitWidth::native(),
}));
}
let u8_slice = self.stream.borrow_read(bit_width.bytes() * len)?;
let conv: &[isize] = bytemuck::try_cast_slice(u8_slice)
.map_err(|_| EncodingError::BorrowError(BorrowError::AlignmentMismatch))?;
Ok(conv)
}
}
impl<T: Seek> Encoder<'_, T> {
#[inline]
pub fn stream_position(&mut self) -> EncodingResult<usize> {
self.stream.seek(SeekFrom::POSITION)
}
#[inline]
pub fn seek(&mut self, seek: SeekFrom) -> EncodingResult<usize> {
self.stream.seek(seek)
}
#[inline]
pub fn with_seek<F, R>(&mut self, f: F, seek: SeekFrom) -> EncodingResult<R>
where
F: FnOnce(&mut Encoder<T>) -> EncodingResult<R>,
{
let prev = self.stream_position()? as isize;
let ret = f(self);
let cur = self.stream.seek(seek)? as isize;
let diff = prev - cur;
self.stream.seek(SeekFrom::Current(diff))?;
ret
}
}
pub trait Encode<W: Write> {
fn encode(&self, encoder: &mut Encoder<W>) -> EncodingResult<()>;
}
pub trait Decode<R: Read>: Sized {
fn decode(decoder: &mut Encoder<R>) -> EncodingResult<Self>;
fn decode_in_place(&mut self, decoder: &mut Encoder<R>) -> EncodingResult<()> {
*self = Self::decode(decoder)?;
Ok(())
}
}