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

434 lines
19 KiB
Rust

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<D>(Arc<dyn ValueImpl<D>>);
pub trait ValueImpl<D: Domain> {
fn write_domain(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode<D>) -> 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<D>;
fn value_class(&self) -> ValueClass;
fn as_boolean(&self) -> Option<bool> { None }
fn as_float(&self) -> Option<f32> { None }
fn as_double(&self) -> Option<f64> { None }
fn as_signed_integer(&self) -> Option<Cow<'_, SignedInteger>> { None }
fn as_string(&self) -> Option<Cow<'_, str>> { None }
fn as_bytestring(&self) -> Option<Cow<'_, [u8]>> { None }
fn as_symbol(&self) -> Option<Cow<'_, str>> { None }
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 { false }
fn label(&self) -> Value<D> { 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<D> { panic!("Not indexable") }
fn iter(&self) -> Box<dyn Iterator<Item = Value<D>> + '_> { panic!("Not iterable") }
fn is_set(&self) -> bool { false }
fn has(&self, _v: &Value<D>) -> bool { panic!("Not set-like") }
fn is_dictionary(&self) -> bool { false }
fn get(&self, _k: &Value<D>) -> Option<Value<D>> { panic!("Not a dictionary") }
fn entries(&self) -> Box<dyn Iterator<Item = (Value<D>, Value<D>)> + '_> { panic!("Not a dictionary") }
fn as_embedded(&self) -> Option<Cow<'_, D>> { None }
// INVARIANT: return Some() *only* when the contained collection is nonempty
fn annotations(&self) -> Option<Cow<'_, [IOValue]>> { None }
fn peeled(self: Arc<Self>) -> Value<D>;
//---------------------------------------------------------------------------
fn to_boolean(&self) -> Result<bool, ExpectedKind> { self.as_boolean().ok_or(ExpectedKind::Boolean) }
fn to_float(&self) -> Result<f32, ExpectedKind> { self.as_float().ok_or(ExpectedKind::Float) }
fn to_double(&self) -> Result<f64, ExpectedKind> { self.as_double().ok_or(ExpectedKind::Double) }
fn to_signed_integer(&self) -> Result<Cow<'_, SignedInteger>, ExpectedKind> { self.as_signed_integer().ok_or(ExpectedKind::SignedInteger) }
fn to_str/*ing*/(&self) -> Result<Cow<'_, str>, ExpectedKind> { self.as_string().ok_or(ExpectedKind::String) }
fn to_bytestring(&self) -> Result<Cow<'_, [u8]>, ExpectedKind> { self.as_bytestring().ok_or(ExpectedKind::ByteString) }
fn to_symbol(&self) -> Result<Cow<'_, str>, ExpectedKind> { self.as_symbol().ok_or(ExpectedKind::Symbol) }
fn to_i8(&self) -> Result<Result<i8, OutOfRange>, ExpectedKind> { self.as_i8().ok_or(ExpectedKind::SignedInteger) }
fn to_u8(&self) -> Result<Result<u8, OutOfRange>, ExpectedKind> { self.as_u8().ok_or(ExpectedKind::SignedInteger) }
fn to_i16(&self) -> Result<Result<i16, OutOfRange>, ExpectedKind> { self.as_i16().ok_or(ExpectedKind::SignedInteger) }
fn to_u16(&self) -> Result<Result<u16, OutOfRange>, ExpectedKind> { self.as_u16().ok_or(ExpectedKind::SignedInteger) }
fn to_i32(&self) -> Result<Result<i32, OutOfRange>, ExpectedKind> { self.as_i32().ok_or(ExpectedKind::SignedInteger) }
fn to_u32(&self) -> Result<Result<u32, OutOfRange>, ExpectedKind> { self.as_u32().ok_or(ExpectedKind::SignedInteger) }
fn to_i64(&self) -> Result<Result<i64, OutOfRange>, ExpectedKind> { self.as_i64().ok_or(ExpectedKind::SignedInteger) }
fn to_u64(&self) -> Result<Result<u64, OutOfRange>, ExpectedKind> { self.as_u64().ok_or(ExpectedKind::SignedInteger) }
fn to_i128(&self) -> Result<Result<i128, OutOfRange>, ExpectedKind> { self.as_i128().ok_or(ExpectedKind::SignedInteger) }
fn to_u128(&self) -> Result<Result<u128, OutOfRange>, ExpectedKind> { self.as_u128().ok_or(ExpectedKind::SignedInteger) }
fn to_isize(&self) -> Result<Result<isize, OutOfRange>, ExpectedKind> { self.as_isize().ok_or(ExpectedKind::SignedInteger) }
fn to_usize(&self) -> Result<Result<usize, OutOfRange>, ExpectedKind> { self.as_usize().ok_or(ExpectedKind::SignedInteger) }
fn is_simple_record(&self, name: &str, arity: Option<usize>) -> 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<D: Domain> Deref for Value<D> {
type Target = dyn ValueImpl<D>;
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
impl<Err: Into<io::Error>, D: Domain + FromStr<Err = Err>> FromStr for Value<D> {
type Err = io::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
TreeReader::from_str(s, true)
}
}
impl<D: Domain> Value<D> {
pub fn new<V: ValueImpl<D> + 'static>(v: V) -> Self {
Value(Arc::new(v))
}
pub fn from_arc(a: Arc<dyn ValueImpl<D>>) -> Self {
Value(a)
}
pub fn into_arc(self) -> Arc<dyn ValueImpl<D>> {
self.0
}
pub fn as_arc(&self) -> &Arc<dyn ValueImpl<D>> {
&self.0
}
}
impl<D: Domain> ValueImpl<D> for Value<D> {
fn write_domain(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode<D>) -> io::Result<()> { self.deref().write_domain(w, enc) }
fn owned_value(&self) -> Value<D> { self.clone() }
fn value_class(&self) -> ValueClass { self.deref().value_class() }
fn as_boolean(&self) -> Option<bool> { self.deref().as_boolean() }
fn as_float(&self) -> Option<f32> { self.deref().as_float() }
fn as_double(&self) -> Option<f64> { self.deref().as_double() }
fn as_signed_integer(&self) -> Option<Cow<'_, SignedInteger>> { self.deref().as_signed_integer() }
fn as_string(&self) -> Option<Cow<'_, str>> { self.deref().as_string() }
fn as_bytestring(&self) -> Option<Cow<'_, [u8]>> { self.deref().as_bytestring() }
fn as_symbol(&self) -> Option<Cow<'_, str>> { self.deref().as_symbol() }
fn as_i8(&self) -> Option<Result<i8, OutOfRange>> { self.deref().as_i8() }
fn as_u8(&self) -> Option<Result<u8, OutOfRange>> { self.deref().as_u8() }
fn as_i16(&self) -> Option<Result<i16, OutOfRange>> { self.deref().as_i16() }
fn as_u16(&self) -> Option<Result<u16, OutOfRange>> { self.deref().as_u16() }
fn as_i32(&self) -> Option<Result<i32, OutOfRange>> { self.deref().as_i32() }
fn as_u32(&self) -> Option<Result<u32, OutOfRange>> { self.deref().as_u32() }
fn as_i64(&self) -> Option<Result<i64, OutOfRange>> { self.deref().as_i64() }
fn as_u64(&self) -> Option<Result<u64, OutOfRange>> { self.deref().as_u64() }
fn as_i128(&self) -> Option<Result<i128, OutOfRange>> { self.deref().as_i128() }
fn as_u128(&self) -> Option<Result<u128, OutOfRange>> { self.deref().as_u128() }
fn as_isize(&self) -> Option<Result<isize, OutOfRange>> { self.deref().as_isize() }
fn as_usize(&self) -> Option<Result<usize, OutOfRange>> { self.deref().as_usize() }
fn is_record(&self) -> bool { self.deref().is_record() }
fn label(&self) -> Value<D> { 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<D> { self.deref().index(i) }
fn iter(&self) -> Box<dyn Iterator<Item = Value<D>> + '_> { self.deref().iter() }
fn is_set(&self) -> bool { self.deref().is_set() }
fn has(&self, v: &Value<D>) -> bool { self.deref().has(v) }
fn is_dictionary(&self) -> bool { self.deref().is_dictionary() }
fn get(&self, k: &Value<D>) -> Option<Value<D>> { self.deref().get(k) }
fn entries(&self) -> Box<dyn Iterator<Item = (Value<D>, Value<D>)> + '_> { self.deref().entries() }
fn as_embedded(&self) -> Option<Cow<'_, D>> { self.deref().as_embedded() }
fn annotations(&self) -> Option<Cow<'_, [IOValue]>> { self.deref().annotations() }
fn peeled(self: Arc<Self>) -> Value<D> { Arc::clone(&self.0).peeled() }
}
pub fn value_hash<D: Domain, V: ValueImpl<D> + ?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<D: Domain>(
i: &mut dyn Iterator<Item = Value<D>>,
j: &mut dyn Iterator<Item = Value<D>>,
) -> 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<D: Domain, V: ValueImpl<D> + ?Sized, W: ValueImpl<D> + ?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::<BTreeSet<Value<D>>>();
let s2 = w.iter().collect::<BTreeSet<Value<D>>>();
s1 == s2
}
CompoundClass::Dictionary => {
let d1 = v.entries().collect::<BTreeMap<Value<D>, Value<D>>>();
let d2 = w.entries().collect::<BTreeMap<Value<D>, Value<D>>>();
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<D: Domain>(
i: &mut dyn Iterator<Item = Value<D>>,
j: &mut dyn Iterator<Item = Value<D>>,
) -> 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<D: Domain, V: ValueImpl<D> + ?Sized, W: ValueImpl<D> + ?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::<BTreeSet<_>>();
let s2 = w.iter().collect::<BTreeSet<_>>();
s1.cmp(&s2)
}
CompoundClass::Dictionary => {
let d1 = v.entries().collect::<BTreeMap<_, _>>();
let d2 = w.entries().collect::<BTreeMap<_, _>>();
d1.cmp(&d2)
}
},
ValueClass::Embedded => v.as_embedded().unwrap().cmp(&w.as_embedded().unwrap()),
})
}
pub fn value_deepcopy<D: Domain>(v: &Value<D>) -> Value<D>
{
value_deepcopy_via(v, &mut |d| Result::<_,()>::Ok(Value::new(Embedded::new(d.clone())))).unwrap()
}
pub fn value_deepcopy_via<D: Domain, E: Domain, F, R: Into<Value<E>>, Err>(v: &Value<D>, f: &mut F) -> Result<Value<E>, Err>
where
F: FnMut(&D) -> Result<R, Err>
{
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::<Result<Vec<_>, _>>()?)),
CompoundClass::Sequence => Value::new(
v.iter().map(|w| value_deepcopy_via(&w, f)).collect::<Result<Vec<_>, _>>()?),
CompoundClass::Set => Value::new(
v.iter().map(|w| value_deepcopy_via(&w, f)).collect::<Result<Set<_>, _>>()?),
CompoundClass::Dictionary => Value::new(
v.entries().map(|(k,w)| Ok((value_deepcopy_via(&k, f)?,
value_deepcopy_via(&w, f)?)))
.collect::<Result<Map<_, _>, _>>()?),
}),
ValueClass::Embedded => f(v.as_embedded().unwrap().as_ref()).map(|r| r.into()),
}
}
pub fn value_map_embedded<D: Domain, E: Domain, F, Err>(v: &Value<D>, f: &mut F) -> Result<Value<E>, Err>
where
F: FnMut(&D) -> Result<E, Err>
{
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<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)
}
}
};
}
impl_value_methods!({ D: Domain }, dyn ValueImpl<D>);
impl_value_methods!({ D: Domain }, Value<D>);