#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
use std::mem::MaybeUninit;
mod const_buffers;
pub use const_buffers::ConstReadBuffer;
mod cbor;
mod const_vec;
mod r#enum;
pub use r#enum::*;
mod r#struct;
pub use r#struct::*;
mod primitive;
pub use primitive::*;
mod list;
pub use list::*;
mod array;
pub use array::*;
mod str;
pub use str::*;
pub use const_serialize_macro::SerializeConst;
pub use const_vec::ConstVec;
use crate::cbor::{
str_eq, take_array, take_bytes, take_map, take_number, take_str, write_array, write_bytes,
write_map, write_map_key, write_number,
};
#[derive(Debug, Copy, Clone)]
pub enum Layout {
Enum(EnumLayout),
Struct(StructLayout),
Array(ArrayLayout),
Primitive(PrimitiveLayout),
List(ListLayout),
}
impl Layout {
pub const fn size(&self) -> usize {
match self {
Layout::Enum(layout) => layout.size,
Layout::Struct(layout) => layout.size,
Layout::Array(layout) => layout.len * layout.item_layout.size(),
Layout::List(layout) => layout.size,
Layout::Primitive(layout) => layout.size,
}
}
}
pub unsafe trait SerializeConst: Sized {
const MEMORY_LAYOUT: Layout;
const _ASSERT: () = assert!(Self::MEMORY_LAYOUT.size() == std::mem::size_of::<Self>());
}
const unsafe fn serialize_const_ptr(
ptr: *const (),
to: ConstVec<u8>,
layout: &Layout,
) -> ConstVec<u8> {
match layout {
Layout::Enum(layout) => serialize_const_enum(ptr, to, layout),
Layout::Struct(layout) => serialize_const_struct(ptr, to, layout),
Layout::Array(layout) => serialize_const_array(ptr, to, layout),
Layout::List(layout) => serialize_const_list(ptr, to, layout),
Layout::Primitive(layout) => serialize_const_primitive(ptr, to, layout),
}
}
#[must_use = "The data is serialized into the returned buffer"]
pub const fn serialize_const<T: SerializeConst>(data: &T, to: ConstVec<u8>) -> ConstVec<u8> {
let ptr = data as *const T as *const ();
unsafe { serialize_const_ptr(ptr, to, &T::MEMORY_LAYOUT) }
}
const fn deserialize_const_ptr<'a>(
from: &'a [u8],
layout: &Layout,
out: &mut [MaybeUninit<u8>],
) -> Option<&'a [u8]> {
match layout {
Layout::Enum(layout) => deserialize_const_enum(from, layout, out),
Layout::Struct(layout) => deserialize_const_struct(from, layout, out),
Layout::Array(layout) => deserialize_const_array(from, layout, out),
Layout::List(layout) => deserialize_const_list(from, layout, out),
Layout::Primitive(layout) => deserialize_const_primitive(from, layout, out),
}
}
#[macro_export]
macro_rules! deserialize_const {
($type:ty, $buffer:expr) => {
unsafe {
const __SIZE: usize = std::mem::size_of::<$type>();
$crate::deserialize_const_raw::<__SIZE, $type>($buffer)
}
};
}
#[must_use = "The data is deserialized from the input buffer"]
pub const unsafe fn deserialize_const_raw<const N: usize, T: SerializeConst>(
from: &[u8],
) -> Option<(&[u8], T)> {
let mut out = [MaybeUninit::uninit(); N];
let Some(from) = deserialize_const_ptr(from, &T::MEMORY_LAYOUT, &mut out) else {
return None;
};
Some((from, unsafe {
std::mem::transmute_copy::<[MaybeUninit<u8>; N], T>(&out)
}))
}
pub const fn serialize_eq<T: SerializeConst>(first: &T, second: &T) -> bool {
let first_serialized = ConstVec::<u8>::new();
let first_serialized = serialize_const(first, first_serialized);
let second_serialized = ConstVec::<u8>::new();
let second_serialized = serialize_const(second, second_serialized);
let first_buf = first_serialized.as_ref();
let second_buf = second_serialized.as_ref();
if first_buf.len() != second_buf.len() {
return false;
}
let mut i = 0;
while i < first_buf.len() {
if first_buf[i] != second_buf[i] {
return false;
}
i += 1;
}
true
}