use crate::varint::{
de_zig_zag_i16, de_zig_zag_i32, de_zig_zag_i64, de_zig_zag_i128, max_of_last_byte, varint_max,
};
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct UnexpectedEnd;
impl core::fmt::Display for UnexpectedEnd {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("UnexpectedEnd")
}
}
pub trait Flavor<'de>: 'de {
type Remainder: 'de;
type Source: 'de;
type PopError: core::fmt::Debug + core::fmt::Display;
type FinalizeError: core::fmt::Debug + core::fmt::Display;
fn pop(&mut self) -> Result<u8, Self::PopError>;
fn size_hint(&self) -> Option<usize> {
None
}
fn try_take_n(&mut self, ct: usize) -> Result<&'de [u8], Self::PopError>;
fn try_take_n_temp<'a>(&'a mut self, ct: usize) -> Result<&'a [u8], Self::PopError>
where
'de: 'a,
{
self.try_take_n(ct)
}
fn finalize(self) -> Result<Self::Remainder, Self::FinalizeError>;
}
#[inline]
pub fn try_take_bool<'de, F: Flavor<'de>>(f: &mut F) -> Result<Option<bool>, F::PopError> {
match f.pop()? {
0 => Ok(Some(false)),
1 => Ok(Some(true)),
_ => Ok(None),
}
}
#[inline]
pub fn try_take_u8<'de, F: Flavor<'de>>(f: &mut F) -> Result<u8, F::PopError> {
f.pop()
}
#[inline]
pub fn try_take_u16<'de, F: Flavor<'de>>(f: &mut F) -> Result<Option<u16>, F::PopError> {
let mut out = 0;
for i in 0..varint_max::<u16>() {
let val = f.pop()?;
let carry = (val & 0x7F) as u16;
out |= carry << (7 * i);
if (val & 0x80) == 0 {
if i == varint_max::<u16>() - 1 && val > max_of_last_byte::<u16>() {
break;
} else {
return Ok(Some(out));
}
}
}
Ok(None)
}
#[inline]
pub fn try_take_u32<'de, F: Flavor<'de>>(f: &mut F) -> Result<Option<u32>, F::PopError> {
let mut out = 0;
for i in 0..varint_max::<u32>() {
let val = f.pop()?;
let carry = (val & 0x7F) as u32;
out |= carry << (7 * i);
if (val & 0x80) == 0 {
if i == varint_max::<u32>() - 1 && val > max_of_last_byte::<u32>() {
break;
} else {
return Ok(Some(out));
}
}
}
Ok(None)
}
#[inline]
pub fn try_take_u64<'de, F: Flavor<'de>>(f: &mut F) -> Result<Option<u64>, F::PopError> {
let mut out = 0;
for i in 0..varint_max::<u64>() {
let val = f.pop()?;
let carry = (val & 0x7F) as u64;
out |= carry << (7 * i);
if (val & 0x80) == 0 {
if i == varint_max::<u64>() - 1 && val > max_of_last_byte::<u64>() {
break;
} else {
return Ok(Some(out));
}
}
}
Ok(None)
}
#[inline]
pub fn try_take_u128<'de, F: Flavor<'de>>(f: &mut F) -> Result<Option<u128>, F::PopError> {
let mut out = 0;
for i in 0..varint_max::<u128>() {
let val = f.pop()?;
let carry = (val & 0x7F) as u128;
out |= carry << (7 * i);
if (val & 0x80) == 0 {
if i == varint_max::<u128>() - 1 && val > max_of_last_byte::<u128>() {
break;
} else {
return Ok(Some(out));
}
}
}
Ok(None)
}
#[inline]
pub fn try_take_usize<'de, F: Flavor<'de>>(f: &mut F) -> Result<Option<usize>, F::PopError> {
#[cfg(target_pointer_width = "16")]
let u = try_take_u16(f);
#[cfg(target_pointer_width = "32")]
let u = try_take_u32(f);
#[cfg(target_pointer_width = "64")]
let u = try_take_u64(f);
u.map(|u| u.map(|u| u as usize))
}
#[inline]
pub fn try_take_i8<'de, F: Flavor<'de>>(f: &mut F) -> Result<i8, F::PopError> {
let u = try_take_u8(f)?;
Ok(u as i8)
}
#[inline]
pub fn try_take_i16<'de, F: Flavor<'de>>(f: &mut F) -> Result<Option<i16>, F::PopError> {
let u = try_take_u16(f)?;
Ok(u.map(de_zig_zag_i16))
}
#[inline]
pub fn try_take_i32<'de, F: Flavor<'de>>(f: &mut F) -> Result<Option<i32>, F::PopError> {
let u = try_take_u32(f)?;
Ok(u.map(de_zig_zag_i32))
}
#[inline]
pub fn try_take_i64<'de, F: Flavor<'de>>(f: &mut F) -> Result<Option<i64>, F::PopError> {
let u = try_take_u64(f)?;
Ok(u.map(de_zig_zag_i64))
}
#[inline]
pub fn try_take_i128<'de, F: Flavor<'de>>(f: &mut F) -> Result<Option<i128>, F::PopError> {
let u = try_take_u128(f)?;
Ok(u.map(de_zig_zag_i128))
}
#[inline]
pub fn try_take_isize<'de, F: Flavor<'de>>(f: &mut F) -> Result<Option<isize>, F::PopError> {
#[cfg(target_pointer_width = "16")]
{
let i = try_take_i16(f)?;
Ok(i.map(|i| i as isize))
}
#[cfg(target_pointer_width = "32")]
{
let i = try_take_i32(f)?;
Ok(i.map(|i| i as isize))
}
#[cfg(target_pointer_width = "64")]
{
let i = try_take_i64(f)?;
Ok(i.map(|i| i as isize))
}
}
#[inline]
pub fn try_take_f32<'de, F: Flavor<'de>>(f: &mut F) -> Result<f32, F::PopError> {
let bytes = f.try_take_n_temp(4)?;
let mut buf = [0u8; 4];
buf.copy_from_slice(bytes);
Ok(f32::from_bits(u32::from_le_bytes(buf)))
}
#[inline]
pub fn try_take_f64<'de, F: Flavor<'de>>(f: &mut F) -> Result<f64, F::PopError> {
let bytes = f.try_take_n_temp(8)?;
let mut buf = [0u8; 8];
buf.copy_from_slice(bytes);
Ok(f64::from_bits(u64::from_le_bytes(buf)))
}
#[inline]
pub fn try_take_bytes<'de, F: Flavor<'de>>(f: &mut F) -> Result<Option<&'de [u8]>, F::PopError> {
let len = match try_take_length(f) {
Ok(Some(l)) => l,
Ok(None) => return Ok(None),
Err(e) => return Err(e),
};
let sli = f.try_take_n(len)?;
Ok(Some(sli))
}
#[inline]
pub fn try_take_bytes_temp<'a, 'de: 'a, F: Flavor<'de>>(
f: &'a mut F,
) -> Result<Option<&'a [u8]>, F::PopError> {
let len = match try_take_length(f) {
Ok(Some(l)) => l,
Ok(None) => return Ok(None),
Err(e) => return Err(e),
};
let sli = f.try_take_n_temp(len)?;
Ok(Some(sli))
}
#[inline]
pub fn try_take_str<'de, F: Flavor<'de>>(f: &mut F) -> Result<Option<&'de str>, F::PopError> {
match try_take_bytes(f) {
Ok(Some(sli)) => Ok(core::str::from_utf8(sli).ok()),
Ok(None) => Ok(None),
Err(e) => Err(e),
}
}
#[inline]
pub fn try_take_str_temp<'a, 'de: 'a, F: Flavor<'de>>(
f: &'a mut F,
) -> Result<Option<&'a str>, F::PopError> {
match try_take_bytes_temp(f) {
Ok(Some(sli)) => Ok(core::str::from_utf8(sli).ok()),
Ok(None) => Ok(None),
Err(e) => Err(e),
}
}
#[inline]
pub fn try_take_char<'de, F: Flavor<'de>>(f: &mut F) -> Result<Option<char>, F::PopError> {
let Some(sz) = try_take_usize(f)? else {
return Ok(None);
};
if sz > 4 {
return Ok(None);
}
let bytes: &[u8] = f.try_take_n_temp(sz)?;
let Ok(strsl) = core::str::from_utf8(bytes) else {
return Ok(None);
};
Ok(strsl.chars().next())
}
#[inline]
pub fn try_take_option_discrim<'de, F: Flavor<'de>>(
f: &mut F,
) -> Result<Option<bool>, F::PopError> {
try_take_bool(f)
}
#[inline]
pub fn try_take_discriminant<'de, F: Flavor<'de>>(f: &mut F) -> Result<Option<u32>, F::PopError> {
try_take_u32(f)
}
#[inline]
pub fn try_take_length<'de, F: Flavor<'de>>(f: &mut F) -> Result<Option<usize>, F::PopError> {
try_take_usize(f)
}