use crate::entity::field::*;
use crate::error::SerializerError;
use crate::HashMap;
use std::cell::UnsafeCell;
use std::rc::Rc;
struct CacheCell<T>(UnsafeCell<T>);
impl<T> CacheCell<T> {
fn new(value: T) -> Self {
Self(UnsafeCell::new(value))
}
#[inline(always)]
fn get(&self) -> &T {
unsafe { &*self.0.get() }
}
}
#[derive(Clone)]
pub(crate) struct Serializer {
pub(crate) fields: Vec<Rc<Field>>,
fp_cache: Rc<CacheCell<HashMap<Box<str>, FieldPath>>>,
}
impl Default for Serializer {
fn default() -> Self {
Self {
fields: Vec::new(),
fp_cache: Rc::new(CacheCell::new(HashMap::default())),
}
}
}
impl Serializer {
#[inline]
pub(crate) fn get_name(&self, fp: &FieldPath) -> String {
let mut i = 0;
let mut current_serializer = self;
let mut current_field = ¤t_serializer.fields[fp.path[i] as usize];
let mut name = String::new();
loop {
name += ¤t_field.var_name;
i += 1;
match ¤t_field.model {
FieldModel::Array | FieldModel::ValueVector(_) => {
if i > fp.last {
break;
}
name += &format!(".{:04}", fp.path[i]);
break;
}
FieldModel::Vector(serializer) => {
if i > fp.last {
break;
}
name += &format!(".{:04}.", fp.path[i]);
i += 1;
current_serializer = serializer;
}
FieldModel::Pointer(serializer) => {
if i > fp.last {
break;
}
name += ".";
current_serializer = serializer;
}
FieldModel::Value => break,
}
current_field = ¤t_serializer.fields[fp.path[i] as usize];
}
name
}
#[inline]
pub(crate) fn get_type(&self, fp: &FieldPath) -> &FieldType {
let mut i = 0;
let mut current_serializer = self;
let mut current_field = ¤t_serializer.fields[fp.path[i] as usize];
loop {
i += 1;
match ¤t_field.model {
FieldModel::Value | FieldModel::Array => return current_field.field_type.as_ref(),
FieldModel::ValueVector(_) => {
if i == fp.last {
return current_field.field_type.as_ref().generic.as_ref().unwrap();
}
return current_field.field_type.as_ref();
}
FieldModel::Vector(serializer) => {
if i >= fp.last {
return current_field.field_type.as_ref();
}
i += 1;
current_serializer = serializer;
}
FieldModel::Pointer(serializer) => {
if i > fp.last {
return current_field.field_type.as_ref();
}
current_serializer = serializer;
}
}
current_field = ¤t_serializer.fields[fp.path[i] as usize];
}
}
#[inline]
pub(crate) fn get_decoder(&self, fp: &FieldPath) -> &FieldDecoder {
let mut i = 0;
let mut current_serializer = self;
let mut current_field = ¤t_serializer.fields[fp.path[i] as usize];
loop {
i += 1;
match ¤t_field.model {
FieldModel::Value | FieldModel::Array => return ¤t_field.decoder,
FieldModel::ValueVector(decoder) => {
if i == fp.last {
return decoder;
}
return ¤t_field.decoder;
}
FieldModel::Vector(serializer) => {
if i >= fp.last {
return ¤t_field.decoder;
}
i += 1;
current_serializer = serializer;
}
FieldModel::Pointer(serializer) => {
if i > fp.last {
return ¤t_field.decoder;
}
current_serializer = serializer;
}
}
current_field = ¤t_serializer.fields[fp.path[i] as usize];
}
}
#[inline]
pub(crate) fn get_path(&self, name: &str) -> Result<FieldPath, SerializerError> {
if let Some(&fp) = self.fp_cache.get().get(name) {
return Ok(fp);
}
let mut current_serializer = self;
let mut fp = FieldPath::default();
let mut offset = 0;
'outer: loop {
for (i, f) in current_serializer.fields.iter().enumerate() {
if &name[offset..] == f.var_name.as_ref() {
fp.path[fp.last] = i as u16;
break 'outer;
}
if name.as_bytes()[offset..]
.get(f.var_name.len())
.is_some_and(|&b| b == b'.')
&& &name[offset..(offset + f.var_name.len())] == f.var_name.as_ref()
{
fp.path[fp.last] = i as u16;
fp.last += 1;
offset += f.var_name.len() + 1;
match &f.model {
FieldModel::Array | FieldModel::ValueVector(_) => {
fp.path[fp.last] = name[offset..].parse::<u16>().unwrap();
break 'outer;
}
FieldModel::Vector(serializer) => {
fp.path[fp.last] = name[offset..(offset + 4)].parse::<u16>().unwrap();
fp.last += 1;
offset += 5;
current_serializer = serializer;
continue 'outer;
}
FieldModel::Pointer(serializer) => {
current_serializer = serializer;
continue 'outer;
}
FieldModel::Value => unreachable!(),
}
}
}
return Err(SerializerError::NoFieldPath(name.to_string()));
}
unsafe {
(*self.fp_cache.0.get()).insert(name.into(), fp);
}
Ok(fp)
}
pub(crate) fn get_paths<'a>(
&'a self,
fp: &'a mut FieldPath,
st: &'a FieldState,
) -> Vec<FieldPath> {
self.fields
.iter()
.enumerate()
.flat_map(|(i, f)| {
fp.path[fp.last] = i as u16;
f.get_paths(fp, st)
})
.collect::<Vec<_>>()
}
}