use std::io;
use std::fmt::Debug;
use std::ops::Index;
use std::collections::HashMap;
use std::str::FromStr;
use crate::parser::{Parser, ParseError};
pub type ArrayType = Vec<Value>;
pub type ArrayIter<'a> = std::slice::Iter<'a, Value>;
pub type ObjectType = HashMap<String, Value>;
pub type ObjectIter<'a> = std::collections::hash_map::Iter<'a, String, Value>;
#[derive(Debug)]
pub enum Value {
Null,
Bool(bool),
Number(f64),
String(String),
Array(ArrayType),
Object(ObjectType),
}
impl Value {
pub fn is_null(&self) -> bool {
match self {
Value::Null => true,
_ => false,
}
}
pub fn is_bool(&self) -> bool {
match self {
Value::Bool(_) => true,
_ => false,
}
}
pub fn as_bool(&self) -> bool {
match self {
Value::Null => false,
Value::Bool(v) => *v,
Value::Number(v) => *v as i64 != 0,
Value::String(v) => {
let s = v.to_ascii_lowercase();
s == "true" || s == "yes"
}
Value::Array(v) => !v.is_empty(),
Value::Object(v) => !v.is_empty(),
}
}
pub fn is_number(&self) -> bool {
match self {
Value::Number(_) => true,
_ => false,
}
}
pub fn as_i64(&self) -> i64 {
match self {
Value::Null => 0,
Value::Bool(v) => if *v { 1 } else { 0 },
Value::Number(v) => *v as i64,
Value::String(v) => {
if let Ok(i) = i64::from_str(v) {
i
} else {
0
}
}
Value::Array(_) => 0,
Value::Object(_) => 0,
}
}
pub fn as_f64(&self) -> f64 {
match self {
Value::Null => 0.0,
Value::Bool(v) => if *v { 1.0 } else { 0.0 },
Value::Number(v) => *v,
Value::String(v) => {
if let Ok(f) = f64::from_str(v) {
f
} else {
0.0
}
}
Value::Array(_) => 0.0,
Value::Object(_) => 0.0,
}
}
pub fn is_string(&self) -> bool {
match self {
Value::String(_) => true,
_ => false,
}
}
pub fn as_str(&self) -> &str {
match self {
Value::Null => "null",
Value::Bool(v) => if *v { "true" } else { "false" },
Value::Number(_) => "",
Value::String(v) => v,
Value::Array(_) => "",
Value::Object(_) => "",
}
}
pub fn len(&self) -> usize {
match self {
Value::Null => 0,
Value::Bool(_) => 1,
Value::Number(_) => 1,
Value::String(v) => v.len(),
Value::Array(v) => v.len(),
Value::Object(v) => v.len(),
}
}
pub fn is_array(&self) -> bool {
match self {
Value::Array(_) => true,
_ => false,
}
}
pub fn is_object(&self) -> bool {
match self {
Value::Object(_) => true,
_ => false,
}
}
pub fn has(&self, key: &str) -> bool {
match self {
Value::Object(v) => v.get(key).is_some(),
_ => false,
}
}
pub fn iter_array(&self) -> ArrayIter {
match self {
Value::Array(v) => v.iter(),
_ => panic!("call iter_array on non-array type"),
}
}
pub fn iter_object(&self) -> ObjectIter {
match self {
Value::Object(v) => v.iter(),
_ => panic!("call iter_object() on non-object type"),
}
}
}
impl Index<usize> for Value {
type Output = Value;
fn index(&self, idx: usize) -> &Self::Output {
match self {
Value::Array(v) => {
&v[idx]
}
_ => panic!("can not index[usize] non-array json value"),
}
}
}
impl Index<&str> for Value {
type Output = Value;
fn index(&self, idx: &str) -> &Self::Output {
match self {
Value::Object(v) => {
&v[idx]
}
_ => panic!("can not index[str] non-object json value"),
}
}
}
impl FromStr for Value {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Parser::new(s.as_bytes()).parse()
}
}
impl<T: io::Read + Debug> From<T> for Value {
fn from(src: T) -> Self {
Parser::new(src).parse().unwrap()
}
}