use crate::value::TypeToValue;
use crate::Value;
use std::collections::{BTreeMap, HashMap};
use std::iter::Iterator;
#[derive(Debug, Clone, PartialEq)]
pub enum Object {
BTreeMap(BTreeMap<String, Value>),
HashMap(HashMap<String, Value>),
}
impl Object {
pub fn get(&self, key: &str) -> Option<&Value> {
match self {
Object::BTreeMap(map) => map.get(key),
Object::HashMap(map) => map.get(key),
}
}
pub fn insert(&mut self, key: String, value: Value) -> Option<Value> {
match self {
Object::BTreeMap(map) => map.insert(key, value),
Object::HashMap(map) => map.insert(key, value),
}
}
pub fn remove(&mut self, key: &str) -> Option<Value> {
match self {
Object::BTreeMap(map) => map.remove(key),
Object::HashMap(map) => map.remove(key),
}
}
pub fn contains_key(&self, key: &str) -> bool {
match self {
Object::BTreeMap(map) => map.contains_key(key),
Object::HashMap(map) => map.contains_key(key),
}
}
pub fn keys(&self) -> Vec<&String> {
match self {
Object::BTreeMap(map) => map.keys().collect(),
Object::HashMap(map) => map.keys().collect(),
}
}
pub fn values(&self) -> Vec<&Value> {
match self {
Object::BTreeMap(map) => map.values().collect(),
Object::HashMap(map) => map.values().collect(),
}
}
pub fn len(&self) -> usize {
match self {
Object::BTreeMap(map) => map.len(),
Object::HashMap(map) => map.len(),
}
}
pub fn is_empty(&self) -> bool {
match self {
Object::BTreeMap(map) => map.is_empty(),
Object::HashMap(map) => map.is_empty(),
}
}
pub fn clear(&mut self) {
match self {
Object::BTreeMap(map) => map.clear(),
Object::HashMap(map) => map.clear(),
}
}
}
impl Default for Object {
fn default() -> Self {
Object::HashMap(HashMap::new())
}
}
impl TypeToValue for Object {
fn to_value(&self) -> Value {
Value::Object(self.clone())
}
}
impl From<BTreeMap<String, Value>> for Object {
fn from(value: BTreeMap<String, Value>) -> Self {
Object::BTreeMap(value)
}
}
impl From<HashMap<String, Value>> for Object {
fn from(value: HashMap<String, Value>) -> Self {
Object::HashMap(value)
}
}
impl From<Vec<(String, Value)>> for Object {
fn from(value: Vec<(String, Value)>) -> Self {
Object::HashMap(value.into_iter().collect())
}
}
impl Into<HashMap<String, Value>> for Object {
fn into(self) -> HashMap<String, Value> {
match self {
Object::BTreeMap(map) => map.into_iter().collect(),
Object::HashMap(map) => map,
}
}
}
impl Into<BTreeMap<String, Value>> for Object {
fn into(self) -> BTreeMap<String, Value> {
match self {
Object::BTreeMap(map) => map,
Object::HashMap(map) => map.into_iter().collect(),
}
}
}
#[allow(dead_code)]
pub struct ObjectIter<'a> {
object: &'a Object,
state: IterState<'a>,
}
enum IterState<'a> {
BTreeMap(std::collections::btree_map::Iter<'a, String, Value>),
HashMap(std::collections::hash_map::Iter<'a, String, Value>),
}
impl<'a> Iterator for ObjectIter<'a> {
type Item = (&'a String, &'a Value);
fn next(&mut self) -> Option<Self::Item> {
match &mut self.state {
IterState::BTreeMap(iter) => iter.next(),
IterState::HashMap(iter) => iter.next(),
}
}
}
impl<'a> Object {
pub fn iter(&'a self) -> ObjectIter<'a> {
match self {
Object::BTreeMap(map) => ObjectIter {
object: self,
state: IterState::BTreeMap(map.iter()),
},
Object::HashMap(map) => ObjectIter {
object: self,
state: IterState::HashMap(map.iter()),
},
}
}
}
#[cfg(test)]
mod tests {
use crate::StringB;
use super::*;
#[test]
fn test_object_iter() {
let value1 = Value::Null;
let value2 = StringB::from("ok").to_value();
let mut map = BTreeMap::new();
map.insert("key1".to_string(), value1.clone());
map.insert("key2".to_string(), value2.clone());
let obj = Object::from(map);
let mut iter = obj.iter();
let mut results = vec![];
while let Some((key, value)) = iter.next() {
results.push((key.clone(), value.clone()));
}
assert_eq!(
results,
vec![("key1".to_string(), value1), ("key2".to_string(), value2)]
);
}
#[test]
fn test_object_from_vec() {
let vec = vec![
("key1".to_string(), Value::Null),
("key2".to_string(), StringB::from("ok").to_value()),
];
let obj = Object::from(vec);
assert_eq!(obj.get("key1"), Some(&Value::Null));
assert_eq!(obj.get("key2"), Some(&StringB::from("ok").to_value()));
}
}