use core::{cmp::Ordering, marker::PhantomData, num::NonZeroU32, ops::ControlFlow};
use std::collections::HashSet;
use rapira::{FromU8, Rapira, RapiraError, byte_rapira};
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
use thiserror::Error;
use xxhash_rust::xxh3::xxh3_64;
use crate::Value;
fn is_uniq_sorted(mut iter: impl Iterator<Item = u32>) -> Ordering {
let first = iter.next();
match first {
Some(first) => {
let is_uniq = iter.try_fold(first, |acc, item| match acc.cmp(&item) {
Ordering::Less => ControlFlow::Continue(item),
Ordering::Equal => ControlFlow::Break(Ordering::Equal),
Ordering::Greater => ControlFlow::Break(Ordering::Greater),
});
match is_uniq {
ControlFlow::Continue(_) => Ordering::Less,
ControlFlow::Break(ordering) => ordering,
}
}
None => Ordering::Less,
}
}
#[derive(PartialEq, Clone, Serialize, Deserialize, Debug, Rapira)]
pub struct NamedField {
pub name: String,
pub typ: Scheme,
}
type FieldsArr<T> = Vec<T>;
#[derive(PartialEq, Clone, Serialize, Deserialize, Debug, Rapira)]
#[serde(tag = "type", content = "data")]
pub enum Fields {
Named(FieldsArr<NamedField>),
Unnamed(FieldsArr<Scheme>),
}
#[derive(PartialEq, Clone, Serialize, Deserialize, Debug, Rapira)]
pub struct StructType {
pub fields: Fields,
}
impl StructType {
pub fn check_bytes(
&self,
slice: &mut &[u8],
types: &[StoredType<IdWithPath>],
) -> rapira::Result<()> {
match &self.fields {
Fields::Named(named) => named
.iter()
.try_for_each(|item| item.typ.check_bytes(slice, types)),
Fields::Unnamed(unnamed) => unnamed
.iter()
.try_for_each(|item| item.check_bytes(slice, types)),
}
}
pub fn check_scheme(&self) -> Result<(), SchemeError> {
match &self.fields {
Fields::Named(named) => {
let mut uniq = HashSet::with_capacity(named.len());
if !named.iter().all(|n| uniq.insert(&n.name)) {
Err(SchemeError::OtherError)
} else {
Ok(())
}
}
Fields::Unnamed(_) => Ok(()),
}
}
}
type Variants<T> = Vec<(u16, T)>;
#[derive(PartialEq, Clone, Serialize, Deserialize, Debug, Rapira)]
pub struct EnumType {
pub variants: Variants<NamedField>,
}
#[derive(PartialEq, Eq, Clone, Serialize, Deserialize, Debug, Rapira)]
pub struct SimpleEnum {
pub variants: Variants<String>,
}
pub type PathArr = Vec<String>;
pub trait Ident {}
#[derive(PartialEq, Eq, Clone, Debug, Rapira, Serialize, Deserialize)]
pub struct TypePath(PathArr);
impl Ident for TypePath {}
#[derive(PartialEq, Eq, Clone, Copy, Debug, Rapira, Serialize, Deserialize)]
#[repr(transparent)]
pub struct TypeId(NonZeroU32);
impl Ident for TypeId {}
#[derive(PartialEq, Eq, Clone, Debug, Rapira, Serialize, Deserialize)]
pub struct IdWithPath {
pub id: NonZeroU32,
pub path: PathArr,
}
impl Ident for IdWithPath {}
#[derive(PartialEq, Eq, Clone, Copy, Debug, Rapira, Serialize, Deserialize)]
pub struct IndexedId {
pub id: NonZeroU32,
pub index: u32,
}
#[derive(PartialEq, Eq, Clone, Copy, Debug, Rapira, Serialize, Deserialize, FromU8)]
#[repr(u8)]
pub enum TypeIdent {
Id,
Path,
IdWithPath,
}
#[derive(PartialEq, Clone, Serialize, Deserialize, Debug, Rapira)]
#[repr(u8)]
pub enum ComplexType {
SimpleEnum(SimpleEnum),
Struct(StructType),
Enum(EnumType),
}
impl ComplexType {
pub fn check_scheme(&mut self) -> Result<(), SchemeError> {
match self {
ComplexType::SimpleEnum(simple) => {
let ord = is_uniq_sorted(simple.variants.iter().map(|v| v.0 as u32));
match ord {
Ordering::Less => Ok(()),
Ordering::Equal => Err(SchemeError::OtherError),
Ordering::Greater => {
simple.variants.sort_unstable_by_key(|v| v.0);
let ord = is_uniq_sorted(simple.variants.iter().map(|v| v.0 as u32));
if !matches!(ord, Ordering::Less) {
Err(SchemeError::OtherError)
} else {
Ok(())
}
}
}
}
ComplexType::Struct(s) => s.check_scheme(),
ComplexType::Enum(e) => {
let ord = is_uniq_sorted(e.variants.iter().map(|v| v.0 as u32));
match ord {
Ordering::Less => Ok(()),
Ordering::Equal => Err(SchemeError::OtherError),
Ordering::Greater => {
e.variants.sort_unstable_by_key(|v| v.0);
let ord = is_uniq_sorted(e.variants.iter().map(|v| v.0 as u32));
if !matches!(ord, Ordering::Less) {
Err(SchemeError::OtherError)
} else {
Ok(())
}
}
}
}
}
}
}
#[derive(PartialEq, Clone, Serialize, Deserialize, Debug, Rapira)]
pub struct StoredType<T: Ident> {
ident: T,
typ: ComplexType,
}
#[derive(PartialEq, Clone, Serialize, Deserialize, Debug, Rapira)]
#[serde(tag = "type", content = "data")]
#[rapira(static_size = None)]
#[rapira(min_size = 1)]
#[repr(u8)]
pub enum Scheme {
Void,
Bool,
U8,
U16,
U32,
U64,
I32,
I64,
F32,
F64,
Str,
ID,
Dynamic,
Array(u32, Box<Scheme>),
Vec(Box<Scheme>),
Optional(Box<Scheme>),
Struct(Box<StructType>),
Stored(IndexedId),
}
#[cfg_attr(feature = "std", derive(Error, Debug))]
pub enum SchemeError {
#[cfg_attr(feature = "std", error("type not found"))]
TypeNotFound,
#[cfg_attr(feature = "std", error("deserialize error"))]
DeserializeError,
#[cfg_attr(feature = "std", error("identifications error"))]
IdentsError,
#[cfg_attr(feature = "std", error("rapira error"))]
RapiraError(#[from] RapiraError),
#[cfg_attr(feature = "std", error("other error"))]
OtherError,
}
impl Scheme {
pub fn is_stored(&self) -> bool {
match self {
Scheme::Array(_, inner) => inner.is_stored(),
Scheme::Vec(inner) => inner.is_stored(),
Scheme::Optional(inner) => inner.is_stored(),
Scheme::Struct(struct_type) => match &struct_type.fields {
Fields::Named(named) => named.iter().any(|item| item.typ.is_stored()),
Fields::Unnamed(unnamed) => unnamed.iter().any(|item| item.is_stored()),
},
Scheme::Stored(_) => true,
_ => false,
}
}
pub fn init_stored(&mut self, ids: &[NonZeroU32]) -> Result<(), SchemeError> {
match self {
Scheme::Array(_, inner) => inner.init_stored(ids),
Scheme::Vec(inner) => inner.init_stored(ids),
Scheme::Optional(inner) => inner.init_stored(ids),
Scheme::Struct(struct_type) => match &mut struct_type.fields {
Fields::Named(named) => named
.iter_mut()
.try_for_each(|item| item.typ.init_stored(ids)),
Fields::Unnamed(unnamed) => unnamed
.iter_mut()
.try_for_each(|item| item.init_stored(ids)),
},
Scheme::Stored(typ) => ids
.binary_search(&typ.id)
.map(|index| {
typ.index = index as u32;
})
.map_err(|_| SchemeError::TypeNotFound),
_ => Ok(()),
}
}
#[inline]
pub fn check_bytes(
&self,
slice: &mut &[u8],
types: &[StoredType<IdWithPath>],
) -> Result<(), RapiraError> {
match self {
Scheme::Void => Ok(()),
Scheme::Bool => bool::check_bytes(slice),
Scheme::U8 => byte_rapira::check_bytes::<()>(PhantomData, slice),
Scheme::U16 => u16::check_bytes(slice),
Scheme::U32 => u32::check_bytes(slice),
Scheme::U64 => u64::check_bytes(slice),
Scheme::I32 => i32::check_bytes(slice),
Scheme::I64 => i64::check_bytes(slice),
Scheme::F32 => f32::check_bytes(slice),
Scheme::F64 => f64::check_bytes(slice),
Scheme::Str => String::check_bytes(slice),
Scheme::ID => NonZeroU32::check_bytes(slice),
Scheme::Dynamic => Value::check_bytes(slice),
Scheme::Array(n, s) => (0u32..*n).try_for_each(|_| s.check_bytes(slice, types)),
Scheme::Vec(s) => {
let size = u32::from_slice(slice)?;
(0u32..size).try_for_each(|_| s.check_bytes(slice, types))
}
Scheme::Optional(s) => {
let exist = bool::from_slice(slice)?;
if exist {
s.check_bytes(slice, types)
} else {
Ok(())
}
}
Scheme::Struct(s) => s.check_bytes(slice, types),
Scheme::Stored(stored) => match types.get(stored.index as usize) {
Some(ty) => match &ty.typ {
ComplexType::SimpleEnum(simple) => {
let variant = byte_rapira::from_slice(slice)? as u16;
if simple
.variants
.binary_search_by_key(&variant, |i| i.0)
.is_err()
{
Err(RapiraError::EnumVariant)
} else {
Ok(())
}
}
ComplexType::Struct(s) => s.check_bytes(slice, types),
ComplexType::Enum(e) => {
let variant = byte_rapira::from_slice(slice)? as u16;
let variant = e
.variants
.binary_search_by_key(&variant, |i| i.0)
.map(|i| &e.variants[i])
.ok();
match variant {
Some((_, NamedField { typ, .. })) => typ.check_bytes(slice, types),
None => Err(RapiraError::EnumVariant),
}
}
},
None => Err(RapiraError::IterNext),
},
}
}
}
pub fn parse_scheme(
bytes: &[u8],
scheme: &[u8],
is_enumerated: bool,
) -> Result<(Scheme, Vec<StoredType<IdWithPath>>), SchemeError> {
let mut new_types: Vec<StoredType<IdWithPath>> =
rapira::deserialize(bytes).map_err(|_| SchemeError::DeserializeError)?;
let mut scheme: Scheme =
rapira::deserialize(scheme).map_err(|_| SchemeError::DeserializeError)?;
if is_enumerated {
let ord = is_uniq_sorted(new_types.iter().map(|item| item.ident.id.get()));
match ord {
Ordering::Less => {}
Ordering::Equal => return Err(SchemeError::IdentsError),
Ordering::Greater => {
new_types.sort_unstable_by_key(|item| item.ident.id);
let ord = is_uniq_sorted(new_types.iter().map(|item| item.ident.id.get()));
if !matches!(ord, Ordering::Less) {
return Err(SchemeError::OtherError);
}
}
}
} else {
for StoredType { ident, typ: _ } in &mut new_types {
let full_path = ident.path.join("");
let hash = xxh3_64(full_path.as_bytes());
let hash = hash as u32;
ident.id = NonZeroU32::new(hash).ok_or(SchemeError::IdentsError)?;
}
new_types.sort_unstable_by_key(|item| item.ident.id);
}
new_types
.iter_mut()
.try_for_each(|item| item.typ.check_scheme())?;
let ids: Vec<NonZeroU32> = new_types.iter().map(|i| i.ident.id).collect();
let len = new_types.len();
let mut iter = new_types.into_iter();
let types: Vec<StoredType<IdWithPath>> =
iter.try_fold(Vec::with_capacity(len), |mut acc, mut new_type| {
let item = match &mut new_type.typ {
ComplexType::SimpleEnum(_) => new_type,
ComplexType::Struct(struct_type) => match &mut struct_type.fields {
Fields::Named(named) => {
for item in named {
item.typ.init_stored(&ids)?;
}
new_type
}
Fields::Unnamed(unnamed) => {
for item in unnamed {
item.init_stored(&ids)?;
}
new_type
}
},
ComplexType::Enum(enum_type) => {
for (_, variant) in &mut enum_type.variants {
variant.typ.init_stored(&ids)?;
}
new_type
}
};
acc.push(item);
Ok(acc) as Result<Vec<StoredType<IdWithPath>>, SchemeError>
})?;
scheme.init_stored(&ids)?;
Ok((scheme, types))
}