1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
//! Type flags available for `musli-wire`.
#![allow(clippy::unusual_byte_groupings)]
use core::fmt;
use core::mem;
use musli::{Decode, Decoder};
/// Data masked into the data type.
pub(crate) const DATA_MASK: u8 = 0b00_111111;
/// The maximum length that can be inlined in the tag without adding additional
/// data to the wire format.
pub const MAX_INLINE_LEN: usize = (DATA_MASK - 1) as usize;
/// The structure of a type tag.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Kind {
/// A packed sequence. The length of the packed sequence is the 2 to the
/// power of the mask as an unsigned integer.
Pack = 0b00_000000,
/// A fixed element where data indicates how many bytes it consists of. Data
/// contains the prefix length unless it's set to all 1s after which a
/// continuation sequence indicating the length should be decoded.
Prefix = 0b01_000000,
/// A length-prefixed sequence of values. Data contains the length of the
/// sequence if it's short enough to fit in 6 bits. All bits as 1s is
/// reserved to indicate when it's empty.
Sequence = 0b10_000000,
/// A continuation-encoded value. Data is the immediate value embedded if
/// it's small enough to fit in 6 bits. All bits as 1s is reserved to
/// indicate when a continuation sequence is used.
Continuation = 0b11_000000,
}
/// A type tag.
///
/// The [Kind] of the element is indicates by its 2 MSBs, and remaining 6 bits
/// is the data field. The exact use of the data field depends on the [Kind] in
/// question. It is primarily used to smuggle extra data for the kind in
/// question.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct Tag {
/// The internal representation of the tag.
repr: u8,
}
impl Tag {
/// Construct a new tag through an unchecked constructor.
///
/// `data` must not be equal to or larger than [MAX_INLINE_LEN], or else it
/// could corrupt the payload.
#[inline]
pub const fn new(kind: Kind, data: u8) -> Self {
Self {
repr: kind as u8 | data,
}
}
/// Construct a new empty tag of the given [Kind].
#[inline]
pub const fn empty(kind: Kind) -> Self {
Self {
repr: kind as u8 | DATA_MASK,
}
}
/// Construct from a byte.
#[inline]
pub const fn from_byte(repr: u8) -> Self {
Self { repr }
}
/// Coerce type flag into a byte.
#[inline]
pub const fn byte(self) -> u8 {
self.repr
}
/// Access the kind of the tag.
#[inline]
pub const fn kind(self) -> Kind {
// SAFETY: this is safe because we've ensured that all available Kind
// variants occupy all available bit patterns.
unsafe { mem::transmute(self.repr & !DATA_MASK) }
}
/// Perform raw access over the data payload. Will return [DATA_MASK] if
/// data is empty.
#[inline]
pub(crate) const fn data_raw(self) -> u8 {
self.repr & DATA_MASK
}
/// Perform checked access over the internal data. Returns [None] if data is
/// empty.
#[inline]
pub const fn data(self) -> Option<u8> {
let data = self.data_raw();
if data == DATA_MASK {
None
} else {
Some(data)
}
}
/// Attempt to construct a type tag with the given length embedded.
///
/// Returns a tuple where the boolean indicates if the value was embedded or
/// not.
#[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)
}
}
/// Attempt to construct a type tag with the given length embedded.
///
/// Returns a tuple where the boolean indicates if the value was embedded or
/// not.
#[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 {
#[inline]
fn decode<D>(_: &D::Cx, decoder: D) -> Result<Self, D::Error>
where
D: Decoder<'de, Mode = M>,
{
Ok(Self::from_byte(decoder.decode()?))
}
}