#![allow(clippy::unusual_byte_groupings)]
use core::fmt;
use core::mem;
use crate::{Allocator, Decode, Decoder};
#[derive(Debug)]
#[repr(u8)]
pub(crate) enum Mark {
None = 0b000,
Some = 0b001,
True = 0b010,
False = 0b011,
Variant = 0b100,
Char = 0b101,
Unit = 0b110,
#[allow(unused)]
Reserved0 = 0b111,
}
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub(crate) enum NumberKind {
Signed = 0b00,
Unsigned = 0b01,
Float = 0b10,
#[allow(unused)]
Reserved0 = 0b11,
}
#[repr(u8)]
pub(crate) enum Width {
#[allow(unused)]
Reserved0 = 0b000,
#[allow(unused)]
Reserved1 = 0b001,
#[allow(unused)]
Reserved2 = 0b010,
U8 = 0b011,
U16 = 0b100,
U32 = 0b101,
U64 = 0b110,
U128 = 0b111,
}
#[test]
fn ensure_width() {
assert_eq!(2u32.pow(Width::U8 as u32), 8u32);
assert_eq!(1u32 << Width::U8 as u32, 8u32);
assert_eq!(2u32.pow(Width::U16 as u32), 16u32);
assert_eq!(1u32 << Width::U16 as u32, 16u32);
assert_eq!(2u32.pow(Width::U32 as u32), 32u32);
assert_eq!(1u32 << Width::U32 as u32, 32u32);
assert_eq!(2u32.pow(Width::U64 as u32), 64u32);
assert_eq!(1u32 << Width::U64 as u32, 64u32);
assert_eq!(2u32.pow(Width::U128 as u32), 128u32);
assert_eq!(1u32 << Width::U128 as u32, 128u32);
}
pub(crate) const U8: u8 = ((Width::U8 as u8) << 2) | NumberKind::Unsigned as u8;
pub(crate) const U16: u8 = ((Width::U16 as u8) << 2) | NumberKind::Unsigned as u8;
pub(crate) const U32: u8 = ((Width::U32 as u8) << 2) | NumberKind::Unsigned as u8;
pub(crate) const U64: u8 = ((Width::U64 as u8) << 2) | NumberKind::Unsigned as u8;
pub(crate) const U128: u8 = ((Width::U128 as u8) << 2) | NumberKind::Unsigned as u8;
pub(crate) const I8: u8 = ((Width::U8 as u8) << 2) | NumberKind::Signed as u8;
pub(crate) const I16: u8 = ((Width::U16 as u8) << 2) | NumberKind::Signed as u8;
pub(crate) const I32: u8 = ((Width::U32 as u8) << 2) | NumberKind::Signed as u8;
pub(crate) const I64: u8 = ((Width::U64 as u8) << 2) | NumberKind::Signed as u8;
pub(crate) const I128: u8 = ((Width::U128 as u8) << 2) | NumberKind::Signed as u8;
pub(crate) const F32: u8 = ((Width::U32 as u8) << 2) | NumberKind::Float as u8;
pub(crate) const F64: u8 = ((Width::U64 as u8) << 2) | NumberKind::Float as u8;
#[cfg(target_pointer_width = "32")]
pub(crate) const USIZE: u8 = U32;
#[cfg(target_pointer_width = "64")]
pub(crate) const USIZE: u8 = U64;
#[cfg(target_pointer_width = "32")]
pub(crate) const ISIZE: u8 = I32;
#[cfg(target_pointer_width = "64")]
pub(crate) const ISIZE: u8 = I64;
pub(crate) const DATA_MASK: u8 = 0b000_11111;
pub(crate) const MARK_MASK: u8 = 0b00000_111;
pub(crate) const NUMBER_KIND_MASK: u8 = 0b000000_11;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub(crate) enum Kind {
#[allow(unused)]
Reserved0 = 0b000_00000,
#[allow(unused)]
Reserved1 = 0b001_00000,
Number = 0b010_00000,
Sequence = 0b011_00000,
Map = 0b100_00000,
Bytes = 0b101_00000,
String = 0b110_00000,
Mark = 0b111_00000,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub(crate) struct Tag {
repr: u8,
}
impl Tag {
#[inline]
pub(crate) const fn new(kind: Kind, data: u8) -> Self {
debug_assert!(data <= DATA_MASK, "Data must fit in DATA_MASK");
Self {
repr: kind as u8 | data,
}
}
#[inline]
pub(crate) const fn from_mark(mark: Mark) -> Self {
Self {
repr: Kind::Mark as u8 | mark as u8,
}
}
#[inline]
pub(crate) const fn mark(&self) -> Mark {
unsafe { mem::transmute(self.repr & MARK_MASK) }
}
#[inline]
pub(crate) const fn number_kind(&self) -> NumberKind {
unsafe { mem::transmute(self.repr & NUMBER_KIND_MASK) }
}
#[inline]
pub(crate) const fn from_byte(repr: u8) -> Self {
Self { repr }
}
#[inline]
pub(crate) const fn byte(self) -> u8 {
self.repr
}
#[inline]
pub(crate) const fn kind(self) -> Kind {
unsafe { mem::transmute(self.repr & !DATA_MASK) }
}
#[inline]
pub(crate) const fn data_raw(self) -> u8 {
self.repr & DATA_MASK
}
#[inline]
pub(crate) const fn data(self) -> Option<u8> {
let data = self.data_raw();
if data == DATA_MASK { None } else { Some(data) }
}
#[inline]
pub(crate) const fn with_len(kind: Kind, len: usize) -> (Self, bool) {
if len < DATA_MASK as usize {
(Self::new(kind, len as u8), true)
} else {
(Self::new(kind, DATA_MASK), false)
}
}
}
impl fmt::Debug for Tag {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Tag")
.field("kind", &self.kind())
.field("data", &self.data())
.finish()
}
}
impl<'de, M, A> Decode<'de, M, A> for Tag
where
A: Allocator,
{
const IS_BITWISE_DECODE: bool = true;
#[inline]
fn decode<D>(decoder: D) -> Result<Self, D::Error>
where
D: Decoder<'de, Mode = M, Allocator = A>,
{
Ok(Self::from_byte(decoder.decode_u8()?))
}
}