use std::cmp::Ordering;
use std::fmt;
use crate::model::KStringCow;
use super::DisplayCow;
use super::State;
use super::Value;
use crate::model::ArrayView;
use crate::model::ObjectView;
use crate::model::ScalarCow;
pub trait ValueView: fmt::Debug {
fn as_debug(&self) -> &dyn fmt::Debug;
fn render(&self) -> DisplayCow<'_>;
fn source(&self) -> DisplayCow<'_>;
fn type_name(&self) -> &'static str;
fn query_state(&self, state: State) -> bool;
fn to_kstr(&self) -> KStringCow<'_>;
fn to_value(&self) -> Value;
fn as_scalar(&self) -> Option<ScalarCow<'_>> {
None
}
fn is_scalar(&self) -> bool {
self.as_scalar().is_some()
}
fn as_array(&self) -> Option<&dyn ArrayView> {
None
}
fn is_array(&self) -> bool {
self.as_array().is_some()
}
fn as_object(&self) -> Option<&dyn ObjectView> {
None
}
fn is_object(&self) -> bool {
self.as_object().is_some()
}
fn as_state(&self) -> Option<State> {
None
}
fn is_state(&self) -> bool {
self.as_state().is_some()
}
fn is_nil(&self) -> bool {
false
}
}
impl<'v, V: ValueView + ?Sized> ValueView for &'v V {
fn as_debug(&self) -> &dyn fmt::Debug {
<V as ValueView>::as_debug(self)
}
fn render(&self) -> DisplayCow<'_> {
<V as ValueView>::render(self)
}
fn source(&self) -> DisplayCow<'_> {
<V as ValueView>::source(self)
}
fn type_name(&self) -> &'static str {
<V as ValueView>::type_name(self)
}
fn query_state(&self, state: State) -> bool {
<V as ValueView>::query_state(self, state)
}
fn to_kstr(&self) -> KStringCow<'_> {
<V as ValueView>::to_kstr(self)
}
fn to_value(&self) -> Value {
<V as ValueView>::to_value(self)
}
fn as_scalar(&self) -> Option<ScalarCow<'_>> {
<V as ValueView>::as_scalar(self)
}
fn as_array(&self) -> Option<&dyn ArrayView> {
<V as ValueView>::as_array(self)
}
fn as_object(&self) -> Option<&dyn ObjectView> {
<V as ValueView>::as_object(self)
}
fn as_state(&self) -> Option<State> {
<V as ValueView>::as_state(self)
}
fn is_nil(&self) -> bool {
<V as ValueView>::is_nil(self)
}
}
static NIL: Value = Value::Nil;
impl<T: ValueView> ValueView for Option<T> {
fn as_debug(&self) -> &dyn fmt::Debug {
self
}
fn render(&self) -> DisplayCow<'_> {
forward(self).render()
}
fn source(&self) -> DisplayCow<'_> {
forward(self).source()
}
fn type_name(&self) -> &'static str {
forward(self).type_name()
}
fn query_state(&self, state: State) -> bool {
forward(self).query_state(state)
}
fn to_kstr(&self) -> KStringCow<'_> {
forward(self).to_kstr()
}
fn to_value(&self) -> Value {
forward(self).to_value()
}
fn as_scalar(&self) -> Option<ScalarCow<'_>> {
forward(self).as_scalar()
}
fn as_array(&self) -> Option<&dyn ArrayView> {
forward(self).as_array()
}
fn as_object(&self) -> Option<&dyn ObjectView> {
forward(self).as_object()
}
fn as_state(&self) -> Option<State> {
forward(self).as_state()
}
fn is_nil(&self) -> bool {
forward(self).is_nil()
}
}
fn forward(o: &Option<impl ValueView>) -> &dyn ValueView {
o.as_ref()
.map(|v| v as &dyn ValueView)
.unwrap_or(&NIL as &dyn ValueView)
}
#[derive(Copy, Clone, Debug)]
pub struct ValueViewCmp<'v>(&'v dyn ValueView);
impl<'v> ValueViewCmp<'v> {
pub fn new(v: &dyn ValueView) -> ValueViewCmp<'_> {
ValueViewCmp(v)
}
}
impl<'v> PartialEq<ValueViewCmp<'v>> for ValueViewCmp<'v> {
fn eq(&self, other: &Self) -> bool {
value_eq(self.0, other.0)
}
}
impl<'v> PartialEq<i64> for ValueViewCmp<'v> {
fn eq(&self, other: &i64) -> bool {
super::value_eq(self.0, other)
}
}
impl<'v> PartialEq<f64> for ValueViewCmp<'v> {
fn eq(&self, other: &f64) -> bool {
super::value_eq(self.0, other)
}
}
impl<'v> PartialEq<bool> for ValueViewCmp<'v> {
fn eq(&self, other: &bool) -> bool {
super::value_eq(self.0, other)
}
}
impl<'v> PartialEq<crate::model::scalar::DateTime> for ValueViewCmp<'v> {
fn eq(&self, other: &crate::model::scalar::DateTime) -> bool {
super::value_eq(self.0, other)
}
}
impl<'v> PartialEq<crate::model::scalar::Date> for ValueViewCmp<'v> {
fn eq(&self, other: &crate::model::scalar::Date) -> bool {
super::value_eq(self.0, other)
}
}
impl<'v> PartialEq<str> for ValueViewCmp<'v> {
fn eq(&self, other: &str) -> bool {
let other = KStringCow::from_ref(other);
super::value_eq(self.0, &other)
}
}
impl<'v> PartialEq<&'v str> for ValueViewCmp<'v> {
fn eq(&self, other: &&str) -> bool {
super::value_eq(self.0, other)
}
}
impl<'v> PartialEq<String> for ValueViewCmp<'v> {
fn eq(&self, other: &String) -> bool {
self == other.as_str()
}
}
impl<'v> PartialEq<crate::model::KString> for ValueViewCmp<'v> {
fn eq(&self, other: &crate::model::KString) -> bool {
super::value_eq(self.0, &other.as_ref())
}
}
impl<'v> PartialEq<crate::model::KStringRef<'v>> for ValueViewCmp<'v> {
fn eq(&self, other: &crate::model::KStringRef<'v>) -> bool {
super::value_eq(self.0, other)
}
}
impl<'v> PartialEq<crate::model::KStringCow<'v>> for ValueViewCmp<'v> {
fn eq(&self, other: &crate::model::KStringCow<'v>) -> bool {
super::value_eq(self.0, other)
}
}
impl<'v> PartialOrd<ValueViewCmp<'v>> for ValueViewCmp<'v> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
value_cmp(self.0, other.0)
}
}
pub(crate) fn value_eq(lhs: &dyn ValueView, rhs: &dyn ValueView) -> bool {
if let (Some(x), Some(y)) = (lhs.as_array(), rhs.as_array()) {
if x.size() != y.size() {
return false;
}
return x.values().zip(y.values()).all(|(x, y)| value_eq(x, y));
}
if let (Some(x), Some(y)) = (lhs.as_object(), rhs.as_object()) {
if x.size() != y.size() {
return false;
}
return x.iter().all(|(key, value)| {
y.get(key.as_str())
.map(|v| value_eq(v, value))
.unwrap_or(false)
});
}
if lhs.is_nil() && rhs.is_nil() {
return true;
}
if let Some(state) = lhs.as_state() {
return rhs.query_state(state);
} else if let Some(state) = rhs.as_state() {
return lhs.query_state(state);
}
match (lhs.as_scalar(), rhs.as_scalar()) {
(Some(x), Some(y)) => return x == y,
(None, None) => (),
(Some(x), _) => {
if rhs.is_nil() {
return !x.to_bool().unwrap_or(true);
} else {
return x.to_bool().unwrap_or(false);
}
}
(_, Some(x)) => {
if lhs.is_nil() {
return !x.to_bool().unwrap_or(true);
} else {
return x.to_bool().unwrap_or(false);
}
}
}
false
}
pub(crate) fn value_cmp(lhs: &dyn ValueView, rhs: &dyn ValueView) -> Option<Ordering> {
if let (Some(x), Some(y)) = (lhs.as_scalar(), rhs.as_scalar()) {
return x.partial_cmp(&y);
}
if let (Some(x), Some(y)) = (lhs.as_array(), rhs.as_array()) {
return x
.values()
.map(|v| ValueViewCmp(v))
.partial_cmp(y.values().map(|v| ValueViewCmp(v)));
}
if let (Some(x), Some(y)) = (lhs.as_object(), rhs.as_object()) {
return x
.iter()
.map(|(k, v)| (k, ValueViewCmp(v)))
.partial_cmp(y.iter().map(|(k, v)| (k, ValueViewCmp(v))));
}
None
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_debug() {
let scalar = 5;
println!("{:?}", scalar);
let view: &dyn ValueView = &scalar;
println!("{:?}", view);
let debug: &dyn fmt::Debug = view.as_debug();
println!("{:?}", debug);
}
}