use std::collections::{BTreeMap, HashMap};
use crate::constants::ExpressionEnum;
use crate::reader::Reader;
use crate::wxf::reader::WxfReader;
use crate::Error;
pub trait FromWXF<'de>: Sized {
fn from_wxf<R: Reader<'de>>(r: &mut WxfReader<R>) -> Result<Self, Error> {
let tok = r.read_expr_token()?;
Self::from_wxf_with_tag(r, tok)
}
fn from_wxf_with_tag<R: Reader<'de>>(
r: &mut WxfReader<R>,
tok: ExpressionEnum,
) -> Result<Self, Error>;
}
pub fn err_at(path: impl Into<String>, expected: &'static str, got: String) -> Error {
Error::Deserialize {
path: path.into(),
expected: expected,
got: got,
}
}
impl<'de> FromWXF<'de> for &'de str {
fn from_wxf_with_tag<R: Reader<'de>>(
r: &mut WxfReader<R>,
tok: ExpressionEnum,
) -> Result<Self, Error> {
if tok != ExpressionEnum::String {
return Err(Error::unexpected_token(&["String"], tok));
}
r.read_str()
}
}
impl<'de> FromWXF<'de> for &'de [u8] {
fn from_wxf_with_tag<R: Reader<'de>>(
r: &mut WxfReader<R>,
tok: ExpressionEnum,
) -> Result<Self, Error> {
if tok != ExpressionEnum::ByteArray {
return Err(Error::unexpected_token(&["ByteArray"], tok));
}
r.read_byte_array()
}
}
macro_rules! read_wire {
(Integer8, $r:expr) => {
$r.read_i8()? as _
};
(Integer16, $r:expr) => {
$r.read_i16()? as _
};
(Integer32, $r:expr) => {
$r.read_i32()? as _
};
(Integer64, $r:expr) => {
$r.read_i64()? as _
};
(Real64, $r:expr) => {
$r.read_f64()? as _
};
}
macro_rules! impl_numeric_from_wxf {
($t:ty, [$($tok:ident),+]) => {
impl<'de> FromWXF<'de> for $t {
fn from_wxf_with_tag<R: Reader<'de>>(
r: &mut WxfReader<R>,
tok: ExpressionEnum,
) -> Result<Self, Error> {
match tok {
$(ExpressionEnum::$tok => Ok(read_wire!($tok, r)),)+
other => Err(Error::unexpected_token(
&[$(stringify!($tok)),+],
other,
)),
}
}
}
};
}
impl_numeric_from_wxf!(i8, [Integer8]);
impl_numeric_from_wxf!(i16, [Integer8, Integer16]);
impl_numeric_from_wxf!(i32, [Integer8, Integer16, Integer32]);
impl_numeric_from_wxf!(i64, [Integer8, Integer16, Integer32, Integer64]);
impl_numeric_from_wxf!(f32, [Integer8, Integer16]);
impl_numeric_from_wxf!(f64, [Integer8, Integer16, Integer32, Real64]);
impl<'de> FromWXF<'de> for bool {
fn from_wxf_with_tag<R: Reader<'de>>(
r: &mut WxfReader<R>,
tok: ExpressionEnum,
) -> Result<Self, Error> {
if tok != ExpressionEnum::Symbol {
return Err(Error::unexpected_token(&["Symbol"], tok));
}
match r.read_str()? {
"System`True" => Ok(true),
"System`False" => Ok(false),
other => Err(Error::UnexpectedSymbol {
expected: vec!["System`True", "System`False"],
got: other.to_owned(),
}),
}
}
}
impl<'de> FromWXF<'de> for String {
fn from_wxf_with_tag<R: Reader<'de>>(
r: &mut WxfReader<R>,
tok: ExpressionEnum,
) -> Result<Self, Error> {
<&str as FromWXF<'de>>::from_wxf_with_tag(r, tok).map(str::to_owned)
}
}
impl<'de> FromWXF<'de> for () {
fn from_wxf_with_tag<R: Reader<'de>>(
r: &mut WxfReader<R>,
tok: ExpressionEnum,
) -> Result<Self, Error> {
if tok != ExpressionEnum::Symbol {
return Err(Error::unexpected_token(&["Symbol"], tok));
}
match r.read_str()? {
"Null" | "System`Null" => Ok(()),
other => Err(Error::UnexpectedSymbol {
expected: vec!["Null", "System`Null"],
got: other.to_owned(),
}),
}
}
}
impl<'de, T: FromWXF<'de>> FromWXF<'de> for Option<T> {
fn from_wxf_with_tag<R: Reader<'de>>(
r: &mut WxfReader<R>,
tok: ExpressionEnum,
) -> Result<Self, Error> {
let (_n, variant) = crate::strategy::read_enum_header(r, tok)?;
match variant.as_str() {
"None" => Ok(None),
"Some" => {
crate::strategy::read_data_header(r, 1)?;
Ok(Some(T::from_wxf(r)?))
},
other => Err(Error::UnexpectedSymbol {
expected: vec!["None", "Some"],
got: other.to_owned(),
}),
}
}
}
impl<'de, T: FromWXF<'de>, E: FromWXF<'de>> FromWXF<'de> for Result<T, E> {
fn from_wxf_with_tag<R: Reader<'de>>(
r: &mut WxfReader<R>,
tok: ExpressionEnum,
) -> Result<Self, Error> {
let (_n, variant) = crate::strategy::read_enum_header(r, tok)?;
match variant.as_str() {
"Ok" => {
crate::strategy::read_data_header(r, 1)?;
Ok(Ok(T::from_wxf(r)?))
},
"Err" => {
crate::strategy::read_data_header(r, 1)?;
Ok(Err(E::from_wxf(r)?))
},
other => Err(Error::UnexpectedSymbol {
expected: vec!["Ok", "Err"],
got: other.to_owned(),
}),
}
}
}
impl<'de, K, V> FromWXF<'de> for HashMap<K, V>
where
K: FromWXF<'de> + Eq + std::hash::Hash,
V: FromWXF<'de>,
{
fn from_wxf_with_tag<R: Reader<'de>>(
r: &mut WxfReader<R>,
tok: ExpressionEnum,
) -> Result<Self, Error> {
if tok != ExpressionEnum::Association {
return Err(Error::unexpected_token(&["Association"], tok));
}
let n = r.read_varint()?;
let mut out = HashMap::with_capacity(n as usize);
for _ in 0..n {
let _delayed = r.read_rule()?;
let k = K::from_wxf(r)?;
let v = V::from_wxf(r)?;
out.insert(k, v);
}
Ok(out)
}
}
impl<'de, K, V> FromWXF<'de> for BTreeMap<K, V>
where
K: FromWXF<'de> + Ord,
V: FromWXF<'de>,
{
fn from_wxf_with_tag<R: Reader<'de>>(
r: &mut WxfReader<R>,
tok: ExpressionEnum,
) -> Result<Self, Error> {
if tok != ExpressionEnum::Association {
return Err(Error::unexpected_token(&["Association"], tok));
}
let n = r.read_varint()?;
let mut out = BTreeMap::new();
for _ in 0..n {
let _delayed = r.read_rule()?;
let k = K::from_wxf(r)?;
let v = V::from_wxf(r)?;
out.insert(k, v);
}
Ok(out)
}
}
impl<'de> FromWXF<'de> for Vec<u8> {
fn from_wxf_with_tag<R: Reader<'de>>(
r: &mut WxfReader<R>,
tok: ExpressionEnum,
) -> Result<Self, Error> {
<&[u8] as FromWXF<'de>>::from_wxf_with_tag(r, tok).map(<[u8]>::to_vec)
}
}
macro_rules! impl_vec_numeric_from_wxf {
($($t:ty),+ $(,)?) => {
$(
impl<'de> FromWXF<'de> for Vec<$t> {
fn from_wxf_with_tag<R: Reader<'de>>(r: &mut WxfReader<R>, tok: ExpressionEnum) -> Result<Self, Error> {
crate::numeric_in::read_vec_with_tag::<$t, R>(r, tok, "")
}
}
)+
};
}
impl_vec_numeric_from_wxf!(i8, i16, i32, i64, u16, u32, u64, f32, f64);
impl<'de, T: FromWXF<'de> + crate::to_wxf::WxfStruct> FromWXF<'de> for Vec<T> {
fn from_wxf_with_tag<R: Reader<'de>>(
r: &mut WxfReader<R>,
tok: ExpressionEnum,
) -> Result<Self, Error> {
if tok != ExpressionEnum::Function {
return Err(Error::unexpected_token(&["Function"], tok));
}
let n = r.read_varint()?;
r.skip()?; let mut items = Vec::with_capacity(n as usize);
for _ in 0..n {
items.push(T::from_wxf(r)?);
}
Ok(items)
}
}