use alloc::borrow::Cow;
use alloc::format;
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;
use core::ops::Deref;
use crate::BytesFormat;
use crate::error::{Error, ErrorKind};
use crate::ext::ExtValue;
use crate::text::{Slice, Text};
#[derive(Debug, PartialEq, Clone)]
#[non_exhaustive]
#[repr(C, u64)]
pub enum Atom<'a> {
Null,
Bool(bool),
Str(Text<'a>),
Lexical(Text<'a>),
Bytes(Bytes<'a>),
Char(char),
U64(u64),
I64(i64),
F32(f32),
F64(f64),
Ext(ExtValue<'a>),
Implicit(Implicit<'a>),
}
impl<'a> Atom<'a> {
pub fn to_static(&self) -> Atom<'static> {
match *self {
Atom::Null => Atom::Null,
Atom::Bool(v) => Atom::Bool(v),
Atom::Str(ref v) => Atom::Str(v.to_static()),
Atom::Lexical(ref v) => Atom::Lexical(v.to_static()),
Atom::Bytes(ref v) => Atom::Bytes(v.to_static()),
Atom::Char(v) => Atom::Char(v),
Atom::U64(v) => Atom::U64(v),
Atom::I64(v) => Atom::I64(v),
Atom::F32(v) => Atom::F32(v),
Atom::F64(v) => Atom::F64(v),
Atom::Ext(ref v) => Atom::Ext(v.to_static()),
Atom::Implicit(ref v) => Atom::Implicit(v.to_static()),
}
}
pub fn as_borrowed(&self) -> Atom<'_> {
match *self {
Atom::Null => Atom::Null,
Atom::Bool(v) => Atom::Bool(v),
Atom::Str(ref v) => Atom::Str(v.as_borrowed()),
Atom::Lexical(ref v) => Atom::Lexical(v.as_borrowed()),
Atom::Bytes(ref v) => Atom::Bytes(v.as_borrowed()),
Atom::Char(v) => Atom::Char(v),
Atom::U64(v) => Atom::U64(v),
Atom::I64(v) => Atom::I64(v),
Atom::F32(v) => Atom::F32(v),
Atom::F64(v) => Atom::F64(v),
Atom::Ext(ref v) => Atom::Ext(v.as_borrowed()),
Atom::Implicit(ref v) => Atom::Implicit(v.as_borrowed()),
}
}
#[inline]
pub fn as_str(&self) -> Option<&str> {
match self {
Atom::Str(v) | Atom::Lexical(v) => Some(v),
_ => None,
}
}
pub fn name(&self) -> &str {
match *self {
Atom::Null => "null",
Atom::Bool(_) => "bool",
Atom::Str(_) | Atom::Lexical(_) => "string",
Atom::Bytes(_) => "bytes",
Atom::Char(_) => "char",
Atom::U64(_) => "unsigned integer",
Atom::I64(_) => "signed integer",
Atom::F32(_) | Atom::F64(_) => "float",
Atom::Ext(ref v) => v.name(),
Atom::Implicit(ref v) => v.value().name(),
}
}
pub fn unexpected_error(&self, expectation: &str) -> Error {
Error::new(
ErrorKind::InvalidType,
format!("unexpected {}, expected {}", self.name(), expectation),
)
}
}
#[derive(Clone)]
pub struct Implicit<'a> {
text: Text<'a>,
bits: u64,
}
impl<'a> Implicit<'a> {
#[inline]
pub fn new<T: Into<Text<'a>>>(text: T, value: ImplicitValue) -> Implicit<'a> {
let (kind, bits) = value.pack();
Implicit {
text: text.into().with_tag(kind),
bits,
}
}
#[inline]
pub fn text(&self) -> &Text<'a> {
&self.text
}
#[inline]
pub fn value(&self) -> ImplicitValue {
ImplicitValue::unpack(self.text.tag(), self.bits)
}
#[inline]
pub fn into_parts(self) -> (Text<'a>, ImplicitValue) {
let value = self.value();
(self.text.with_tag(0), value)
}
#[inline]
pub fn as_borrowed(&self) -> Implicit<'_> {
Implicit {
text: self.text.as_borrowed().with_tag(self.text.tag()),
bits: self.bits,
}
}
#[inline]
pub fn to_static(&self) -> Implicit<'static> {
Implicit {
text: self.text.to_static().with_tag(self.text.tag()),
bits: self.bits,
}
}
}
impl fmt::Debug for Implicit<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Implicit")
.field("text", &self.text)
.field("value", &self.value())
.finish()
}
}
impl PartialEq for Implicit<'_> {
fn eq(&self, other: &Self) -> bool {
self.text == other.text && self.value() == other.value()
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum ImplicitValue {
Null,
Bool(bool),
U64(u64),
I64(i64),
F64(f64),
}
impl ImplicitValue {
#[inline]
fn pack(self) -> (u8, u64) {
match self {
ImplicitValue::Null => (0, 0),
ImplicitValue::Bool(value) => (1, value as u64),
ImplicitValue::U64(value) => (2, value),
ImplicitValue::I64(value) => (3, value as u64),
ImplicitValue::F64(value) => (4, value.to_bits()),
}
}
#[inline]
fn unpack(kind: u8, bits: u64) -> ImplicitValue {
match kind {
1 => ImplicitValue::Bool(bits != 0),
2 => ImplicitValue::U64(bits),
3 => ImplicitValue::I64(bits as i64),
4 => ImplicitValue::F64(f64::from_bits(bits)),
_ => ImplicitValue::Null,
}
}
pub fn from_atom(atom: &Atom<'_>) -> Option<ImplicitValue> {
match *atom {
Atom::Null => Some(ImplicitValue::Null),
Atom::Bool(value) => Some(ImplicitValue::Bool(value)),
Atom::U64(value) => Some(ImplicitValue::U64(value)),
Atom::I64(value) => Some(ImplicitValue::I64(value)),
Atom::F64(value) => Some(ImplicitValue::F64(value)),
_ => None,
}
}
#[inline]
pub fn to_atom(self) -> Atom<'static> {
match self {
ImplicitValue::Null => Atom::Null,
ImplicitValue::Bool(value) => Atom::Bool(value),
ImplicitValue::U64(value) => Atom::U64(value),
ImplicitValue::I64(value) => Atom::I64(value),
ImplicitValue::F64(value) => Atom::F64(value),
}
}
pub fn is_same(self, other: ImplicitValue) -> bool {
match (self, other) {
(ImplicitValue::F64(a), ImplicitValue::F64(b)) => a.to_bits() == b.to_bits(),
(a, b) => a == b,
}
}
pub fn name(&self) -> &'static str {
match *self {
ImplicitValue::Null => "null",
ImplicitValue::Bool(_) => "bool",
ImplicitValue::U64(_) => "unsigned integer",
ImplicitValue::I64(_) => "signed integer",
ImplicitValue::F64(_) => "float",
}
}
}
macro_rules! impl_from {
($ty:ty, $atom:ident) => {
impl From<$ty> for Event<'static> {
fn from(value: $ty) -> Self {
Event::Atom(Atom::$atom(value as _))
}
}
};
}
impl_from!(u64, U64);
impl_from!(i64, I64);
impl_from!(usize, U64);
impl_from!(isize, I64);
impl_from!(bool, Bool);
impl_from!(char, Char);
impl From<f64> for Event<'static> {
fn from(value: f64) -> Self {
Event::Atom(Atom::F64(value))
}
}
impl From<f32> for Event<'static> {
fn from(value: f32) -> Self {
Event::Atom(Atom::F32(value))
}
}
impl From<u128> for Event<'static> {
fn from(value: u128) -> Self {
Event::Atom(Atom::Ext(ExtValue::owned(value)))
}
}
impl From<i128> for Event<'static> {
fn from(value: i128) -> Self {
Event::Atom(Atom::Ext(ExtValue::owned(value)))
}
}
impl From<()> for Event<'static> {
fn from(_: ()) -> Event<'static> {
Event::Atom(Atom::Null)
}
}
impl<'a> From<&'a str> for Event<'a> {
fn from(value: &'a str) -> Event<'a> {
Event::Atom(Atom::Str(Text::borrowed(value)))
}
}
impl<'a> From<Cow<'a, str>> for Event<'a> {
fn from(value: Cow<'a, str>) -> Event<'a> {
Event::Atom(Atom::Str(value.into()))
}
}
impl<'a> From<Text<'a>> for Event<'a> {
fn from(value: Text<'a>) -> Event<'a> {
Event::Atom(Atom::Str(value))
}
}
impl<'a> From<&'a [u8]> for Event<'a> {
fn from(value: &'a [u8]) -> Event<'a> {
Event::Atom(Atom::Bytes(Bytes::borrowed(value)))
}
}
impl From<String> for Event<'static> {
fn from(value: String) -> Event<'static> {
Event::Atom(Atom::Str(value.into()))
}
}
impl<'a> From<Atom<'a>> for Event<'a> {
fn from(atom: Atom<'a>) -> Self {
Event::Atom(atom)
}
}
#[derive(PartialEq, Clone)]
pub enum Event<'a> {
Atom(Atom<'a>),
MapStart(ContainerShape),
MapEnd,
SeqStart(ContainerShape),
SeqEnd,
}
impl<'a> Event<'a> {
pub const fn map_start() -> Event<'static> {
Event::MapStart(ContainerShape::new())
}
pub const fn seq_start() -> Event<'static> {
Event::SeqStart(ContainerShape::new())
}
pub fn as_borrowed(&self) -> Event<'_> {
match *self {
Event::Atom(ref atom) => Event::Atom(atom.as_borrowed()),
Event::MapStart(shape) => Event::MapStart(shape),
Event::MapEnd => Event::MapEnd,
Event::SeqStart(shape) => Event::SeqStart(shape),
Event::SeqEnd => Event::SeqEnd,
}
}
pub fn to_static(&self) -> Event<'static> {
match *self {
Event::Atom(ref atom) => Event::Atom(atom.to_static()),
Event::MapStart(shape) => Event::MapStart(shape),
Event::MapEnd => Event::MapEnd,
Event::SeqStart(shape) => Event::SeqStart(shape),
Event::SeqEnd => Event::SeqEnd,
}
}
}
impl fmt::Debug for Event<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (name, shape) = match *self {
Event::Atom(ref atom) => return f.debug_tuple("Atom").field(atom).finish(),
Event::MapStart(shape) => ("MapStart", shape),
Event::MapEnd => return f.write_str("MapEnd"),
Event::SeqStart(shape) => ("SeqStart", shape),
Event::SeqEnd => return f.write_str("SeqEnd"),
};
if shape == ContainerShape::new() {
f.write_str(name)
} else {
f.debug_tuple(name).field(&shape).finish()
}
}
}
#[derive(Clone)]
#[non_exhaustive]
pub struct Bytes<'a> {
data: Slice<'a>,
pub fallback: Option<&'static BytesFormat>,
}
impl<'a> Bytes<'a> {
#[inline]
pub fn new<D: Into<Cow<'a, [u8]>>>(data: D) -> Bytes<'a> {
Bytes {
data: Slice::from_cow(data.into()),
fallback: None,
}
}
#[inline]
pub const fn borrowed(data: &'a [u8]) -> Bytes<'a> {
Bytes {
data: Slice::borrowed(data),
fallback: None,
}
}
#[inline]
pub fn data(&self) -> &[u8] {
self.data.as_slice()
}
#[inline]
pub fn is_borrowed(&self) -> bool {
!self.data.is_owned()
}
#[inline]
pub fn borrowed_data(&self) -> Option<&'a [u8]> {
self.data.borrowed_slice()
}
#[inline]
pub fn into_data(self) -> Cow<'a, [u8]> {
self.data.into_cow()
}
#[inline]
pub fn into_owned(self) -> Vec<u8> {
self.data.into_box().into_vec()
}
pub fn as_borrowed(&self) -> Bytes<'_> {
Bytes {
data: self.data.reborrow(),
fallback: self.fallback,
}
}
pub fn to_static(&self) -> Bytes<'static> {
Bytes {
data: self.data.to_static(),
fallback: self.fallback,
}
}
}
impl PartialEq for Bytes<'_> {
fn eq(&self, other: &Self) -> bool {
self.data() == other.data() && self.fallback == other.fallback
}
}
impl Deref for Bytes<'_> {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
self.data()
}
}
impl AsRef<[u8]> for Bytes<'_> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.data()
}
}
impl<'a> From<&'a [u8]> for Bytes<'a> {
fn from(data: &'a [u8]) -> Bytes<'a> {
Bytes::borrowed(data)
}
}
impl From<Vec<u8>> for Bytes<'static> {
fn from(data: Vec<u8>) -> Bytes<'static> {
Bytes::new(data)
}
}
impl<'a> From<Cow<'a, [u8]>> for Bytes<'a> {
fn from(data: Cow<'a, [u8]>) -> Bytes<'a> {
Bytes::new(data)
}
}
impl fmt::Debug for Bytes<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.data(), f)?;
if let Some(format) = self.fallback {
write!(f, " as {}", format.name())?;
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub enum Order {
#[default]
Natural,
Arbitrary,
Sorted,
Significant,
}
impl Order {
const fn to_bits(self) -> u32 {
match self {
Order::Natural => 0,
Order::Arbitrary => 1,
Order::Sorted => 2,
Order::Significant => 3,
}
}
const fn from_bits(bits: u32) -> Order {
match bits & ORDER_MASK {
1 => Order::Arbitrary,
2 => Order::Sorted,
3 => Order::Significant,
_ => Order::Natural,
}
}
}
const ORDER_MASK: u32 = 0b11;
const MULTIMAP: u32 = 0b100;
const LEN_HINT: u32 = 0b1000;
const AMBIGUOUS_EMPTY: u32 = 0b1_0000;
const UNKNOWN_LEN: usize = usize::MAX;
const MAX_PREALLOCATION: usize = 1024 * 1024;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct ContainerShape {
len: usize,
flags: u32,
}
impl ContainerShape {
#[inline]
pub const fn new() -> ContainerShape {
ContainerShape {
len: UNKNOWN_LEN,
flags: 0,
}
}
#[inline]
pub const fn with_len(len: usize) -> ContainerShape {
let mut shape = ContainerShape::new();
shape.set_len(len);
shape
}
#[inline]
pub const fn with_order(order: Order) -> ContainerShape {
let mut shape = ContainerShape::new();
shape.set_order(order);
shape
}
#[inline]
pub const fn set_len(&mut self, len: usize) {
self.len = len;
self.flags &= !LEN_HINT;
}
#[inline]
pub const fn set_len_hint(&mut self, len: usize) {
self.len = len;
self.flags |= LEN_HINT;
}
#[inline]
pub const fn set_order(&mut self, order: Order) {
self.flags = (self.flags & !ORDER_MASK) | order.to_bits();
}
#[inline]
#[allow(clippy::len_without_is_empty)]
pub const fn len(&self) -> Option<usize> {
if self.len == UNKNOWN_LEN || self.flags & LEN_HINT != 0 {
None
} else {
Some(self.len)
}
}
#[inline]
pub const fn cautious_capacity<T>(&self) -> usize {
let max = match core::mem::size_of::<T>() {
0 => MAX_PREALLOCATION,
size => MAX_PREALLOCATION / size,
};
match self.len {
UNKNOWN_LEN => 0,
len if len < max => len,
_ => max,
}
}
#[inline]
pub const fn order(&self) -> Order {
Order::from_bits(self.flags)
}
#[inline]
pub const fn set_multimap(&mut self, yes: bool) {
if yes {
self.flags |= MULTIMAP;
} else {
self.flags &= !MULTIMAP;
}
}
#[inline]
pub const fn is_multimap(&self) -> bool {
self.flags & MULTIMAP != 0
}
#[inline]
pub const fn set_ambiguous_empty(&mut self, yes: bool) {
if yes {
self.flags |= AMBIGUOUS_EMPTY;
} else {
self.flags &= !AMBIGUOUS_EMPTY;
}
}
#[inline]
pub const fn is_ambiguous_empty(&self) -> bool {
self.flags & AMBIGUOUS_EMPTY != 0 && matches!(self.len(), Some(0))
}
}
impl Default for ContainerShape {
fn default() -> ContainerShape {
ContainerShape::new()
}
}
impl fmt::Debug for ContainerShape {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = f.debug_struct("ContainerShape");
s.field("len", &self.len()).field("order", &self.order());
if self.flags & LEN_HINT != 0 && self.len != UNKNOWN_LEN {
s.field("len_hint", &self.len);
}
if self.is_multimap() {
s.field("is_multimap", &true);
}
if self.is_ambiguous_empty() {
s.field("is_ambiguous_empty", &true);
}
s.finish()
}
}
#[cfg(test)]
pub(crate) fn without_len(event: Event<'static>) -> Event<'static> {
match event {
Event::MapStart(shape) => Event::MapStart({
let mut shape = ContainerShape::with_order(shape.order());
shape.set_multimap(shape.is_multimap());
shape
}),
Event::SeqStart(shape) => Event::SeqStart(ContainerShape::with_order(shape.order())),
event => event,
}
}
#[cfg(target_pointer_width = "64")]
const _: () = {
assert!(core::mem::size_of::<Atom<'static>>() == 32);
assert!(core::mem::size_of::<Event<'static>>() == 32);
assert!(core::mem::size_of::<Implicit<'static>>() == 24);
};
#[cfg(target_pointer_width = "32")]
const _: () = {
assert!(core::mem::size_of::<Atom<'static>>() == 24);
assert!(core::mem::size_of::<Event<'static>>() == 24);
assert!(core::mem::size_of::<Implicit<'static>>() == 16);
};
#[test]
fn test_implicit_packing() {
for value in [
ImplicitValue::Null,
ImplicitValue::Bool(false),
ImplicitValue::Bool(true),
ImplicitValue::U64(u64::MAX),
ImplicitValue::I64(i64::MIN),
ImplicitValue::I64(-1),
ImplicitValue::F64(-0.0),
ImplicitValue::F64(f64::NAN),
ImplicitValue::F64(1.1),
] {
for implicit in [
Implicit::new("text", value),
Implicit::new(String::from("text"), value),
] {
let borrowed = implicit.text().is_borrowed();
assert!(implicit.value().is_same(value));
assert_eq!(implicit.text(), "text");
assert_eq!(implicit.text().len(), 4);
assert!(implicit.clone().value().is_same(value));
assert!(implicit.as_borrowed().value().is_same(value));
assert!(implicit.to_static().value().is_same(value));
assert_eq!(implicit.clone().text().is_borrowed(), borrowed);
let (text, inner) = implicit.into_parts();
assert_eq!(text, "text");
assert_eq!(text.tag(), 0);
assert!(inner.is_same(value));
}
}
}