#![allow(clippy::unusual_byte_groupings)]
use core::fmt;
use core::mem;
use musli::mode::Mode;
use musli::Context;
use musli::{Decode, Decoder};
pub(crate) const DATA_MASK: u8 = 0b00_111111;
pub const MAX_INLINE_LEN: usize = (DATA_MASK - 1) as usize;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Kind {
Pack = 0b00_000000,
Prefix = 0b01_000000,
Sequence = 0b10_000000,
Continuation = 0b11_000000,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct Tag {
repr: u8,
}
impl Tag {
#[inline]
pub const fn new(kind: Kind, data: u8) -> Self {
Self {
repr: kind as u8 | data,
}
}
#[inline]
pub const fn empty(kind: Kind) -> Self {
Self {
repr: kind as u8 | DATA_MASK,
}
}
#[inline]
pub const fn from_byte(repr: u8) -> Self {
Self { repr }
}
#[inline]
pub const fn byte(self) -> u8 {
self.repr
}
#[inline]
pub 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 const fn data(self) -> Option<u8> {
let data = self.data_raw();
if data == DATA_MASK {
None
} else {
Some(data)
}
}
#[inline]
pub 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)
}
}
#[inline]
pub const fn with_byte(kind: Kind, len: u8) -> (Self, bool) {
if len < DATA_MASK {
(Self::new(kind, len), 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> Decode<'de, M> for Tag
where
M: Mode,
{
#[inline]
fn decode<C, D>(cx: &mut C, decoder: D) -> Result<Self, C::Error>
where
C: Context<Input = D::Error>,
D: Decoder<'de>,
{
Ok(Self::from_byte(decoder.decode_u8(cx)?))
}
}