use std::borrow::Cow; use std::cmp::Ordering; use std::collections::BTreeMap; use std::collections::BTreeSet; use std::hash::Hash; use std::hash::Hasher; use std::io; use std::ops::Deref; use std::str::FromStr; use std::sync::Arc; use crate::AtomClass; use crate::Bytes; use crate::CompoundClass; use crate::DefaultDomainCodec; use crate::Domain; use crate::DomainEncode; use crate::Embedded; use crate::ExpectedKind; use crate::IOValue; use crate::Map; use crate::Record; use crate::Set; use crate::SignedInteger; use crate::Symbol; use crate::TreeReader; use crate::ValueClass; use crate::ValueReader; use crate::Writer; use crate::signed_integer::OutOfRange; use crate::write_value; use super::float::{eq_f32, eq_f64, cmp_f32, cmp_f64}; #[derive(Clone)] pub struct Value(Arc>); pub trait ValueImpl { fn write_domain(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode) -> io::Result<()> { write_value(w, self, enc) } fn write(&self, w: &mut dyn Writer) -> io::Result<()> { self.write_domain(w, &mut DefaultDomainCodec) } fn owned_value(&self) -> Value; fn value_class(&self) -> ValueClass; fn as_boolean(&self) -> Option { None } fn as_float(&self) -> Option { None } fn as_double(&self) -> Option { None } fn as_signed_integer(&self) -> Option> { None } fn as_string(&self) -> Option> { None } fn as_bytestring(&self) -> Option> { None } fn as_symbol(&self) -> Option> { None } fn as_i8(&self) -> Option> { self.as_signed_integer().map(|i| (&*i).try_into()) } fn as_u8(&self) -> Option> { self.as_signed_integer().map(|i| (&*i).try_into()) } fn as_i16(&self) -> Option> { self.as_signed_integer().map(|i| (&*i).try_into()) } fn as_u16(&self) -> Option> { self.as_signed_integer().map(|i| (&*i).try_into()) } fn as_i32(&self) -> Option> { self.as_signed_integer().map(|i| (&*i).try_into()) } fn as_u32(&self) -> Option> { self.as_signed_integer().map(|i| (&*i).try_into()) } fn as_i64(&self) -> Option> { self.as_signed_integer().map(|i| (&*i).try_into()) } fn as_u64(&self) -> Option> { self.as_signed_integer().map(|i| (&*i).try_into()) } fn as_i128(&self) -> Option> { self.as_signed_integer().map(|i| (&*i).try_into()) } fn as_u128(&self) -> Option> { self.as_signed_integer().map(|i| (&*i).try_into()) } fn as_isize(&self) -> Option> { self.as_signed_integer().map(|i| (&*i).try_into()) } fn as_usize(&self) -> Option> { self.as_signed_integer().map(|i| (&*i).try_into()) } fn is_record(&self) -> bool { false } fn label(&self) -> Value { panic!("Not a record") } fn is_sequence(&self) -> bool { false } fn len(&self) -> usize { panic!("Not a compound value") } fn index(&self, _i: usize) -> Value { panic!("Not indexable") } fn iter(&self) -> Box> + '_> { panic!("Not iterable") } fn is_set(&self) -> bool { false } fn has(&self, _v: &Value) -> bool { panic!("Not set-like") } fn is_dictionary(&self) -> bool { false } fn get(&self, _k: &Value) -> Option> { panic!("Not a dictionary") } fn entries(&self) -> Box, Value)> + '_> { panic!("Not a dictionary") } fn as_embedded(&self) -> Option> { None } // INVARIANT: return Some() *only* when the contained collection is nonempty fn annotations(&self) -> Option> { None } fn peeled(self: Arc) -> Value; //--------------------------------------------------------------------------- fn to_boolean(&self) -> Result { self.as_boolean().ok_or(ExpectedKind::Boolean) } fn to_float(&self) -> Result { self.as_float().ok_or(ExpectedKind::Float) } fn to_double(&self) -> Result { self.as_double().ok_or(ExpectedKind::Double) } fn to_signed_integer(&self) -> Result, ExpectedKind> { self.as_signed_integer().ok_or(ExpectedKind::SignedInteger) } fn to_str/*ing*/(&self) -> Result, ExpectedKind> { self.as_string().ok_or(ExpectedKind::String) } fn to_bytestring(&self) -> Result, ExpectedKind> { self.as_bytestring().ok_or(ExpectedKind::ByteString) } fn to_symbol(&self) -> Result, ExpectedKind> { self.as_symbol().ok_or(ExpectedKind::Symbol) } fn to_i8(&self) -> Result, ExpectedKind> { self.as_i8().ok_or(ExpectedKind::SignedInteger) } fn to_u8(&self) -> Result, ExpectedKind> { self.as_u8().ok_or(ExpectedKind::SignedInteger) } fn to_i16(&self) -> Result, ExpectedKind> { self.as_i16().ok_or(ExpectedKind::SignedInteger) } fn to_u16(&self) -> Result, ExpectedKind> { self.as_u16().ok_or(ExpectedKind::SignedInteger) } fn to_i32(&self) -> Result, ExpectedKind> { self.as_i32().ok_or(ExpectedKind::SignedInteger) } fn to_u32(&self) -> Result, ExpectedKind> { self.as_u32().ok_or(ExpectedKind::SignedInteger) } fn to_i64(&self) -> Result, ExpectedKind> { self.as_i64().ok_or(ExpectedKind::SignedInteger) } fn to_u64(&self) -> Result, ExpectedKind> { self.as_u64().ok_or(ExpectedKind::SignedInteger) } fn to_i128(&self) -> Result, ExpectedKind> { self.as_i128().ok_or(ExpectedKind::SignedInteger) } fn to_u128(&self) -> Result, ExpectedKind> { self.as_u128().ok_or(ExpectedKind::SignedInteger) } fn to_isize(&self) -> Result, ExpectedKind> { self.as_isize().ok_or(ExpectedKind::SignedInteger) } fn to_usize(&self) -> Result, ExpectedKind> { self.as_usize().ok_or(ExpectedKind::SignedInteger) } fn is_simple_record(&self, name: &str, arity: Option) -> bool { if !self.is_record() { return false; } match self.label().as_symbol() { None => false, Some(s) => s.as_ref() == name && (arity.is_none() || arity.unwrap() == self.len()) } } } impl Deref for Value { type Target = dyn ValueImpl; fn deref(&self) -> &Self::Target { self.0.deref() } } impl, D: Domain + FromStr> FromStr for Value { type Err = io::Error; fn from_str(s: &str) -> Result { TreeReader::from_str(s, true) } } impl Value { pub fn new + 'static>(v: V) -> Self { Value(Arc::new(v)) } pub fn from_arc(a: Arc>) -> Self { Value(a) } pub fn into_arc(self) -> Arc> { self.0 } pub fn as_arc(&self) -> &Arc> { &self.0 } } impl ValueImpl for Value { fn write_domain(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode) -> io::Result<()> { self.deref().write_domain(w, enc) } fn owned_value(&self) -> Value { self.clone() } fn value_class(&self) -> ValueClass { self.deref().value_class() } fn as_boolean(&self) -> Option { self.deref().as_boolean() } fn as_float(&self) -> Option { self.deref().as_float() } fn as_double(&self) -> Option { self.deref().as_double() } fn as_signed_integer(&self) -> Option> { self.deref().as_signed_integer() } fn as_string(&self) -> Option> { self.deref().as_string() } fn as_bytestring(&self) -> Option> { self.deref().as_bytestring() } fn as_symbol(&self) -> Option> { self.deref().as_symbol() } fn as_i8(&self) -> Option> { self.deref().as_i8() } fn as_u8(&self) -> Option> { self.deref().as_u8() } fn as_i16(&self) -> Option> { self.deref().as_i16() } fn as_u16(&self) -> Option> { self.deref().as_u16() } fn as_i32(&self) -> Option> { self.deref().as_i32() } fn as_u32(&self) -> Option> { self.deref().as_u32() } fn as_i64(&self) -> Option> { self.deref().as_i64() } fn as_u64(&self) -> Option> { self.deref().as_u64() } fn as_i128(&self) -> Option> { self.deref().as_i128() } fn as_u128(&self) -> Option> { self.deref().as_u128() } fn as_isize(&self) -> Option> { self.deref().as_isize() } fn as_usize(&self) -> Option> { self.deref().as_usize() } fn is_record(&self) -> bool { self.deref().is_record() } fn label(&self) -> Value { self.deref().label() } fn is_sequence(&self) -> bool { self.deref().is_sequence() } fn len(&self) -> usize { self.deref().len() } fn index(&self, i: usize) -> Value { self.deref().index(i) } fn iter(&self) -> Box> + '_> { self.deref().iter() } fn is_set(&self) -> bool { self.deref().is_set() } fn has(&self, v: &Value) -> bool { self.deref().has(v) } fn is_dictionary(&self) -> bool { self.deref().is_dictionary() } fn get(&self, k: &Value) -> Option> { self.deref().get(k) } fn entries(&self) -> Box, Value)> + '_> { self.deref().entries() } fn as_embedded(&self) -> Option> { self.deref().as_embedded() } fn annotations(&self) -> Option> { self.deref().annotations() } fn peeled(self: Arc) -> Value { Arc::clone(&self.0).peeled() } } pub fn value_hash + ?Sized, H: Hasher>(v: &V, state: &mut H) { match v.value_class() { ValueClass::Atomic(a) => match a { AtomClass::Boolean => v.as_boolean().unwrap().hash(state), AtomClass::Float => v.as_float().unwrap().to_bits().hash(state), AtomClass::Double => v.as_double().unwrap().to_bits().hash(state), AtomClass::SignedInteger => v.as_signed_integer().unwrap().hash(state), AtomClass::String => v.as_string().unwrap().hash(state), AtomClass::ByteString => v.as_bytestring().unwrap().hash(state), AtomClass::Symbol => v.as_symbol().unwrap().hash(state), } ValueClass::Compound(c) => match c { CompoundClass::Sequence | CompoundClass::Set => { state.write_usize(v.len()); for v in v.iter() { v.hash(state) } } CompoundClass::Record => { v.label().hash(state); state.write_usize(v.len()); for v in v.iter() { v.hash(state) } } CompoundClass::Dictionary => { state.write_usize(v.len()); for (k, v) in v.entries() { k.hash(state); v.hash(state); } } } ValueClass::Embedded => v.as_embedded().unwrap().hash(state), } } // TODO: when unstable feature iter_order_by stabilises, use that instead fn iters_eq( i: &mut dyn Iterator>, j: &mut dyn Iterator>, ) -> bool { loop { match i.next() { None => return j.next().is_none(), Some(ii) => match j.next() { None => return false, Some(jj) => if !value_eq(&*ii, &*jj) { return false }, } } } } pub fn value_eq + ?Sized, W: ValueImpl + ?Sized>(v: &V, w: &W) -> bool { let cls = v.value_class(); if cls != w.value_class() { return false; } match cls { ValueClass::Atomic(a) => match a { AtomClass::Boolean => v.as_boolean().unwrap() == w.as_boolean().unwrap(), AtomClass::Float => eq_f32(v.as_float().unwrap(), w.as_float().unwrap()), AtomClass::Double => eq_f64(v.as_double().unwrap(), w.as_double().unwrap()), AtomClass::SignedInteger => v.as_signed_integer().unwrap() == w.as_signed_integer().unwrap(), AtomClass::String => v.as_string().unwrap() == w.as_string().unwrap(), AtomClass::ByteString => v.as_bytestring().unwrap() == w.as_bytestring().unwrap(), AtomClass::Symbol => v.as_symbol().unwrap() == w.as_symbol().unwrap(), } ValueClass::Compound(c) => match c { CompoundClass::Record => { if !value_eq(&*v.label(), &*w.label()) { return false; } iters_eq(&mut v.iter(), &mut w.iter()) } CompoundClass::Sequence => { iters_eq(&mut v.iter(), &mut w.iter()) } CompoundClass::Set => { let s1 = v.iter().collect::>>(); let s2 = w.iter().collect::>>(); s1 == s2 } CompoundClass::Dictionary => { let d1 = v.entries().collect::, Value>>(); let d2 = w.entries().collect::, Value>>(); d1 == d2 } } ValueClass::Embedded => v.as_embedded().unwrap() == w.as_embedded().unwrap(), } } // TODO: when unstable feature iter_order_by stabilises, use that instead fn iters_cmp( i: &mut dyn Iterator>, j: &mut dyn Iterator>, ) -> Ordering { loop { match i.next() { None => return if j.next().is_none() { Ordering::Equal } else { Ordering::Less }, Some(ii) => match j.next() { None => return Ordering::Greater, Some(jj) => { let r = value_cmp(&*ii, &*jj); if !r.is_eq() { return r } } } } } } pub fn value_cmp + ?Sized, W: ValueImpl + ?Sized>(v: &V, w: &W) -> Ordering { let cls = v.value_class(); cls.cmp(&w.value_class()).then_with(|| match cls { ValueClass::Atomic(a) => match a { AtomClass::Boolean => v.as_boolean().cmp(&w.as_boolean()), AtomClass::Float => cmp_f32(v.as_float().unwrap(), w.as_float().unwrap()), AtomClass::Double => cmp_f64(v.as_double().unwrap(), w.as_double().unwrap()), AtomClass::SignedInteger => v.as_signed_integer().cmp(&w.as_signed_integer()), AtomClass::String => v.as_string().cmp(&w.as_string()), AtomClass::ByteString => v.as_bytestring().cmp(&w.as_bytestring()), AtomClass::Symbol => v.as_symbol().cmp(&w.as_symbol()), }, ValueClass::Compound(c) => match c { CompoundClass::Record => value_cmp(&*v.label(), &*w.label()).then_with( || iters_cmp(&mut v.iter(), &mut w.iter())), CompoundClass::Sequence => iters_cmp(&mut v.iter(), &mut w.iter()), CompoundClass::Set => { let s1 = v.iter().collect::>(); let s2 = w.iter().collect::>(); s1.cmp(&s2) } CompoundClass::Dictionary => { let d1 = v.entries().collect::>(); let d2 = w.entries().collect::>(); d1.cmp(&d2) } }, ValueClass::Embedded => v.as_embedded().unwrap().cmp(&w.as_embedded().unwrap()), }) } pub fn value_deepcopy(v: &Value) -> Value { value_deepcopy_via(v, &mut |d| Result::<_,()>::Ok(Value::new(Embedded::new(d.clone())))).unwrap() } pub fn value_deepcopy_via>, Err>(v: &Value, f: &mut F) -> Result, Err> where F: FnMut(&D) -> Result { match v.value_class() { ValueClass::Atomic(a) => Ok(match a { AtomClass::Boolean => Value::new(v.as_boolean().unwrap()), AtomClass::Float => Value::new(v.as_float().unwrap()), AtomClass::Double => Value::new(v.as_double().unwrap()), AtomClass::SignedInteger => Value::new(v.as_signed_integer().unwrap().into_owned()), AtomClass::String => Value::new(v.as_string().unwrap().into_owned()), AtomClass::ByteString => Value::new(Bytes::new(v.as_bytestring().unwrap().into_owned())), AtomClass::Symbol => Value::new(Symbol::new(v.as_symbol().unwrap().into_owned())), }), ValueClass::Compound(c) => Ok(match c { CompoundClass::Record => Value::new(Record::new( value_deepcopy_via(&v.label(), f)?, v.iter().map(|w| value_deepcopy_via(&w, f)).collect::, _>>()?)), CompoundClass::Sequence => Value::new( v.iter().map(|w| value_deepcopy_via(&w, f)).collect::, _>>()?), CompoundClass::Set => Value::new( v.iter().map(|w| value_deepcopy_via(&w, f)).collect::, _>>()?), CompoundClass::Dictionary => Value::new( v.entries().map(|(k,w)| Ok((value_deepcopy_via(&k, f)?, value_deepcopy_via(&w, f)?))) .collect::, _>>()?), }), ValueClass::Embedded => f(v.as_embedded().unwrap().as_ref()).map(|r| r.into()), } } pub fn value_map_embedded(v: &Value, f: &mut F) -> Result, Err> where F: FnMut(&D) -> Result { value_deepcopy_via(v, &mut |d| Ok(Value::new(Embedded::new(f(d)?)))) } #[macro_export] macro_rules! impl_value_methods { ({ $($gdecls:tt)* }, $t:ty) => { impl< $($gdecls)* > std::fmt::Debug for $t { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { crate::TextWriter::fmt_value(f, &mut crate::DefaultDomainCodec, self) .map_err(|_| std::fmt::Error) } } impl< $($gdecls)* > PartialEq for $t { fn eq(&self, other: &Self) -> bool { crate::value_eq(self, other) } } impl< $($gdecls)* > Eq for $t {} impl< $($gdecls)* > PartialOrd for $t { fn partial_cmp(&self, other: &Self) -> Option { Some(crate::value_cmp(self, other)) } } impl< $($gdecls)* > Ord for $t { fn cmp(&self, other: &Self) -> std::cmp::Ordering { crate::value_cmp(self, other) } } impl< $($gdecls)* > std::hash::Hash for $t { fn hash(&self, state: &mut H) { crate::value_hash(self, state) } } }; } impl_value_methods!({ D: Domain }, dyn ValueImpl); impl_value_methods!({ D: Domain }, Value);