use std::collections::HashMap;
use itertools::Itertools;
use nom::multi::count;
use nom::number::complete::{le_u16, le_u32};
use nom::AsBytes;
use serde::{Deserialize, Serialize};
use serde_json::Value as JSONValue;
use utils::IntoSubValue;
use wot_types::WotValue;
use crate::battle_results::Field;
use crate::error::Error::{self, *};
use crate::{AnyErr, PickleValue};
pub fn pickle_val_to_json_manual(
pickle_value: PickleValue, field: &Field,
) -> Result<JSONValue, (Error, JSONValue)> {
let result = match field.name {
"accountCompDescr" => parse_account_comp_descr(pickle_value).map_err(AccountCompDescrError),
"xpReplay" | "creditsReplay" | "freeXPReplay" | "eventCoinReplay" | "goldReplay" | "tmenXPReplay"
| "bpcoinReplay" | "crystalReplay" => parse_value_replay(pickle_value).map_err(ValueReplayError),
_ => pickle_to_wotvalue_to_json(pickle_value).map_err(ManualParserError),
};
result.map_err(|err| (err, field.default.to_json_value()))
}
fn pickle_to_wotvalue_to_json(pickle: PickleValue) -> Result<JSONValue, AnyErr> {
let wot_value: WotValue = serde_pickle::from_value(pickle)?;
let json_value = if let WotValue::Bytes(bytes) = wot_value {
JSONValue::String(hex::encode_upper(bytes))
} else {
serde_json::to_value(wot_value)?
};
Ok(json_value)
}
#[serde_with::serde_as]
#[derive(Debug, Serialize, Deserialize)]
struct AccountCompDescr {
id: i64,
#[serde_as(as = "serde_with::hex::Hex<serde_with::formats::Uppercase>")]
val: Vec<u8>,
}
fn parse_account_comp_descr(pickle_value: PickleValue) -> Result<JSONValue, AnyErr> {
use PickleValue::*;
let format_err = || "format error".into();
let dict = pickle_value.try_dict(format_err)?;
let mut return_dict = HashMap::new();
for (key, value) in dict.into_iter() {
let int_key = key.try_i64(format_err)?;
let list_iter = value.try_list(format_err)?.into_iter();
let Ok(Tuple(mut value)) = list_iter.exactly_one() else { return Err(format_err()) };
let [I64(id), Bytes(val)] = value.as_mut_slice() else { return Err(format_err()) };
let account_comp_descr = AccountCompDescr {
id: *id,
val: std::mem::take(val),
};
return_dict.insert(int_key.to_string(), account_comp_descr);
}
Ok(serde_json::to_value(return_dict)?)
}
struct NomError;
impl<I> nom::error::ParseError<I> for NomError {
fn from_error_kind(_: I, _: nom::error::ErrorKind) -> Self {
NomError
}
fn append(_: I, _: nom::error::ErrorKind, _: Self) -> Self {
NomError
}
}
fn parse_value_replay(wot_value: PickleValue) -> Result<JSONValue, AnyErr> {
let nom_err = |_: nom::Err<NomError>| "nom error";
let packed_value = wot_value.try_bytes(|| "expected bytes")?;
let (packed_value, size) = le_u16(packed_value.as_bytes()).map_err(nom_err)?;
let (rest, value_list) = count(le_u32, size as usize)(packed_value).map_err(nom_err)?;
if !rest.is_empty() {
return Err("Buffer not empty".into());
}
Ok(serde_json::to_value(value_list)?)
}