#![doc = include_str!("../README.md")]
#![warn(missing_docs, missing_debug_implementations)]
mod string;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::{
borrow::Cow,
collections::HashMap,
fmt::{Debug, Display},
};
pub use string::*;
#[derive(Debug, Clone)]
pub struct Map {
inner: Box<HashMap<String, Value>>,
}
impl Map {
pub fn new() -> Self {
Self {
inner: Box::new(HashMap::new()),
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
inner: Box::new(HashMap::with_capacity(capacity)),
}
}
#[cfg(all(feature = "json"))]
pub fn from_json(s: &str) -> Result<Self, serde_json::Error> {
serde_json::from_str(s)
}
#[cfg(all(feature = "json"))]
pub fn to_json(&self) -> Result<String, serde_json::Error> {
serde_json::to_string(&self)
}
#[cfg(all(feature = "json"))]
pub fn to_json_writer<W: std::io::Write>(&self, writer: W) -> Result<(), serde_json::Error> {
serde_json::to_writer(writer, &self)
}
}
impl std::ops::Index<&str> for Map {
type Output = Value;
fn index(&self, index: &str) -> &Self::Output {
&self.inner[index]
}
}
impl std::ops::IndexMut<&str> for Map {
fn index_mut(&mut self, index: &str) -> &mut Self::Output {
self.inner
.entry(index.to_string())
.or_insert(Value::from(""))
}
}
impl std::ops::Deref for Map {
type Target = HashMap<String, Value>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl std::ops::DerefMut for Map {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl Default for Map {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct Array {
inner: Box<Vec<Value>>,
}
impl Array {
pub fn new() -> Self {
Self {
inner: Box::new(Vec::new()),
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
inner: Box::new(Vec::with_capacity(capacity)),
}
}
#[cfg(all(feature = "json"))]
pub fn from_json(s: &str) -> Result<Self, serde_json::Error> {
serde_json::from_str(s)
}
#[cfg(all(feature = "json"))]
pub fn to_json(&self) -> Result<String, serde_json::Error> {
serde_json::to_string(&self)
}
#[cfg(all(feature = "json"))]
pub fn to_json_writer<W: std::io::Write>(&self, writer: W) -> Result<(), serde_json::Error> {
serde_json::to_writer(writer, &self)
}
}
impl std::ops::Deref for Array {
type Target = Vec<Value>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl std::ops::DerefMut for Array {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl Default for Array {
fn default() -> Self {
Self::new()
}
}
pub enum Value {
Float(f64),
Int(i64),
Bool(bool),
String(Str),
Map(Map),
Array(Array),
None,
}
#[derive(Debug)]
pub enum ValueRef<'a> {
Float(&'a f64),
Int(&'a i64),
Bool(&'a bool),
String(&'a Str),
Map(&'a Map),
Array(&'a Array),
None,
}
#[derive(Debug)]
pub enum ValueRefMut<'a> {
Float(&'a mut f64),
Int(&'a mut i64),
Bool(&'a mut bool),
String(&'a mut Str),
Map(&'a mut Map),
Array(&'a mut Array),
None,
}
impl Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::String(s) => write!(f, "{}", s),
Value::Float(fl) => write!(f, "{}", fl),
Value::Int(i) => write!(f, "{}", i),
Value::Bool(b) => write!(f, "{}", b),
Value::Map(_) => write!(f, "[object Map]"),
Value::Array(_) => write!(f, "[object Array]"),
Value::None => write!(f, "null"),
}
}
}
impl Debug for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::String(s) => write!(f, "{:?}", s),
Value::Float(fl) => write!(f, "Value::Float({:?})", fl),
Value::Int(i) => write!(f, "Value::Int({:?})", i),
Value::Bool(b) => write!(f, "Value::Bool({:?})", b),
Value::Map(m) => write!(f, "Value::Map({:?})", m),
Value::Array(a) => write!(f, "Value::Array({:?})", a),
Value::None => write!(f, "Value::None"),
}
}
}
impl Clone for Value {
fn clone(&self) -> Self {
match self {
Value::String(s) => Value::String(s.clone()),
Value::Float(fl) => Value::Float(*fl),
Value::Int(i) => Value::Int(*i),
Value::Bool(b) => Value::Bool(*b),
Value::Map(m) => Value::Map(m.clone()),
Value::Array(a) => Value::Array(a.clone()),
Value::None => Value::None,
}
}
}
impl Value {
pub fn from<T: Into<Value>>(value: T) -> Self {
value.into()
}
pub fn as_str(&self) -> Cow<'_, str> {
match self {
Value::String(s) => Cow::Borrowed(s.as_str()),
_ => Cow::Owned(self.to_string()),
}
}
pub fn as_float(&self) -> f64 {
match self {
Value::Float(f) => *f,
Value::Int(i) => *i as f64,
Value::String(str) => str.as_str().parse::<f64>().unwrap_or(0.0),
Value::Bool(b) => {
if *b {
1.0
} else {
0.0
}
}
_ => 0.0,
}
}
pub fn as_int(&self) -> i64 {
match self {
Value::Int(i) => *i,
Value::Float(f) => *f as i64,
Value::String(str) => str.as_str().parse::<i64>().unwrap_or(0),
Value::Bool(b) => {
if *b {
1
} else {
0
}
}
_ => 0,
}
}
pub fn as_bool(&self) -> bool {
match self {
Value::Bool(b) => *b,
Value::Int(i) => *i != 0,
Value::Float(f) => *f != 0.0,
Value::String(s) => !s.as_str().is_empty(),
Value::Map(m) => !m.is_empty(),
Value::Array(a) => !a.is_empty(),
Value::None => false,
}
}
pub fn as_map(&self) -> Option<&Map> {
match self {
Value::Map(m) => Some(m),
_ => None,
}
}
pub fn as_array(&self) -> Option<&Array> {
match self {
Value::Array(a) => Some(a),
_ => None,
}
}
pub fn is_float(&self) -> bool {
matches!(self, Value::Float(_))
}
pub fn is_int(&self) -> bool {
matches!(self, Value::Int(_))
}
pub fn is_bool(&self) -> bool {
matches!(self, Value::Bool(_))
}
pub fn is_string(&self) -> bool {
matches!(self, Value::String(_))
}
pub fn is_map(&self) -> bool {
matches!(self, Value::Map(_))
}
pub fn is_array(&self) -> bool {
matches!(self, Value::Array(_))
}
pub fn new_map() -> Self {
Value::Map(Map::new())
}
pub fn new_array() -> Self {
Value::Array(Array::new())
}
pub fn get(&self, key: &str) -> Option<&Value> {
self.as_map()?.get(key)
}
pub fn get_index(&self, index: usize) -> Option<&Value> {
self.as_array()?.get(index)
}
#[cfg(all(feature = "json"))]
pub fn from_json(s: &str) -> Result<Self, serde_json::Error> {
serde_json::from_str(s)
}
#[cfg(all(feature = "json"))]
pub fn to_json(&self) -> Result<String, serde_json::Error> {
serde_json::to_string(&self)
}
#[cfg(all(feature = "json"))]
pub fn to_json_writer<W: std::io::Write>(&self, writer: W) -> Result<(), serde_json::Error> {
serde_json::to_writer(writer, &self)
}
}
#[cfg(feature = "serde")]
impl Serialize for Value {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
Value::Float(f) => serializer.serialize_f64(*f),
Value::Int(i) => serializer.serialize_i64(*i),
Value::Bool(b) => serializer.serialize_bool(*b),
Value::String(s) => serializer.serialize_str(s.as_str()),
Value::Map(m) => m.inner.serialize(serializer),
Value::Array(a) => a.inner.serialize(serializer),
Value::None => serializer.serialize_none(),
}
}
}
impl std::ops::Index<&str> for Value {
type Output = Value;
fn index(&self, index: &str) -> &Self::Output {
match self {
Value::Map(m) => &m[index],
_ => &Value::None,
}
}
}
impl std::ops::IndexMut<&str> for Value {
fn index_mut(&mut self, index: &str) -> &mut Self::Output {
match self {
Value::Map(m) => &mut m[index],
_ => {
*self = Value::None;
self
}
}
}
}
impl std::ops::Index<usize> for Value {
type Output = Value;
fn index(&self, index: usize) -> &Self::Output {
match self {
Value::Array(a) => &a[index],
_ => &Value::None,
}
}
}
impl std::ops::IndexMut<usize> for Value {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match self {
Value::Array(a) => &mut a[index],
_ => {
*self = Value::None;
self
}
}
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Value {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct ValueVisitor;
impl<'de> serde::de::Visitor<'de> for ValueVisitor {
type Value = Value;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid Value")
}
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Float(v))
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Int(v))
}
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Bool(v))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::String(Str::from_owned(v.to_string())))
}
fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_i64(v as i64)
}
fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_i64(v as i64)
}
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_i64(v as i64)
}
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let mut writer = String::new();
std::fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as i128", v))
.unwrap();
Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Other(writer.as_str()),
&self,
))
}
fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_i64(v as i64)
}
fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_i64(v as i64)
}
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_i64(v as i64)
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
if v <= i64::MAX as u64 {
Ok(Value::Int(v as i64))
} else {
Ok(Value::Float(v as f64))
}
}
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
if v <= i64::MAX as u128 {
Ok(Value::Int(v as i64))
} else {
Ok(Value::Float(v as f64))
}
}
fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_f64(v as f64)
}
fn visit_char<E>(self, v: char) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_str(v.encode_utf8(&mut [0u8; 4]))
}
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_str(v)
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_str(&v)
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Bytes(v),
&self,
))
}
fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_bytes(v)
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_bytes(&v)
}
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::None)
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
let _ = deserializer;
Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Option,
&self,
))
}
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let inner = Map::deserialize(serde::de::value::MapAccessDeserializer::new(map))?;
Ok(Value::Map(inner))
}
fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let inner = Array::deserialize(serde::de::value::SeqAccessDeserializer::new(seq))?;
Ok(Value::Array(inner))
}
}
deserializer.deserialize_any(ValueVisitor)
}
}
#[cfg(feature = "serde")]
impl Serialize for Map {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.inner.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Map {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let inner = Box::new(HashMap::deserialize(deserializer)?);
Ok(Map { inner })
}
}
#[cfg(feature = "serde")]
impl Serialize for Array {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.inner.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Array {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let inner = Box::new(Vec::<Value>::deserialize(deserializer)?);
Ok(Array { inner })
}
}
impl From<f64> for Value {
fn from(f: f64) -> Self {
Value::Float(f)
}
}
impl From<i64> for Value {
fn from(i: i64) -> Self {
Value::Int(i)
}
}
impl From<bool> for Value {
fn from(b: bool) -> Self {
Value::Bool(b)
}
}
impl From<Map> for Value {
fn from(m: Map) -> Self {
Value::Map(m)
}
}
impl From<Array> for Value {
fn from(a: Array) -> Self {
Value::Array(a)
}
}
impl From<i32> for Value {
fn from(i: i32) -> Self {
Value::Int(i as i64)
}
}
impl From<i128> for Value {
fn from(i: i128) -> Self {
if i <= i64::MAX as i128 && i >= i64::MIN as i128 {
Value::Int(i as i64)
} else {
Value::Float(i as f64)
}
}
}
impl From<u64> for Value {
fn from(u: u64) -> Self {
if u <= i64::MAX as u64 {
Value::Int(u as i64)
} else {
Value::Float(u as f64)
}
}
}
impl From<u128> for Value {
fn from(u: u128) -> Self {
if u <= i64::MAX as u128 {
Value::Int(u as i64)
} else {
Value::Float(u as f64)
}
}
}
impl From<f32> for Value {
fn from(f: f32) -> Self {
Value::Float(f as f64)
}
}
impl Into<f64> for Value {
fn into(self) -> f64 {
self.as_float()
}
}
impl Into<i8> for Value {
fn into(self) -> i8 {
self.as_int() as i8
}
}
impl Into<i16> for Value {
fn into(self) -> i16 {
self.as_int() as i16
}
}
impl Into<i32> for Value {
fn into(self) -> i32 {
self.as_int() as i32
}
}
impl Into<i64> for Value {
fn into(self) -> i64 {
self.as_int()
}
}
impl Into<i128> for Value {
fn into(self) -> i128 {
self.as_int() as i128
}
}
impl Into<isize> for Value {
fn into(self) -> isize {
self.as_int() as isize
}
}
impl Into<usize> for Value {
fn into(self) -> usize {
self.as_int() as usize
}
}
impl Into<bool> for Value {
fn into(self) -> bool {
self.as_bool()
}
}
impl From<&String> for Value {
fn from(s: &String) -> Self {
Value::String(Str::from_owned(s.clone()))
}
}
impl TryFrom<Value> for String {
type Error = &'static str;
fn try_from(value: Value) -> Result<Self, Self::Error> {
match value {
Value::String(s) => Ok(s.to_string()),
_ => Err("Value is not a string"),
}
}
}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Value::Float(a), Value::Float(b)) => a == b,
(Value::Int(a), Value::Int(b)) => a == b,
(Value::Bool(a), Value::Bool(b)) => a == b,
(Value::String(a), Value::String(b)) => a.as_str() == b.as_str(),
(Value::None, Value::None) => true,
(Value::Float(f), Value::Int(i)) | (Value::Int(i), Value::Float(f)) => *f == *i as f64,
_ => false,
}
}
}
impl IntoIterator for Array {
type Item = Value;
type IntoIter = std::vec::IntoIter<Value>;
fn into_iter(self) -> Self::IntoIter {
self.inner.into_iter()
}
}
impl<'a> IntoIterator for &'a Array {
type Item = &'a Value;
type IntoIter = std::slice::Iter<'a, Value>;
fn into_iter(self) -> Self::IntoIter {
self.inner.iter()
}
}
impl Value {
pub fn as_map_mut(&mut self) -> Option<&mut Map> {
match self {
Value::Map(m) => Some(m),
_ => None,
}
}
pub fn as_array_mut(&mut self) -> Option<&mut Array> {
match self {
Value::Array(a) => Some(a),
_ => None,
}
}
pub fn is_none(&self) -> bool {
matches!(self, Value::None)
}
pub fn take(&mut self) -> Value {
std::mem::replace(self, Value::None)
}
}
impl FromIterator<Value> for Array {
fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
Array {
inner: Box::new(iter.into_iter().collect()),
}
}
}
impl FromIterator<(String, Value)> for Map {
fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
Map {
inner: Box::new(iter.into_iter().collect()),
}
}
}
#[macro_export]
macro_rules! map {
() => {
$crate::Map::new()
};
($($key:expr => $val:expr),* $(,)?) => {{
let mut m = $crate::Map::with_capacity(count_tts::count_tts!($($key)*));
$(
m[$key] = $val.into();
)*
m
}};
}
#[macro_export]
macro_rules! array {
() => {
$crate::Array::new()
};
($($val:expr),* $(,)?) => {{
let mut a = $crate::Array::with_capacity(count_tts::count_tts!($($val)*));
$(
a.push($val.into());
)*
a
}};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_map_macro_empty() {
let m = map! {};
assert_eq!(m.len(), 0);
}
#[test]
fn test_map_macro_single_entry() {
let m = map! {
"key" => "value"
};
assert_eq!(m.len(), 1);
assert_eq!(m["key"].as_str(), "value");
}
#[test]
fn test_map_macro_multiple_entries() {
let m = map! {
"name" => "Alice",
"age" => 30,
"active" => true,
};
assert_eq!(m.len(), 3);
assert_eq!(m["name"].as_str(), "Alice");
assert_eq!(m["age"].as_int(), 30);
assert_eq!(m["active"].as_bool(), true);
}
#[test]
fn test_map_macro_mixed_types() {
let m = map! {
"float" => 3.14,
"int" => 42,
"bool" => false,
"string" => "hello",
};
assert_eq!(m["float"].as_float(), 3.14);
assert_eq!(m["int"].as_int(), 42);
assert_eq!(m["bool"].as_bool(), false);
assert_eq!(m["string"].as_str(), "hello");
}
#[test]
fn test_map_macro_nested() {
let inner = map! {
"inner_key" => "inner_value"
};
let m = map! {
"outer" => Value::Map(inner)
};
assert_eq!(m["outer"]["inner_key"].as_str(), "inner_value");
}
#[test]
fn test_array_macro_empty() {
let a = array![];
assert_eq!(a.len(), 0);
}
#[test]
fn test_array_macro_single_element() {
let a = array![42];
assert_eq!(a.len(), 1);
assert_eq!(a[0].as_int(), 42);
}
#[test]
fn test_array_macro_multiple_elements() {
let a = array![1, 2, 3, 4, 5];
assert_eq!(a.len(), 5);
assert_eq!(a[0].as_int(), 1);
assert_eq!(a[4].as_int(), 5);
}
#[test]
fn test_array_macro_mixed_types() {
let a = array!["hello", 42, true, 3.14];
assert_eq!(a.len(), 4);
assert_eq!(a[0].as_str(), "hello");
assert_eq!(a[1].as_int(), 42);
assert_eq!(a[2].as_bool(), true);
assert_eq!(a[3].as_float(), 3.14);
}
#[test]
fn test_array_macro_trailing_comma() {
let a = array![1, 2, 3,];
assert_eq!(a.len(), 3);
}
#[test]
fn test_array_macro_nested() {
let inner = array![1, 2, 3];
let a = array![Value::Array(inner), 42];
assert_eq!(a.len(), 2);
assert_eq!(a[0][0].as_int(), 1);
assert_eq!(a[1].as_int(), 42);
}
#[test]
fn test_map_macro_with_array_values() {
let arr = array![1, 2, 3];
let m = map! {
"numbers" => Value::Array(arr)
};
assert_eq!(m["numbers"][0].as_int(), 1);
}
#[test]
fn test_array_macro_with_map_values() {
let m = map! {
"key" => "value"
};
let a = array![Value::Map(m), "other"];
assert_eq!(a[0]["key"].as_str(), "value");
assert_eq!(a[1].as_str(), "other");
}
#[test]
fn test_complex_nested_structure() {
let m = map! {
"users" => array! [
map! {
"name" => "Alice",
"age" => 30
},
map! {
"name" => "Bob",
"age" => 25
}
],
"count" => 2
};
assert_eq!(m["users"][0]["name"].as_str(), "Alice");
assert_eq!(m["users"][1]["age"].as_int(), 25);
assert_eq!(m["count"].as_int(), 2);
}
}