use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use std::{borrow::Borrow, fmt, hash::Hash};
use crate::{value, IntoValue, Value};
#[macro_export]
macro_rules! object {
(@single $($x:tt)*) => (());
(@count $($rest:expr),*) => (<[()]>::len(&[$($crate::object!(@single $rest)),*]));
($($key:expr => $value:expr,)+) => { $crate::object!($($key => $value),+) };
($($key:expr => $value:expr),*) => {
{
let _cap = $crate::object!(@count $($key),*);
let mut _obj = $crate::Object::with_capacity(_cap);
$(
_obj.insert($key, $value);
)*
_obj
}
};
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Object {
inner: IndexMap<String, Value>,
}
impl Object {
pub fn new() -> Self {
Self {
inner: IndexMap::new(),
}
}
pub fn with_capacity(n: usize) -> Self {
Self {
inner: IndexMap::with_capacity(n),
}
}
pub fn insert<K: Into<String>, V: IntoValue>(&mut self, key: K, val: V) {
self.inner.insert(key.into(), val.into_value());
}
pub fn insert_serialize<K: Into<String>, V: Serialize>(&mut self, key: K, val: V) {
if let Ok(val) = value::serialize_to_value(val) {
self.inner.insert(key.into(), val);
}
}
pub fn remove<K: Hash + Eq + ?Sized>(&mut self, key: &K) -> Option<Value>
where
String: Borrow<K>,
{
self.inner.swap_remove(key)
}
pub fn contains_key<K: Hash + Eq + ?Sized>(&self, key: &K) -> bool
where
String: Borrow<K>,
{
self.inner.contains_key(key)
}
pub fn get<K: Hash + Eq + ?Sized>(&self, key: &K) -> Option<&Value>
where
String: Borrow<K>,
{
self.inner.get(key)
}
pub fn get_mut<K: Hash + Eq + ?Sized>(&mut self, key: &K) -> Option<&mut Value>
where
String: Borrow<K>,
{
self.inner.get_mut(key)
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn iter(&self) -> indexmap::map::Iter<'_, String, Value> {
self.inner.iter()
}
pub fn iter_mut(&mut self) -> indexmap::map::IterMut<'_, String, Value> {
self.inner.iter_mut()
}
}
impl From<IndexMap<String, Value>> for Object {
fn from(inner: IndexMap<String, Value>) -> Self {
Self { inner }
}
}
impl From<Object> for IndexMap<String, Value> {
fn from(val: Object) -> Self {
val.inner
}
}
impl FromIterator<(String, Value)> for Object {
fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
let mut obj = Self::new();
for (k, v) in iter {
obj.insert(k, v);
}
Self { inner: obj.inner }
}
}
impl IntoIterator for Object {
type Item = (String, Value);
type IntoIter = indexmap::map::IntoIter<String, Value>;
fn into_iter(self) -> Self::IntoIter {
self.inner.into_iter()
}
}
impl<'a> IntoIterator for &'a Object {
type Item = (&'a String, &'a Value);
type IntoIter = indexmap::map::Iter<'a, String, Value>;
fn into_iter(self) -> Self::IntoIter {
self.inner.iter()
}
}
impl<'a> IntoIterator for &'a mut Object {
type IntoIter = indexmap::map::IterMut<'a, String, Value>;
type Item = (&'a String, &'a mut Value);
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl Extend<(String, Value)> for Object {
fn extend<T: IntoIterator<Item = (String, Value)>>(&mut self, iter: T) {
for (k, v) in iter {
self.insert(k, v);
}
}
}
impl fmt::Display for Object {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", Value::Object(self.clone()))
}
}
#[cfg(test)]
mod tests {
use crate::deserialize_from_value;
use super::*;
#[test]
fn deserialize_object() {
let obj = object! {
"name" => "John",
"age" => 32,
};
let val = Value::Object(obj.clone());
assert_eq!(deserialize_from_value::<Object>(val).unwrap(), obj);
}
}