use crate::errors::*;
use crate::hlua::AnyLuaValue;
use serde_json::{self, Value, Number};
use std::collections::HashMap;
pub fn decode(x: &str) -> Result<AnyLuaValue> {
let v: Value = serde_json::from_str(x)
.context("deserialize failed")?;
let v: LuaJsonValue = v.into();
Ok(v.into())
}
pub fn encode(v: AnyLuaValue) -> Result<String> {
let v: LuaJsonValue = v.into();
let v: Value = v.into();
let s = serde_json::to_string(&v)
.context("Serialize failed")?;
Ok(s)
}
pub fn lua_array_is_list(array: &[(AnyLuaValue, AnyLuaValue)]) -> bool {
if !array.is_empty() {
let first = &array[0];
matches!(first.0, AnyLuaValue::LuaNumber(_))
} else {
false
}
}
#[derive(Debug)]
pub enum LuaJsonValue {
Null,
Bool(bool),
Number(Number),
String(String),
Array(Vec<LuaJsonValue>),
Object(HashMap<String, LuaJsonValue>),
}
impl From<LuaJsonValue> for AnyLuaValue {
fn from(x: LuaJsonValue) -> AnyLuaValue {
match x {
LuaJsonValue::Null => AnyLuaValue::LuaNil,
LuaJsonValue::Bool(v) => AnyLuaValue::LuaBoolean(v),
LuaJsonValue::Number(v) => AnyLuaValue::LuaNumber(v.as_f64().unwrap()),
LuaJsonValue::String(v) => AnyLuaValue::LuaString(v),
LuaJsonValue::Array(v) => AnyLuaValue::LuaArray(v.into_iter().enumerate()
.map(|(i, x)| (AnyLuaValue::LuaNumber(i as f64), x.into()))
.collect()
),
LuaJsonValue::Object(v) => AnyLuaValue::LuaArray(v.into_iter()
.map(|(k, v)| (AnyLuaValue::LuaString(k), v.into()))
.collect()
),
}
}
}
impl From<AnyLuaValue> for LuaJsonValue {
fn from(x: AnyLuaValue) -> LuaJsonValue {
match x {
AnyLuaValue::LuaNil => LuaJsonValue::Null,
AnyLuaValue::LuaBoolean(v) => LuaJsonValue::Bool(v),
AnyLuaValue::LuaString(v) => LuaJsonValue::String(v),
AnyLuaValue::LuaAnyString(v) => LuaJsonValue::Array(v.0.into_iter()
.map(|x| LuaJsonValue::Number(x.into()))
.collect()
),
AnyLuaValue::LuaNumber(v) => {
LuaJsonValue::Number(if v % 1f64 == 0f64 {
(v as u64).into()
} else {
Number::from_f64(v).expect("invalid LuaJson::Number")
})
},
AnyLuaValue::LuaArray(v) => {
if lua_array_is_list(&v) {
LuaJsonValue::Array(v.into_iter()
.map(|(_, v)| v.into())
.collect()
)
} else {
LuaJsonValue::Object(v.into_iter()
.filter_map(|(k, v)| match k {
AnyLuaValue::LuaString(k) => Some((k, v.into())),
_ => None,
})
.collect()
)
}
},
AnyLuaValue::LuaOther => LuaJsonValue::Null,
}
}
}
impl From<LuaJsonValue> for Value {
fn from(x: LuaJsonValue) -> Value {
match x {
LuaJsonValue::Null => Value::Null,
LuaJsonValue::Bool(v) => Value::Bool(v),
LuaJsonValue::Number(v) => Value::Number(v),
LuaJsonValue::String(v) => Value::String(v),
LuaJsonValue::Array(v) => Value::Array(v.into_iter()
.map(|x| x.into())
.collect()
),
LuaJsonValue::Object(v) => Value::Object(v.into_iter()
.map(|(k, v)| (k, v.into()))
.collect()
),
}
}
}
impl From<Value> for LuaJsonValue {
fn from(x: Value) -> LuaJsonValue {
match x {
Value::Null => LuaJsonValue::Null,
Value::Bool(v) => LuaJsonValue::Bool(v),
Value::Number(v) => LuaJsonValue::Number(v),
Value::String(v) => LuaJsonValue::String(v),
Value::Array(v) => LuaJsonValue::Array(v.into_iter()
.map(|x| x.into())
.collect()
),
Value::Object(v) => LuaJsonValue::Object(v.into_iter()
.map(|(k, v)| (k, v.into()))
.collect()
),
}
}
}