use std::{fmt::Debug, collections::HashMap};
use serde::{Serialize, Deserialize};
use crate::{Number, ResolvesFields, ConvertFrom};
#[derive(Debug, Serialize, Deserialize)]
#[serde(bound = "", untagged)]
pub enum Value {
Bool(bool),
Number(Number),
String(String),
Vec(Vec<Value>),
Object(HashMap<Box<str>, Value>),
Option(Option<Box<Value>>),
#[serde(skip)]
ResolveFields(Box<dyn ResolvesFields>),
Void,
}
impl<IV: Into<Value>> ConvertFrom<IV> for Result<Value, anyhow::Error> {
fn from(value: IV) -> Self {
Ok(value.into())
}
}
impl<IV: Into<Value>> ConvertFrom<Result<IV, anyhow::Error>> for Result<Value, anyhow::Error> {
fn from(value: Result<IV, anyhow::Error>) -> Self {
value.map(Into::into)
}
}
impl<IV: Into<Value>> From<Option<IV>> for Value {
fn from(opt: Option<IV>) -> Self {
match opt {
Some(value) => Value::Option(Some(Box::new(value.into()))),
None => Value::Option(None),
}
}
}
impl From<Number> for Value {
fn from(number: Number) -> Self {
Value::Number(number)
}
}
impl From<bool> for Value {
fn from(value: bool) -> Self {
Value::Bool(value)
}
}
impl From<String> for Value {
fn from(value: String) -> Self {
Value::String(value)
}
}
impl From<&str> for Value {
fn from(value: &str) -> Self {
Value::String(value.to_string())
}
}
impl From<()> for Value {
fn from(_: ()) -> Self {
Value::Void
}
}
impl<VT> From<Vec<VT>> for Value where VT: Into<Value> {
fn from(value: Vec<VT>) -> Self {
Value::Vec(value.into_iter().map(Into::into).collect())
}
}
impl<IntoV: Into<Value>, AsStr: AsRef<str>> From<HashMap<AsStr, IntoV>> for Value {
fn from(value: HashMap<AsStr, IntoV>) -> Self {
Value::Object(value.into_iter().map(|(k, v)| (k.as_ref().into(), v.into())).collect())
}
}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
(Self::Number(l0), Self::Number(r0)) => l0 == r0,
(Self::String(l0), Self::String(r0)) => l0 == r0,
(Self::Vec(l0), Self::Vec(r0)) => l0 == r0,
(Self::Object(l0), Self::Object(r0)) => l0 == r0,
(Self::Void, Self::Void) => true,
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
}
}
}
macro_rules! impl_from_primitive {
($($t:ty,)*) => {
$(
impl From<$t> for Value {
fn from(value: $t) -> Self {
Value::Number(value.into())
}
}
)*
};
}
impl_from_primitive!(
usize,
u8,
u16,
u32,
u64,
isize,
i8,
i16,
i32,
i64,
f32,
f64,
);