use crate::prelude::*; use crate::object::{Primitive, Value}; use derive_new::new; use indexmap::IndexMap; use serde::{Deserialize, Serialize}; use std::cmp::{Ordering, PartialOrd}; use std::fmt; #[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize, Clone, new)] pub struct Dictionary { pub entries: IndexMap>, } impl PartialOrd for Dictionary { fn partial_cmp(&self, other: &Dictionary) -> Option { let this: Vec<&String> = self.entries.keys().collect(); let that: Vec<&String> = other.entries.keys().collect(); if this != that { return this.partial_cmp(&that); } let this: Vec<&Value> = self.entries.values().map(|v| v.item()).collect(); let that: Vec<&Value> = self.entries.values().map(|v| v.item()).collect(); this.partial_cmp(&that) } } impl From>> for Dictionary { fn from(input: IndexMap>) -> Dictionary { let mut out = IndexMap::default(); for (key, value) in input { out.insert(key, value); } Dictionary::new(out) } } impl Ord for Dictionary { fn cmp(&self, other: &Dictionary) -> Ordering { let this: Vec<&String> = self.entries.keys().collect(); let that: Vec<&String> = other.entries.keys().collect(); if this != that { return this.cmp(&that); } let this: Vec<&Value> = self.entries.values().map(|v| v.item()).collect(); let that: Vec<&Value> = self.entries.values().map(|v| v.item()).collect(); this.cmp(&that) } } impl PartialOrd for Dictionary { fn partial_cmp(&self, _other: &Value) -> Option { Some(Ordering::Less) } } impl PartialEq for Dictionary { fn eq(&self, other: &Value) -> bool { match other { Value::Object(d) => self == d, _ => false, } } } impl Dictionary { pub fn get_data(&self, desc: &String) -> MaybeOwned<'_, Value> { match self.entries.get(desc) { Some(v) => MaybeOwned::Borrowed(v), None => MaybeOwned::Owned(Value::Primitive(Primitive::Nothing)), } } pub(crate) fn get_data_by_key(&self, name: &str) -> Option<&Tagged> { match self .entries .iter() .find(|(desc_name, _)| *desc_name == name) { Some((_, v)) => Some(v), None => None, } } pub(crate) fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut debug = f.debug_struct("Dictionary"); for (desc, value) in self.entries.iter() { debug.field(desc, &value.debug()); } debug.finish() } } #[derive(Debug)] pub struct TaggedListBuilder { pub tag: Tag, list: Vec>, } impl TaggedListBuilder { pub fn new(tag: impl Into) -> TaggedListBuilder { TaggedListBuilder { tag: tag.into(), list: vec![], } } pub fn push(&mut self, value: impl Into) { self.list.push(value.into().tagged(self.tag)); } pub fn insert_tagged(&mut self, value: impl Into>) { self.list.push(value.into()); } pub fn into_tagged_value(self) -> Tagged { Value::List(self.list).tagged(self.tag) } } impl From for Tagged { fn from(input: TaggedListBuilder) -> Tagged { input.into_tagged_value() } } #[derive(Debug)] pub struct TaggedDictBuilder { tag: Tag, dict: IndexMap>, } impl TaggedDictBuilder { pub fn new(tag: impl Into) -> TaggedDictBuilder { TaggedDictBuilder { tag: tag.into(), dict: IndexMap::default(), } } pub fn with_capacity(tag: impl Into, n: usize) -> TaggedDictBuilder { TaggedDictBuilder { tag: tag.into(), dict: IndexMap::with_capacity(n), } } pub fn insert(&mut self, key: impl Into, value: impl Into) { self.dict.insert(key.into(), value.into().tagged(self.tag)); } pub fn insert_tagged(&mut self, key: impl Into, value: impl Into>) { self.dict.insert(key.into(), value.into()); } pub fn into_tagged_value(self) -> Tagged { self.into_tagged_dict().map(Value::Object) } pub fn into_tagged_dict(self) -> Tagged { Dictionary { entries: self.dict }.tagged(self.tag) } } impl From for Tagged { fn from(input: TaggedDictBuilder) -> Tagged { input.into_tagged_value() } }