use core::hint::cold_path;
use alloc::vec::Vec;
use crate::Error;
use crate::Result;
use crate::consts::*;
const MAX_ENCODED_INT: usize = 9;
#[inline(always)]
unsafe fn encode_argument_at(output: *mut u8, major_type: u8, value: u64) -> usize {
unsafe {
if value <= 23 {
output.write(major_type | value as u8);
1
} else if value <= u8::MAX as u64 {
output.write(major_type | ADDITIONAL_INFO_1_BYTE);
output.add(1).write(value as u8);
2
} else if value <= u16::MAX as u64 {
output.write(major_type | ADDITIONAL_INFO_2_BYTES);
output
.add(1)
.cast::<u16>()
.write_unaligned((value as u16).to_be());
3
} else {
encode_wide_argument_at(output, major_type, value)
}
}
}
#[inline(always)]
unsafe fn encode_wide_argument_at(output: *mut u8, major_type: u8, value: u64) -> usize {
unsafe {
if value <= u32::MAX as u64 {
output.write(major_type | ADDITIONAL_INFO_4_BYTES);
output
.add(1)
.cast::<u32>()
.write_unaligned((value as u32).to_be());
5
} else {
output.write(major_type | ADDITIONAL_INFO_8_BYTES);
output.add(1).cast::<u64>().write_unaligned(value.to_be());
9
}
}
}
#[inline(always)]
unsafe fn encode_unsigned_at(output: *mut u8, value: u64) -> usize {
unsafe { encode_argument_at(output, MAJOR_TYPE_UNSIGNED_INT, value) }
}
#[inline(always)]
unsafe fn encode_negative_at(output: *mut u8, value: i64) -> usize {
encode_negative_argument_at(output, (-1 - value) as u64)
}
#[inline(always)]
fn encode_negative_argument_at(output: *mut u8, abs: u64) -> usize {
unsafe { encode_argument_at(output, MAJOR_TYPE_NEGATIVE_INT, abs) }
}
#[inline(always)]
fn encode_signed_at(output: *mut u8, value: u64) -> usize {
if value <= i64::MAX as u64 {
unsafe { encode_unsigned_at(output, value) }
} else {
unsafe { encode_negative_at(output, value as i64) }
}
}
#[inline(always)]
pub(crate) const fn head_len_for(len: usize) -> usize {
if len <= 23 {
1
} else if len <= u8::MAX as usize {
2
} else if len <= u16::MAX as usize {
3
} else if len <= u32::MAX as usize {
5
} else {
9
}
}
pub fn decode_f16(bits: u16) -> f32 {
const SIGN_MASK: u16 = 0x8000;
const EXP_MASK: u16 = 0x7c00;
const MANT_MASK: u16 = 0x03ff;
let sign = u32::from(bits & SIGN_MASK) << 16;
let exp = u32::from(bits & EXP_MASK) >> 10;
let mant = u32::from(bits & MANT_MASK);
let f32_bits = if exp == 0 {
if mant == 0 {
sign
} else {
let k = 31 - mant.leading_zeros();
let f32_exp = (k as i32 - 24 + 127) as u32;
let f32_mant = (mant << (23 - k)) & 0x007f_ffff;
sign | (f32_exp << 23) | f32_mant
}
} else if exp == 0x1f {
sign | (0xff << 23) | (mant << 13)
} else {
sign | ((exp + 127 - 15) << 23) | (mant << 13)
};
f32::from_bits(f32_bits)
}
pub fn encode_f16(value: f32) -> u16 {
const F32_EXP: u32 = 0x7f80_0000;
const F32_MANT: u32 = 0x007f_ffff;
let bits = value.to_bits();
let sign = ((bits >> 16) as u16) & 0x8000;
let exp = ((bits & F32_EXP) >> 23) as i32;
let mant = bits & F32_MANT;
if exp == 0xff {
if mant == 0 {
return sign | 0x7c00;
}
let payload = (mant >> 13) as u16;
return sign | 0x7c00 | payload | u16::from(payload == 0);
}
if exp == 0 {
return sign;
}
let half_exp = (exp - 127) + 15;
let full_mant = mant | 0x0080_0000;
if half_exp >= 0x1f {
return sign | 0x7c00;
}
if half_exp >= 1 {
let mut half_mant = ((full_mant >> 13) & 0x03ff) as u16;
let remainder = full_mant & 0x1fff;
if remainder > 0x1000 || (remainder == 0x1000 && half_mant & 1 == 1) {
half_mant += 1;
if half_mant == 0x400 {
return sign | (((half_exp + 1) as u16) << 10);
}
}
sign | ((half_exp as u16) << 10) | half_mant
} else if half_exp >= -10 {
let shift = 14 - half_exp;
let mut half_mant = ((full_mant >> shift) & 0x03ff) as u16;
let remainder = full_mant & ((1 << shift) - 1);
let halfway = 1 << (shift - 1);
if remainder > halfway || (remainder == halfway && half_mant & 1 == 1) {
half_mant += 1;
if half_mant == 0x400 {
return sign | (1 << 10);
}
}
sign | half_mant
} else {
sign
}
}
macro_rules! impl_slice_writers {
($($method:ident, $scalar:ident, $ty:ty, $encode:expr;)*) => {
$(
#[doc = concat!("Writes a slice of `", stringify!($ty), "` values without an array header.")]
#[inline]
fn $method(&mut self, values: &[$ty]) -> Result<()> {
if values.is_empty() {
return Ok(());
}
let Some(worst_case) = values.len().checked_mul(MAX_ENCODED_INT) else {
return Err(Error::BufferTooSmall);
};
if worst_case > self.buffer.len() - self.pos {
for &value in values {
self.$scalar(value)?;
}
return Ok(());
}
let output = unsafe { self.buffer.as_mut_ptr().add(self.pos) };
let encode: fn(*mut u8, $ty) -> usize = $encode;
let mut written = 0;
for &value in values {
written += unsafe { encode(output.add(written), value) };
}
self.pos += written;
Ok(())
}
)*
};
}
#[inline(always)]
fn encode_u8_at(output: *mut u8, value: u8) -> usize {
unsafe { encode_unsigned_at(output, value as u64) }
}
#[inline(always)]
fn encode_u16_at(output: *mut u8, value: u16) -> usize {
unsafe { encode_unsigned_at(output, value as u64) }
}
#[inline(always)]
fn encode_u32_at(output: *mut u8, value: u32) -> usize {
unsafe { encode_unsigned_at(output, value as u64) }
}
#[inline(always)]
fn encode_u64_at(output: *mut u8, value: u64) -> usize {
unsafe {
if value > u16::MAX as u64 {
encode_wide_argument_at(output, MAJOR_TYPE_UNSIGNED_INT, value)
} else {
encode_unsigned_at(output, value)
}
}
}
#[inline(always)]
fn encode_i8_at(output: *mut u8, value: i8) -> usize {
encode_signed_at(output, value as i64 as u64)
}
#[inline(always)]
fn encode_i16_at(output: *mut u8, value: i16) -> usize {
encode_signed_at(output, value as i64 as u64)
}
#[inline(always)]
fn encode_i32_at(output: *mut u8, value: i32) -> usize {
encode_signed_at(output, value as i64 as u64)
}
#[inline(always)]
fn encode_i64_at(output: *mut u8, value: i64) -> usize {
encode_signed_at(output, value as u64)
}
#[inline(always)]
fn encode_f32_int_at(output: *mut u8, value: u64) -> usize {
encode_f32_at(output, f32::from_bits(value as u32))
}
#[inline(always)]
fn encode_f32_at(output: *mut u8, value: f32) -> usize {
unsafe {
output.write(FLOAT32_MARKER);
output
.add(1)
.cast::<u32>()
.write_unaligned(value.to_bits().to_be());
}
5
}
#[inline(always)]
fn encode_f64_int_at(output: *mut u8, value: u64) -> usize {
encode_f64_at(output, f64::from_bits(value))
}
#[inline(always)]
fn encode_f64_at(output: *mut u8, value: f64) -> usize {
unsafe {
output.write(FLOAT64_MARKER);
output
.add(1)
.cast::<u64>()
.write_unaligned(value.to_bits().to_be());
}
9
}
#[inline(always)]
fn encode_u8_int_at(output: *mut u8, value: u64) -> usize {
encode_u8_at(output, value as u8)
}
#[inline(always)]
fn encode_u16_int_at(output: *mut u8, value: u64) -> usize {
encode_u16_at(output, value as u16)
}
#[inline(always)]
fn encode_u32_int_at(output: *mut u8, value: u64) -> usize {
encode_u32_at(output, value as u32)
}
#[inline(always)]
fn encode_u64_int_at(output: *mut u8, value: u64) -> usize {
encode_u64_at(output, value)
}
#[inline(always)]
fn encode_i8_int_at(output: *mut u8, value: u64) -> usize {
encode_i8_at(output, value as u8 as i8)
}
#[inline(always)]
fn encode_i16_int_at(output: *mut u8, value: u64) -> usize {
encode_i16_at(output, value as u16 as i16)
}
#[inline(always)]
fn encode_i32_int_at(output: *mut u8, value: u64) -> usize {
encode_i32_at(output, value as u32 as i32)
}
#[inline(always)]
fn encode_i64_int_at(output: *mut u8, value: u64) -> usize {
encode_i64_at(output, value as i64)
}
#[inline(always)]
fn encode_f16_int_at(output: *mut u8, value: u64) -> usize {
unsafe {
output.write(FLOAT16_MARKER);
output
.add(1)
.cast::<u16>()
.write_unaligned((value as u16).to_be());
}
3
}
#[inline(always)]
fn encode_bool_at(output: *mut u8, value: bool) -> usize {
unsafe {
output.write(if value {
SIMPLE_VALUE_TRUE
} else {
SIMPLE_VALUE_FALSE
});
}
1
}
macro_rules! impl_scalar_writers {
() => {
#[inline(always)]
fn write_null(&mut self) -> Result<()> {
self.write_bytes(&[SIMPLE_VALUE_NULL])
}
#[inline(always)]
fn write_boolean(&mut self, value: bool) -> Result<()> {
self.write_bytes(&[if value {
SIMPLE_VALUE_TRUE
} else {
SIMPLE_VALUE_FALSE
}])
}
#[inline(always)]
fn write_simple_value(&mut self, value: u8) -> Result<()> {
match value {
0..=23 => self.write_bytes(&[MAJOR_TYPE_SIMPLE_FLOAT | value]),
24..=31 => {
cold_path();
Err(Error::InvalidSimpleValue(value))
}
_ => self.write_bytes(&[MAJOR_TYPE_SIMPLE_FLOAT | ADDITIONAL_INFO_1_BYTE, value]),
}
}
#[inline(always)]
fn write_undefined(&mut self) -> Result<()> {
self.write_bytes(&[SIMPLE_VALUE_UNDEFINED])
}
#[inline(always)]
fn write_u8(&mut self, value: u8) -> Result<()> {
self.write_int(value as u64, encode_u8_int_at)
}
#[inline(always)]
fn write_u16(&mut self, value: u16) -> Result<()> {
self.write_int(value as u64, encode_u16_int_at)
}
#[inline(always)]
fn write_u32(&mut self, value: u32) -> Result<()> {
self.write_int(value as u64, encode_u32_int_at)
}
#[inline(always)]
fn write_u64(&mut self, value: u64) -> Result<()> {
self.write_int(value, encode_u64_int_at)
}
#[inline(always)]
fn write_negative(&mut self, argument: u64) -> Result<()> {
self.write_int(argument, encode_negative_argument_at)
}
#[inline(always)]
fn write_i8(&mut self, value: i8) -> Result<()> {
self.write_int(value as i64 as u64, encode_i8_int_at)
}
#[inline(always)]
fn write_i16(&mut self, value: i16) -> Result<()> {
self.write_int(value as i64 as u64, encode_i16_int_at)
}
#[inline(always)]
fn write_i32(&mut self, value: i32) -> Result<()> {
self.write_int(value as i64 as u64, encode_i32_int_at)
}
#[inline(always)]
fn write_i64(&mut self, value: i64) -> Result<()> {
self.write_int(value as u64, encode_i64_int_at)
}
#[inline(always)]
fn write_f16(&mut self, value: f32) -> Result<()> {
self.write_int(encode_f16(value) as u64, encode_f16_int_at)
}
#[inline(always)]
fn write_f32(&mut self, value: f32) -> Result<()> {
self.write_int(value.to_bits() as u64, encode_f32_int_at)
}
#[inline(always)]
fn write_f64(&mut self, value: f64) -> Result<()> {
self.write_int(value.to_bits(), encode_f64_int_at)
}
};
}
pub trait Write {
fn write_bytes(&mut self, bytes: &[u8]) -> Result<()>;
fn write_null(&mut self) -> Result<()>;
fn write_boolean(&mut self, b: bool) -> Result<()>;
fn write_simple_value(&mut self, value: u8) -> Result<()>;
fn write_undefined(&mut self) -> Result<()>;
fn write_u8(&mut self, u: u8) -> Result<()>;
fn write_u16(&mut self, u: u16) -> Result<()>;
fn write_u32(&mut self, u: u32) -> Result<()>;
fn write_u64(&mut self, u: u64) -> Result<()>;
fn write_negative(&mut self, argument: u64) -> Result<()>;
fn write_i8(&mut self, i: i8) -> Result<()>;
fn write_i16(&mut self, i: i16) -> Result<()>;
fn write_i32(&mut self, i: i32) -> Result<()>;
fn write_i64(&mut self, i: i64) -> Result<()>;
fn write_f16(&mut self, f: f32) -> Result<()>;
fn write_f32(&mut self, f: f32) -> Result<()>;
fn write_f64(&mut self, f: f64) -> Result<()>;
#[inline(always)]
fn write_boolean_slice(&mut self, values: &[bool]) -> Result<()> {
for &value in values {
self.write_boolean(value)?;
}
Ok(())
}
#[inline(always)]
fn write_u8_slice(&mut self, values: &[u8]) -> Result<()> {
for &value in values {
self.write_u8(value)?;
}
Ok(())
}
#[inline(always)]
fn write_u16_slice(&mut self, values: &[u16]) -> Result<()> {
for &value in values {
self.write_u16(value)?;
}
Ok(())
}
#[inline(always)]
fn write_u32_slice(&mut self, values: &[u32]) -> Result<()> {
for &value in values {
self.write_u32(value)?;
}
Ok(())
}
#[inline(always)]
fn write_u64_slice(&mut self, values: &[u64]) -> Result<()> {
for &value in values {
self.write_u64(value)?;
}
Ok(())
}
#[inline(always)]
fn write_i8_slice(&mut self, values: &[i8]) -> Result<()> {
for &value in values {
self.write_i8(value)?;
}
Ok(())
}
#[inline(always)]
fn write_i16_slice(&mut self, values: &[i16]) -> Result<()> {
for &value in values {
self.write_i16(value)?;
}
Ok(())
}
#[inline(always)]
fn write_i32_slice(&mut self, values: &[i32]) -> Result<()> {
for &value in values {
self.write_i32(value)?;
}
Ok(())
}
#[inline(always)]
fn write_i64_slice(&mut self, values: &[i64]) -> Result<()> {
for &value in values {
self.write_i64(value)?;
}
Ok(())
}
#[inline(always)]
fn write_f32_slice(&mut self, values: &[f32]) -> Result<()> {
for &value in values {
self.write_f32(value)?;
}
Ok(())
}
#[inline(always)]
fn write_f64_slice(&mut self, values: &[f64]) -> Result<()> {
for &value in values {
self.write_f64(value)?;
}
Ok(())
}
fn write_string(&mut self, s: &str) -> Result<()>;
fn write_binary(&mut self, data: &[u8]) -> Result<()>;
fn write_tag(&mut self, tag: u64) -> Result<()>;
fn write_array_len(&mut self, len: usize) -> Result<()>;
fn write_map_len(&mut self, len: usize) -> Result<()>;
}
pub(crate) struct SliceWriter<'a> {
buffer: &'a mut [u8],
pos: usize,
}
impl<'a> SliceWriter<'a> {
#[inline(always)]
fn write_int(&mut self, value: u64, encode: fn(*mut u8, u64) -> usize) -> Result<()> {
if MAX_ENCODED_INT > self.buffer.len() - self.pos {
return self.write_int_narrow(value, encode);
}
let written = unsafe { encode(self.buffer.as_mut_ptr().add(self.pos), value) };
self.pos += written;
Ok(())
}
pub fn new(buffer: &'a mut [u8]) -> Self {
SliceWriter { buffer, pos: 0 }
}
}
impl<'a> SliceWriter<'a> {
#[inline(always)]
pub fn position(&self) -> usize {
self.pos
}
#[cold]
#[inline(never)]
fn write_int_narrow(&mut self, value: u64, encode: fn(*mut u8, u64) -> usize) -> Result<()> {
let mut tmp = [0u8; MAX_ENCODED_INT];
let written = encode(tmp.as_mut_ptr(), value);
self.write_bytes(&tmp[..written])
}
#[inline(always)]
fn write_payload(&mut self, major: u8, payload: &[u8]) -> Result<()> {
let head_len = head_len_for(payload.len());
if head_len > self.buffer.len() - self.pos {
return Err(Error::BufferTooSmall);
}
let written = unsafe {
encode_argument_at(
self.buffer.as_mut_ptr().add(self.pos),
major,
payload.len() as u64,
)
};
self.pos += written;
self.write_bytes(payload)
}
#[inline(always)]
fn take_slice(&mut self, len: usize) -> Result<&mut [u8]> {
if len > self.buffer.len() - self.pos {
cold_path();
return Err(Error::BufferTooSmall);
}
let slice = unsafe { self.buffer.get_unchecked_mut(self.pos..self.pos + len) };
self.pos += len;
Ok(slice)
}
}
impl<'a> Write for SliceWriter<'a> {
#[inline(always)]
fn write_bytes(&mut self, bytes: &[u8]) -> Result<()> {
self.take_slice(bytes.len())?.copy_from_slice(bytes);
Ok(())
}
impl_scalar_writers!();
impl_slice_writers! {
write_boolean_slice, write_boolean, bool, encode_bool_at;
write_u8_slice, write_u8, u8, encode_u8_at;
write_u16_slice, write_u16, u16, encode_u16_at;
write_u32_slice, write_u32, u32, encode_u32_at;
write_u64_slice, write_u64, u64, encode_u64_at;
write_i8_slice, write_i8, i8, encode_i8_at;
write_i16_slice, write_i16, i16, encode_i16_at;
write_i32_slice, write_i32, i32, encode_i32_at;
write_i64_slice, write_i64, i64, encode_i64_at;
write_f32_slice, write_f32, f32, encode_f32_at;
write_f64_slice, write_f64, f64, encode_f64_at;
}
#[inline(always)]
fn write_string(&mut self, s: &str) -> Result<()> {
self.write_payload(MAJOR_TYPE_TEXT_STRING, s.as_bytes())
}
#[inline(always)]
fn write_binary(&mut self, data: &[u8]) -> Result<()> {
self.write_payload(MAJOR_TYPE_BYTE_STRING, data)
}
#[inline(always)]
fn write_tag(&mut self, tag: u64) -> Result<()> {
write_tag(self, tag)
}
#[inline(always)]
fn write_array_len(&mut self, len: usize) -> Result<()> {
write_head(self, MAJOR_TYPE_ARRAY, len)
}
#[inline(always)]
fn write_map_len(&mut self, len: usize) -> Result<()> {
write_head(self, MAJOR_TYPE_MAP, len)
}
}
#[inline(always)]
fn write_head_and_payload<W: Write>(writer: &mut W, major_type: u8, payload: &[u8]) -> Result<()> {
let mut head = [0u8; MAX_ENCODED_INT];
let head_len =
unsafe { encode_argument_at(head.as_mut_ptr(), major_type, payload.len() as u64) };
debug_assert_eq!(head_len, head_len_for(payload.len()));
writer.write_bytes(&head[..head_len])?;
writer.write_bytes(payload)
}
pub(crate) struct VecWriter {
buffer: Vec<u8>,
}
impl Default for VecWriter {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl VecWriter {
#[inline(always)]
fn write_int(&mut self, value: u64, encode: fn(*mut u8, u64) -> usize) -> Result<()> {
self.buffer.reserve(MAX_ENCODED_INT);
let start = self.buffer.len();
let written = unsafe { encode(self.buffer.as_mut_ptr().add(start), value) };
unsafe { self.buffer.set_len(start + written) };
Ok(())
}
pub fn new() -> Self {
VecWriter { buffer: Vec::new() }
}
pub fn with_capacity_hint(capacity: usize) -> Self {
let mut buffer = Vec::new();
let _ = buffer.try_reserve(capacity);
VecWriter { buffer }
}
pub fn into_vec(self) -> Vec<u8> {
self.buffer
}
#[inline]
fn write_slice_values<T, E>(&mut self, values: &[T], encode: E) -> Result<()>
where
T: Copy,
E: Fn(*mut u8, T) -> usize,
{
if values.is_empty() {
return Ok(());
}
let Some(worst_case) = values.len().checked_mul(MAX_ENCODED_INT) else {
return Err(Error::BufferTooSmall);
};
self.buffer.reserve(worst_case);
let start = self.buffer.len();
let output = unsafe { self.buffer.as_mut_ptr().add(start) };
let mut written = 0;
for value in values {
written += unsafe { encode(output.add(written), *value) };
}
unsafe { self.buffer.set_len(start + written) };
Ok(())
}
}
macro_rules! impl_vec_slice_writers {
() => {
#[inline(always)]
fn write_boolean_slice(&mut self, values: &[bool]) -> Result<()> {
self.write_slice_values(values, encode_bool_at)
}
#[inline(always)]
fn write_u8_slice(&mut self, values: &[u8]) -> Result<()> {
self.write_slice_values(values, encode_u8_at)
}
#[inline(always)]
fn write_u16_slice(&mut self, values: &[u16]) -> Result<()> {
self.write_slice_values(values, encode_u16_at)
}
#[inline(always)]
fn write_u32_slice(&mut self, values: &[u32]) -> Result<()> {
self.write_slice_values(values, encode_u32_at)
}
#[inline(always)]
fn write_u64_slice(&mut self, values: &[u64]) -> Result<()> {
self.write_slice_values(values, encode_u64_at)
}
#[inline(always)]
fn write_i8_slice(&mut self, values: &[i8]) -> Result<()> {
self.write_slice_values(values, encode_i8_at)
}
#[inline(always)]
fn write_i16_slice(&mut self, values: &[i16]) -> Result<()> {
self.write_slice_values(values, encode_i16_at)
}
#[inline(always)]
fn write_i32_slice(&mut self, values: &[i32]) -> Result<()> {
self.write_slice_values(values, encode_i32_at)
}
#[inline(always)]
fn write_i64_slice(&mut self, values: &[i64]) -> Result<()> {
self.write_slice_values(values, encode_i64_at)
}
#[inline(always)]
fn write_f32_slice(&mut self, values: &[f32]) -> Result<()> {
self.write_slice_values(values, encode_f32_at)
}
#[inline(always)]
fn write_f64_slice(&mut self, values: &[f64]) -> Result<()> {
self.write_slice_values(values, encode_f64_at)
}
};
}
impl Write for VecWriter {
#[inline(always)]
fn write_bytes(&mut self, bytes: &[u8]) -> Result<()> {
self.buffer.extend_from_slice(bytes);
Ok(())
}
impl_scalar_writers!();
impl_vec_slice_writers!();
#[inline(always)]
fn write_string(&mut self, s: &str) -> Result<()> {
write_head_and_payload(self, MAJOR_TYPE_TEXT_STRING, s.as_bytes())
}
#[inline(always)]
fn write_binary(&mut self, data: &[u8]) -> Result<()> {
write_head_and_payload(self, MAJOR_TYPE_BYTE_STRING, data)
}
#[inline(always)]
fn write_tag(&mut self, tag: u64) -> Result<()> {
write_tag(self, tag)
}
#[inline(always)]
fn write_array_len(&mut self, len: usize) -> Result<()> {
write_head(self, MAJOR_TYPE_ARRAY, len)
}
#[inline(always)]
fn write_map_len(&mut self, len: usize) -> Result<()> {
write_head(self, MAJOR_TYPE_MAP, len)
}
}
#[cfg(feature = "std")]
pub(crate) struct IOWriter<W: std::io::Write> {
writer: W,
}
#[cfg(feature = "std")]
impl<W: std::io::Write> IOWriter<W> {
#[inline(always)]
fn write_int(&mut self, value: u64, encode: fn(*mut u8, u64) -> usize) -> Result<()> {
let mut buf = [0u8; MAX_ENCODED_INT];
let written = encode(buf.as_mut_ptr(), value);
self.write_bytes(&buf[..written])
}
pub fn new(writer: W) -> Self {
IOWriter { writer }
}
}
#[cfg(feature = "std")]
impl<W: std::io::Write> Write for IOWriter<W> {
#[inline(always)]
fn write_bytes(&mut self, bytes: &[u8]) -> Result<()> {
self.writer.write_all(bytes).map_err(Error::IoError)
}
impl_scalar_writers!();
#[inline(always)]
fn write_boolean_slice(&mut self, values: &[bool]) -> Result<()> {
let mut buf = [0u8; 256];
for chunk in values.chunks(buf.len()) {
for (slot, &value) in buf.iter_mut().zip(chunk) {
*slot = if value {
SIMPLE_VALUE_TRUE
} else {
SIMPLE_VALUE_FALSE
};
}
self.write_bytes(&buf[..chunk.len()])?;
}
Ok(())
}
#[inline(always)]
fn write_string(&mut self, s: &str) -> Result<()> {
write_head_and_payload(self, MAJOR_TYPE_TEXT_STRING, s.as_bytes())
}
#[inline(always)]
fn write_binary(&mut self, data: &[u8]) -> Result<()> {
write_head_and_payload(self, MAJOR_TYPE_BYTE_STRING, data)
}
#[inline(always)]
fn write_tag(&mut self, tag: u64) -> Result<()> {
write_tag(self, tag)
}
#[inline(always)]
fn write_array_len(&mut self, len: usize) -> Result<()> {
write_head(self, MAJOR_TYPE_ARRAY, len)
}
#[inline(always)]
fn write_map_len(&mut self, len: usize) -> Result<()> {
write_head(self, MAJOR_TYPE_MAP, len)
}
}
#[inline(always)]
fn write_tag<W: Write>(writer: &mut W, tag: u64) -> Result<()> {
let mut head = [0u8; MAX_ENCODED_INT];
let head_len = unsafe { encode_argument_at(head.as_mut_ptr(), MAJOR_TYPE_TAG, tag) };
writer.write_bytes(&head[..head_len])
}
#[inline(always)]
fn write_head<W: Write>(writer: &mut W, major_type: u8, len: usize) -> Result<()> {
let mut head = [0u8; MAX_ENCODED_INT];
let head_len = unsafe { encode_argument_at(head.as_mut_ptr(), major_type, len as u64) };
writer.write_bytes(&head[..head_len])
}
#[cfg(test)]
mod tests {
use alloc::vec;
use super::*;
#[track_caller]
fn check_slice<T, F, S>(values: &[T], bulk: F, scalar: S)
where
T: Copy,
F: Fn(&mut SliceWriter<'_>, &[T]) -> Result<()>,
S: Fn(&mut SliceWriter<'_>, T) -> Result<()>,
{
let mut expected = vec![0u8; values.len() * MAX_ENCODED_INT + 1];
let written = {
let mut writer = SliceWriter::new(&mut expected);
for &value in values {
scalar(&mut writer, value).unwrap();
}
writer.position()
};
let expected = expected[..written].to_vec();
let mut exact = vec![0u8; expected.len()];
let written = {
let mut writer = SliceWriter::new(&mut exact);
bulk(&mut writer, values).unwrap();
writer.position()
};
assert_eq!(&exact[..written], &expected[..], "fallback path differs");
let mut roomy = vec![0u8; values.len() * MAX_ENCODED_INT + 1];
let written = {
let mut writer = SliceWriter::new(&mut roomy);
bulk(&mut writer, values).unwrap();
writer.position()
};
assert_eq!(&roomy[..written], &expected[..], "fast path differs");
}
#[test]
fn bulk_slices_match_the_scalar_path() {
macro_rules! check {
($ty:ty, $values:expr, $slice:ident, $scalar:ident) => {
check_slice(
&$values,
|w, v: &[$ty]| w.$slice(v),
|w, v: $ty| w.$scalar(v),
)
};
}
check!(bool, [false, true], write_boolean_slice, write_boolean);
check!(u8, [0u8, 23, 24, u8::MAX], write_u8_slice, write_u8);
check!(
u16,
[0u16, 23, 24, 255, 256, u16::MAX],
write_u16_slice,
write_u16
);
check!(
u32,
[0u32, 23, 24, 255, 256, 65535, 65536, u32::MAX],
write_u32_slice,
write_u32
);
check!(
u64,
[
0u64,
23,
24,
255,
256,
65535,
65536,
u32::MAX as u64,
u64::MAX
],
write_u64_slice,
write_u64
);
check!(i8, [i8::MIN, -24, -1, 0, i8::MAX], write_i8_slice, write_i8);
check!(
i16,
[i16::MIN, -256, -24, -1, 0, i16::MAX],
write_i16_slice,
write_i16
);
check!(
i32,
[i32::MIN, -65536, -256, -24, -1, 0, i32::MAX],
write_i32_slice,
write_i32
);
check!(
i64,
[i64::MIN, -4294967296, -65536, -256, -24, -1, 0, 1, i64::MAX],
write_i64_slice,
write_i64
);
check!(
f32,
[0.0f32, -0.0, 1.0, f32::MIN, f32::MAX],
write_f32_slice,
write_f32
);
check!(
f64,
[0.0f64, -0.0, 1.0, f64::MIN, f64::MAX],
write_f64_slice,
write_f64
);
}
}