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) -> Typ {
match w {
TypWire::Bool => Typ::Bool,
TypWire::U8 => Typ::U8,
TypWire::U16 => Typ::U16,
TypWire::U32 => Typ::U32,
TypWire::U64 => Typ::U64,
TypWire::I32 => Typ::I32,
TypWire::I64 => Typ::I64,
TypWire::F32 => Typ::F32,
TypWire::F64 => Typ::F64,
TypWire::Str => Typ::Str,
TypWire::Datetime => Typ::Datetime,
TypWire::Timestamp => Typ::Timestamp,
TypWire::Decimal => Typ::Decimal,
TypWire::Id32 => Typ::Id32,
TypWire::Id64 => Typ::Id64,
TypWire::Fuid => Typ::Fuid,
TypWire::LowId => Typ::LowId,
TypWire::Bytes => Typ::Bytes,
TypWire::ArrayBytes(n) => Typ::ArrayBytes(n),
TypWire::Array(n, inner) => Typ::Array(n, Box::leak(Box::new(wire_to_typ(*inner)))),
TypWire::Vec(inner) => Typ::Vec(Box::leak(Box::new(wire_to_typ(*inner)))),
TypWire::Optional(inner) => 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().expect("SimpleEnum variant key must be u8");
let name: &'static str = match value {
serde_json::Value::String(s) => leak_str(s),
_ => panic!("SimpleEnum variant value must be string"),
};
(tag, name)
})
.collect();
Typ::SimpleEnum(SimpleEnumType {
name: leak_str(name),
variants: leak_slice(v),
})
}
TypWire::Struct(StructWire { name, fields }) => 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().expect("Enum variant key must be u8");
let pair: (String, TypWire) =
serde_json::from_value(value).expect("Enum variant value shape");
(tag, (leak_str(pair.0), wire_to_typ(pair.1)))
})
.collect();
Typ::Enum(EnumType {
name: leak_str(name),
variants: leak_slice(v),
})
}
TypWire::Void => Typ::Void,
TypWire::Json => Typ::RustJson,
TypWire::JsonBytes => Typ::JsonBytes,
TypWire::Custom(name, args) => {
let args: Vec<Typ> = args.into_iter().map(wire_to_typ).collect();
Typ::Custom(leak_str(name), leak_slice(args))
}
}
}
fn wire_to_fields(f: FieldsWire) -> Fields {
match f {
FieldsWire::Named(v) => {
let arr: Vec<NamedField> = v
.into_iter()
.map(|(n, t)| (leak_str(n), wire_to_typ(t)))
.collect();
Fields::Named(leak_slice(arr))
}
FieldsWire::Unnamed(v) => {
let arr: Vec<Typ> = v.into_iter().map(wire_to_typ).collect();
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)?;
Ok(wire_to_typ(w))
}
}
#[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,
})
}
}