use serde::Deserialize;
use crate::key_type::{KeyScheme, KeyType};
use crate::typ::{EnumType, Fields, NamedField, SimpleEnumType, StructType, Typ};
fn leak_str(s: String) -> &'static str {
Box::leak(s.into_boxed_str())
}
fn leak_slice<T>(v: Vec<T>) -> &'static [T] {
Box::leak(v.into_boxed_slice())
}
#[derive(Deserialize)]
#[serde(tag = "type", content = "data")]
enum TypWire {
Bool,
U8,
U16,
U32,
U64,
I32,
I64,
F32,
F64,
Str,
Datetime,
Timestamp,
Decimal,
Id32,
Id64,
Fuid,
LowId,
Bytes,
ArrayBytes(u32),
Array(u32, Box<TypWire>),
Vec(Box<TypWire>),
Optional(Box<TypWire>),
SimpleEnum(SimpleEnumWire),
Struct(StructWire),
Enum(EnumWire),
Void,
Json,
JsonBytes,
Custom(String, Vec<TypWire>),
}
#[derive(Deserialize)]
struct StructWire {
name: String,
fields: FieldsWire,
}
#[derive(Deserialize)]
#[serde(tag = "type", content = "data")]
enum FieldsWire {
Named(Vec<(String, TypWire)>),
Unnamed(Vec<TypWire>),
}
#[derive(Deserialize)]
struct EnumWire {
name: String,
variants: serde_json::Map<String, serde_json::Value>,
}
#[derive(Deserialize)]
struct SimpleEnumWire {
name: String,
variants: serde_json::Map<String, serde_json::Value>,
}
fn wire_to_typ(w: TypWire) -> Result<Typ, String> {
match w {
TypWire::Bool => Ok(Typ::Bool),
TypWire::U8 => Ok(Typ::U8),
TypWire::U16 => Ok(Typ::U16),
TypWire::U32 => Ok(Typ::U32),
TypWire::U64 => Ok(Typ::U64),
TypWire::I32 => Ok(Typ::I32),
TypWire::I64 => Ok(Typ::I64),
TypWire::F32 => Ok(Typ::F32),
TypWire::F64 => Ok(Typ::F64),
TypWire::Str => Ok(Typ::Str),
TypWire::Datetime => Ok(Typ::Datetime),
TypWire::Timestamp => Ok(Typ::Timestamp),
TypWire::Decimal => Ok(Typ::Decimal),
TypWire::Id32 => Ok(Typ::Id32),
TypWire::Id64 => Ok(Typ::Id64),
TypWire::Fuid => Ok(Typ::Fuid),
TypWire::LowId => Ok(Typ::LowId),
TypWire::Bytes => Ok(Typ::Bytes),
TypWire::ArrayBytes(n) => Ok(Typ::ArrayBytes(n)),
TypWire::Array(n, inner) => Ok(Typ::Array(n, Box::leak(Box::new(wire_to_typ(*inner)?)))),
TypWire::Vec(inner) => Ok(Typ::Vec(Box::leak(Box::new(wire_to_typ(*inner)?)))),
TypWire::Optional(inner) => Ok(Typ::Optional(Box::leak(Box::new(wire_to_typ(*inner)?)))),
TypWire::SimpleEnum(SimpleEnumWire { name, variants }) => {
let v: Vec<(u8, &'static str)> = variants
.into_iter()
.map(|(k, value)| {
let tag: u8 = k
.parse()
.map_err(|_| format!("SimpleEnum variant key must be u8: {k:?}"))?;
let name: &'static str = match value {
serde_json::Value::String(s) => leak_str(s),
other => {
return Err(format!(
"SimpleEnum variant value must be string, got {other:?}"
));
}
};
Ok((tag, name))
})
.collect::<Result<Vec<_>, String>>()?;
Ok(Typ::SimpleEnum(SimpleEnumType {
name: leak_str(name),
variants: leak_slice(v),
}))
}
TypWire::Struct(StructWire { name, fields }) => Ok(Typ::Struct(StructType {
name: leak_str(name),
fields: wire_to_fields(fields)?,
})),
TypWire::Enum(EnumWire { name, variants }) => {
let v: Vec<(u8, NamedField)> = variants
.into_iter()
.map(|(k, value)| {
let tag: u8 = k
.parse()
.map_err(|_| format!("Enum variant key must be u8: {k:?}"))?;
let pair: (String, TypWire) = serde_json::from_value(value)
.map_err(|e| format!("Enum variant value shape: {e}"))?;
Ok((tag, (leak_str(pair.0), wire_to_typ(pair.1)?)))
})
.collect::<Result<Vec<_>, String>>()?;
Ok(Typ::Enum(EnumType {
name: leak_str(name),
variants: leak_slice(v),
}))
}
TypWire::Void => Ok(Typ::Void),
TypWire::Json => Ok(Typ::RustJson),
TypWire::JsonBytes => Ok(Typ::JsonBytes),
TypWire::Custom(name, args) => {
let args: Vec<Typ> = args
.into_iter()
.map(wire_to_typ)
.collect::<Result<Vec<_>, String>>()?;
Ok(Typ::Custom(leak_str(name), leak_slice(args)))
}
}
}
fn wire_to_fields(f: FieldsWire) -> Result<Fields, String> {
match f {
FieldsWire::Named(v) => {
let arr: Vec<NamedField> = v
.into_iter()
.map(|(n, t)| Ok((leak_str(n), wire_to_typ(t)?)))
.collect::<Result<Vec<_>, String>>()?;
Ok(Fields::Named(leak_slice(arr)))
}
FieldsWire::Unnamed(v) => {
let arr: Vec<Typ> = v
.into_iter()
.map(wire_to_typ)
.collect::<Result<Vec<_>, String>>()?;
Ok(Fields::Unnamed(leak_slice(arr)))
}
}
}
impl<'de> Deserialize<'de> for Typ {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let w = TypWire::deserialize(d)?;
wire_to_typ(w).map_err(serde::de::Error::custom)
}
}
#[derive(Deserialize)]
#[serde(tag = "type", content = "data")]
enum KeySchemeWire {
Typed(Vec<KeyType>),
Bytes,
}
impl<'de> Deserialize<'de> for KeyScheme {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let w = KeySchemeWire::deserialize(d)?;
Ok(match w {
KeySchemeWire::Typed(v) => KeyScheme::Typed(leak_slice(v)),
KeySchemeWire::Bytes => KeyScheme::Bytes,
})
}
}