#![deny(clippy::std_instead_of_alloc, clippy::std_instead_of_core)]
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
extern crate alloc;
extern crate core;
use alloc::string::{String, ToString};
use core::{convert::Infallible, fmt};
#[cfg(feature = "std")]
use std::io;
mod de;
mod segmented_buf;
mod ser;
#[cfg(test)]
mod tests;
mod types;
mod utf;
mod util;
#[cfg(feature = "std")]
pub use self::{de::from_reader, ser::to_writer};
pub use self::{
de::{DeserializeOptions, from_slice},
segmented_buf::GrowStrategy,
ser::{SerializeOptions, to_boxed_slice},
types::{as_date, as_object, as_set}
};
macro_rules! define_tags {
(
$(#[$attr:meta])*
$vis:vis enum $name:ident {
$($variant:ident = $x:literal),*
}
) => {
$(#[$attr])*
$vis enum $name {
$($variant = $x,)*
}
impl TryFrom<u8> for $name {
type Error = u8;
fn try_from(value: u8) -> Result<Self, u8> {
match value {
$($x => Ok(Self::$variant),)*
_ => Err(value)
}
}
}
};
}
define_tags! {
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[doc(hidden)] pub enum SerializationTag {
Version = 0xFF,
Padding = 0x00,
VerifyObjectCount = b'?',
TheHole = b'-',
Undefined = b'_',
Null = b'0',
True = b'T',
False = b'F',
Int32 = b'I',
Uint32 = b'U',
Double = b'N',
BigInt = b'Z',
Utf8String = b'S',
OneByteString = b'"',
TwoByteString = b'c',
ObjectReference = b'^',
BeginJSObject = b'o',
EndJSObject = b'{', BeginSparseJSArray = b'a',
EndSparseJSArray = b'@',
BeginDenseJSArray = b'A',
EndDenseJSArray = b'$',
Date = b'D',
TrueObject = b'y',
FalseObject = b'x',
NumberObject = b'n',
BigIntObject = b'z',
StringObject = b's',
RegExp = b'R',
BeginJSMap = b';',
EndJSMap = b':',
BeginJSSet = b'\'',
EndJSSet = b',',
ArrayBuffer = b'B',
ResizableArrayBuffer = b'~',
ArrayBufferTransfer = b't',
ArrayBufferView = b'V',
SharedArrayBuffer = b'u',
SharedObject = b'p',
WasmModuleTransfer = b'w',
HostObject = b'\\',
WasmMemoryTransfer = b'm',
Error = b'r'
}
}
define_tags! {
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ArrayBufferViewTag {
Int8Array = b'b',
Uint8Array = b'B',
Uint8ClampedArray = b'C',
Int16Array = b'w',
Uint16Array = b'W',
Int32Array = b'd',
Uint32Array = b'D',
Float16Array = b'h',
Float32Array = b'f',
Float64Array = b'F',
BigInt64Array = b'q',
BigUint64Array = b'Q',
DataView = b'?'
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ErrorTag {
EvalErrorPrototype = b'E',
RangeErrorPrototype = b'R',
ReferenceErrorPrototype = b'F',
SyntaxErrorPrototype = b'S',
TypeErrorPrototype = b'T',
UriErrorPrototype = b'U',
Message = b'm',
Cause = b'c',
Stack = b's',
End = b'.'
}
const SMI_MIN: i64 = -2_i64.pow(30);
const SMI_MAX: i64 = 2_i64.pow(30) - 1;
const REGEXP_FLAG_GLOBAL: u32 = 1 << 0;
const REGEXP_FLAG_IGNORE_CASE: u32 = 1 << 1;
const REGEXP_FLAG_MULTILINE: u32 = 1 << 2;
const REGEXP_FLAG_STICKY: u32 = 1 << 3;
const REGEXP_FLAG_UNICODE: u32 = 1 << 4;
const REGEXP_FLAG_DOT_ALL: u32 = 1 << 5;
#[derive(Debug)]
pub enum Error {
UnexpectedEof,
BadUtf8,
BadUtf16,
BadVersion(u8),
UnknownTag(u8),
UnknownTypedArrayType(u8),
UnhandledTag(SerializationTag),
ArrayWithProperties,
BytesTooBig,
BigIntTooBig,
LengthMismatch {
head: u64,
tail: u64
},
Custom(String),
#[cfg(feature = "std")]
Io(io::Error)
}
#[cfg(feature = "std")]
impl From<io::Error> for Error {
fn from(value: io::Error) -> Self {
if value.kind() == io::ErrorKind::UnexpectedEof {
Self::UnexpectedEof
} else {
Error::Io(value)
}
}
}
impl From<Infallible> for Error {
fn from(_: Infallible) -> Self {
unsafe { core::hint::unreachable_unchecked() }
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::UnexpectedEof => f.write_str("unexpected end of stream"),
Error::BadUtf8 => f.write_str("malformed UTF-8 string"),
Error::BadUtf16 => f.write_str("malformed UTF-16 string"),
Error::BadVersion(v) => f.write_fmt(format_args!("unacceptable format version {v}")),
Error::BytesTooBig => f.write_str("byte arrays larger than 4 GB can only be serialized in format versions 16+"),
Error::BigIntTooBig => f.write_str("serialized BigInt exceeds i128"),
Error::UnknownTag(c) => f.write_fmt(format_args!("unknown tag {c:02X}")),
Error::UnknownTypedArrayType(c) => f.write_fmt(format_args!("unknown or unhandled typed array type {c:02X}")),
Error::ArrayWithProperties => f.write_str("arrays with properties are not supported"),
Error::UnhandledTag(c) => f.write_fmt(format_args!("unhandled tag {c:?}")),
Error::LengthMismatch { head, tail } => f.write_fmt(format_args!("array length mismatch: header says {head} elements, but tail says {tail}")),
Error::Custom(c) => f.write_str(c),
#[cfg(feature = "std")]
Error::Io(io) => f.write_fmt(format_args!("IO error: {io}"))
}
}
}
impl core::error::Error for Error {}
impl serde_core::ser::Error for Error {
fn custom<T>(msg: T) -> Self
where
T: fmt::Display
{
Error::Custom(msg.to_string())
}
}
impl serde_core::de::Error for Error {
fn custom<T>(msg: T) -> Self
where
T: fmt::Display
{
Error::Custom(msg.to_string())
}
}