use std::{borrow::Cow, collections::HashMap, fmt, fmt::Formatter, str};
use crate::{number::Number, parser, path::Path, Result};
#[derive(PartialEq, Eq, Clone)]
pub enum Value<'a> {
String(Cow<'a, str>),
Number(Number<'a>),
Usize(usize),
Object(Cow<'a, str>),
Array(Cow<'a, str>),
Boolean(bool),
Null,
}
impl<'a> fmt::Debug for Value<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::String(s) => write!(f, r#""{}""#, s),
Value::Number(n) => write!(f, "{}", n.as_str()),
Value::Usize(n) => write!(f, "{}", n),
Value::Object(s) | Value::Array(s) => write!(f, "{}", s),
Value::Boolean(b) => write!(f, "{}", b),
Value::Null => write!(f, "null"),
}
}
}
impl<'a> Value<'a> {
pub fn get(&self, path: &'a str) -> Result<Option<Value>> {
match self {
Value::Array(s) | Value::Object(s) => {
let p = Path::from_slice(path.as_ref())?;
let (a, _left) = parser::bytes_get(s.as_bytes(), &p)?;
Ok(a.map(|el| el.to_value()))
}
_ => Ok(None),
}
}
}
impl<'a> Value<'a> {
pub fn is_string(&self) -> bool {
matches!(self, Value::String(_))
}
pub fn is_number(&self) -> bool {
matches!(self, Value::Number(_))
}
pub fn is_array(&self) -> bool {
matches!(self, Value::Array(_))
}
pub fn is_object(&self) -> bool {
matches!(self, Value::Object(_))
}
pub fn is_bool(&self) -> bool {
matches!(self, Value::Boolean(_))
}
pub fn is_null(&self) -> bool {
matches!(self, Value::Null)
}
}
impl<'a> std::fmt::Display for Value<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Value::String(ref s) => write!(f, "{}", s),
Value::Number(number) => write!(f, "{}", number.as_str()),
Value::Boolean(true) => write!(f, "true"),
Value::Boolean(false) => write!(f, "false"),
Value::Object(ref s) => write!(f, "{}", s),
Value::Array(ref s) => write!(f, "{}", s),
Value::Usize(u) => write!(f, "{}", u),
Value::Null => write!(f, "null"),
}
}
}
impl<'a> Value<'a> {
pub fn as_str(&self) -> Option<&str> {
match self {
Value::String(s) => Some(s),
_ => None,
}
}
pub fn as_f64(&self) -> Option<f64> {
match self {
Value::Number(number) => Some(number.to_f64()),
Value::Usize(n) => Some(*n as f64),
_ => None,
}
}
pub fn as_u64(&self) -> Option<u64> {
match self {
Value::Number(number) => Some(number.to_u64()),
Value::Usize(n) => Some(*n as u64),
_ => None,
}
}
pub fn as_i64(&self) -> Option<i64> {
match self {
Value::Number(number) => Some(number.to_i64()),
Value::Usize(n) => Some(*n as i64),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match *self {
Value::Boolean(b) => Some(b),
_ => None,
}
}
pub fn as_vec(&self) -> Option<Vec<Value>> {
match self {
Value::Array(s) => parser::bytes_to_vec(s.as_bytes()).ok(),
_ => None,
}
}
pub fn as_object(&self) -> Option<HashMap<&str, Value>> {
match self {
Value::Object(s) => parser::bytes_to_map(s.as_bytes()).ok(),
_ => None,
}
}
}
fn eq_f64(value: &Value, other: f64) -> bool {
value.as_f64().map_or(false, |i| i == other)
}
fn eq_i64(value: &Value, other: i64) -> bool {
value.as_i64().map_or(false, |i| i == other)
}
fn eq_u64(value: &Value, other: u64) -> bool {
value.as_u64().map_or(false, |i| i == other)
}
fn eq_bool(value: &Value, other: bool) -> bool {
value.as_bool().map_or(false, |i| i == other)
}
fn eq_str(value: &Value, other: &str) -> bool {
value.as_str().map_or(false, |i| i == other)
}
impl<'a> PartialEq<str> for Value<'a> {
fn eq(&self, other: &str) -> bool {
eq_str(self, other)
}
}
impl<'a> PartialEq<&'a str> for Value<'a> {
fn eq(&self, other: &&str) -> bool {
eq_str(self, *other)
}
}
impl<'a> PartialEq<Value<'a>> for str {
fn eq(&self, other: &Value) -> bool {
eq_str(other, self)
}
}
impl<'a> PartialEq<Value<'a>> for &'a str {
fn eq(&self, other: &Value) -> bool {
eq_str(other, *self)
}
}
impl<'a> PartialEq<String> for Value<'a> {
fn eq(&self, other: &String) -> bool {
eq_str(self, other.as_str())
}
}
impl<'a> PartialEq<Value<'a>> for String {
fn eq(&self, other: &Value) -> bool {
eq_str(other, self.as_str())
}
}
macro_rules! partialeq_numeric {
($($eq:ident [$($ty:ty)*])*) => {
$($(
impl<'a> PartialEq<$ty> for Value<'a> {
fn eq(&self, other: &$ty) -> bool {
$eq(self, *other as _)
}
}
impl<'a> PartialEq<Value<'a>> for $ty {
fn eq(&self, other: &Value) -> bool {
$eq(other, *self as _)
}
}
impl<'a> PartialEq<$ty> for &'a Value<'a> {
fn eq(&self, other: &$ty) -> bool {
$eq(*self, *other as _)
}
}
impl<'a> PartialEq<$ty> for &'a mut Value<'a> {
fn eq(&self, other: &$ty) -> bool {
$eq(*self, *other as _)
}
}
)*)*
}
}
partialeq_numeric! {
eq_i64[i8 i16 i32 i64 isize]
eq_u64[u8 u16 u32 u64 usize]
eq_f64[f32 f64]
eq_bool[bool]
}