preserves/implementations/rust/preserves/src/repr.rs

330 lines
13 KiB
Rust

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<R: Reader<'de> + ?Sized, Dec: DomainDecode<'de, <Self::Impl as ValueImpl<'de>>::Embedded>>(
r: &mut R,
read_annotations: bool,
dec: &mut Dec,
) -> Result<Self::Impl, ReadError>;
fn read_domain<R: Reader<'de> + ?Sized, Dec: DomainDecode<'de, <Self::Impl as ValueImpl<'de>>::Embedded>>(
r: &mut R,
read_annotations: bool,
dec: &mut Dec,
) -> Result<<Self::Impl as ValueImpl<'de>>::Handle, ReadError> {
Ok(Self::read_impl(r, read_annotations, dec)?.wrap())
}
fn read<R: Reader<'de> + ?Sized>(
r: &mut R,
read_annotations: bool,
) -> Result<<Self::Impl as ValueImpl<'de>>::Handle, ReadError> {
Self::read_domain(r, read_annotations, &mut DefaultDomainCodec)
}
fn read_iovalue<R: Reader<'de> + ?Sized>(
r: &mut R,
read_annotations: bool,
) -> Result<<Self::Impl as ValueImpl<'de>>::IOEmbedded, ReadError>;
fn gather_annotations<R: Reader<'de> + ?Sized>(
r: &mut R,
) -> io::Result<Option<(Vec<<<Self::Impl as ValueImpl<'de>>::Mapped<<Self::Impl as ValueImpl<'de>>::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<Self> + Clone + From<Self> + Hash + Eq + Ord + PartialEq + PartialOrd;
type Embedded: Domain<'de>;
type Mapped<E: Domain<'de>>: ValueImpl<'de, Embedded = E>;
type Items<'a>: Iterator<Item = Self::Handle> + 'a where Self: 'a;
type Entries<'a>: Iterator<Item = (Self::Handle, Self::Handle)> + 'a where Self: 'a;
type IOEmbedded: From<<Self::Mapped<Self::IOEmbedded> as ValueImpl<'de>>::Handle> +
Into<<Self::Mapped<Self::IOEmbedded> as ValueImpl<'de>>::Handle> +
AsRef<<Self::Mapped<Self::IOEmbedded> as ValueImpl<'de>>::Handle> +
Domain<'de>;
fn wrap(self) -> Self::Handle;
fn write(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode<Self::Embedded>) -> io::Result<()> {
write_value(w, self, enc)
}
fn value_class(&self) -> ValueClass;
fn as_boolean(&self) -> Option<bool>;
fn as_float(&self) -> Option<f32>;
fn as_double(&self) -> Option<f64>;
fn as_signed_integer(&self) -> Option<Cow<'_, SignedInteger>>;
fn as_string(&self) -> Option<Cow<'_, str>>;
fn as_bytestring(&self) -> Option<Cow<'_, [u8]>>;
fn as_symbol(&self) -> Option<Cow<'_, str>>;
fn as_i8(&self) -> Option<Result<i8, OutOfRange>> { self.as_signed_integer().map(|i| (&*i).try_into()) }
fn as_u8(&self) -> Option<Result<u8, OutOfRange>> { self.as_signed_integer().map(|i| (&*i).try_into()) }
fn as_i16(&self) -> Option<Result<i16, OutOfRange>> { self.as_signed_integer().map(|i| (&*i).try_into()) }
fn as_u16(&self) -> Option<Result<u16, OutOfRange>> { self.as_signed_integer().map(|i| (&*i).try_into()) }
fn as_i32(&self) -> Option<Result<i32, OutOfRange>> { self.as_signed_integer().map(|i| (&*i).try_into()) }
fn as_u32(&self) -> Option<Result<u32, OutOfRange>> { self.as_signed_integer().map(|i| (&*i).try_into()) }
fn as_i64(&self) -> Option<Result<i64, OutOfRange>> { self.as_signed_integer().map(|i| (&*i).try_into()) }
fn as_u64(&self) -> Option<Result<u64, OutOfRange>> { self.as_signed_integer().map(|i| (&*i).try_into()) }
fn as_i128(&self) -> Option<Result<i128, OutOfRange>> { self.as_signed_integer().map(|i| (&*i).try_into()) }
fn as_u128(&self) -> Option<Result<u128, OutOfRange>> { self.as_signed_integer().map(|i| (&*i).try_into()) }
fn as_isize(&self) -> Option<Result<isize, OutOfRange>> { self.as_signed_integer().map(|i| (&*i).try_into()) }
fn as_usize(&self) -> Option<Result<usize, OutOfRange>> { 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<E: ValueImpl<'de, Embedded = Self::Embedded>>(&self, _v: &E::Handle) -> bool;
fn is_dictionary(&self) -> bool;
fn get<K: ValueImpl<'de, Embedded = Self::Embedded>>(&self, _k: &K::Handle) -> Option<Self::Handle>;
fn entries(&self) -> Self::Entries<'_>;
fn as_embedded(&self) -> Option<Cow<'_, Self::Embedded>>;
// INVARIANT: return Some() *only* when the contained collection is nonempty
fn annotations(&self) -> Option<Cow<'_, [<Self::Mapped<Self::IOEmbedded> as ValueImpl<'de>>::Handle]>>;
fn peeled(v: &Self::Handle) -> Self::Handle;
fn copy<E: ValueImpl<'de>, F, Err>(w: &E::Handle, f: &mut F) -> Result<Self::Handle, Err>
where
F: FnMut(&E::Embedded) -> Result<Self::Handle, Err>;
fn map_embedded<E: Domain<'de>, F, Err>(v: &Self::Handle, f: &mut F) -> Result<<Self::Mapped<E> as ValueImpl<'de>>::Handle, Err>
where
F: FnMut(&Self::Embedded) -> Result<E, Err>;
}
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, W>(&v.iter(), &w.iter())
}
CompoundClass::Sequence => {
iters_eq::<V, W>(&v.iter(), &w.iter())
}
CompoundClass::Set => {
let s1 = v.iter().collect::<BTreeSet<_>>();
let s2 = w.iter().collect::<BTreeSet<_>>();
todo!() // s1 == s2
}
CompoundClass::Dictionary => {
let d1 = v.entries().collect::<BTreeMap<_, _>>();
let d2 = w.entries().collect::<BTreeMap<_, _>>();
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, W>(&v.iter(), &w.iter())),
CompoundClass::Sequence => iters_cmp::<V, W>(&v.iter(), &w.iter()),
CompoundClass::Set => {
let s1 = v.iter().collect::<BTreeSet<_>>();
let s2 = w.iter().collect::<BTreeSet<_>>();
todo!() // s1.cmp(&s2)
}
CompoundClass::Dictionary => {
let d1 = v.entries().collect::<BTreeMap<_, _>>();
let d2 = w.entries().collect::<BTreeMap<_, _>>();
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<std::cmp::Ordering> {
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<H: std::hash::Hasher>(&self, state: &mut H) {
crate::value_hash(self, state)
}
}
};
}