use indexmap::IndexMap;
use std::fmt;
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
Null,
Bool(bool),
Number(String),
String(String),
Array(Vec<Value>),
Object(IndexMap<String, Value>),
}
impl Value {
pub fn null() -> Self {
Value::Null
}
pub fn bool(v: bool) -> Self {
Value::Bool(v)
}
pub fn integer(v: i64) -> Self {
Value::Number(v.to_string())
}
pub fn float(v: f64) -> Self {
let s = if v.fract() == 0.0 {
format!("{:.0}", v)
} else {
format!("{}", v)
};
Value::Number(s)
}
pub fn string(v: impl Into<String>) -> Self {
Value::String(v.into())
}
pub fn array(v: Vec<Value>) -> Self {
Value::Array(v)
}
pub fn object(v: IndexMap<String, Value>) -> Self {
Value::Object(v)
}
pub fn is_null(&self) -> bool {
matches!(self, Value::Null)
}
pub fn is_bool(&self) -> bool {
matches!(self, Value::Bool(_))
}
pub fn is_number(&self) -> bool {
matches!(self, Value::Number(_))
}
pub fn is_string(&self) -> bool {
matches!(self, Value::String(_))
}
pub fn is_array(&self) -> bool {
matches!(self, Value::Array(_))
}
pub fn is_object(&self) -> bool {
matches!(self, Value::Object(_))
}
pub fn as_bool(&self) -> Option<bool> {
match self {
Value::Bool(v) => Some(*v),
_ => None,
}
}
pub fn as_i64(&self) -> Option<i64> {
match self {
Value::Number(s) => s.parse().ok(),
_ => None,
}
}
pub fn as_f64(&self) -> Option<f64> {
match self {
Value::Number(s) => s.parse().ok(),
_ => None,
}
}
pub fn as_str(&self) -> Option<&str> {
match self {
Value::String(s) => Some(s),
_ => None,
}
}
pub fn as_array(&self) -> Option<&Vec<Value>> {
match self {
Value::Array(a) => Some(a),
_ => None,
}
}
pub fn as_object(&self) -> Option<&IndexMap<String, Value>> {
match self {
Value::Object(o) => Some(o),
_ => None,
}
}
pub fn get(&self, key: &str) -> Option<&Value> {
match self {
Value::Object(o) => o.get(key),
_ => None,
}
}
pub fn get_index(&self, index: usize) -> Option<&Value> {
match self {
Value::Array(a) => a.get(index),
_ => None,
}
}
pub fn len(&self) -> usize {
match self {
Value::Array(a) => a.len(),
Value::Object(o) => o.len(),
_ => 0,
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl Default for Value {
fn default() -> Self {
Value::Null
}
}
impl From<()> for Value {
fn from(_: ()) -> Self {
Value::Null
}
}
impl From<bool> for Value {
fn from(v: bool) -> Self {
Value::Bool(v)
}
}
impl From<i8> for Value {
fn from(v: i8) -> Self {
Value::integer(v as i64)
}
}
impl From<i16> for Value {
fn from(v: i16) -> Self {
Value::integer(v as i64)
}
}
impl From<i32> for Value {
fn from(v: i32) -> Self {
Value::integer(v as i64)
}
}
impl From<i64> for Value {
fn from(v: i64) -> Self {
Value::integer(v)
}
}
impl From<u8> for Value {
fn from(v: u8) -> Self {
Value::integer(v as i64)
}
}
impl From<u16> for Value {
fn from(v: u16) -> Self {
Value::integer(v as i64)
}
}
impl From<u32> for Value {
fn from(v: u32) -> Self {
Value::integer(v as i64)
}
}
impl From<u64> for Value {
fn from(v: u64) -> Self {
Value::Number(v.to_string())
}
}
impl From<f32> for Value {
fn from(v: f32) -> Self {
Value::float(v as f64)
}
}
impl From<f64> for Value {
fn from(v: f64) -> Self {
Value::float(v)
}
}
impl From<String> for Value {
fn from(v: String) -> Self {
Value::String(v)
}
}
impl From<&str> for Value {
fn from(v: &str) -> Self {
Value::String(v.to_string())
}
}
impl<T: Into<Value>> From<Vec<T>> for Value {
fn from(v: Vec<T>) -> Self {
Value::Array(v.into_iter().map(Into::into).collect())
}
}
impl<K: Into<String>, V: Into<Value>> From<IndexMap<K, V>> for Value {
fn from(v: IndexMap<K, V>) -> Self {
Value::Object(
v.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect(),
)
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::Null => write!(f, "null"),
Value::Bool(true) => write!(f, "true"),
Value::Bool(false) => write!(f, "false"),
Value::Number(n) => write!(f, "{}", n),
Value::String(s) => write!(f, "\"{}\"", s),
Value::Array(arr) => {
write!(f, "[")?;
for (i, v) in arr.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", v)?;
}
write!(f, "]")
}
Value::Object(obj) => {
write!(f, "{{")?;
for (i, (k, v)) in obj.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "\"{}\": {}", k, v)?;
}
write!(f, "}}")
}
}
}
}