#![allow(clippy::upper_case_acronyms)]
use crate::serialize::writer::*;
use crate::serialize::writer_unchecked::*;
pub(crate) trait Put {
fn put_bytes(&mut self, bytes: &[u8]) -> WriteResult<()>;
fn put_opaque_variable(&mut self, bytes: &[u8]) -> WriteResult<()>;
fn put_opaque_fixed(&mut self, bytes: &[u8]) -> WriteResult<()>;
}
pub struct TXS;
#[inline]
fn padding_len(len: usize) -> usize {
(4 - len % 4) % 4
}
static PADDING: [u8; 3] = [0; 3];
macro_rules! write_int {
[ $($write:ident($nbytes:expr): $ty:ty),* $(,)? ] => {
$(
#[inline]
fn $write(&mut self, n: $ty) -> WriteResult<()> {
let bytes: [u8; $nbytes] = n.to_be_bytes();
self.put_bytes(&bytes)
}
)*
};
}
impl<P> Writer<TXS> 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_opaque_fixed(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<()> {
self.put_bytes(&PADDING[..padding_len(len)])
}
#[inline]
fn write_opaque_variable(&mut self, bytes: &[u8]) -> WriteResult<()> {
if bytes.len() > u32::MAX as usize {
return Err(WriteError::InvalidArrayLength);
}
self.put_opaque_variable(bytes)
}
#[inline]
fn write_bool(&mut self, v: bool) -> WriteResult<()> {
self.write_i32(if v { 1 } else { 0 })
}
#[inline]
fn write_i16(&mut self, n: i16) -> WriteResult<()> {
self.write_i32(n as i32)
}
#[inline]
fn write_u16(&mut self, n: u16) -> WriteResult<()> {
self.write_u32(n as u32)
}
write_int! [
write_i64(8): i64,
write_i32(4): i32,
write_u64(8): u64,
write_u32(4): u32,
];
#[inline]
fn write_f32(&mut self, n: f32) -> WriteResult<()> {
let bytes: [u8; 4] = n.to_be_bytes();
self.put_bytes(&bytes)
}
#[inline]
fn write_f64(&mut self, n: f64) -> WriteResult<()> {
let bytes: [u8; 8] = n.to_be_bytes();
self.put_bytes(&bytes)
}
}
pub(crate) trait PutUnchecked {
unsafe fn put_bytes(&mut self, bytes: &[u8]);
unsafe fn put_opaque_variable(&mut self, bytes: &[u8]);
unsafe fn put_opaque_fixed(&mut self, bytes: &[u8]);
}
macro_rules! write_int_unchecked {
[ $($write:ident($nbytes:expr): $ty:ty),* $(,)? ] => {
$(
#[inline]
unsafe fn $write(&mut self, n: $ty) {
let bytes: [u8; $nbytes] = n.to_be_bytes();
unsafe { self.put_bytes(&bytes) }
}
)*
};
}
impl<P> WriterUnchecked<TXS> 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_opaque_fixed(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 { self.put_bytes(&PADDING[..padding_len(len)]) }
}
#[inline]
unsafe fn write_opaque_variable(&mut self, bytes: &[u8]) {
debug_assert!(bytes.len() <= u32::MAX as usize);
unsafe { self.put_opaque_variable(bytes) }
}
#[inline]
unsafe fn write_bool(&mut self, v: bool) {
unsafe { self.write_i32(if v { 1 } else { 0 }) }
}
#[inline]
unsafe fn write_i16(&mut self, n: i16) {
unsafe { self.write_i32(n as i32) }
}
#[inline]
unsafe fn write_u16(&mut self, n: u16) {
unsafe { self.write_u32(n as u32) }
}
write_int_unchecked![
write_i64(8): i64,
write_i32(4): i32,
write_u64(8): u64,
write_u32(4): u32,
];
#[inline]
unsafe fn write_f32(&mut self, n: f32) {
let bytes: [u8; 4] = n.to_be_bytes();
unsafe { self.put_bytes(&bytes) }
}
#[inline]
unsafe fn write_f64(&mut self, n: f64) {
let bytes: [u8; 8] = n.to_be_bytes();
unsafe { self.put_bytes(&bytes) }
}
}