#[cfg(feature = "alloc")]
use alloc::{string::String, vec::Vec};
use crate::io::{Read, Write};
pub mod simple {
pub const FALSE: u8 = 20;
pub const TRUE: u8 = 21;
pub const NULL: u8 = 22;
pub const UNDEFINED: u8 = 23;
}
pub mod tag {
pub const BIGPOS: u64 = 2;
pub const BIGNEG: u64 = 3;
}
#[derive(Debug)]
pub enum Error {
Io(crate::io::Error),
Syntax(usize),
}
impl From<crate::io::Error> for Error {
#[inline]
fn from(value: crate::io::Error) -> Self {
Self::Io(value)
}
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Error::Io(err) => write!(f, "i/o error: {err}"),
Error::Syntax(offset) => write!(f, "syntax error at offset {offset}"),
}
}
}
impl serde::ser::StdError for Error {
fn source(&self) -> Option<&(dyn serde::ser::StdError + 'static)> {
match self {
Error::Io(err) => Some(err),
Error::Syntax(..) => None,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Header {
Positive(u64),
Negative(u64),
Float(f64),
Simple(u8),
Tag(u64),
Break,
Bytes(Option<usize>),
Text(Option<usize>),
Array(Option<usize>),
Map(Option<usize>),
}
pub struct Encoder<W>(W);
impl<W: Write> From<W> for Encoder<W> {
#[inline]
fn from(writer: W) -> Self {
Self(writer)
}
}
impl<W: Write> Encoder<W> {
#[inline]
pub(crate) fn reserve(&mut self, additional: usize) {
self.0.reserve(additional);
}
#[inline]
pub(crate) fn push_uint(&mut self, major: u8, value: u64) -> Result<(), crate::io::Error> {
let prefix = major << 5;
match value {
x if x <= 23 => self.0.write_all(&[prefix | x as u8]),
x if x <= u8::MAX as u64 => self.0.write_all(&[prefix | 24, x as u8]),
x if x <= u16::MAX as u64 => {
let b = (x as u16).to_be_bytes();
self.0.write_all(&[prefix | 25, b[0], b[1]])
}
x if x <= u32::MAX as u64 => {
let b = (x as u32).to_be_bytes();
self.0.write_all(&[prefix | 26, b[0], b[1], b[2], b[3]])
}
x => {
let b = x.to_be_bytes();
self.0
.write_all(&[prefix | 27, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
}
}
}
#[inline]
pub(crate) fn push_len(
&mut self,
major: u8,
len: Option<usize>,
) -> Result<(), crate::io::Error> {
match len {
Some(len) => self.push_uint(major, len as u64),
None => self.0.write_all(&[(major << 5) | 31]),
}
}
#[inline]
pub(crate) fn positive(&mut self, value: u64) -> Result<(), crate::io::Error> {
self.push_uint(0, value)
}
#[inline]
pub(crate) fn negative(&mut self, value: u64) -> Result<(), crate::io::Error> {
self.push_uint(1, value)
}
#[inline]
pub(crate) fn tag(&mut self, value: u64) -> Result<(), crate::io::Error> {
self.push_uint(6, value)
}
#[inline]
pub(crate) fn array(&mut self, len: Option<usize>) -> Result<(), crate::io::Error> {
self.push_len(4, len)
}
#[inline]
pub(crate) fn map(&mut self, len: Option<usize>) -> Result<(), crate::io::Error> {
self.push_len(5, len)
}
#[inline]
pub(crate) fn simple(&mut self, value: u8) -> Result<(), crate::io::Error> {
match value {
0..=23 => self.0.write_all(&[0xe0 | value]),
value => self.0.write_all(&[0xf8, value]),
}
}
#[inline]
pub(crate) fn float(&mut self, value: f64) -> Result<(), crate::io::Error> {
if value.is_nan() {
if let Some(n16) = f64_to_f16(value) {
let b = n16.to_be_bytes();
return self.0.write_all(&[0xf9, b[0], b[1]]);
}
} else {
let n32 = value as f32;
if (n32 as f64).to_bits() == value.to_bits() {
if let Some(n16) = f64_to_f16(value) {
let b = n16.to_be_bytes();
return self.0.write_all(&[0xf9, b[0], b[1]]);
}
let b = n32.to_bits().to_be_bytes();
return self.0.write_all(&[0xfa, b[0], b[1], b[2], b[3]]);
}
}
let b = value.to_bits().to_be_bytes();
self.0
.write_all(&[0xfb, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
}
#[inline]
pub fn push(&mut self, header: Header) -> Result<(), crate::io::Error> {
match header {
Header::Positive(x) => self.positive(x),
Header::Negative(x) => self.negative(x),
Header::Bytes(x) => self.push_len(2, x),
Header::Text(x) => self.push_len(3, x),
Header::Array(x) => self.array(x),
Header::Map(x) => self.map(x),
Header::Tag(x) => self.tag(x),
Header::Break => self.0.write_all(&[0xff]),
Header::Simple(x) => self.simple(x),
Header::Float(x) => self.float(x),
}
}
#[inline]
pub fn bytes(&mut self, value: &[u8]) -> Result<(), crate::io::Error> {
self.reserve(value.len().saturating_add(9));
self.push_len(2, Some(value.len()))?;
self.0.write_all(value)
}
#[inline]
pub fn text(&mut self, value: &str) -> Result<(), crate::io::Error> {
self.reserve(value.len().saturating_add(9));
self.push_len(3, Some(value.len()))?;
self.0.write_all(value.as_bytes())
}
#[inline]
pub fn write_all(&mut self, data: &[u8]) -> Result<(), crate::io::Error> {
self.0.write_all(data)
}
#[inline]
pub fn flush(&mut self) -> Result<(), crate::io::Error> {
self.0.flush()
}
}
#[cfg(feature = "alloc")]
const CHUNK: usize = 16 * 1024;
pub struct Decoder<R> {
reader: R,
offset: usize,
pushback: Option<(Header, usize)>,
mark: usize,
#[cfg(feature = "alloc")]
last_header: ([u8; 9], u8),
#[cfg(feature = "alloc")]
record: Option<Vec<u8>>,
}
impl<R: Read> From<R> for Decoder<R> {
#[inline]
fn from(reader: R) -> Self {
Self {
reader,
offset: 0,
pushback: None,
mark: 0,
#[cfg(feature = "alloc")]
last_header: ([0; 9], 0),
#[cfg(feature = "alloc")]
record: None,
}
}
}
#[inline]
fn decode_header(raw: &[u8; 9], arg: Option<u64>, start: usize) -> Result<Header, Error> {
let major = raw[0] >> 5;
let minor = raw[0] & 0b00011111;
#[cfg(target_pointer_width = "64")]
let len = |arg: Option<u64>| Ok::<_, Error>(arg.map(|x| x as usize));
#[cfg(not(target_pointer_width = "64"))]
let len = |arg: Option<u64>| match arg {
Some(x) => usize::try_from(x)
.map(Some)
.map_err(|_| Error::Syntax(start)),
None => Ok(None),
};
Ok(match major {
0 => Header::Positive(arg.ok_or(Error::Syntax(start))?),
1 => Header::Negative(arg.ok_or(Error::Syntax(start))?),
2 => Header::Bytes(len(arg)?),
3 => Header::Text(len(arg)?),
4 => Header::Array(len(arg)?),
5 => Header::Map(len(arg)?),
6 => Header::Tag(arg.ok_or(Error::Syntax(start))?),
_ => match minor {
x @ 0..=23 => Header::Simple(x),
24 if raw[1] >= 32 => Header::Simple(raw[1]),
24 => return Err(Error::Syntax(start)),
25 => Header::Float(f16_to_f64(u16::from_be_bytes([raw[1], raw[2]]))),
26 => Header::Float(
f32::from_bits(u32::from_be_bytes([raw[1], raw[2], raw[3], raw[4]])) as f64,
),
27 => Header::Float(f64::from_bits(u64::from_be_bytes([
raw[1], raw[2], raw[3], raw[4], raw[5], raw[6], raw[7], raw[8],
]))),
31 => Header::Break,
_ => return Err(Error::Syntax(start)),
},
})
}
impl<R: Read> Decoder<R> {
pub fn pull(&mut self) -> Result<Header, Error> {
if let Some((header, end)) = self.pushback.take() {
self.mark = self.offset;
self.offset = end;
return Ok(header);
}
let start = self.offset;
self.mark = start;
let mut raw = [0u8; 9];
self.read_exact(&mut raw[..1])?;
let minor = raw[0] & 0b00011111;
let (arg, raw_len) = match minor {
x @ 0..=23 => (Some(u64::from(x)), 1),
24 => {
self.read_exact(&mut raw[1..2])?;
(Some(u64::from(raw[1])), 2)
}
25 => {
self.read_exact(&mut raw[1..3])?;
(Some(u64::from(u16::from_be_bytes([raw[1], raw[2]]))), 3)
}
26 => {
self.read_exact(&mut raw[1..5])?;
(
Some(u64::from(u32::from_be_bytes([
raw[1], raw[2], raw[3], raw[4],
]))),
5,
)
}
27 => {
self.read_exact(&mut raw[1..9])?;
(
Some(u64::from_be_bytes([
raw[1], raw[2], raw[3], raw[4], raw[5], raw[6], raw[7], raw[8],
])),
9,
)
}
31 => (None, 1),
_ => return Err(Error::Syntax(start)),
};
#[cfg(feature = "alloc")]
{
self.last_header.0 = raw;
self.last_header.1 = raw_len;
}
#[cfg(not(feature = "alloc"))]
let _ = raw_len;
decode_header(&raw, arg, start)
}
pub fn push(&mut self, header: Header) {
assert!(self.pushback.is_none(), "header already buffered");
self.pushback = Some((header, self.offset));
self.offset = self.mark;
}
#[inline]
pub fn offset(&self) -> usize {
self.offset
}
pub fn read_exact(&mut self, data: &mut [u8]) -> Result<(), crate::io::Error> {
debug_assert!(self.pushback.is_none());
self.reader.read_exact(data)?;
self.offset += data.len();
#[cfg(feature = "alloc")]
if let Some(record) = &mut self.record {
record.extend_from_slice(data);
}
Ok(())
}
#[cfg(feature = "alloc")]
pub(crate) fn start_recording(&mut self) {
let mut record = Vec::new();
if self.pushback.is_some() {
let (raw, raw_len) = &self.last_header;
record.extend_from_slice(&raw[..*raw_len as usize]);
}
self.record = Some(record);
}
#[cfg(feature = "alloc")]
pub(crate) fn take_recording(&mut self) -> Vec<u8> {
self.record.take().unwrap_or_default()
}
#[cfg(feature = "alloc")]
fn read_body(&mut self, len: usize, out: &mut Vec<u8>) -> Result<(), Error> {
let mut remaining = len;
while remaining > 0 {
let chunk = remaining.min(CHUNK);
let used = out.len();
out.resize(used + chunk, 0);
self.read_exact(&mut out[used..])?;
remaining -= chunk;
}
Ok(())
}
#[cfg(feature = "alloc")]
pub fn bytes_body(&mut self, len: Option<usize>, out: &mut Vec<u8>) -> Result<(), Error> {
match len {
Some(len) => self.read_body(len, out),
None => loop {
let offset = self.offset;
match self.pull()? {
Header::Break => return Ok(()),
Header::Bytes(Some(len)) => self.read_body(len, out)?,
_ => return Err(Error::Syntax(offset)),
}
},
}
}
#[cfg(feature = "alloc")]
pub fn text_body(&mut self, len: Option<usize>, out: &mut String) -> Result<(), Error> {
let read_segment = |me: &mut Self, len: usize, out: &mut String| {
let offset = me.offset;
let mut buffer = Vec::new();
me.read_body(len, &mut buffer)?;
match String::from_utf8(buffer) {
Ok(s) if out.is_empty() => {
*out = s;
Ok(())
}
Ok(s) => {
out.push_str(&s);
Ok(())
}
Err(..) => Err(Error::Syntax(offset)),
}
};
match len {
Some(len) => read_segment(self, len, out),
None => loop {
let offset = self.offset;
match self.pull()? {
Header::Break => return Ok(()),
Header::Text(Some(len)) => read_segment(self, len, out)?,
_ => return Err(Error::Syntax(offset)),
}
},
}
}
}
#[cfg(feature = "alloc")]
impl<'de> Decoder<&'de [u8]> {
#[inline]
fn slice_eof_after_prefix(&mut self) -> Error {
if let Some(record) = &mut self.record {
record.push(self.reader[0]);
}
self.reader = &self.reader[1..];
self.offset += 1;
crate::io::Error::from(crate::io::ErrorKind::UnexpectedEof).into()
}
#[inline]
fn finish_slice_header(&mut self, raw: [u8; 9], raw_len: u8) {
self.last_header.0 = raw;
self.last_header.1 = raw_len;
if let Some(record) = &mut self.record {
record.extend_from_slice(&raw[..raw_len as usize]);
}
self.reader = &self.reader[raw_len as usize..];
self.offset += raw_len as usize;
}
pub(crate) fn integer_slice(&mut self) -> Option<Result<(bool, u64), Error>> {
if self.pushback.is_some() {
return None;
}
let start = self.offset;
let first = *self.reader.first()?;
let major = first >> 5;
if major > 1 {
return None;
}
self.mark = start;
let minor = first & 0b00011111;
let (value, raw_len) = match minor {
x @ 0..=23 => (u64::from(x), 1),
24 => {
if self.reader.len() < 2 {
return Some(Err(self.slice_eof_after_prefix()));
}
(u64::from(self.reader[1]), 2)
}
25 => {
if self.reader.len() < 3 {
return Some(Err(self.slice_eof_after_prefix()));
}
(
u64::from(u16::from_be_bytes([self.reader[1], self.reader[2]])),
3,
)
}
26 => {
if self.reader.len() < 5 {
return Some(Err(self.slice_eof_after_prefix()));
}
(
u64::from(u32::from_be_bytes([
self.reader[1],
self.reader[2],
self.reader[3],
self.reader[4],
])),
5,
)
}
27 => {
if self.reader.len() < 9 {
return Some(Err(self.slice_eof_after_prefix()));
}
(
u64::from_be_bytes([
self.reader[1],
self.reader[2],
self.reader[3],
self.reader[4],
self.reader[5],
self.reader[6],
self.reader[7],
self.reader[8],
]),
9,
)
}
_ => return Some(Err(Error::Syntax(start))),
};
self.reader = &self.reader[raw_len as usize..];
self.offset += raw_len as usize;
Some(Ok((major == 1, value)))
}
pub(crate) fn bool_slice(&mut self) -> Option<bool> {
if self.pushback.is_some() {
return None;
}
let value = match *self.reader.first()? {
0xf4 => false,
0xf5 => true,
_ => return None,
};
self.mark = self.offset;
self.reader = &self.reader[1..];
self.offset += 1;
Some(value)
}
pub(crate) fn float_slice(&mut self) -> Option<Result<f64, Error>> {
if self.pushback.is_some() {
return None;
}
let start = self.offset;
let first = *self.reader.first()?;
let (value, raw_len) = match first {
0xf9 => {
if self.reader.len() < 3 {
return Some(Err(self.slice_eof_after_prefix()));
}
(
f16_to_f64(u16::from_be_bytes([self.reader[1], self.reader[2]])),
3,
)
}
0xfa => {
if self.reader.len() < 5 {
return Some(Err(self.slice_eof_after_prefix()));
}
(
f32::from_bits(u32::from_be_bytes([
self.reader[1],
self.reader[2],
self.reader[3],
self.reader[4],
])) as f64,
5,
)
}
0xfb => {
if self.reader.len() < 9 {
return Some(Err(self.slice_eof_after_prefix()));
}
(
f64::from_bits(u64::from_be_bytes([
self.reader[1],
self.reader[2],
self.reader[3],
self.reader[4],
self.reader[5],
self.reader[6],
self.reader[7],
self.reader[8],
])),
9,
)
}
_ => return None,
};
self.mark = start;
self.reader = &self.reader[raw_len..];
self.offset += raw_len;
Some(Ok(value))
}
pub(crate) fn pull_slice(&mut self) -> Result<Header, Error> {
if let Some((header, end)) = self.pushback.take() {
self.mark = self.offset;
self.offset = end;
return Ok(header);
}
let start = self.offset;
self.mark = start;
if self.reader.is_empty() {
return Err(crate::io::Error::from(crate::io::ErrorKind::UnexpectedEof).into());
}
let mut raw = [0u8; 9];
raw[0] = self.reader[0];
let minor = raw[0] & 0b00011111;
let (arg, raw_len) = match minor {
x @ 0..=23 => (Some(u64::from(x)), 1),
24 => {
if self.reader.len() < 2 {
return Err(self.slice_eof_after_prefix());
}
raw[1] = self.reader[1];
(Some(u64::from(raw[1])), 2)
}
25 => {
if self.reader.len() < 3 {
return Err(self.slice_eof_after_prefix());
}
raw[1] = self.reader[1];
raw[2] = self.reader[2];
(Some(u64::from(u16::from_be_bytes([raw[1], raw[2]]))), 3)
}
26 => {
if self.reader.len() < 5 {
return Err(self.slice_eof_after_prefix());
}
raw[1] = self.reader[1];
raw[2] = self.reader[2];
raw[3] = self.reader[3];
raw[4] = self.reader[4];
(
Some(u64::from(u32::from_be_bytes([
raw[1], raw[2], raw[3], raw[4],
]))),
5,
)
}
27 => {
if self.reader.len() < 9 {
return Err(self.slice_eof_after_prefix());
}
raw[1] = self.reader[1];
raw[2] = self.reader[2];
raw[3] = self.reader[3];
raw[4] = self.reader[4];
raw[5] = self.reader[5];
raw[6] = self.reader[6];
raw[7] = self.reader[7];
raw[8] = self.reader[8];
(
Some(u64::from_be_bytes([
raw[1], raw[2], raw[3], raw[4], raw[5], raw[6], raw[7], raw[8],
])),
9,
)
}
31 => (None, 1),
_ => return Err(Error::Syntax(start)),
};
self.finish_slice_header(raw, raw_len);
decode_header(&raw, arg, start)
}
pub(crate) fn borrow_body(&mut self, len: usize) -> Result<&'de [u8], crate::io::Error> {
debug_assert!(self.pushback.is_none());
if self.reader.len() < len {
return Err(crate::io::ErrorKind::UnexpectedEof.into());
}
let (head, tail) = self.reader.split_at(len);
self.reader = tail;
self.offset += len;
if let Some(record) = &mut self.record {
record.extend_from_slice(head);
}
Ok(head)
}
}
fn exp2(n: i32) -> f64 {
f64::from_bits(((n + 1023) as u64) << 52)
}
pub fn f16_to_f64(bits: u16) -> f64 {
let exp = (bits >> 10) & 0x1f;
let frac = (bits & 0x3ff) as f64;
let value = match exp {
0 => frac * exp2(-24),
31 if frac == 0.0 => f64::INFINITY,
31 => f64::NAN,
_ => (1024.0 + frac) * exp2(exp as i32 - 25),
};
if bits & 0x8000 == 0 {
value
} else {
-value
}
}
pub fn f64_to_f16(value: f64) -> Option<u16> {
let bits = value.to_bits();
let sign = ((bits >> 48) & 0x8000) as u16;
let exp = ((bits >> 52) & 0x7ff) as i32;
let frac = bits & 0x000f_ffff_ffff_ffff;
let half = if exp == 0x7ff {
match frac {
0 => sign | 0x7c00,
_ => 0x7e00,
}
} else {
let unbiased = exp - 1023;
if exp == 0 && frac == 0 {
sign } else if (-14..=15).contains(&unbiased) {
if frac & ((1 << 42) - 1) != 0 {
return None;
}
sign | (((unbiased + 15) as u16) << 10) | (frac >> 42) as u16
} else if (-24..-14).contains(&unbiased) {
let mantissa = (1u64 << 52) | frac;
let shift = 42 + (-14 - unbiased);
if mantissa & ((1 << shift) - 1) != 0 {
return None;
}
sign | (mantissa >> shift) as u16
} else {
return None;
}
};
if f16_to_f64(half).to_bits() == bits {
Some(half)
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn f16_exhaustive_roundtrip() {
for bits in 0..=u16::MAX {
let wide = f16_to_f64(bits);
if wide.is_nan() {
assert!(f64_to_f16(f64::NAN) == Some(0x7e00));
continue;
}
assert_eq!(f64_to_f16(wide), Some(bits), "bits {bits:04x} ({wide})");
}
}
#[test]
fn f16_rejects_lossy() {
for value in [
f64::MIN_POSITIVE, 65504.0 + 32.0, 65536.0, 1.1, 5.960464477539063e-8 / 2.0, 1.5 * 5.960464477539063e-8, ] {
assert_eq!(f64_to_f16(value), None, "{value}");
}
assert_eq!(f64_to_f16(-f64::NAN), None);
assert_eq!(f64_to_f16(f64::from_bits(0x7ff8_0000_0000_0001)), None);
}
#[cfg(feature = "alloc")]
#[test]
fn header_roundtrip() {
let headers = [
Header::Positive(0),
Header::Positive(23),
Header::Positive(24),
Header::Positive(u64::MAX),
Header::Negative(0),
Header::Negative(u64::MAX),
Header::Float(1.5),
Header::Float(f64::MAX),
Header::Simple(simple::FALSE),
Header::Simple(simple::UNDEFINED),
Header::Simple(255),
Header::Tag(0),
Header::Tag(u64::MAX),
Header::Break,
Header::Bytes(Some(0)),
Header::Bytes(Some(usize::MAX)),
Header::Bytes(None),
Header::Text(Some(64)),
Header::Text(None),
Header::Array(Some(1)),
Header::Array(None),
Header::Map(Some(1)),
Header::Map(None),
];
for header in headers {
let mut buffer = Vec::new();
Encoder::from(&mut buffer).push(header).unwrap();
let mut decoder = Decoder::from(&buffer[..]);
assert_eq!(decoder.pull().unwrap(), header, "{header:?}");
assert_eq!(decoder.offset(), buffer.len());
}
}
#[test]
fn pushback() {
let bytes = [0x19, 0x01, 0x00, 0x01]; let mut decoder = Decoder::from(&bytes[..]);
let first = decoder.pull().unwrap();
assert_eq!(first, Header::Positive(256));
assert_eq!(decoder.offset(), 3);
decoder.push(first);
assert_eq!(decoder.offset(), 0);
assert_eq!(decoder.pull().unwrap(), Header::Positive(256));
assert_eq!(decoder.offset(), 3);
assert_eq!(decoder.pull().unwrap(), Header::Positive(1));
assert_eq!(decoder.offset(), 4);
}
}