use std::borrow::Borrow; 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 crate::DefaultDomainCodec; use crate::DomainDecode; use crate::Reader; use crate::error::ReadError; use crate::reader::NextToken; use crate::signed_integer::OutOfRange; use crate::AtomClass; use crate::CompoundClass; use crate::Domain; use crate::DomainEncode; use crate::SignedInteger; use crate::ValueClass; use crate::Writer; use crate::write_value; use super::float::{eq_f32, eq_f64, cmp_f32, cmp_f64}; pub trait ValueReader<'de> { type Impl: ValueImpl<'de>; fn read_impl + ?Sized, Dec: DomainDecode<'de, >::Embedded>>( r: &mut R, read_annotations: bool, dec: &mut Dec, ) -> Result; fn read_domain + ?Sized, Dec: DomainDecode<'de, >::Embedded>>( r: &mut R, read_annotations: bool, dec: &mut Dec, ) -> Result<>::Handle, ReadError> { Ok(Self::read_impl(r, read_annotations, dec)?.wrap()) } fn read + ?Sized>( r: &mut R, read_annotations: bool, ) -> Result<>::Handle, ReadError> { Self::read_domain(r, read_annotations, &mut DefaultDomainCodec) } fn read_iovalue + ?Sized>( r: &mut R, read_annotations: bool, ) -> Result<>::IOEmbedded, ReadError>; fn gather_annotations + ?Sized>( r: &mut R, ) -> io::Result>::Mapped<>::IOEmbedded> as ValueImpl<'de>>::Handle>, ValueClass)>> { let mut anns = Vec::new(); loop { match r.peek_class()? { None => return Ok(None), Some(NextToken::Value(v)) => return Ok(Some((anns, v))), Some(NextToken::Annotation) => { r.open_annotation()?; anns.push(Self::read_iovalue(r, true)?.into()); r.close_annotation()?; } } } } } /// Atomic values from the specification. pub trait ValueImpl<'de>: Sized { type Handle: Borrow + Clone + From + Hash + Eq + Ord + PartialEq + PartialOrd; type Embedded: Domain<'de>; type Mapped>: ValueImpl<'de, Embedded = E>; type Items<'a>: Iterator + 'a where Self: 'a; type Entries<'a>: Iterator + 'a where Self: 'a; type IOEmbedded: From< as ValueImpl<'de>>::Handle> + Into< as ValueImpl<'de>>::Handle> + AsRef< as ValueImpl<'de>>::Handle> + Domain<'de>; fn wrap(self) -> Self::Handle; fn write(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode) -> io::Result<()> { write_value(w, self, enc) } fn value_class(&self) -> ValueClass; fn as_boolean(&self) -> Option; fn as_float(&self) -> Option; fn as_double(&self) -> Option; fn as_signed_integer(&self) -> Option>; fn as_string(&self) -> Option>; fn as_bytestring(&self) -> Option>; fn as_symbol(&self) -> Option>; 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; fn label(&self) -> Self::Handle; fn is_sequence(&self) -> bool; fn len(&self) -> usize; fn index(&self, _i: usize) -> Self::Handle; fn iter(&self) -> Self::Items<'_>; fn is_set(&self) -> bool; fn has>(&self, _v: &E::Handle) -> bool; fn is_dictionary(&self) -> bool; fn get>(&self, _k: &K::Handle) -> Option; fn entries(&self) -> Self::Entries<'_>; fn as_embedded(&self) -> Option>; // INVARIANT: return Some() *only* when the contained collection is nonempty fn annotations(&self) -> Option as ValueImpl<'de>>::Handle]>>; fn peeled(v: &Self::Handle) -> Self::Handle; fn copy, F, Err>(w: &E::Handle, f: &mut F) -> Result where F: FnMut(&E::Embedded) -> Result; fn map_embedded, F, Err>(v: &Self::Handle, f: &mut F) -> Result< as ValueImpl<'de>>::Handle, Err> where F: FnMut(&Self::Embedded) -> Result; } pub fn value_hash<'de, V: ValueImpl<'de>, 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<'de, V: ValueImpl<'de>, W: ValueImpl<'de, Embedded = V::Embedded>>(i: &V::Items<'_>, j: &W::Items<'_>) -> 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.borrow(), jj.borrow()) { return false }, } } } } pub fn value_eq<'de, V: ValueImpl<'de>, W: ValueImpl<'de, Embedded = V::Embedded>>(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().borrow(), w.label().borrow()) { return false; } iters_eq::(&v.iter(), &w.iter()) } CompoundClass::Sequence => { iters_eq::(&v.iter(), &w.iter()) } CompoundClass::Set => { let s1 = v.iter().collect::>(); let s2 = w.iter().collect::>(); todo!() // s1 == s2 } CompoundClass::Dictionary => { let d1 = v.entries().collect::>(); let d2 = w.entries().collect::>(); todo!() // 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<'de, V: ValueImpl<'de>, W: ValueImpl<'de, Embedded = V::Embedded>>(i: &V::Items<'_>, j: &W::Items<'_>) -> 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.borrow(), jj.borrow()); if !r.is_eq() { return r } } } } } } pub fn value_cmp<'de, V: ValueImpl<'de>, W: ValueImpl<'de, Embedded = V::Embedded>>(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().borrow(), w.label().borrow()).then_with( || iters_cmp::(&v.iter(), &w.iter())), CompoundClass::Sequence => iters_cmp::(&v.iter(), &w.iter()), CompoundClass::Set => { let s1 = v.iter().collect::>(); let s2 = w.iter().collect::>(); todo!() // s1.cmp(&s2) } CompoundClass::Dictionary => { let d1 = v.entries().collect::>(); let d2 = w.entries().collect::>(); todo!() // d1.cmp(&d2) } }, ValueClass::Embedded => v.as_embedded().unwrap().cmp(&w.as_embedded().unwrap()), }) } #[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) } } }; }