#![allow(clippy::upper_case_acronyms)]
use super::limits::*;
use crate::serialize::writer::*;
use crate::serialize::writer_unchecked::*;
const V_MULTIBYTE: u8 = 63;
const S_8BYTE: u8 = 3 << 6;
const S_4BYTE: u8 = 2 << 6;
const S_2BYTE: u8 = 1 << 6;
const S_1BYTE: u8 = 0 << 6;
const S_HEADER: u8 = 0 << 6;
pub(crate) trait Put {
fn put_byte(&mut self, b: u8) -> WriteResult<()>;
fn put_bytes(&mut self, bytes: &[u8]) -> WriteResult<()>;
}
pub struct CXS;
impl<P> Writer<CXS> for P
where
P: Put,
{
#[inline]
fn write_opaque_fixed(&mut self, bytes: &[u8]) -> WriteResult<()> {
debug_assert!(bytes.len() <= u32::MAX as usize);
self.put_bytes(bytes)
}
#[inline]
fn write_opaque_unpadded(&mut self, bytes: &[u8]) -> WriteResult<()> {
self.put_bytes(bytes)
}
#[inline]
fn write_opaque_padding(&mut self, _len: usize) -> WriteResult<()> {
Ok(())
}
fn write_opaque_variable(&mut self, bytes: &[u8]) -> WriteResult<()> {
if bytes.len() > u32::MAX as usize {
return Err(WriteError::InvalidArrayLength);
}
self.write_u32(bytes.len() as u32)?;
self.put_bytes(bytes)
}
#[inline]
fn write_bool(&mut self, v: bool) -> WriteResult<()> {
self.write_i32(if v { 1 } else { 0 })
}
#[inline]
fn write_i64(&mut self, n: i64) -> WriteResult<()> {
if n > i32::MAX as i64 || n < i32::MIN as i64 {
let h = V_MULTIBYTE | S_8BYTE;
let b = n.to_le_bytes();
let combined = [h, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]];
self.put_bytes(&combined)
} else {
self.write_i32(n as i32)
}
}
#[inline]
fn write_i32(&mut self, n: i32) -> WriteResult<()> {
if n > i16::MAX as i32 || n < i16::MIN as i32 {
let h = V_MULTIBYTE | S_4BYTE;
let b = n.to_le_bytes();
let combined = [h, b[0], b[1], b[2], b[3]];
self.put_bytes(&combined)
} else {
self.write_i16(n as i16)
}
}
#[inline]
fn write_i16(&mut self, n: i16) -> WriteResult<()> {
if n > i8::MAX as i16 || n < i8::MIN as i16 {
let h = V_MULTIBYTE | S_2BYTE;
let b = n.to_le_bytes();
let combined = [h, b[0], b[1]];
self.put_bytes(&combined)
} else {
write_i8(self, n as i8)
}
}
#[inline]
fn write_u64(&mut self, n: u64) -> WriteResult<()> {
if n > u32::MAX as u64 {
let h = V_MULTIBYTE | S_8BYTE;
let b = n.to_le_bytes();
let combined = [h, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]];
self.put_bytes(&combined)
} else {
self.write_u32(n as u32)
}
}
#[inline]
fn write_u32(&mut self, n: u32) -> WriteResult<()> {
if n > u16::MAX as u32 {
let h = V_MULTIBYTE | S_4BYTE;
let b = n.to_le_bytes();
let combined = [h, b[0], b[1], b[2], b[3]];
self.put_bytes(&combined)
} else {
self.write_u16(n as u16)
}
}
#[inline]
fn write_u16(&mut self, n: u16) -> WriteResult<()> {
if n > u8::MAX as u16 {
let h = V_MULTIBYTE | S_2BYTE;
let b = n.to_le_bytes();
let combined = [h, b[0], b[1]];
self.put_bytes(&combined)
} else {
write_u8(self, n as u8)
}
}
#[inline]
fn write_f32(&mut self, n: f32) -> WriteResult<()> {
let bytes: [u8; 4] = n.to_le_bytes();
self.put_bytes(&bytes)
}
#[inline]
fn write_f64(&mut self, n: f64) -> WriteResult<()> {
let bytes: [u8; 8] = n.to_le_bytes();
self.put_bytes(&bytes)
}
}
#[inline]
fn write_u8<P>(p: &mut P, n: u8) -> WriteResult<()>
where
P: Put,
{
if n > UH_MAX {
let h = V_MULTIBYTE | S_1BYTE;
let combined = [h, n];
p.put_bytes(&combined)
} else {
p.put_byte(n)
}
}
#[inline]
fn write_i8<P>(p: &mut P, n: i8) -> WriteResult<()>
where
P: Put,
{
if !(IH_MIN..=IH_MAX).contains(&n) {
let h = V_MULTIBYTE | S_1BYTE;
let combined = [h, n as u8];
p.put_bytes(&combined)
} else {
let nu: u8 = n.unsigned_abs();
let v = if n >= 0 {
nu
} else {
(!nu & 0b01_1111) | 0b0010_0000
};
let s = S_HEADER;
let h = v | s;
p.put_byte(h)
}
}
pub(crate) trait PutUnchecked {
unsafe fn put_byte(&mut self, b: u8);
unsafe fn put_bytes(&mut self, bytes: &[u8]);
}
impl<P> WriterUnchecked<CXS> for P
where
P: PutUnchecked,
{
#[inline]
unsafe fn write_opaque_fixed(&mut self, bytes: &[u8]) {
debug_assert!(bytes.len() <= u32::MAX as usize);
unsafe { self.put_bytes(bytes) }
}
#[inline]
unsafe fn write_opaque_unpadded(&mut self, bytes: &[u8]) {
unsafe { self.put_bytes(bytes) }
}
#[inline]
unsafe fn write_opaque_padding(&mut self, _len: usize) {}
unsafe fn write_opaque_variable(&mut self, bytes: &[u8]) {
debug_assert!(bytes.len() <= u32::MAX as usize);
unsafe {
self.write_u32(bytes.len() as u32);
self.put_bytes(bytes);
}
}
#[inline]
unsafe fn write_bool(&mut self, v: bool) {
unsafe { self.write_i32(if v { 1 } else { 0 }) }
}
#[inline]
unsafe fn write_i64(&mut self, n: i64) {
if n > i32::MAX as i64 || n < i32::MIN as i64 {
let h = V_MULTIBYTE | S_8BYTE;
let b = n.to_le_bytes();
let combined = [h, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]];
unsafe { self.put_bytes(&combined) }
} else {
unsafe { self.write_i32(n as i32) }
}
}
#[inline]
unsafe fn write_i32(&mut self, n: i32) {
if n > i16::MAX as i32 || n < i16::MIN as i32 {
let h = V_MULTIBYTE | S_4BYTE;
let b = n.to_le_bytes();
let combined = [h, b[0], b[1], b[2], b[3]];
unsafe { self.put_bytes(&combined) }
} else {
unsafe { self.write_i16(n as i16) }
}
}
#[inline]
unsafe fn write_i16(&mut self, n: i16) {
if n > i8::MAX as i16 || n < i8::MIN as i16 {
let h = V_MULTIBYTE | S_2BYTE;
let b = n.to_le_bytes();
let combined = [h, b[0], b[1]];
unsafe { self.put_bytes(&combined) }
} else {
unsafe { write_i8_unchecked(self, n as i8) }
}
}
#[inline]
unsafe fn write_u64(&mut self, n: u64) {
if n > u32::MAX as u64 {
let h = V_MULTIBYTE | S_8BYTE;
let b = n.to_le_bytes();
let combined = [h, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]];
unsafe { self.put_bytes(&combined) }
} else {
unsafe { self.write_u32(n as u32) }
}
}
#[inline]
unsafe fn write_u32(&mut self, n: u32) {
if n > u16::MAX as u32 {
let h = V_MULTIBYTE | S_4BYTE;
let b = n.to_le_bytes();
let combined = [h, b[0], b[1], b[2], b[3]];
unsafe { self.put_bytes(&combined) }
} else {
unsafe { self.write_u16(n as u16) }
}
}
#[inline]
unsafe fn write_u16(&mut self, n: u16) {
if n > u8::MAX as u16 {
let h = V_MULTIBYTE | S_2BYTE;
let b = n.to_le_bytes();
let combined = [h, b[0], b[1]];
unsafe { self.put_bytes(&combined) }
} else {
unsafe { write_u8_unchecked(self, n as u8) }
}
}
#[inline]
unsafe fn write_f32(&mut self, n: f32) {
let bytes: [u8; 4] = n.to_le_bytes();
unsafe { self.put_bytes(&bytes) }
}
#[inline]
unsafe fn write_f64(&mut self, n: f64) {
let bytes: [u8; 8] = n.to_le_bytes();
unsafe { self.put_bytes(&bytes) }
}
}
#[inline]
unsafe fn write_u8_unchecked<P>(p: &mut P, n: u8)
where
P: PutUnchecked,
{
if n > UH_MAX {
let h = V_MULTIBYTE | S_1BYTE;
let combined = [h, n];
unsafe { p.put_bytes(&combined) }
} else {
unsafe { p.put_byte(n) }
}
}
#[inline]
unsafe fn write_i8_unchecked<P>(p: &mut P, n: i8)
where
P: PutUnchecked,
{
if !(IH_MIN..=IH_MAX).contains(&n) {
let h = V_MULTIBYTE | S_1BYTE;
let combined = [h, n as u8];
unsafe { p.put_bytes(&combined) }
} else {
let nu: u8 = n.unsigned_abs();
let v = if n >= 0 {
nu
} else {
(!nu & 0b01_1111) | 0b0010_0000
};
let s = S_HEADER;
let h = v | s;
unsafe { p.put_byte(h) }
}
}