use std::fmt::{Display, Formatter};
use bincode::{Decode as BincodeDecode, Encode as BincodeEncode};
use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize};
use serde_json::{json, to_value, Value as JsonValue};
use crate::rline_error::RlineError;
use crate::rline_error::RlineError::{BadTypeError, RuntimeError};
#[derive(
SerdeSerialize, SerdeDeserialize, BincodeDecode, BincodeEncode, Debug, Clone, PartialEq,
)]
pub enum Value {
String(String),
Integer(isize),
Float(f64),
VecString(Vec<String>),
VecInteger(Vec<isize>),
VecFloat(Vec<f64>),
VecU8(Vec<u8>),
}
impl Value {
pub fn as_string(&self) -> Result<&String, RlineError> {
if let Self::String(v) = self {
Ok(v)
} else {
Err(BadTypeError(String::from("Not a string")))
}
}
pub fn as_integer(&self) -> Result<&isize, RlineError> {
if let Self::Integer(v) = self {
Ok(v)
} else {
Err(BadTypeError(String::from("Not an integer")))
}
}
pub fn as_float(&self) -> Result<&f64, RlineError> {
if let Self::Float(v) = self {
Ok(v)
} else {
Err(BadTypeError(String::from("Not a float")))
}
}
pub fn as_vec_string(&self) -> Result<&Vec<String>, RlineError> {
if let Self::VecString(v) = self {
Ok(v)
} else {
Err(BadTypeError(String::from("Not a vector<string>")))
}
}
pub fn as_vec_integer(&self) -> Result<&Vec<isize>, RlineError> {
if let Self::VecInteger(v) = self {
Ok(v)
} else {
Err(BadTypeError(String::from("Not a vector<integer>")))
}
}
pub fn as_vec_float(&self) -> Result<&Vec<f64>, RlineError> {
if let Self::VecFloat(v) = self {
Ok(v)
} else {
Err(BadTypeError(String::from("Not a vector<float>")))
}
}
pub fn as_vec_u8(&self) -> Result<&Vec<u8>, RlineError> {
if let Self::VecU8(v) = self {
Ok(v)
} else {
Err(BadTypeError(String::from("Not a vector<u8>")))
}
}
pub fn from_json_value(json_value: JsonValue) -> Result<Self, RlineError> {
match json_value {
JsonValue::Null => Err(RuntimeError(format!("Invalid null value {}", json_value))),
JsonValue::Bool(b) => Ok(Self::Integer(b as isize)),
JsonValue::Number(number) => {
if let Some(f) = number.as_f64() {
Ok(Self::Float(f))
} else if let Some(i) = number.as_i64() {
Ok(Self::Integer(i as isize))
} else {
return Err(RuntimeError("Invalid number from json value".into()));
}
}
JsonValue::String(s) => Ok(Self::String(s)),
JsonValue::Array(values) => {
if let Some(first) = values.get(0) {
match first {
JsonValue::Null => Err(RuntimeError("Invalid null value".into())),
JsonValue::Array(_) | JsonValue::Object(_) => {
Ok(Self::String(
serde_json::to_string(&values)
.map_err(|e| RlineError::runtime_error(&e))?,
))
}
JsonValue::String(_) => {
let mut res: Vec<String> = Vec::with_capacity(values.len());
for v in values {
if let JsonValue::String(s) = v {
res.push(s)
} else {
return Err(RuntimeError(
"Unsupported heterogenous list".into(),
));
}
}
Ok(Self::VecString(res))
}
JsonValue::Bool(_) => {
let mut res: Vec<isize> = Vec::with_capacity(values.len());
for v in values {
if let JsonValue::Bool(b) = v {
res.push(b as isize)
} else {
return Err(RuntimeError(
"Unsupported heterogenous list".into(),
));
}
}
Ok(Self::VecInteger(res))
}
JsonValue::Number(first_number) => {
if first_number.as_f64().is_some() {
let mut res: Vec<f64> = Vec::with_capacity(values.len());
for v in values {
if let JsonValue::Number(number) = v {
if let Some(f) = number.as_f64() {
res.push(f);
continue;
}
}
return Err(RuntimeError(
"Unsupported heterogenous list".into(),
));
}
Ok(Self::VecFloat(res))
} else if first_number.as_i64().is_some() {
let mut res: Vec<isize> = Vec::with_capacity(values.len());
for v in values {
if let JsonValue::Number(number) = v {
if let Some(i) = number.as_i64() {
res.push(i as isize);
continue;
}
}
return Err(RuntimeError(
"Unsupported heterogenous list".into(),
));
}
Ok(Self::VecInteger(res))
} else {
return Err(RuntimeError("Invalid number from json value".into()));
}
}
}
} else {
Ok(Self::VecInteger(Vec::new()))
}
}
JsonValue::Object(map) => Ok(Self::String(
serde_json::to_string(&map).map_err(|e| RlineError::runtime_error(&e))?,
)),
}
}
}
impl Display for Value {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Value::String(v) => f.write_str(v),
Value::Integer(v) => f.write_str(&v.to_string()),
Value::Float(v) => f.write_str(&v.to_string()),
Value::VecString(v) => f.write_str(&format!("[{}]", v.to_vec().join(","))),
Value::VecInteger(v) => f.write_str(&format!(
"[{}]",
v.iter()
.map(|i| i.to_string())
.collect::<Vec<String>>()
.join(",")
)),
Value::VecFloat(v) => f.write_str(&format!(
"[{}]",
v.iter()
.map(|i| i.to_string())
.collect::<Vec<String>>()
.join(",")
)),
Value::VecU8(v) => f.write_str(&format!(
"[{}]",
v.iter()
.map(|i| i.to_string())
.collect::<Vec<String>>()
.join(",")
)),
}
}
}
impl From<String> for Value {
fn from(value: String) -> Self {
Self::String(value)
}
}
impl From<isize> for Value {
fn from(value: isize) -> Self {
Self::Integer(value)
}
}
impl From<f64> for Value {
fn from(value: f64) -> Self {
Self::Float(value)
}
}
impl From<Vec<String>> for Value {
fn from(value: Vec<String>) -> Self {
Self::VecString(value)
}
}
impl From<Vec<isize>> for Value {
fn from(value: Vec<isize>) -> Self {
Self::VecInteger(value)
}
}
impl From<Vec<f64>> for Value {
fn from(value: Vec<f64>) -> Self {
Self::VecFloat(value)
}
}
impl From<Vec<u8>> for Value {
fn from(value: Vec<u8>) -> Self {
Self::VecU8(value)
}
}
impl TryFrom<JsonValue> for Value {
type Error = RlineError;
fn try_from(value: JsonValue) -> Result<Self, Self::Error> {
match value {
JsonValue::String(v) => Ok(Self::String(v)),
JsonValue::Number(v) => match v.as_f64() {
Some(w) => Ok(Self::Float(w)),
None => Ok(Self::Integer(
v.as_i64()
.ok_or(BadTypeError("Not an integer".to_string()))?
as isize,
)),
},
JsonValue::Array(v) => v.try_into(),
JsonValue::Null => Ok(Self::String("".to_string())),
JsonValue::Bool(v) => Ok(Self::Integer(v as isize)),
JsonValue::Object(v) => Ok(Self::String(json!(v).to_string())),
}
}
}
impl TryInto<JsonValue> for Value {
type Error = RlineError;
fn try_into(self) -> Result<JsonValue, Self::Error> {
match self {
Value::String(v) => to_value(v).map_err(|e| RlineError::runtime_error(&e)),
Value::Integer(v) => to_value(v).map_err(|e| RlineError::runtime_error(&e)),
Value::Float(v) => to_value(v).map_err(|e| RlineError::runtime_error(&e)),
Value::VecString(v) => to_value(v).map_err(|e| RlineError::runtime_error(&e)),
Value::VecInteger(v) => to_value(v).map_err(|e| RlineError::runtime_error(&e)),
Value::VecFloat(v) => to_value(v).map_err(|e| RlineError::runtime_error(&e)),
Value::VecU8(v) => to_value(v).map_err(|e| RlineError::runtime_error(&e)),
}
}
}
impl TryFrom<Vec<JsonValue>> for Value {
type Error = RlineError;
fn try_from(value: Vec<JsonValue>) -> Result<Self, Self::Error> {
match value.first() {
Some(first) => match first {
JsonValue::String(_)
| JsonValue::Array(_)
| JsonValue::Object(_)
| JsonValue::Null => Ok(Self::VecString(
value.iter().map(|e| e.to_string()).collect(),
)),
JsonValue::Number(_) | JsonValue::Bool(_) => {
if value.iter().any(|e| e.is_f64()) {
let mut res = Vec::new();
for e in value.iter() {
match e {
JsonValue::Number(v) => {
res.push(v.as_f64().ok_or(BadTypeError("".to_string()))?)
}
JsonValue::Bool(v) => res.push(*v as i8 as f64),
_ => return Err(BadTypeError("".to_string())),
}
}
Ok(Self::VecFloat(res))
} else {
let mut res = Vec::new();
for e in value.iter() {
match e {
JsonValue::Number(v) => res
.push(v.as_i64().ok_or(BadTypeError("".to_string()))? as isize),
JsonValue::Bool(v) => res.push(*v as isize),
_ => return Err(BadTypeError("".to_string())),
}
}
Ok(Self::VecInteger(res))
}
}
},
None => Ok(Self::VecString(vec![])),
}
}
}