pub mod map;
mod ser;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::fmt;
use crate::model::KStringCow;
use crate::model::value::DisplayCow;
use crate::model::State;
use crate::model::{Value, ValueView};
pub use map::Object;
pub use ser::to_object;
pub trait ObjectView: ValueView {
fn as_value(&self) -> &dyn ValueView;
fn size(&self) -> i64;
fn keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k>;
fn values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k>;
fn iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k>;
fn contains_key(&self, index: &str) -> bool;
fn get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView>;
}
impl ValueView for Object {
fn as_debug(&self) -> &dyn fmt::Debug {
self
}
fn render(&self) -> DisplayCow<'_> {
DisplayCow::Owned(Box::new(ObjectRender { s: self }))
}
fn source(&self) -> DisplayCow<'_> {
DisplayCow::Owned(Box::new(ObjectSource { s: self }))
}
fn type_name(&self) -> &'static str {
"object"
}
fn query_state(&self, state: State) -> bool {
match state {
State::Truthy => true,
State::DefaultValue | State::Empty | State::Blank => self.is_empty(),
}
}
fn to_kstr(&self) -> KStringCow<'_> {
let s = ObjectRender { s: self }.to_string();
KStringCow::from_string(s)
}
fn to_value(&self) -> Value {
Value::Object(self.clone())
}
fn as_object(&self) -> Option<&dyn ObjectView> {
Some(self)
}
}
impl ObjectView for Object {
fn as_value(&self) -> &dyn ValueView {
self
}
fn size(&self) -> i64 {
self.len() as i64
}
fn keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k> {
let keys = Object::keys(self).map(|s| s.as_ref().into());
Box::new(keys)
}
fn values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k> {
let i = Object::values(self).map(|v| v.as_view());
Box::new(i)
}
fn iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k> {
let i = Object::iter(self).map(|(k, v)| (k.as_str().into(), v.as_view()));
Box::new(i)
}
fn contains_key(&self, index: &str) -> bool {
Object::contains_key(self, index)
}
fn get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView> {
Object::get(self, index).map(|v| v.as_view())
}
}
impl<'o, O: ObjectView + ?Sized> ObjectView for &'o O {
fn as_value(&self) -> &dyn ValueView {
<O as ObjectView>::as_value(self)
}
fn size(&self) -> i64 {
<O as ObjectView>::size(self)
}
fn keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k> {
<O as ObjectView>::keys(self)
}
fn values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k> {
<O as ObjectView>::values(self)
}
fn iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k> {
<O as ObjectView>::iter(self)
}
fn contains_key(&self, index: &str) -> bool {
<O as ObjectView>::contains_key(self, index)
}
fn get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView> {
<O as ObjectView>::get(self, index)
}
}
pub trait ObjectIndex:
fmt::Debug + fmt::Display + Ord + std::hash::Hash + Eq + std::borrow::Borrow<str>
{
fn as_index(&self) -> &str;
}
impl ObjectIndex for String {
fn as_index(&self) -> &str {
self.as_str()
}
}
impl ObjectIndex for crate::model::KString {
fn as_index(&self) -> &str {
self.as_str()
}
}
impl<'s> ObjectIndex for crate::model::KStringRef<'s> {
fn as_index(&self) -> &str {
self.as_str()
}
}
impl<'s> ObjectIndex for crate::model::KStringCow<'s> {
fn as_index(&self) -> &str {
self.as_str()
}
}
impl<K: ObjectIndex, V: ValueView, S: ::std::hash::BuildHasher> ValueView for HashMap<K, V, S> {
fn as_debug(&self) -> &dyn fmt::Debug {
self
}
fn render(&self) -> DisplayCow<'_> {
DisplayCow::Owned(Box::new(ObjectRender { s: self }))
}
fn source(&self) -> DisplayCow<'_> {
DisplayCow::Owned(Box::new(ObjectSource { s: self }))
}
fn type_name(&self) -> &'static str {
"object"
}
fn query_state(&self, state: State) -> bool {
match state {
State::Truthy => true,
State::DefaultValue | State::Empty | State::Blank => self.is_empty(),
}
}
fn to_kstr(&self) -> KStringCow<'_> {
let s = ObjectRender { s: self }.to_string();
KStringCow::from_string(s)
}
fn to_value(&self) -> Value {
Value::Object(
self.iter()
.map(|(k, v)| (crate::model::KString::from_ref(k.as_index()), v.to_value()))
.collect(),
)
}
fn as_object(&self) -> Option<&dyn ObjectView> {
Some(self)
}
}
impl<K: ObjectIndex, V: ValueView, S: ::std::hash::BuildHasher> ObjectView for HashMap<K, V, S> {
fn as_value(&self) -> &dyn ValueView {
self
}
fn size(&self) -> i64 {
self.len() as i64
}
fn keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k> {
let keys = HashMap::keys(self).map(|s| s.as_index().into());
Box::new(keys)
}
fn values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k> {
let i = HashMap::values(self).map(as_view);
Box::new(i)
}
fn iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k> {
let i = HashMap::iter(self).map(|(k, v)| (k.as_index().into(), as_view(v)));
Box::new(i)
}
fn contains_key(&self, index: &str) -> bool {
HashMap::contains_key(self, index)
}
fn get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView> {
HashMap::get(self, index).map(as_view)
}
}
impl<K: ObjectIndex, V: ValueView> ValueView for BTreeMap<K, V> {
fn as_debug(&self) -> &dyn fmt::Debug {
self
}
fn render(&self) -> DisplayCow<'_> {
DisplayCow::Owned(Box::new(ObjectRender { s: self }))
}
fn source(&self) -> DisplayCow<'_> {
DisplayCow::Owned(Box::new(ObjectSource { s: self }))
}
fn type_name(&self) -> &'static str {
"object"
}
fn query_state(&self, state: State) -> bool {
match state {
State::Truthy => true,
State::DefaultValue | State::Empty | State::Blank => self.is_empty(),
}
}
fn to_kstr(&self) -> KStringCow<'_> {
let s = ObjectRender { s: self }.to_string();
KStringCow::from_string(s)
}
fn to_value(&self) -> Value {
Value::Object(
self.iter()
.map(|(k, v)| (crate::model::KString::from_ref(k.as_index()), v.to_value()))
.collect(),
)
}
fn as_object(&self) -> Option<&dyn ObjectView> {
Some(self)
}
}
impl<K: ObjectIndex, V: ValueView> ObjectView for BTreeMap<K, V> {
fn as_value(&self) -> &dyn ValueView {
self
}
fn size(&self) -> i64 {
self.len() as i64
}
fn keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k> {
let keys = BTreeMap::keys(self).map(|s| s.as_index().into());
Box::new(keys)
}
fn values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k> {
let i = BTreeMap::values(self).map(as_view);
Box::new(i)
}
fn iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k> {
let i = BTreeMap::iter(self).map(|(k, v)| (k.as_index().into(), as_view(v)));
Box::new(i)
}
fn contains_key(&self, index: &str) -> bool {
BTreeMap::contains_key(self, index)
}
fn get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView> {
BTreeMap::get(self, index).map(as_view)
}
}
fn as_view<T: ValueView>(value: &T) -> &dyn ValueView {
value
}
#[derive(Debug)]
pub struct ObjectSource<'s, O: ObjectView> {
s: &'s O,
}
impl<'s, O: ObjectView> ObjectSource<'s, O> {
#[doc(hidden)]
pub fn new(other: &'s O) -> Self {
Self { s: other }
}
}
impl<'s, O: ObjectView> fmt::Display for ObjectSource<'s, O> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{{")?;
for (k, v) in self.s.iter() {
write!(f, r#""{}": {}, "#, k, v.render())?;
}
write!(f, "}}")?;
Ok(())
}
}
#[derive(Debug)]
pub struct ObjectRender<'s, O: ObjectView> {
s: &'s O,
}
impl<'s, O: ObjectView> ObjectRender<'s, O> {
#[doc(hidden)]
pub fn new(other: &'s O) -> Self {
Self { s: other }
}
}
impl<'s, O: ObjectView> fmt::Display for ObjectRender<'s, O> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (k, v) in self.s.iter() {
write!(f, "{}{}", k, v.render())?;
}
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_object() {
let obj = Object::new();
println!("{}", obj.source());
let object: &dyn ObjectView = &obj;
println!("{}", object.source());
let view: &dyn ValueView = object.as_value();
println!("{}", view.source());
}
}