use crate::*;
pub(crate) const unsafe fn serialize_const_enum(
ptr: *const (),
mut to: ConstVec<u8>,
layout: &EnumLayout,
) -> ConstVec<u8> {
let byte_ptr = ptr as *const u8;
let discriminant = layout.discriminant.read(byte_ptr);
let mut i = 0;
while i < layout.variants.len() {
let EnumVariant {
tag, name, data, ..
} = &layout.variants[i];
if discriminant == *tag {
to = write_map(to, 1);
to = write_map_key(to, name);
let data_ptr = ptr.wrapping_byte_offset(layout.variants_offset as _);
to = serialize_const_struct(data_ptr, to, data);
break;
}
i += 1;
}
to
}
#[derive(Debug, Copy, Clone)]
pub struct EnumLayout {
pub(crate) size: usize,
discriminant: PrimitiveLayout,
variants_offset: usize,
variants: &'static [EnumVariant],
}
impl EnumLayout {
pub const fn new(
size: usize,
discriminant: PrimitiveLayout,
variants: &'static [EnumVariant],
) -> Self {
let mut max_align = 1;
let mut i = 0;
while i < variants.len() {
let EnumVariant { align, .. } = &variants[i];
if *align > max_align {
max_align = *align;
}
i += 1;
}
let variants_offset_raw = discriminant.size;
let padding = (max_align - (variants_offset_raw % max_align)) % max_align;
let variants_offset = variants_offset_raw + padding;
assert!(variants_offset % max_align == 0);
Self {
size,
discriminant,
variants_offset,
variants,
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct EnumVariant {
name: &'static str,
tag: u32,
data: StructLayout,
align: usize,
}
impl EnumVariant {
pub const fn new(name: &'static str, tag: u32, data: StructLayout, align: usize) -> Self {
Self {
name,
tag,
data,
align,
}
}
}
pub(crate) const fn deserialize_const_enum<'a>(
from: &'a [u8],
layout: &EnumLayout,
out: &mut [MaybeUninit<u8>],
) -> Option<&'a [u8]> {
let Ok((map, remaining)) = take_map(from) else {
return None;
};
let Ok((deserilized_name, from)) = take_str(map.bytes) else {
return None;
};
let mut i = 0;
let mut matched_variant = false;
while i < layout.variants.len() {
let EnumVariant {
name, data, tag, ..
} = &layout.variants[i];
if str_eq(deserilized_name, name) {
layout.discriminant.write(*tag, out);
let Some((_, out)) = out.split_at_mut_checked(layout.variants_offset) else {
return None;
};
if deserialize_const_struct(from, data, out).is_none() {
return None;
}
matched_variant = true;
break;
}
i += 1;
}
if !matched_variant {
return None;
}
Some(remaining)
}