use crate::{DataType, buffer::Buffer, read::{ListView, ReadAt}};
use std::mem::{size_of, align_of};
pub trait Serialize: Sized {
const SIZE: usize = size_of::<Self>(); const ALIGN: usize = align_of::<Self>(); const ALIGNR: usize = Self::ALIGN -1;
const ALIGN_MASK: usize = !Self::ALIGNR;
const MODE: DataType;
fn size_hint(&self) -> usize;
fn write_to<B: Buffer>(&self, buffer: &mut B) -> usize;
fn write_to_unchecked<B: Buffer>(&self, buffer: &mut B) -> usize;
fn is_absent(&self) -> bool;
#[inline(always)]
fn tag(&self) -> u8 {
0
}
}
pub trait SerializeBytes {
fn size_hint(&self) -> usize;
fn write_bytes_to<B: Buffer>(&self, buffer: &mut B) -> usize;
fn write_bytes_to_unchecked<B: Buffer>(&self, buffer: &mut B) -> usize;
}
impl SerializeBytes for &[u8] {
#[inline(always)]
fn size_hint(&self) -> usize { self.len() }
#[inline]
fn write_bytes_to<B: Buffer>(&self, buffer: &mut B) -> usize {
buffer.ensure_capacity(self.len());
self.write_bytes_to_unchecked(buffer)
}
#[inline]
fn write_bytes_to_unchecked<B: Buffer>(&self, buffer: &mut B) -> usize {
let len = self.len();
*buffer.head_mut() -= len;
let head = buffer.head();
buffer.buffer_mut()[head..head + len].copy_from_slice(self);
buffer.slot()
}
}
macro_rules! impl_serialize_scalar {
($($t:ty),*) => {$(
impl Serialize for $t {
const MODE: DataType = DataType::Inline;
#[inline(always)]
fn size_hint(&self) -> usize { size_of::<Self>() + align_of::<Self>() - 1 }
#[inline]
fn write_to<B: Buffer>(&self, buffer: &mut B) -> usize {
buffer.ensure_capacity(size_of::<Self>() + align_of::<Self>() - 1);
self.write_to_unchecked(buffer)
}
#[inline]
fn write_to_unchecked<B: Buffer>(&self, buffer: &mut B) -> usize {
let size = size_of::<Self>();
let mask = align_of::<Self>() - 1;
*buffer.head_mut() -= size;
*buffer.head_mut() &= !mask;
let head = buffer.head();
buffer.buffer_mut()[head..head + size]
.copy_from_slice(&self.to_le_bytes());
buffer.slot()
}
#[inline(always)]
fn is_absent(&self) -> bool { *self == (0 as $t) }
}
)*};
}
impl Serialize for u8 {
const MODE: DataType = DataType::Inline;
#[inline(always)]
fn size_hint(&self) -> usize { 1 }
#[inline]
fn write_to<B: Buffer>(&self, buffer: &mut B) -> usize {
buffer.ensure_capacity(1);
self.write_to_unchecked(buffer)
}
#[inline]
fn write_to_unchecked<B: Buffer>(&self, buffer: &mut B) -> usize {
let size = 1;
*buffer.head_mut() -= size;
let head = buffer.head();
buffer.buffer_mut()[head]= *self;
buffer.slot()
}
#[inline(always)]
fn is_absent(&self) -> bool { *self == 0 }
}
impl_serialize_scalar!(u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64);
macro_rules! impl_serialize_str {
($($t:ty),*) => {$(
impl Serialize for $t {
const SIZE: usize = 4;
const ALIGN: usize = 4;
const MODE: DataType = DataType::Offset;
#[inline(always)]
fn size_hint(&self) -> usize { self.len() + 11 }
#[inline]
fn write_to<B: Buffer>(&self, buffer: &mut B) -> usize {
buffer.ensure_capacity(Serialize::size_hint(self));
self.write_to_unchecked(buffer)
}
#[inline]
fn write_to_unchecked<B: Buffer>(&self, buffer: &mut B) -> usize {
let bytes = self.as_bytes();
let data_len = bytes.len();
*buffer.head_mut() -= data_len;
*buffer.head_mut() &= !3;
let data_head = buffer.head();
buffer.buffer_mut()[data_head..data_head + data_len]
.copy_from_slice(bytes);
(data_len as u32).write_to_unchecked(buffer)
}
#[inline(always)]
fn is_absent(&self) -> bool { self.is_empty() }
}
)*};
}
impl_serialize_str!(&str, String);
impl<T: Serialize> Serialize for &[T] {
const SIZE: usize = 4;
const ALIGN: usize = 4;
const MODE: DataType = DataType::Offset;
#[inline]
fn size_hint(&self) -> usize {
match T::MODE {
DataType::Inline => {
(self.len() * size_of::<T>()) + align_of::<T>().max(4) + 4
}
DataType::Offset => {
let data: usize = self.iter().map(|s| Serialize::size_hint(s)).sum();
4 + (self.len() * 4) + data
}
DataType::Union => {
let data: usize = self.iter().map(|s| Serialize::size_hint(s)).sum();
let offset: usize = (7+5*self.len())&!3;
data + offset
}
}
}
#[inline]
fn write_to<B: Buffer>(&self, buffer: &mut B) -> usize {
buffer.ensure_capacity(self.size_hint());
self.write_to_unchecked(buffer)
}
#[inline]
fn write_to_unchecked<B: Buffer>(&self, buffer: &mut B) -> usize {
match T::MODE {
DataType::Inline => {
let len = self.len();
let total = len * size_of::<T>();
let align_mask = align_of::<T>().max(4) - 1;
*buffer.head_mut() -= total;
*buffer.head_mut() &= !align_mask;
let head = buffer.head();
let src = unsafe {
std::slice::from_raw_parts(self.as_ptr() as *const u8, total)
};
buffer.buffer_mut()[head..head + total].copy_from_slice(src);
(len as u32).write_to_unchecked(buffer)
}
_ => {
let len = self.len();
let mut slots = Vec::with_capacity(len);
for s in self.iter().rev() {
slots.push(Serialize::write_to_unchecked(s, buffer));
};
*buffer.head_mut() &= !3;
let union_flag = T::MODE.is_union_flag() as usize;
let padding = (3 & (4-(len&3))) * union_flag;
*buffer.head_mut() -= padding;
for i in (0..len*union_flag).rev() {
unsafe { self.get_unchecked(i).tag().write_to_unchecked(buffer) };
};
for target_slot in slots {
*buffer.head_mut() -= 4;
*buffer.head_mut() &= !3;
let head = buffer.head();
let jump = if target_slot == 0 { 0u32 }
else { (buffer.slot() - target_slot) as u32 };
buffer.buffer_mut()[head..head + 4]
.copy_from_slice(&jump.to_le_bytes());
}
(len as u32).write_to_unchecked(buffer)
}
}
}
#[inline(always)]
fn is_absent(&self) -> bool { self.is_empty() }
}
impl<T: Serialize> Serialize for Vec<T> {
const SIZE: usize = 4;
const MODE: DataType = DataType::Offset;
#[inline]
fn size_hint(&self) -> usize { Serialize::size_hint(&self.as_slice()) }
#[inline]
fn write_to<B: Buffer>(&self, b: &mut B) -> usize {
Serialize::write_to(&self.as_slice(), b)
}
#[inline]
fn write_to_unchecked<B: Buffer>(&self, b: &mut B) -> usize {
Serialize::write_to_unchecked(&self.as_slice(), b)
}
#[inline(always)]
fn is_absent(&self) -> bool { self.is_empty() }
}
impl<'a, T> Serialize for ListView<'a, T>
where
T: ReadAt<'a>,
T::ReadOutput: Serialize,
{
const SIZE: usize = 4;
const MODE: DataType = DataType::Offset;
#[inline]
fn size_hint(&self) -> usize {
match <T::ReadOutput as Serialize>::MODE {
DataType::Inline => {
let elem_size = size_of::<T::ReadOutput>();
let align = align_of::<T::ReadOutput>().max(4);
4 + self.len() * elem_size + align
}
DataType::Offset => {
let data: usize = (0..self.len())
.map(|i| Serialize::size_hint(&self.get(i)))
.sum();
4 + self.len() * 4 + data
}
DataType::Union => {
let data: usize = (0..self.len())
.map(|i| Serialize::size_hint(&self.get(i)))
.sum();
let offset: usize = (7+5*self.len())&!3;
data + offset
}
}
}
#[inline]
fn write_to<B: Buffer>(&self, buffer: &mut B) -> usize {
buffer.ensure_capacity(Serialize::size_hint(self));
self.write_to_unchecked(buffer)
}
#[inline]
fn write_to_unchecked<B: Buffer>(&self, buffer: &mut B) -> usize {
match <T::ReadOutput as Serialize>::MODE {
DataType::Inline => {
let len = self.len();
let elem_size = size_of::<T::ReadOutput>();
let total = len * elem_size;
let align_mask = align_of::<T::ReadOutput>().max(4) - 1;
*buffer.head_mut() -= total;
*buffer.head_mut() &= !align_mask;
let head = buffer.head();
buffer.buffer_mut()[head..head + total]
.copy_from_slice(&self.buf[self.offset..self.offset + total]);
(len as u32).write_to_unchecked(buffer)
}
_ => {
let len = self.len();
let mut slots = Vec::with_capacity(len);
for i in (0..len).rev() {
slots.push(Serialize::write_to_unchecked(&self.get(i), buffer));
}
*buffer.head_mut() &= !3;
let union_flag =T::MODE.is_union_flag() as usize;
let padding = (3 & (4-(len&3))) * union_flag;
*buffer.head_mut() -= padding;
for i in (0..len*union_flag).rev() {
self.get(i).tag().write_to_unchecked(buffer);
};
for target_slot in slots {
*buffer.head_mut() -= 4;
*buffer.head_mut() &= !3;
let head = buffer.head();
let jump = (buffer.slot() - target_slot) as u32;
buffer.buffer_mut()[head..head + 4]
.copy_from_slice(&jump.to_le_bytes());
}
(len as u32).write_to_unchecked(buffer)
}
}
}
#[inline(always)]
fn is_absent(&self) -> bool { self.is_empty() }
}