use core::fmt;
#[cfg(not(feature = "std"))]
use alloc::{
collections::BTreeMap as HashMap,
string::{String, ToString},
vec::Vec,
};
use indexmap::IndexMap;
#[derive(Debug, Clone, PartialEq)]
pub enum RsonValue {
Null,
Bool(bool),
Int(i64),
Float(f64),
String(String),
Char(char),
Array(Vec<RsonValue>),
Map(IndexMap<String, RsonValue>),
Struct {
name: String,
fields: IndexMap<String, RsonValue>,
},
Tuple(Vec<RsonValue>),
Enum {
name: String,
variant: String,
value: Option<Box<RsonValue>>,
},
Option(Option<Box<RsonValue>>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RsonType {
Null,
Bool,
Int,
Float,
String,
Char,
Array,
Map,
Struct,
Tuple,
Enum,
Option,
}
impl RsonValue {
pub fn value_type(&self) -> RsonType {
match self {
RsonValue::Null => RsonType::Null,
RsonValue::Bool(_) => RsonType::Bool,
RsonValue::Int(_) => RsonType::Int,
RsonValue::Float(_) => RsonType::Float,
RsonValue::String(_) => RsonType::String,
RsonValue::Char(_) => RsonType::Char,
RsonValue::Array(_) => RsonType::Array,
RsonValue::Map(_) => RsonType::Map,
RsonValue::Struct { .. } => RsonType::Struct,
RsonValue::Tuple(_) => RsonType::Tuple,
RsonValue::Enum { .. } => RsonType::Enum,
RsonValue::Option(_) => RsonType::Option,
}
}
pub fn is_null(&self) -> bool {
matches!(self, RsonValue::Null)
}
pub fn is_bool(&self) -> bool {
matches!(self, RsonValue::Bool(_))
}
pub fn is_number(&self) -> bool {
matches!(self, RsonValue::Int(_) | RsonValue::Float(_))
}
pub fn is_string(&self) -> bool {
matches!(self, RsonValue::String(_))
}
pub fn is_array(&self) -> bool {
matches!(self, RsonValue::Array(_))
}
pub fn is_object(&self) -> bool {
matches!(self, RsonValue::Map(_) | RsonValue::Struct { .. })
}
pub fn as_bool(&self) -> Option<bool> {
match self {
RsonValue::Bool(b) => Some(*b),
_ => None,
}
}
pub fn as_i64(&self) -> Option<i64> {
match self {
RsonValue::Int(i) => Some(*i),
RsonValue::Float(f) if f.fract() == 0.0 => Some(*f as i64),
_ => None,
}
}
pub fn as_f64(&self) -> Option<f64> {
match self {
RsonValue::Float(f) => Some(*f),
RsonValue::Int(i) => Some(*i as f64),
_ => None,
}
}
pub fn as_str(&self) -> Option<&str> {
match self {
RsonValue::String(s) => Some(s),
_ => None,
}
}
pub fn as_array(&self) -> Option<&Vec<RsonValue>> {
match self {
RsonValue::Array(arr) => Some(arr),
_ => None,
}
}
pub fn as_map(&self) -> Option<&IndexMap<String, RsonValue>> {
match self {
RsonValue::Map(map) => Some(map),
_ => None,
}
}
pub fn get_index(&self, index: usize) -> Option<&RsonValue> {
match self {
RsonValue::Array(arr) => arr.get(index),
RsonValue::Tuple(arr) => arr.get(index),
_ => None,
}
}
pub fn get(&self, key: &str) -> Option<&RsonValue> {
match self {
RsonValue::Map(map) => map.get(key),
RsonValue::Struct { fields, .. } => fields.get(key),
_ => None,
}
}
pub fn some(value: RsonValue) -> Self {
RsonValue::Option(Some(Box::new(value)))
}
pub fn none() -> Self {
RsonValue::Option(None)
}
}
impl fmt::Display for RsonValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RsonValue::Null => write!(f, "null"),
RsonValue::Bool(b) => write!(f, "{}", b),
RsonValue::Int(i) => write!(f, "{}", i),
RsonValue::Float(fl) => write!(f, "{}", fl),
RsonValue::String(s) => write!(f, "\"{}\"", s),
RsonValue::Char(c) => write!(f, "'{}'", c),
RsonValue::Array(arr) => {
write!(f, "[")?;
for (i, item) in arr.iter().enumerate() {
if i > 0 { write!(f, ", ")?; }
write!(f, "{}", item)?;
}
write!(f, "]")
}
RsonValue::Map(map) => {
write!(f, "{{")?;
for (i, (key, value)) in map.iter().enumerate() {
if i > 0 { write!(f, ", ")?; }
write!(f, "{}: {}", key, value)?;
}
write!(f, "}}")
}
RsonValue::Struct { name, fields } => {
write!(f, "{}(", name)?;
for (i, (key, value)) in fields.iter().enumerate() {
if i > 0 { write!(f, ", ")?; }
write!(f, "{}: {}", key, value)?;
}
write!(f, ")")
}
RsonValue::Tuple(values) => {
write!(f, "(")?;
for (i, value) in values.iter().enumerate() {
if i > 0 { write!(f, ", ")?; }
write!(f, "{}", value)?;
}
write!(f, ")")
}
RsonValue::Enum { name, variant, value } => {
write!(f, "{}::{}", name, variant)?;
if let Some(val) = value {
write!(f, "({})", val)?;
}
Ok(())
}
RsonValue::Option(Some(value)) => write!(f, "Some({})", value),
RsonValue::Option(None) => write!(f, "None"),
}
}
}
impl fmt::Display for RsonType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RsonType::Null => write!(f, "null"),
RsonType::Bool => write!(f, "bool"),
RsonType::Int => write!(f, "int"),
RsonType::Float => write!(f, "float"),
RsonType::String => write!(f, "string"),
RsonType::Char => write!(f, "char"),
RsonType::Array => write!(f, "array"),
RsonType::Map => write!(f, "map"),
RsonType::Struct => write!(f, "struct"),
RsonType::Tuple => write!(f, "tuple"),
RsonType::Enum => write!(f, "enum"),
RsonType::Option => write!(f, "option"),
}
}
}
impl From<bool> for RsonValue {
fn from(b: bool) -> Self {
RsonValue::Bool(b)
}
}
impl From<i32> for RsonValue {
fn from(i: i32) -> Self {
RsonValue::Int(i as i64)
}
}
impl From<i64> for RsonValue {
fn from(i: i64) -> Self {
RsonValue::Int(i)
}
}
impl From<f64> for RsonValue {
fn from(f: f64) -> Self {
RsonValue::Float(f)
}
}
impl From<String> for RsonValue {
fn from(s: String) -> Self {
RsonValue::String(s)
}
}
impl From<&str> for RsonValue {
fn from(s: &str) -> Self {
RsonValue::String(s.to_string())
}
}
impl From<char> for RsonValue {
fn from(c: char) -> Self {
RsonValue::Char(c)
}
}
impl<T: Into<RsonValue>> From<Vec<T>> for RsonValue {
fn from(vec: Vec<T>) -> Self {
RsonValue::Array(vec.into_iter().map(Into::into).collect())
}
}
impl<T: Into<RsonValue>> From<Option<T>> for RsonValue {
fn from(opt: Option<T>) -> Self {
RsonValue::Option(opt.map(|v| Box::new(v.into())))
}
}