use crate::data::base::{Primitive, UntaggedValue, Value}; use crate::prelude::*; use derive_new::new; use getset::Getters; use indexmap::IndexMap; use nu_source::Spanned; use nu_source::{b, PrettyDebug}; use pretty::{BoxAllocator, DocAllocator}; use serde::{Deserialize, Serialize}; use std::cmp::{Ordering, PartialOrd}; #[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize, Clone, Getters, new)] pub struct Dictionary { #[get = "pub"] pub entries: IndexMap, } #[derive(Debug, new)] struct DebugEntry<'a> { key: &'a str, value: &'a Value, } impl<'a> PrettyDebug for DebugEntry<'a> { fn pretty(&self) -> DebugDocBuilder { (b::key(self.key.to_string()) + b::equals() + self.value.pretty().as_value()).group() } } impl PrettyDebug for Dictionary { fn pretty(&self) -> DebugDocBuilder { BoxAllocator .text("(") .append( BoxAllocator .intersperse( self.entries() .iter() .map(|(key, value)| DebugEntry::new(key, value).to_doc()), BoxAllocator.space(), ) .nest(1) .group(), ) .append(BoxAllocator.text(")")) .into() } } 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().collect(); let that: Vec<&Value> = self.entries.values().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().collect(); let that: Vec<&Value> = self.entries.values().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 { UntaggedValue::Row(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( UntaggedValue::Primitive(Primitive::Nothing).into_untagged_value(), ), } } pub fn keys(&self) -> impl Iterator { self.entries.keys() } pub(crate) fn get_data_by_key(&self, name: Spanned<&str>) -> Option { let result = self .entries .iter() .find(|(desc_name, _)| *desc_name == name.item)? .1; Some( result .value .clone() .into_value(Tag::new(result.anchor(), name.span)), ) } pub(crate) fn get_mut_data_by_key(&mut self, name: &str) -> Option<&mut Value> { match self .entries .iter_mut() .find(|(desc_name, _)| *desc_name == name) { Some((_, v)) => Some(v), None => None, } } pub(crate) fn insert_data_at_key(&mut self, name: &str, value: Value) { self.entries.insert(name.to_string(), value); } } #[derive(Debug)] pub struct TaggedListBuilder { tag: Tag, pub list: Vec, } impl TaggedListBuilder { pub fn new(tag: impl Into) -> TaggedListBuilder { TaggedListBuilder { tag: tag.into(), list: vec![], } } pub fn push_value(&mut self, value: impl Into) { self.list.push(value.into()); } pub fn push_untagged(&mut self, value: impl Into) { self.list.push(value.into().into_value(self.tag.clone())); } pub fn into_value(self) -> Value { UntaggedValue::Table(self.list).into_value(self.tag) } pub fn into_untagged_value(self) -> UntaggedValue { UntaggedValue::Table(self.list).into_value(self.tag).value } } impl From for Value { fn from(input: TaggedListBuilder) -> Value { input.into_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 build(tag: impl Into, block: impl FnOnce(&mut TaggedDictBuilder)) -> Value { let mut builder = TaggedDictBuilder::new(tag); block(&mut builder); builder.into_value() } pub fn with_capacity(tag: impl Into, n: usize) -> TaggedDictBuilder { TaggedDictBuilder { tag: tag.into(), dict: IndexMap::with_capacity(n), } } pub fn insert_untagged(&mut self, key: impl Into, value: impl Into) { self.dict .insert(key.into(), value.into().into_value(&self.tag)); } pub fn insert_value(&mut self, key: impl Into, value: impl Into) { self.dict.insert(key.into(), value.into()); } pub fn into_value(self) -> Value { let tag = self.tag.clone(); self.into_untagged_value().into_value(tag) } pub fn into_untagged_value(self) -> UntaggedValue { UntaggedValue::Row(Dictionary { entries: self.dict }) } pub fn is_empty(&self) -> bool { self.dict.is_empty() } } impl From for Value { fn from(input: TaggedDictBuilder) -> Value { input.into_value() } }