From 4070c5252db9a6dfa830a95ea89a9a9ddc889185 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Fri, 18 Nov 2022 15:21:33 +0100 Subject: [PATCH] More WIP; Handles --- implementations/rust/preserves/src/domain.rs | 7 +- implementations/rust/preserves/src/error.rs | 6 + implementations/rust/preserves/src/lib.rs | 69 +- .../rust/preserves/src/packed/mod.rs | 17 +- .../rust/preserves/src/packed/reader.rs | 15 +- .../rust/preserves/src/packed/view.rs | 136 +-- implementations/rust/preserves/src/reader.rs | 242 +++-- implementations/rust/preserves/src/repr.rs | 932 ++++-------------- implementations/rust/preserves/src/shell.rs | 714 ++++++++++++++ implementations/rust/preserves/src/writer.rs | 17 +- 10 files changed, 1159 insertions(+), 996 deletions(-) create mode 100644 implementations/rust/preserves/src/shell.rs diff --git a/implementations/rust/preserves/src/domain.rs b/implementations/rust/preserves/src/domain.rs index cb1166b..8a96bda 100644 --- a/implementations/rust/preserves/src/domain.rs +++ b/implementations/rust/preserves/src/domain.rs @@ -118,18 +118,13 @@ impl DomainEncode for NoEmbeddedDomainCodec { #[derive(Default)] pub struct IOValueDomainCodec; -impl Domain for IOValue { - type Decode = IOValueDomainCodec; - type Encode = IOValueDomainCodec; -} - impl DomainDecode for IOValueDomainCodec { fn decode_embedded<'de, R: Reader<'de> + ?Sized>( &mut self, r: &mut R, read_annotations: bool, ) -> io::Result { - Ok(r.next_iovalue(read_annotations)?) + Ok(read_iovalue(r, read_annotations)?) } } diff --git a/implementations/rust/preserves/src/error.rs b/implementations/rust/preserves/src/error.rs index ef09674..c869848 100644 --- a/implementations/rust/preserves/src/error.rs +++ b/implementations/rust/preserves/src/error.rs @@ -36,6 +36,12 @@ pub enum ExpectedKind { Annotation, } +impl From for Error { + fn from(e: ExpectedKind) -> Self { + Error::Expected(e) + } +} + impl From for Error { fn from(e: io::Error) -> Self { Error::Io(e) diff --git a/implementations/rust/preserves/src/lib.rs b/implementations/rust/preserves/src/lib.rs index b9dfa4d..55371ea 100644 --- a/implementations/rust/preserves/src/lib.rs +++ b/implementations/rust/preserves/src/lib.rs @@ -4,9 +4,10 @@ pub mod error; pub mod float; pub mod hex; pub mod merge; -// pub mod packed; +pub mod packed; pub mod reader; pub mod repr; +pub mod shell; pub mod signed_integer; pub mod source; // pub mod text; @@ -18,24 +19,28 @@ pub use error::Error; pub use error::ExpectedKind; pub use merge::merge; pub use merge::merge2; -// pub use packed::PackedReader; -// pub use packed::PackedWriter; -// pub use packed::annotated_from_bytes; -// pub use packed::annotated_iovalue_from_bytes; -// pub use packed::from_bytes; -// pub use packed::iovalue_from_bytes; +pub use packed::PackedReader; +pub use packed::PackedWriter; +pub use packed::annotated_from_bytes; +pub use packed::annotated_iovalue_from_bytes; +pub use packed::from_bytes; +pub use packed::iovalue_from_bytes; pub use reader::IOValues; pub use reader::Reader; -pub use repr::Annotations; -pub use repr::ArcValue; -pub use repr::Atom; -pub use repr::IOValue; -pub use repr::Map; -pub use repr::NoValue; -pub use repr::Record; -pub use repr::Set; -pub use repr::Value; +pub use reader::read; +pub use reader::read_iovalue; pub use repr::ValueImpl; +pub use repr::value_eq; +pub use repr::value_cmp; +pub use repr::value_hash; +pub use shell::Annotations; +pub use shell::Atom; +pub use shell::IOValue; +pub use shell::Map; +pub use shell::Record; +pub use shell::Set; +pub use shell::Shell; +pub use shell::ShellHandle; pub use signed_integer::SignedInteger; pub use source::BinarySource; pub use source::BytesBinarySource; @@ -136,8 +141,8 @@ mod test_domain { r: &mut R, _read_annotations: bool, ) -> io::Result { - let v = r.next_iovalue(false)?; - if v.as_bytestring().is_some() { + let v = read_iovalue(r, false)?; + if v.value().as_bytestring().is_some() { Ok(Dom::One) } else { Ok(Dom::Two) @@ -152,32 +157,34 @@ mod test_domain { d: &Dom, ) -> io::Result<()> { match d { - Dom::One => Bytes::new(vec![255, 255, 255, 255]).write(w, self), - Dom::Two => Symbol::new(&format!("Dom::{:?}", d)).write(w, self), + Dom::One => Shell::from(vec![255, 255, 255, 255]).write(w, self), + Dom::Two => Shell::symbol(&format!("Dom::{:?}", d)).write(w, self), } } } - fn dom_as_preserves(v: &Dom) -> io::Result> { + fn dom_as_preserves(v: &Dom) -> io::Result { Ok(match v { - Dom::One => owned(Bytes::new(vec![255, 255, 255, 255])), - Dom::Two => owned(Symbol::new(format!("Dom::{:?}", v))), + Dom::One => IOValue::from(vec![255, 255, 255, 255]), + Dom::Two => IOValueImpl::symbol(format!("Dom::{:?}", v)).into(), }) } #[test] fn test_one() { - let v = owned(vec![owned(1), - owned(Embedded::new(Dom::One)), - owned(2)]); - assert_eq!(PackedWriter::encode_iovalue(&iovalue(copy_via(&v, &mut dom_as_preserves).unwrap())).unwrap(), + let v = Shell::::from( + vec![SignedInteger::from(1).into(), + Shell::embedded(Dom::One), + SignedInteger::from(2).into()]).wrap(); + assert_eq!(PackedWriter::encode_iovalue(&IOValue::copy::, _, _>(&v, &mut dom_as_preserves).unwrap()).unwrap(), [0xb5, 0x91, 0xb2, 0x04, 255, 255, 255, 255, 0x92, 0x84]); } #[test] fn test_two() { - let v = owned(vec![owned(1), - owned(Embedded::new(Dom::Two)), - owned(2)]); - assert_eq!(PackedWriter::encode_iovalue(&iovalue(copy_via(&v, &mut dom_as_preserves).unwrap())).unwrap(), + let v = Shell::::from( + vec![SignedInteger::from(1).into(), + Shell::embedded(Dom::Two), + SignedInteger::from(2).into()]).wrap(); + assert_eq!(PackedWriter::encode_iovalue(&IOValue::copy::, _, _>(&v, &mut dom_as_preserves).unwrap()).unwrap(), [0xb5, 0x91, 0xb3, 0x08, 68, 111, 109, 58, 58, 84, 119, 111, 0x92, 0x84]); } } diff --git a/implementations/rust/preserves/src/packed/mod.rs b/implementations/rust/preserves/src/packed/mod.rs index 566519a..a34c97d 100644 --- a/implementations/rust/preserves/src/packed/mod.rs +++ b/implementations/rust/preserves/src/packed/mod.rs @@ -1,6 +1,6 @@ pub mod constants; pub mod reader; -// pub mod view; +pub mod view; pub mod writer; pub use reader::PackedReader; @@ -13,14 +13,15 @@ use crate::BytesBinarySource; use crate::Domain; use crate::DomainDecode; use crate::IOValue; -use crate::PlainValue; -use crate::Reader; +use crate::ShellHandle; +use crate::read; +use crate::read_iovalue; pub fn from_bytes<'de, D: Domain, Dec: DomainDecode>( bs: &'de [u8], decode_embedded: &mut Dec, -) -> io::Result> { - BytesBinarySource::new(bs).packed().next(false, decode_embedded) +) -> io::Result> { + read(&mut BytesBinarySource::new(bs).packed(), false, decode_embedded) } pub fn iovalue_from_bytes(bs: &[u8]) -> io::Result { @@ -30,10 +31,10 @@ pub fn iovalue_from_bytes(bs: &[u8]) -> io::Result { pub fn annotated_from_bytes<'de, D: Domain, Dec: DomainDecode>( bs: &'de [u8], decode_embedded: &mut Dec, -) -> io::Result> { - super::BytesBinarySource::new(bs).packed().next(true, decode_embedded) +) -> io::Result> { + read(&mut super::BytesBinarySource::new(bs).packed(), true, decode_embedded) } pub fn annotated_iovalue_from_bytes(bs: &[u8]) -> io::Result { - super::BytesBinarySource::new(bs).packed().next_iovalue(true) + read_iovalue(&mut super::BytesBinarySource::new(bs).packed(), true) } diff --git a/implementations/rust/preserves/src/packed/reader.rs b/implementations/rust/preserves/src/packed/reader.rs index 92ce005..629a025 100644 --- a/implementations/rust/preserves/src/packed/reader.rs +++ b/implementations/rust/preserves/src/packed/reader.rs @@ -300,11 +300,12 @@ impl<'de, S: BinarySource<'de>> Reader<'de> for PackedReader<'de, S> { self.readbytes_into(&mut bs)?; Ok(Atom::Double(f64::from_bits(u64::from_be_bytes(bs)))) } - Tag::SmallInteger(v) => Ok(Atom::SignedInteger(v.into())), - Tag::MediumInteger(count) => Ok(Atom::SignedInteger(self.read_signed_integer(count.into())?)), + Tag::SmallInteger(v) => Ok(Atom::SignedInteger(Cow::Owned(v.into()))), + Tag::MediumInteger(count) => Ok(Atom::SignedInteger(Cow::Owned( + self.read_signed_integer(count.into())?))), Tag::SignedInteger => { let count = self.varint()?; - Ok(Atom::SignedInteger(self.read_signed_integer(count)?)) + Ok(Atom::SignedInteger(Cow::Owned(self.read_signed_integer(count)?))) } Tag::String => { let count = self.varint()?; @@ -383,21 +384,21 @@ impl<'de, S: BinarySource<'de>> Reader<'de> for PackedReader<'de, S> { } } - fn next_signedinteger(&mut self) -> ReaderResult { + fn next_signedinteger(&mut self) -> ReaderResult> { let tag = self.peek_next_nonannotation_tag()?; match tag { Tag::SmallInteger(v) => { self.skip()?; - Ok(SignedInteger::from(v as i32)) + Ok(Cow::Owned(SignedInteger::from(v as i32))) } Tag::MediumInteger(count) => { self.skip()?; - Ok(self.read_signed_integer(count.into())?) + Ok(Cow::Owned(self.read_signed_integer(count.into())?)) } Tag::SignedInteger => { self.skip()?; let count = self.varint()?; - Ok(self.read_signed_integer(count)?) + Ok(Cow::Owned(self.read_signed_integer(count)?)) } _ => Err(error::Error::Expected(ExpectedKind::SignedInteger)) } diff --git a/implementations/rust/preserves/src/packed/view.rs b/implementations/rust/preserves/src/packed/view.rs index c36b124..9f6c14a 100644 --- a/implementations/rust/preserves/src/packed/view.rs +++ b/implementations/rust/preserves/src/packed/view.rs @@ -14,33 +14,27 @@ use crate::DomainDecode; use crate::IOValue; use crate::NoEmbeddedDomainCodec; use crate::PackedWriter; -use crate::PlainValue; use crate::SignedInteger; -use crate::Value; use crate::ValueClass; use crate::ValueImpl; use crate::error; use crate::error::io_eof; -use crate::iovalue; -use crate::owned; -use crate::shell; use crate::reader::NextToken; use super::constants::Tag; -#[derive(Debug, Clone)] +#[derive(Debug)] struct Index { embedded: Option, D)]>>, } -#[derive(Debug, Clone)] +#[derive(Debug)] struct IndexedRepr<'de, Packed: AsRef<[u8]> + 'de, D> { packed: Packed, index: Index, phantom: PhantomData<&'de ()>, } -#[derive(Debug, Clone)] pub struct View<'de, Packed: AsRef<[u8]> + 'de, D: Domain> { repr: Arc>, annotation_offset: usize, @@ -194,6 +188,15 @@ impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> View<'de, Packed, D> { Self::new_offset(packed, dec, 0) } + pub fn trim(&self) -> View<'static, Box<[u8]>, D> { + View { + repr: self.repr.trim(self.annotation_offset .. self.value_range.end), + annotation_offset: 0, + value_range: (self.value_range.start - self.annotation_offset + .. self.value_range.end - self.annotation_offset), + } + } + pub fn new_offset>(packed: Packed, dec: Option<&mut Dec>, offset: usize) -> io::Result { let mut indexer = Indexer { packed: packed.as_ref(), @@ -289,7 +292,27 @@ impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> View<'de, Packed, D> { } } -impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> ValueImpl for View<'de, Packed, D> { +impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> Clone for View<'de, Packed, D> { + fn clone(&self) -> Self { + View { + repr: self.repr.clone(), + annotation_offset: self.annotation_offset, + value_range: self.value_range.clone() + } + } +} + +impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> ValueImpl for View<'de, Packed, D> { + type Handle = Self; + type Embedded = D; + type Mapped = View<'de, Packed, E>; + type Items<'a> = ViewIterator> where Self: 'a; + type Entries<'a> = DictionaryAdapter> where Self: 'a; + + fn wrap(self) -> Self::Handle { + self + } + fn write(&self, w: &mut dyn crate::Writer, enc: &mut dyn crate::DomainEncode) -> io::Result<()> { match w.specialized() { Some(("packed", mut w)) => { @@ -310,15 +333,6 @@ impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> ValueImpl for View<'de, Packe } } - fn value_clone(&self) -> PlainValue<'static, D> { - owned(View { - repr: self.repr.trim(self.annotation_offset .. self.value_range.end), - annotation_offset: 0, - value_range: (self.value_range.start - self.annotation_offset - .. self.value_range.end - self.annotation_offset), - }) - } - fn value_class(&self) -> ValueClass { match self.tag().into() { Some(NextToken::Annotation) | None => unreachable!(), @@ -348,22 +362,13 @@ impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> ValueImpl for View<'de, Packe } } - fn is_signed_integer(&self) -> bool { + fn as_signed_integer(&self) -> Option> { match self.tag() { - Tag::SmallInteger(_) => true, - Tag::MediumInteger(_) => true, - Tag::SignedInteger => true, - _ => false, - } - } - - fn as_signed_integer(&self) -> Option { - match self.tag() { - Tag::SmallInteger(v) => Some(v.into()), - Tag::MediumInteger(n) => Some(self.signed_integer(self.value_range.start + 1, n as usize)), + Tag::SmallInteger(v) => Some(Cow::Owned(v.into())), + Tag::MediumInteger(n) => Some(Cow::Owned(self.signed_integer(self.value_range.start + 1, n as usize))), Tag::SignedInteger => { let (n, i) = self.varint(); - Some(self.signed_integer(i, n as usize)) + Some(Cow::Owned(self.signed_integer(i, n as usize))) } _ => None, } @@ -400,9 +405,9 @@ impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> ValueImpl for View<'de, Packe self.tag() == Tag::Record } - fn label(&self) -> Value<'_, D> { + fn label(&self) -> Self::Handle { if !self.is_record() { panic!("Not a record") } - shell(View::inner_new(&self.repr, self.value_range.start + 1).unwrap()) + View::inner_new(&self.repr, self.value_range.start + 1).unwrap() } fn is_sequence(&self) -> bool { @@ -417,12 +422,12 @@ impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> ValueImpl for View<'de, Packe } } - fn index(&self, i: usize) -> Value<'_, D> { + fn index(&self, i: usize) -> Self::Handle { self.iter().nth(i).unwrap() } - fn iter(&self) -> Box> + '_> { - let mut i = Box::new(ViewIterator::inner_new(&self.repr, self.value_range.start + 1)); + fn iter(&self) -> Self::Items<'_> { + let mut i = ViewIterator::inner_new(&self.repr, self.value_range.start + 1); match self.tag() { Tag::Record => { i.next(); () } Tag::Sequence => (), @@ -436,7 +441,7 @@ impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> ValueImpl for View<'de, Packe self.tag() == Tag::Set } - fn has(&self, v: &dyn ValueImpl) -> bool { + fn has>(&self, v: &E::Handle) -> bool { self.iter().find(|e| v == &**e).is_some() } @@ -444,36 +449,32 @@ impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> ValueImpl for View<'de, Packe self.tag() == Tag::Dictionary } - fn get(&self, k: &dyn ValueImpl) -> Option> { + fn get>(&self, k: &K::Handle) -> Option { for (kk, vv) in self.entries() { if &*kk == k { return Some(vv); } } None } - fn entries(&self) -> Box, Value<'_, D>)> + '_> { + fn entries(&self) -> Self::Entries<'_> { if !self.is_dictionary() { panic!("Not a dictionary") } - Box::new(DictionaryAdapter(ViewIterator::inner_new(&self.repr, self.value_range.start + 1))) + DictionaryAdapter(ViewIterator::inner_new(&self.repr, self.value_range.start + 1)) } - fn is_embedded(&self) -> bool { - self.tag() == Tag::Embedded - } - - fn embedded(&self) -> Cow<'_, D> { - if !self.is_embedded() { panic!("Not an embedded value") } + fn as_embedded(&self) -> Option> { + if self.tag() != Tag::Embedded { return None } match self.repr.index.embedded.as_ref() { Some(e) => { - Cow::Borrowed(e.iter().find_map(|(r, d)| { + Some(Cow::Borrowed(e.iter().find_map(|(r, d)| { if r.start == self.value_range.start { Some(d) } else { None } - }).unwrap()) + }).unwrap())) } None => { let mut r = BytesBinarySource::new( &self.repr.packed.as_ref()[self.value_range.start + 1 .. self.value_range.end]) .into_packed(); let d = D::Decode::default().decode_embedded(&mut r, true).unwrap(); - Cow::Owned(d) + Some(Cow::Owned(d)) } } } @@ -484,17 +485,38 @@ impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> ValueImpl for View<'de, Packe } else { let repr = Arc::new(IndexedRepr { packed: self.repr.packed.as_ref(), - index: Index { embedded: None }, + index: Index:: { embedded: None }, phantom: PhantomData, }); let anns: Vec = AnnotationAdapter(ViewIterator::inner_new(&repr, self.annotation_offset)) - .map(|ann| iovalue(ann.into_owned())) .collect(); Some(Cow::Owned(anns)) } } + + fn peeled(v: &Self::Handle) -> Self::Handle { + View { + repr: v.repr.clone(), + annotation_offset: v.value_range.start, + value_range: v.value_range, + } + } + + fn copy(w: &E::Handle, f: &mut F) -> Result + where + F: FnMut(&E::Embedded) -> Result { + todo!() + } + + fn map_embedded(v: &Self::Handle, f: &mut F) -> Result< as ValueImpl>::Handle, Err> + where + F: FnMut(&Self::Embedded) -> Result { + todo!() + } } +crate::impl_value_methods!({'de, Packed: AsRef<[u8]> + 'de, D: Domain}, View<'de, Packed, D>); + pub struct ViewStream<'de, 'dec, D: Domain, Dec: DomainDecode = ::Decode> { buf: &'de [u8], dec: Option<&'dec mut Dec>, @@ -514,7 +536,7 @@ impl<'de, 'dec, D: Domain, Dec: DomainDecode> ViewStream<'de, 'dec, D, Dec> { } impl<'de, 'dec, D: Domain, Dec: DomainDecode> Iterator for ViewStream<'de, 'dec, D, Dec> { - type Item = io::Result>; + type Item = io::Result>; fn next(&mut self) -> Option { if self.offset >= self.buf.len() { @@ -523,7 +545,7 @@ impl<'de, 'dec, D: Domain, Dec: DomainDecode> Iterator for ViewStream<'de, 'd match View::new_offset(self.buf, self.dec.as_mut().map(|dec| &mut *dec), self.offset) { Ok(v) => { self.offset = v.value_range.end; - Some(Ok(shell(v))) + Some(Ok(v)) } Err(e) => Some(Err(e)), } @@ -543,7 +565,7 @@ impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> ViewIterator + 'de, D: Domain> Iterator for ViewIterator> { - type Item = Value<'de, D>; + type Item = View<'de, Packed, D>; fn next(&mut self) -> Option { if let Ok(Tag::End) = tag_at(self.repr.packed.as_ref(), self.offset) { @@ -551,7 +573,7 @@ impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> Iterator for ViewIterator + 'de, D: Domain> Iterator for ViewIterator(pub ViewIterator); impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> Iterator for DictionaryAdapter> { - type Item = (Value<'de, D>, Value<'de, D>); + type Item = (View<'de, Packed, D>, View<'de, Packed, D>); fn next(&mut self) -> Option { let k = self.0.next()?; @@ -571,7 +593,7 @@ impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> Iterator for DictionaryAdapter(pub ViewIterator); impl<'de, Packed: AsRef<[u8]> + 'de, D: Domain> Iterator for AnnotationAdapter> { - type Item = Value<'de, D>; + type Item = View<'de, Packed, D>; fn next(&mut self) -> Option { if let Ok(Tag::Annotation) = tag_at(self.0.repr.packed.as_ref(), self.0.offset) { diff --git a/implementations/rust/preserves/src/reader.rs b/implementations/rust/preserves/src/reader.rs index a061305..350ec33 100644 --- a/implementations/rust/preserves/src/reader.rs +++ b/implementations/rust/preserves/src/reader.rs @@ -5,9 +5,11 @@ use std::marker::PhantomData; use crate::BinarySource; use crate::CompoundClass; -use crate::PlainValue; +use crate::Shell; +use crate::ShellHandle; use crate::SignedInteger; use crate::ValueClass; +use crate::ValueImpl; use crate::boundary as B; use crate::domain::Domain; use crate::domain::DomainDecode; @@ -17,13 +19,10 @@ use crate::error::ExpectedKind; use crate::error::io_eof; use crate::repr::Annotations; use crate::repr::Atom; -use crate::repr::Embedded; use crate::repr::IOValue; use crate::repr::Map; use crate::repr::Record; use crate::repr::Set; -use crate::repr::ValueImpl; -use crate::repr::owned; pub type ReaderResult = std::result::Result; @@ -129,132 +128,24 @@ pub trait Reader<'de> { } } - fn gather_annotations(&mut self) -> io::Result, ValueClass)>> { - let mut anns = Vec::new(); - loop { - match self.peek_class()? { - None => return Ok(None), - Some(NextToken::Value(v)) => return Ok(Some((anns, v))), - Some(NextToken::Annotation) => { - self.open_annotation()?; - anns.push(self.next_iovalue(true)?); - self.close_annotation()?; - } - } - } - } + fn next_boolean(&mut self) -> ReaderResult { Ok(self.next_atom()?.try_into()?)} + fn next_float(&mut self) -> ReaderResult { Ok(self.next_atom()?.try_into()?)} + fn next_double(&mut self) -> ReaderResult { Ok(self.next_atom()?.try_into()?)} + fn next_signedinteger(&mut self) -> ReaderResult> { Ok(self.next_atom()?.try_into()?) } + fn next_str(&mut self) -> ReaderResult> { Ok(self.next_atom()?.try_into()?) } + fn next_bytestring(&mut self) -> ReaderResult> { Ok(self.next_atom()?.try_into()?) } + fn next_symbol(&mut self) -> ReaderResult> { Ok(self.next_atom()?.try_into_symbol()?) } - fn next<'produced: 'de, D: Domain, Dec: DomainDecode>( - &mut self, - read_annotations: bool, - dec: &mut Dec, - ) -> io::Result> - { - let (anns, v) = match read_annotations { - true => self.gather_annotations()?.ok_or_else(io_eof)?, - false => (Vec::new(), self.skip_annotations()?.ok_or_else(io_eof)?), - }; - let value = match v { - ValueClass::Atomic(_) => - self.next_atom()?.into_value(), - ValueClass::Embedded => { - self.open_embedded()?; - let v = dec.decode_embedded(self, read_annotations)?; - self.close_embedded()?; - Box::new(Embedded::new(v)) - } - ValueClass::Compound(CompoundClass::Record) => { - let mut vs = Vec::new(); - self.open_record()?; - let mut b = B::start(B::Item::RecordLabel); - self.boundary(&b)?; - vs.push(self.next(read_annotations, dec)?); - while !self.close_compound(&mut b, &B::Item::RecordField)? { - vs.push(self.next(read_annotations, dec)?); - } - Box::new(Record::_from_vec(vs)) - } - ValueClass::Compound(CompoundClass::Sequence) => { - let mut vs = Vec::new(); - self.open_sequence()?; - let mut b = B::Type::default(); - while !self.close_compound(&mut b, &B::Item::SequenceValue)? { - vs.push(self.next(read_annotations, dec)?); - } - Box::new(vs) - } - ValueClass::Compound(CompoundClass::Set) => { - let mut s = Set::new(); - self.open_set()?; - let mut b = B::Type::default(); - while !self.close_compound(&mut b, &B::Item::SetValue)? { - s.insert(self.next(read_annotations, dec)?); - } - Box::new(s) - } - ValueClass::Compound(CompoundClass::Dictionary) => { - let mut d = Map::new(); - self.open_dictionary()?; - let mut b = B::Type::default(); - while !self.close_compound(&mut b, &B::Item::DictionaryKey)? { - let k = self.next(read_annotations, dec)?; - b.shift(Some(B::Item::DictionaryValue)); - self.boundary(&b)?; - d.insert(k, self.next(read_annotations, dec)?); - } - Box::new(d) - } - }; - if anns.is_empty() { - Ok(value) - } else { - Ok(owned(Annotations::new(value, anns))) - } - } - - fn next_iovalue(&mut self, read_annotations: bool) -> io::Result - { - Ok(self.next(read_annotations, &mut IOValueDomainCodec)?.into()) - } - - fn next_boolean(&mut self) -> ReaderResult { - self.next_iovalue(false)?.as_boolean().ok_or(Error::Expected(ExpectedKind::Boolean)) - } - - fn next_float(&mut self) -> ReaderResult { - self.next_iovalue(false)?.as_float().ok_or(Error::Expected(ExpectedKind::Float)) - } - - fn next_double(&mut self) -> ReaderResult { - self.next_iovalue(false)?.as_double().ok_or(Error::Expected(ExpectedKind::Double)) - } - - fn next_signedinteger(&mut self) -> ReaderResult { - self.next_iovalue(false)?.as_signed_integer().ok_or(Error::Expected(ExpectedKind::SignedInteger)) - } - - fn next_i8(&mut self) -> ReaderResult { Ok(i8::try_from(&self.next_signedinteger()?)?) } - fn next_u8(&mut self) -> ReaderResult { Ok(u8::try_from(&self.next_signedinteger()?)?) } - fn next_i16(&mut self) -> ReaderResult { Ok(i16::try_from(&self.next_signedinteger()?)?) } - fn next_u16(&mut self) -> ReaderResult { Ok(u16::try_from(&self.next_signedinteger()?)?) } - fn next_i32(&mut self) -> ReaderResult { Ok(i32::try_from(&self.next_signedinteger()?)?) } - fn next_u32(&mut self) -> ReaderResult { Ok(u32::try_from(&self.next_signedinteger()?)?) } - fn next_i64(&mut self) -> ReaderResult { Ok(i64::try_from(&self.next_signedinteger()?)?) } - fn next_u64(&mut self) -> ReaderResult { Ok(u64::try_from(&self.next_signedinteger()?)?) } - fn next_i128(&mut self) -> ReaderResult { Ok(i128::try_from(&self.next_signedinteger()?)?) } - fn next_u128(&mut self) -> ReaderResult { Ok(u128::try_from(&self.next_signedinteger()?)?) } - - fn next_str(&mut self) -> ReaderResult> { - Ok(self.next_iovalue(false)?.as_string().ok_or(Error::Expected(ExpectedKind::String))?.into_owned().into()) - } - - fn next_bytestring(&mut self) -> ReaderResult> { - Ok(self.next_iovalue(false)?.as_bytestring().ok_or(Error::Expected(ExpectedKind::ByteString))?.into_owned().into()) - } - - fn next_symbol(&mut self) -> ReaderResult> { - Ok(self.next_iovalue(false)?.as_symbol().ok_or(Error::Expected(ExpectedKind::Symbol))?.into_owned().into()) - } + fn next_i8(&mut self) -> ReaderResult { Ok(i8::try_from(self.next_signedinteger()?.as_ref())?) } + fn next_u8(&mut self) -> ReaderResult { Ok(u8::try_from(self.next_signedinteger()?.as_ref())?) } + fn next_i16(&mut self) -> ReaderResult { Ok(i16::try_from(self.next_signedinteger()?.as_ref())?) } + fn next_u16(&mut self) -> ReaderResult { Ok(u16::try_from(self.next_signedinteger()?.as_ref())?) } + fn next_i32(&mut self) -> ReaderResult { Ok(i32::try_from(self.next_signedinteger()?.as_ref())?) } + fn next_u32(&mut self) -> ReaderResult { Ok(u32::try_from(self.next_signedinteger()?.as_ref())?) } + fn next_i64(&mut self) -> ReaderResult { Ok(i64::try_from(self.next_signedinteger()?.as_ref())?) } + fn next_u64(&mut self) -> ReaderResult { Ok(u64::try_from(self.next_signedinteger()?.as_ref())?) } + fn next_i128(&mut self) -> ReaderResult { Ok(i128::try_from(self.next_signedinteger()?.as_ref())?) } + fn next_u128(&mut self) -> ReaderResult { Ok(u128::try_from(self.next_signedinteger()?.as_ref())?) } fn open_simple_record(&mut self, name: &str) -> ReaderResult { @@ -288,6 +179,97 @@ pub trait Reader<'de> { fn specialized(&mut self) -> Option<(&str, &mut dyn BinarySource<'de>)> { None } } +pub fn gather_annotations<'de, R: Reader<'de> + ?Sized>( + r: &mut R, +) -> io::Result, 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(read_iovalue(r, true)?); + r.close_annotation()?; + } + } + } +} + +pub fn read<'produced, 'de, R: Reader<'de> + ?Sized, D: Domain, Dec: DomainDecode>( + r: &mut R, + read_annotations: bool, + dec: &mut Dec, +) -> io::Result> { + let (anns, v) = match read_annotations { + true => gather_annotations(r)?.ok_or_else(io_eof)?, + false => (Vec::new(), r.skip_annotations()?.ok_or_else(io_eof)?), + }; + let value = match v { + ValueClass::Atomic(_) => + Shell::Atom(r.next_atom()?), + ValueClass::Embedded => { + r.open_embedded()?; + let v = dec.decode_embedded(r, read_annotations)?; + r.close_embedded()?; + Shell::Embedded(v) + } + ValueClass::Compound(CompoundClass::Record) => { + let mut vs = Vec::new(); + r.open_record()?; + let mut b = B::start(B::Item::RecordLabel); + r.boundary(&b)?; + vs.push(read(r, read_annotations, dec)?); + while !r.close_compound(&mut b, &B::Item::RecordField)? { + vs.push(read(r, read_annotations, dec)?); + } + Shell::Record(Record::_from_vec(vs)) + } + ValueClass::Compound(CompoundClass::Sequence) => { + let mut vs = Vec::new(); + r.open_sequence()?; + let mut b = B::Type::default(); + while !r.close_compound(&mut b, &B::Item::SequenceValue)? { + vs.push(read(r, read_annotations, dec)?); + } + Shell::Sequence(vs) + } + ValueClass::Compound(CompoundClass::Set) => { + let mut s = Set::new(); + r.open_set()?; + let mut b = B::Type::default(); + while !r.close_compound(&mut b, &B::Item::SetValue)? { + s.insert(read(r, read_annotations, dec)?); + } + Shell::Set(s) + } + ValueClass::Compound(CompoundClass::Dictionary) => { + let mut d = Map::new(); + r.open_dictionary()?; + let mut b = B::Type::default(); + while !r.close_compound(&mut b, &B::Item::DictionaryKey)? { + let k = read(r, read_annotations, dec)?; + b.shift(Some(B::Item::DictionaryValue)); + r.boundary(&b)?; + d.insert(k, read(r, read_annotations, dec)?); + } + Shell::Dictionary(d) + } + }; + if anns.is_empty() { + Ok(value.wrap()) + } else { + Ok(Shell::Annotated(Annotations::new(value.wrap(), anns)).wrap()) + } +} + +pub fn read_iovalue<'de, R: Reader<'de> + ?Sized>( + r: &mut R, + read_annotations: bool, +) -> io::Result { + Ok(read(r, read_annotations, &mut IOValueDomainCodec)?.into()) +} + pub struct IOValues<'de, R: Reader<'de>> { pub reader: R, pub read_annotations: bool, @@ -315,7 +297,7 @@ impl<'de, R: Reader<'de>> std::iter::Iterator for IOValues<'de, R> { match self.reader.peek_class() { Err(e) => Some(Err(e)), Ok(None) => None, - Ok(Some(_)) => Some(self.reader.next_iovalue(self.read_annotations)), + Ok(Some(_)) => Some(read_iovalue(&mut self.reader, self.read_annotations)), } } } diff --git a/implementations/rust/preserves/src/repr.rs b/implementations/rust/preserves/src/repr.rs index 3255c7f..50c38e5 100644 --- a/implementations/rust/preserves/src/repr.rs +++ b/implementations/rust/preserves/src/repr.rs @@ -1,38 +1,34 @@ +use std::borrow::Borrow; use std::borrow::Cow; use std::cmp::Ordering; -use std::fmt::Debug; -use std::hash::{Hash, Hasher}; +use std::collections::BTreeMap; +use std::collections::BTreeSet; +use std::hash::Hash; +use std::hash::Hasher; use std::io; -use std::marker::PhantomData; -use std::ops::Deref; -use std::str::FromStr; -use std::sync::Arc; -use std::vec::Vec; - -pub use std::collections::BTreeSet as Set; -pub use std::collections::BTreeMap as Map; use crate::signed_integer::OutOfRange; -use crate::{AtomClass, TextWriter, DefaultDomainCodec, write_value}; +use crate::AtomClass; use crate::CompoundClass; use crate::Domain; +use crate::DomainEncode; use crate::SignedInteger; use crate::ValueClass; use crate::Writer; -use crate::boundary as B; -use crate::domain::{NoEmbeddedDomainCodec, DomainEncode, IOValueDomainCodec}; +use crate::write_value; use super::float::{eq_f32, eq_f64, cmp_f32, cmp_f64}; -#[repr(transparent)] -pub struct Value(pub V); - /// Atomic values from the specification. pub trait ValueImpl: Sized { + type Handle: Borrow + Clone + From + Hash + Eq + Ord + PartialEq + PartialOrd; type Embedded: Domain; type Mapped: ValueImpl; - type Items<'a>: Iterator> + 'a where Self: 'a; - type Entries<'a>: Iterator, &'a Value)> + 'a where Self: 'a; + type Items<'a>: Iterator + 'a where Self: 'a; + type Entries<'a>: Iterator + 'a where Self: 'a; + type IOValueImpl: ValueImpl::Handle>; + + fn wrap(self) -> Self::Handle; fn write(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode) -> io::Result<()> { write_value(w, self, enc) @@ -62,778 +58,216 @@ pub trait ValueImpl: Sized { fn as_usize(&self) -> Option> { self.as_signed_integer().map(|i| (&*i).try_into()) } fn is_record(&self) -> bool; - fn label(&self) -> Value; + fn label(&self) -> Self::Handle; fn is_sequence(&self) -> bool; fn len(&self) -> usize; - fn index(&self, _i: usize) -> Value; + fn index(&self, _i: usize) -> Self::Handle; fn iter(&self) -> Self::Items<'_>; fn is_set(&self) -> bool; - fn has>(&self, _v: &Value) -> bool; + fn has>(&self, _v: &E::Handle) -> bool; fn is_dictionary(&self) -> bool; - fn get>(&self, _k: &Value) -> Option>; + 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>; + fn annotations(&self) -> Option::Handle]>>; - fn peeled(&self) -> &Self; + fn peeled(v: &Self::Handle) -> Self::Handle; - fn copy(w: &Value, f: &mut F) -> Result, Err> + fn copy(w: &E::Handle, f: &mut F) -> Result where - F: FnMut(&E::Embedded) -> Result, Err>; + F: FnMut(&E::Embedded) -> Result; - fn map_embedded(&self, f: &mut F) -> Result>, Err> + fn map_embedded(v: &Self::Handle, f: &mut F) -> Result< as ValueImpl>::Handle, Err> where F: FnMut(&Self::Embedded) -> Result; } -impl Deref for Value { - type Target = V; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Clone for Value { - fn clone(&self) -> Self { - Value(self.0.clone()) - } -} - -impl Value { - pub fn copy(&self, f: &mut F) -> Result, Err> - where - F: FnMut(&V::Embedded) -> Result, Err> - { - W::copy(self, f) - } -} - -impl Debug for Value { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - TextWriter::fmt_value(f, &mut DefaultDomainCodec, self).map_err(|_| std::fmt::Error) - } -} - -impl, D: Domain + FromStr, V: ValueImpl> - FromStr for Value -{ - type Err = io::Error; - - fn from_str(s: &str) -> Result { - Ok(crate::annotated_from_str(s, &mut DefaultDomainCodec)?.value_clone()) - } -} - -impl Hash for Value { - fn hash(&self, state: &mut H) { - match self.value_class() { - ValueClass::Atomic(a) => match a { - AtomClass::Boolean => self.as_boolean().unwrap().hash(state), - AtomClass::Float => self.as_float().unwrap().to_bits().hash(state), - AtomClass::Double => self.as_double().unwrap().to_bits().hash(state), - AtomClass::SignedInteger => self.as_signed_integer().unwrap().hash(state), - AtomClass::String => self.as_string().unwrap().hash(state), - AtomClass::ByteString => self.as_bytestring().unwrap().hash(state), - AtomClass::Symbol => self.as_symbol().unwrap().hash(state), - } - ValueClass::Compound(c) => match c { - CompoundClass::Sequence | - CompoundClass::Set => { - state.write_usize(self.len()); - for v in self.iter() { v.hash(state) } - } - CompoundClass::Record => { - self.label().hash(state); - state.write_usize(self.len()); - for v in self.iter() { v.hash(state) } - } - CompoundClass::Dictionary => { - state.write_usize(self.len()); - for (k, v) in self.entries() { - k.hash(state); - v.hash(state); - } - } - } - ValueClass::Embedded => self.as_embedded().unwrap().hash(state), +pub fn value_hash(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), } - } -} - -impl PartialEq for Value { - fn eq(&self, other: &Self) -> bool { - let cls = self.value_class(); - if cls != other.value_class() { return false; } - match cls { - ValueClass::Atomic(a) => match a { - AtomClass::Boolean => - self.as_boolean().unwrap() == other.as_boolean().unwrap(), - AtomClass::Float => - eq_f32(self.as_float().unwrap(), other.as_float().unwrap()), - AtomClass::Double => - eq_f64(self.as_double().unwrap(), other.as_double().unwrap()), - AtomClass::SignedInteger => - self.as_signed_integer().unwrap() == other.as_signed_integer().unwrap(), - AtomClass::String => - self.as_string().unwrap() == other.as_string().unwrap(), - AtomClass::ByteString => - self.as_bytestring().unwrap() == other.as_bytestring().unwrap(), - AtomClass::Symbol => - self.as_symbol().unwrap() == other.as_symbol().unwrap(), + ValueClass::Compound(c) => match c { + CompoundClass::Sequence | + CompoundClass::Set => { + state.write_usize(v.len()); + for v in v.iter() { v.hash(state) } } - ValueClass::Compound(c) => match c { - CompoundClass::Record => { - if self.label() != other.label() { return false; } - self.iter().eq(other.iter()) - } - CompoundClass::Sequence => { - self.iter().eq(other.iter()) - } - CompoundClass::Set => { - let s1 = self.iter().collect::>(); - let s2 = other.iter().collect::>(); - s1 == s2 - } - CompoundClass::Dictionary => { - let d1 = self.entries().collect::>(); - let d2 = other.entries().collect::>(); - d1 == d2 + 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 => self.as_embedded().unwrap() == other.as_embedded().unwrap(), } + ValueClass::Embedded => v.as_embedded().unwrap().hash(state), } } -impl Ord for Value { - fn cmp(&self, other: &Self) -> Ordering { - let cls = self.value_class(); - cls.cmp(&other.value_class()).then_with(|| match cls { - ValueClass::Atomic(a) => match a { - AtomClass::Boolean => - self.as_boolean().cmp(&other.as_boolean()), - AtomClass::Float => - cmp_f32(self.as_float().unwrap(), other.as_float().unwrap()), - AtomClass::Double => - cmp_f64(self.as_double().unwrap(), other.as_double().unwrap()), - AtomClass::SignedInteger => - self.as_signed_integer().cmp(&other.as_signed_integer()), - AtomClass::String => - self.as_string().cmp(&other.as_string()), - AtomClass::ByteString => - self.as_bytestring().cmp(&other.as_bytestring()), - AtomClass::Symbol => - self.as_symbol().cmp(&other.as_symbol()), - }, - ValueClass::Compound(c) => match c { - CompoundClass::Record => - self.label().cmp(&other.label()).then_with( - || self.iter().cmp(other.iter())), - CompoundClass::Sequence => self.iter().cmp(other.iter()), - CompoundClass::Set => { - let s1 = self.iter().collect::>(); - let s2 = other.iter().collect::>(); - s1.cmp(&s2) - } - CompoundClass::Dictionary => { - let d1 = self.entries().collect::>(); - let d2 = other.entries().collect::>(); - d1.cmp(&d2) - } - }, - ValueClass::Embedded => self.as_embedded().unwrap().cmp(&other.as_embedded().unwrap()), - }) - } -} - -impl Eq for Value {} - -impl PartialOrd for Value { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -#[derive(Debug, Clone)] -pub enum Atom<'a> { - Boolean(bool), - Float(f32), - Double(f64), - SignedInteger(Cow<'a, SignedInteger>), - String(Cow<'a, str>), - ByteString(Cow<'a, [u8]>), - Symbol(Cow<'a, str>), -} - -impl<'a> Atom<'a> { - fn write(&self, w: &mut dyn Writer) -> io::Result<()> { - match self { - Atom::Boolean(b) => w.write_bool(*b), - Atom::Float(f) => w.write_f32(*f), - Atom::Double(d) => w.write_f64(*d), - Atom::SignedInteger(i) => w.write_signed_integer(i), - Atom::String(s) => w.write_string(s), - Atom::ByteString(bs) => w.write_bytes(bs), - Atom::Symbol(s) => w.write_symbol(s), - } - } - - fn symbol>>(v: W) -> Self { - Atom::Symbol(v.into()) - } -} - -impl<'r, 'a> From<&'r Atom<'a>> for AtomClass { - fn from(a: &'r Atom<'a>) -> Self { - match a { - Atom::Boolean(_) => AtomClass::Boolean, - Atom::Float(_) => AtomClass::Float, - Atom::Double(_) => AtomClass::Double, - Atom::SignedInteger(_) => AtomClass::SignedInteger, - Atom::String(_) => AtomClass::String, - Atom::ByteString(_) => AtomClass::ByteString, - Atom::Symbol(_) => AtomClass::Symbol, - } - } -} - -impl<'a> From for Atom<'a> { fn from(v: bool) -> Self { Atom::Boolean(v) } } -impl<'a> From for Atom<'a> { fn from(v: f32) -> Self { Atom::Float(v) } } -impl<'a> From for Atom<'a> { fn from(v: f64) -> Self { Atom::Double(v) } } -impl<'a> From<&'a SignedInteger> for Atom<'a> { fn from(v: &'a SignedInteger) -> Self { Atom::SignedInteger(Cow::Borrowed(v)) } } -impl<'a> From for Atom<'a> { fn from(v: SignedInteger) -> Self { Atom::SignedInteger(Cow::Owned(v)) } } -impl<'a> From<&'a str> for Atom<'a> { fn from(v: &'a str) -> Self { Atom::String(Cow::Borrowed(v)) } } -impl<'a> From for Atom<'a> { fn from(v: String) -> Self { Atom::String(Cow::Owned(v)) } } -impl<'a> From<&'a [u8]> for Atom<'a> { fn from(v: &'a [u8]) -> Self { Atom::ByteString(Cow::Borrowed(v)) } } -impl<'a> From> for Atom<'a> { fn from(v: Vec) -> Self { Atom::ByteString(Cow::Owned(v)) } } - -// #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -// pub enum NoValue {} - -// impl Domain for NoValue { -// type Decode = NoEmbeddedDomainCodec; -// type Encode = NoEmbeddedDomainCodec; -// } - -// impl FromStr for NoValue { -// type Err = io::Error; - -// fn from_str(_s: &str) -> Result { -// Err(io::Error::new(io::ErrorKind::Unsupported, "Embedded values not supported here")) -// } -// } - -// pub struct NoIterator { -// nothing: NoValue, -// phantom: PhantomData, -// } - -// impl Iterator for NoIterator { -// type Item = A; - -// fn next(&mut self) -> Option { -// None -// } -// } - -// impl ValueImpl for NoValue { -// type Embedded = NoValue; -// type Mapped<_E: Domain> = NoValue; -// type Items<'a> = NoIterator<&'a Value>; -// type Entries<'a> = NoIterator<(&'a Value, &'a Value)>; - -// fn write(&self, _w: &mut dyn Writer, _enc: &mut dyn DomainEncode) -> io::Result<()> { unreachable!() } -// fn value_class(&self) -> ValueClass { unreachable!() } -// fn as_boolean(&self) -> Option { unreachable!() } -// fn as_float(&self) -> Option { unreachable!() } -// fn as_double(&self) -> Option { unreachable!() } -// fn as_signed_integer(&self) -> Option> { unreachable!() } -// fn as_string(&self) -> Option> { unreachable!() } -// fn as_bytestring(&self) -> Option> { unreachable!() } -// fn as_symbol(&self) -> Option> { unreachable!() } -// fn is_record(&self) -> bool { unreachable!() } -// fn label(&self) -> Value { unreachable!() } -// fn is_sequence(&self) -> bool { unreachable!() } -// fn len(&self) -> usize { unreachable!() } -// fn index(&self, _i: usize) -> Value { unreachable!() } -// fn iter(&self) -> Self::Items<'_> { unreachable!() } -// fn is_set(&self) -> bool { unreachable!() } -// fn has>(&self, _v: &Value) -> bool { unreachable!() } -// fn is_dictionary(&self) -> bool { unreachable!() } -// fn get>(&self, _k: &Value) -> Option> { unreachable!() } -// fn entries(&self) -> Self::Entries<'_> { unreachable!() } -// fn as_embedded(&self) -> Option> { unreachable!() } -// fn annotations(&self) -> Option> { unreachable!() } -// fn peeled(&self) -> &Self { unreachable!() } - -// fn copy(w: &Value, f: &mut F) -> Result, Err> -// where -// F: FnMut(&E::Embedded) -> Result, Err> -// { -// panic!("Cannot copy into NoValue") -// } - -// fn map_embedded(&self, f: &mut F) -> Result>, Err> -// where -// F: FnMut(&Self::Embedded) -> Result -// { -// unreachable!() -// } -// } - -pub enum Shell<'a, V: ValueImpl> { - Atom(Atom<'a>), - Record(Record>), - Sequence(Vec>), - Set(Set>), - Dictionary(Map, Value>), - Embedded(V::Embedded), - Annotated(Annotations), -} - -impl Shell<'static, Arc>> { - pub fn record(label: ArcValue, fields: Vec>) -> ArcValue { - Value(Arc::new(ArcValueImpl(Shell::Record(Record::new(label, fields)), PhantomData))) - } -} - -impl<'a, V: ValueImpl> ValueImpl for Shell<'a, V> { - type Embedded = V::Embedded; - type Mapped = Shell<'a, V::Mapped>; - type Items<'i> = std::slice::Iter<'i, Value> where Self: 'i; - type Entries<'i> = std::collections::btree_map::Iter<'i, Value, Value> where Self: 'i; - - fn write(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode) -> io::Result<()> { - match self { - Shell::Atom(a) => a.write(w), - Shell::Record(_) => todo!(), - Shell::Sequence(items) => { - w.start_sequence()?; - let mut b = B::Type::default(); - for e in items { - b.shift(Some(B::Item::SequenceValue)); - w.boundary(&b)?; - e.write(w, enc)?; - } - b.shift(None); - w.boundary(&b)?; - w.end_sequence() - } - Shell::Set(items) => { - w.start_set()?; - let mut b = B::Type::default(); - for e in items.iter() { - b.shift(Some(B::Item::SetValue)); - w.boundary(&b)?; - e.write(w, enc)?; - } - b.shift(None); - w.boundary(&b)?; - w.end_set() - } - Shell::Dictionary(entries) => { - w.start_dictionary()?; - let mut b = B::Type::default(); - for (k, v) in entries.iter() { - b.shift(Some(B::Item::DictionaryKey)); - w.boundary(&b)?; - k.write(w, enc)?; - b.shift(Some(B::Item::DictionaryValue)); - w.boundary(&b)?; - v.write(w, enc)?; - } - b.shift(None); - w.boundary(&b)?; - w.end_dictionary() - } - Shell::Embedded(d) => { - w.start_embedded()?; - enc.encode_embedded(w, d)?; - w.end_embedded() - } - Shell::Annotated(b) => { - let (value, anns) = b.0.as_ref(); - w.start_annotations()?; - let mut b = B::Type::default(); - for ann in anns { - b.shift(Some(B::Item::Annotation)); - w.boundary(&b)?; - ann.write(w, &mut IOValueDomainCodec)?; - } - b.shift(Some(B::Item::AnnotatedValue)); - w.boundary(&b)?; - value.write(w, enc)?; - b.shift(None); - w.boundary(&b)?; - w.end_annotations() +// TODO: when unstable feature iter_order_by stabilises, use that instead +fn iters_eq>(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 }, } } } +} - fn value_class(&self) -> ValueClass { - match self { - Shell::Atom(a) => ValueClass::Atomic(a.into()), - Shell::Record(_) => ValueClass::Compound(CompoundClass::Record), - Shell::Sequence(_) => ValueClass::Compound(CompoundClass::Sequence), - Shell::Set(_) => ValueClass::Compound(CompoundClass::Set), - Shell::Dictionary(_) => ValueClass::Compound(CompoundClass::Dictionary), - Shell::Embedded(_) => ValueClass::Embedded, - Shell::Annotated(b) => b.0.0.value_class(), +pub fn value_eq>(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(), } - } - - fn copy(w: &Value, f: &mut F) -> Result, Err> - where - F: FnMut(&E::Embedded) -> Result, Err> - { - let r: Self = match w.value_class() { - ValueClass::Atomic(a) => match a { - AtomClass::Boolean => Shell::Atom(Atom::Boolean(w.as_boolean().unwrap())), - AtomClass::Float => Shell::Atom(Atom::Float(w.as_float().unwrap())), - AtomClass::Double => Shell::Atom(Atom::Double(w.as_double().unwrap())), - AtomClass::SignedInteger => Shell::Atom(Atom::SignedInteger(w.as_signed_integer().unwrap())), - AtomClass::String => Shell::Atom(Atom::String(w.as_string().unwrap())), - AtomClass::ByteString => Shell::Atom(Atom::ByteString(w.as_bytestring().unwrap())), - AtomClass::Symbol => Shell::Atom(Atom::Symbol(w.as_symbol().unwrap())), - }, - ValueClass::Compound(c) => match c { - CompoundClass::Sequence => - Shell::Sequence(w.iter().map(|ww| ww.copy(f)).collect::, _>>()?), - CompoundClass::Set => - Shell::Set(w.iter().map(|ww| ww.copy(f)).collect::, _>>()?), - CompoundClass::Record => - Shell::Record(Record::new( - w.label().copy(f)?, - w.iter().map(|ww| ww.copy(f)).collect::, _>>()?)), - CompoundClass::Dictionary => - Shell::Dictionary(w.entries().map(|(k, ww)| Ok((k.copy(f)?, ww.copy(f)?))) - .collect::, _>>()?), - }, - ValueClass::Embedded => f(&w.as_embedded().unwrap())?.0, - }; - if let Some(anns) = w.annotations() { - Ok(Value(Shell::Annotated(Annotations(Box::new((Value(r), anns.into_owned().into())))))) - } else { - Ok(Value(r)) + 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(), } +} - fn map_embedded(&self, f: &mut F) -> Result>, Err> - where - F: FnMut(&V::Embedded) -> Result - { - Self::Mapped::::copy(&Value(*self), &mut |d| Ok(Value(Self::Mapped::::Embedded(f(d)?)))) - } - - fn as_boolean(&self) -> Option { - match self { - Shell::Atom(Atom::Boolean(b)) => Some(*b), - _ => None, - } - } - - fn as_float(&self) -> Option { - match self { - Shell::Atom(Atom::Float(f)) => Some(*f), - _ => None, - } - } - - fn as_double(&self) -> Option { - match self { - Shell::Atom(Atom::Double(d)) => Some(*d), - _ => None, - } - } - - fn as_signed_integer(&self) -> Option> { - match self { - Shell::Atom(Atom::SignedInteger(i)) => Some(Cow::Borrowed(i)), - _ => None, - } - } - - fn as_string(&self) -> Option> { - match self { - Shell::Atom(Atom::String(s)) => Some(Cow::Borrowed(s)), - _ => None, - } - } - - fn as_bytestring(&self) -> Option> { - match self { - Shell::Atom(Atom::ByteString(bs)) => Some(Cow::Borrowed(bs)), - _ => None, - } - } - - fn as_symbol(&self) -> Option> { - match self { - Shell::Atom(Atom::Symbol(s)) => Some(Cow::Borrowed(s)), - _ => None, - } - } - - fn is_record(&self) -> bool { - matches!(self, Shell::Record(_)) - } - - fn label(&self) -> Value { - match self { - Shell::Record(items) => items.0[0], - _ => panic!("Not a record"), - } - } - - fn is_sequence(&self) -> bool { - matches!(self, Shell::Sequence(_)) - } - - fn len(&self) -> usize { - match self { - Shell::Record(items) => items.0.len() - 1, - Shell::Sequence(items) => items.len(), - Shell::Set(items) => items.len(), - Shell::Dictionary(entries) => entries.len(), - _ => panic!("Not a compound value"), - } - } - - fn index(&self, i: usize) -> Value { - match self { - Shell::Record(items) => items.0[i - 1], - Shell::Sequence(items) => items[i], - _ => panic!("Not indexable"), - } - } - - fn iter(&self) -> Self::Items<'_> { - match self { - Shell::Record(items) => items.0[1..].iter(), - Shell::Sequence(items) => items.iter(), - Shell::Set(items) => todo!(), // TODO: don't use slice iter directly - _ => panic!("Not iterable"), - } - } - - fn is_set(&self) -> bool { - matches!(self, Shell::Set(_)) - } - - fn has>(&self, v: &Value) -> bool { - match self { - Shell::Set(items) => items.contains(v), - _ => false, - } - } - - fn is_dictionary(&self) -> bool { - matches!(self, Shell::Dictionary(_)) - } - - fn get>(&self, k: &Value) -> Option> { - match self { - Shell::Dictionary(entries) => entries.get(k), - _ => None, - } - } - - fn entries(&self) -> Self::Entries<'_> { - match self { - Shell::Dictionary(entries) => entries.iter(), - _ => panic!("Not a dictionary"), - } - } - - fn as_embedded(&self) -> Option> { - match self { - Shell::Embedded(d) => Some(Cow::Borrowed(d)), - _ => None, - } - } - - fn annotations(&self) -> Option> { - match self { - Shell::Annotated(b) => Some(Cow::Borrowed(&b.1)), - _ => None, - } - } - - fn peeled(&self) -> &Self { - match self { - Shell::Annotated(b) => Some(b.0), - _ => self, +// TODO: when unstable feature iter_order_by stabilises, use that instead +fn iters_cmp>(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 } + } + } } } } -impl From for Value { - fn from(v: V) -> Self { - Value(v) - } +pub fn value_cmp>(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()), + }) } -impl<'a, W: Into>, V: ValueImpl> From for Shell<'a, V> { - fn from(w: W) -> Self { - Shell::Atom(w.into()) - } +#[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<'a, V: ValueImpl> From>> for Shell<'a, V> { - fn from(vs: Vec>) -> Self { - Shell::Sequence(vs) - } -} - -impl<'a, V: ValueImpl> From>> for Shell<'a, V> { - fn from(vs: Set>) -> Self { - Shell::Set(vs) - } -} - -impl<'a, V: ValueImpl> From, Value>> for Shell<'a, V> { - fn from(vs: Map, Value>) -> Self { - Shell::Dictionary(vs) - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(transparent)] -pub struct Record(Vec /* at least one element, for the label */); - -impl Record { - pub fn new(label: V, mut fields: Vec) -> Self { - fields.insert(0, label); - Record(fields) - } - - pub fn _from_vec(v: Vec) -> Self { - if v.is_empty() { panic!("Internal error: empty vec supplied to Record::_from_vec") } - Record(v) - } - - pub fn _vec(&self) -> &Vec { - &self.0 - } -} - -#[derive(Clone)] -pub struct Annotations(Box<(Value, Vec)>); - -impl Hash for Annotations { - fn hash(&self, state: &mut H) { - self.0.as_ref().0.hash(state) - } -} - -impl PartialEq for Annotations { - fn eq(&self, other: &Self) -> bool { - self.0.as_ref().0.eq(other.0.as_ref().0) - } -} - -impl Ord for Annotations { - fn cmp(&self, other: &Self) -> Ordering { - self.0.as_ref().0.cmp(other.0.as_ref().0) - } -} - -impl Eq for Annotations {} - -impl PartialOrd for Annotations { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(transparent)] -pub struct ArcValueImpl(Shell<'static, Arc>>, PhantomData); -pub type ArcValue = Value>>; - -#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(transparent)] -pub struct IOValueImpl(ArcValueImpl); -pub type IOValue = Value>; - -unsafe impl bytemuck::TransparentWrapper> for IOValueImpl {} - -impl From> for IOValue { - fn from(v: ArcValue) -> Self { - IOValue::wrap_arc(v) - } -} - -impl From for ArcValue { - fn from(v: IOValue) -> Self { - IOValue::peel_arc(v) - } -} - -impl ValueImpl for ArcValueImpl { -} - -impl ValueImpl for IOValueImpl { -} - -impl ValueImpl for Arc { -} - -// impl Debug for ArcValue { -// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -// value(self).fmt(f) -// } -// } - -// impl Debug for IOValue { -// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -// value(self).fmt(f) -// } -// } - -// impl PartialEq for ArcValue { -// fn eq(&self, other: &Self) -> bool { -// &self.0 == &other.0 -// } -// } - -// impl, D: Domain + FromStr> FromStr for ArcValue { -// type Err = io::Error; - -// fn from_str(s: &str) -> Result { -// Ok(arcvalue(crate::annotated_from_str(s, &mut DefaultDomainCodec)?.value_clone())) -// } -// } - -// impl FromStr for IOValue { -// type Err = io::Error; - -// fn from_str(s: &str) -> Result { -// crate::annotated_iovalue_from_str(s) -// } -// } - -// impl From> for ArcValue { -// fn from(b: PlainValue<'static, D>) -> Self { -// ArcValue(Arc::from(b)) -// } -// } - -// impl From> for IOValue { -// fn from(b: PlainValue<'static, IOValue>) -> Self { -// IOValue(b.into()) -// } -// } - -// impl From> for IOValue { -// fn from(b: ArcValue) -> Self { -// IOValue(b) -// } -// } diff --git a/implementations/rust/preserves/src/shell.rs b/implementations/rust/preserves/src/shell.rs new file mode 100644 index 0000000..f368c85 --- /dev/null +++ b/implementations/rust/preserves/src/shell.rs @@ -0,0 +1,714 @@ +use std::borrow::Borrow; +use std::borrow::Cow; +use std::cmp::Ordering; +use std::fmt::Debug; +use std::hash::Hash; +use std::hash::Hasher; +use std::io; +use std::str::FromStr; +use std::sync::Arc; + +use bytemuck::TransparentWrapper; + +use crate::AtomClass; +use crate::CompoundClass; +use crate::Domain; +use crate::DomainEncode; +use crate::ExpectedKind; +use crate::IOValueDomainCodec; +use crate::SignedInteger; +use crate::ValueClass; +use crate::ValueImpl; +use crate::Writer; +use crate::boundary as B; +use crate::impl_value_methods; + +pub use std::collections::BTreeSet as Set; +pub use std::collections::BTreeMap as Map; + +#[derive(Debug, Clone)] +pub enum Atom<'a> { + Boolean(bool), + Float(f32), + Double(f64), + SignedInteger(Cow<'a, SignedInteger>), + String(Cow<'a, str>), + ByteString(Cow<'a, [u8]>), + Symbol(Cow<'a, str>), +} + +impl<'a> Atom<'a> { + pub fn write(&self, w: &mut dyn Writer) -> io::Result<()> { + match self { + Atom::Boolean(b) => w.write_bool(*b), + Atom::Float(f) => w.write_f32(*f), + Atom::Double(d) => w.write_f64(*d), + Atom::SignedInteger(i) => w.write_signed_integer(i), + Atom::String(s) => w.write_string(s), + Atom::ByteString(bs) => w.write_bytes(bs), + Atom::Symbol(s) => w.write_symbol(s), + } + } + + pub fn symbol>>(v: W) -> Self { + Atom::Symbol(v.into()) + } + + pub fn try_into_symbol(self) -> Result, ExpectedKind> { + match self { + Atom::Symbol(s) => Ok(s), + _ => Err(ExpectedKind::Symbol), + } + } + + pub fn as_symbol(self) -> Result<&'a str, ExpectedKind> { + match self { + Atom::Symbol(s) => Ok(s.as_ref()), + _ => Err(ExpectedKind::Symbol), + } + } +} + +impl<'r, 'a> From<&'r Atom<'a>> for AtomClass { + fn from(a: &'r Atom<'a>) -> Self { + match a { + Atom::Boolean(_) => AtomClass::Boolean, + Atom::Float(_) => AtomClass::Float, + Atom::Double(_) => AtomClass::Double, + Atom::SignedInteger(_) => AtomClass::SignedInteger, + Atom::String(_) => AtomClass::String, + Atom::ByteString(_) => AtomClass::ByteString, + Atom::Symbol(_) => AtomClass::Symbol, + } + } +} + +impl<'a> From for Atom<'a> { fn from(v: bool) -> Self { Atom::Boolean(v) } } +impl<'a> From for Atom<'a> { fn from(v: f32) -> Self { Atom::Float(v) } } +impl<'a> From for Atom<'a> { fn from(v: f64) -> Self { Atom::Double(v) } } +impl<'a> From<&'a SignedInteger> for Atom<'a> { fn from(v: &'a SignedInteger) -> Self { Atom::SignedInteger(Cow::Borrowed(v)) } } +impl<'a> From for Atom<'a> { fn from(v: SignedInteger) -> Self { Atom::SignedInteger(Cow::Owned(v)) } } +impl<'a> From<&'a str> for Atom<'a> { fn from(v: &'a str) -> Self { Atom::String(Cow::Borrowed(v)) } } +impl<'a> From for Atom<'a> { fn from(v: String) -> Self { Atom::String(Cow::Owned(v)) } } +impl<'a> From<&'a [u8]> for Atom<'a> { fn from(v: &'a [u8]) -> Self { Atom::ByteString(Cow::Borrowed(v)) } } +impl<'a> From> for Atom<'a> { fn from(v: Vec) -> Self { Atom::ByteString(Cow::Owned(v)) } } + +macro_rules! from_atom_ref_impl { + ($t:ty, $p:pat, $e:expr, $err:expr) => { + impl<'r, 'a> TryFrom<&'r Atom<'a>> for $t { + type Error = ExpectedKind; + fn try_from(value: &'r Atom<'a>) -> Result { + match value { + $p => Ok($e), + _ => Err($err), + } + } + } + }; +} +from_atom_ref_impl!(bool, Atom::Boolean(b), *b, ExpectedKind::Boolean); +from_atom_ref_impl!(f32, Atom::Float(f), *f, ExpectedKind::Float); +from_atom_ref_impl!(f64, Atom::Double(d), *d, ExpectedKind::Double); +from_atom_ref_impl!(&'a SignedInteger, Atom::SignedInteger(i), i.as_ref(), ExpectedKind::SignedInteger); +from_atom_ref_impl!(&'a str, Atom::String(s), s.as_ref(), ExpectedKind::String); +from_atom_ref_impl!(&'a [u8], Atom::ByteString(bs), bs.as_ref(), ExpectedKind::ByteString); + +macro_rules! from_atom_val_impl { + ($t:ty, $p:pat, $e:expr, $err:expr) => { + impl<'a> TryFrom> for $t { + type Error = ExpectedKind; + fn try_from(value: Atom<'a>) -> Result { + match value { + $p => Ok($e), + _ => Err($err), + } + } + } + }; +} +from_atom_val_impl!(bool, Atom::Boolean(b), b, ExpectedKind::Boolean); +from_atom_val_impl!(f32, Atom::Float(f), f, ExpectedKind::Float); +from_atom_val_impl!(f64, Atom::Double(d), d, ExpectedKind::Double); +from_atom_val_impl!(Cow<'a, SignedInteger>, Atom::SignedInteger(i), i, ExpectedKind::SignedInteger); +from_atom_val_impl!(Cow<'a, str>, Atom::String(s), s, ExpectedKind::String); +from_atom_val_impl!(Cow<'a, [u8]>, Atom::ByteString(bs), bs, ExpectedKind::ByteString); + +pub type ShellHandle<'a, D> = Arc>; +pub enum Shell<'a, D: Domain> { + Atom(Atom<'a>), + Record(Record>), + Sequence(Vec>), + Set(Set>), + Dictionary(Map, ShellHandle<'a, D>>), + Embedded(D), + Annotated(Annotations), +} + +impl<'a, D: Domain> Shell<'a, D> { + pub fn record(label: ShellHandle<'a, D>, fields: Vec>) -> Self { + Shell::Record(Record::new(label, fields)) + } + + pub fn symbol>>(s: S) -> Self { + Shell::Atom(Atom::symbol(s)) + } + + pub fn embedded(d: D) -> Self { + Shell::Embedded(d) + } +} + +impl<'a, D: Domain> ValueImpl for Shell<'a, D> { + type Handle = ShellHandle<'a, D>; + type Embedded = D; + type Mapped = Shell<'a, E>; + type Items<'i> = std::slice::Iter<'i, Self::Handle> where Self: 'i; + type Entries<'i> = std::collections::btree_map::Iter<'i, Self::Handle, Self::Handle> where Self: 'i; + type IOValueImpl = IOValue; + + fn wrap(self) -> Self::Handle { + Self::Handle::new(self) + } + + fn write(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode) -> io::Result<()> { + match self { + Shell::Atom(a) => a.write(w), + Shell::Record(_) => todo!(), + Shell::Sequence(items) => { + w.start_sequence()?; + let mut b = B::Type::default(); + for e in items { + b.shift(Some(B::Item::SequenceValue)); + w.boundary(&b)?; + e.write(w, enc)?; + } + b.shift(None); + w.boundary(&b)?; + w.end_sequence() + } + Shell::Set(items) => { + w.start_set()?; + let mut b = B::Type::default(); + for e in items.iter() { + b.shift(Some(B::Item::SetValue)); + w.boundary(&b)?; + e.write(w, enc)?; + } + b.shift(None); + w.boundary(&b)?; + w.end_set() + } + Shell::Dictionary(entries) => { + w.start_dictionary()?; + let mut b = B::Type::default(); + for (k, v) in entries.iter() { + b.shift(Some(B::Item::DictionaryKey)); + w.boundary(&b)?; + k.write(w, enc)?; + b.shift(Some(B::Item::DictionaryValue)); + w.boundary(&b)?; + v.write(w, enc)?; + } + b.shift(None); + w.boundary(&b)?; + w.end_dictionary() + } + Shell::Embedded(d) => { + w.start_embedded()?; + enc.encode_embedded(w, d)?; + w.end_embedded() + } + Shell::Annotated(b) => { + let (value, anns) = b.0.as_ref(); + w.start_annotations()?; + let mut b = B::Type::default(); + for ann in anns { + b.shift(Some(B::Item::Annotation)); + w.boundary(&b)?; + ann.value().write(w, &mut IOValueDomainCodec)?; + } + b.shift(Some(B::Item::AnnotatedValue)); + w.boundary(&b)?; + value.write(w, enc)?; + b.shift(None); + w.boundary(&b)?; + w.end_annotations() + } + } + } + + fn value_class(&self) -> ValueClass { + match self { + Shell::Atom(a) => ValueClass::Atomic(a.into()), + Shell::Record(_) => ValueClass::Compound(CompoundClass::Record), + Shell::Sequence(_) => ValueClass::Compound(CompoundClass::Sequence), + Shell::Set(_) => ValueClass::Compound(CompoundClass::Set), + Shell::Dictionary(_) => ValueClass::Compound(CompoundClass::Dictionary), + Shell::Embedded(_) => ValueClass::Embedded, + Shell::Annotated(b) => b.0.as_ref().0.value_class(), + } + } + + fn copy(w: &E::Handle, f: &mut F) -> Result + where + F: FnMut(&E::Embedded) -> Result + { + let w = w.borrow(); + let r: Self::Handle = match w.value_class() { + ValueClass::Atomic(a) => match a { + AtomClass::Boolean => Shell::Atom(Atom::Boolean(w.as_boolean().unwrap())), + AtomClass::Float => Shell::Atom(Atom::Float(w.as_float().unwrap())), + AtomClass::Double => Shell::Atom(Atom::Double(w.as_double().unwrap())), + AtomClass::SignedInteger => Shell::Atom(Atom::SignedInteger(w.as_signed_integer().unwrap())), + AtomClass::String => Shell::Atom(Atom::String(w.as_string().unwrap())), + AtomClass::ByteString => Shell::Atom(Atom::ByteString(w.as_bytestring().unwrap())), + AtomClass::Symbol => Shell::Atom(Atom::Symbol(w.as_symbol().unwrap())), + }.wrap(), + ValueClass::Compound(c) => match c { + CompoundClass::Sequence => + Shell::Sequence(w.iter().map(|ww| Self::copy::(&ww, f)).collect::, _>>()?), + CompoundClass::Set => + Shell::Set(w.iter().map(|ww| Self::copy::(&ww, f)).collect::, _>>()?), + CompoundClass::Record => + Shell::Record(Record::new( + Self::copy::(&w.label(), f)?, + w.iter().map(|ww| Self::copy::(&ww, f)).collect::, _>>()?)), + CompoundClass::Dictionary => + Shell::Dictionary( + w.entries().map(|(k, ww)| Ok((Self::copy::(&k, f)?, + Self::copy::(&ww, f)?))) + .collect::, _>>()?), + }.wrap(), + ValueClass::Embedded => f(&w.as_embedded().unwrap())? + }; + if let Some(anns) = w.annotations() { + Ok(Shell::Annotated(Annotations(Box::new(( + r, + anns.iter().map(copy_iovalue::).collect() + )))).wrap()) + } else { + Ok(r) + } + } + + fn map_embedded(v: &Self::Handle, f: &mut F) -> Result< as ValueImpl>::Handle, Err> + where + F: FnMut(&D) -> Result + { + Self::Mapped::::copy::(v, &mut |d| Ok( + ShellHandle::<'a, E>::new(Self::Mapped::::Embedded(f(d)?)))) + } + + fn as_boolean(&self) -> Option { + match self { + Shell::Atom(Atom::Boolean(b)) => Some(*b), + _ => None, + } + } + + fn as_float(&self) -> Option { + match self { + Shell::Atom(Atom::Float(f)) => Some(*f), + _ => None, + } + } + + fn as_double(&self) -> Option { + match self { + Shell::Atom(Atom::Double(d)) => Some(*d), + _ => None, + } + } + + fn as_signed_integer(&self) -> Option> { + match self { + Shell::Atom(Atom::SignedInteger(i)) => Some(Cow::Borrowed(i)), + _ => None, + } + } + + fn as_string(&self) -> Option> { + match self { + Shell::Atom(Atom::String(s)) => Some(Cow::Borrowed(s)), + _ => None, + } + } + + fn as_bytestring(&self) -> Option> { + match self { + Shell::Atom(Atom::ByteString(bs)) => Some(Cow::Borrowed(bs)), + _ => None, + } + } + + fn as_symbol(&self) -> Option> { + match self { + Shell::Atom(Atom::Symbol(s)) => Some(Cow::Borrowed(s)), + _ => None, + } + } + + fn is_record(&self) -> bool { + matches!(self, Shell::Record(_)) + } + + fn label(&self) -> Self::Handle { + match self { + Shell::Record(items) => items.0[0], + _ => panic!("Not a record"), + } + } + + fn is_sequence(&self) -> bool { + matches!(self, Shell::Sequence(_)) + } + + fn len(&self) -> usize { + match self { + Shell::Record(items) => items.0.len() - 1, + Shell::Sequence(items) => items.len(), + Shell::Set(items) => items.len(), + Shell::Dictionary(entries) => entries.len(), + _ => panic!("Not a compound value"), + } + } + + fn index(&self, i: usize) -> Self::Handle { + match self { + Shell::Record(items) => items.0[i - 1], + Shell::Sequence(items) => items[i], + _ => panic!("Not indexable"), + } + } + + fn iter(&self) -> Self::Items<'_> { + match self { + Shell::Record(items) => items.0[1..].iter(), + Shell::Sequence(items) => items.iter(), + Shell::Set(items) => todo!(), // TODO: don't use slice iter directly + _ => panic!("Not iterable"), + } + } + + fn is_set(&self) -> bool { + matches!(self, Shell::Set(_)) + } + + fn has>(&self, v: &E::Handle) -> bool { + match self { + Shell::Set(items) => todo!(), // items.contains(v), + _ => false, + } + } + + fn is_dictionary(&self) -> bool { + matches!(self, Shell::Dictionary(_)) + } + + fn get>(&self, k: &K::Handle) -> Option { + match self { + Shell::Dictionary(entries) => todo!(), // entries.get(k), + _ => None, + } + } + + fn entries(&self) -> Self::Entries<'_> { + match self { + Shell::Dictionary(entries) => entries.iter(), + _ => panic!("Not a dictionary"), + } + } + + fn as_embedded(&self) -> Option> { + match self { + Shell::Embedded(d) => Some(Cow::Borrowed(d)), + _ => None, + } + } + + fn annotations(&self) -> Option::Handle]>> { + match self { + Shell::Annotated(b) => Some(Cow::Borrowed(&b.0.as_ref().1)), + _ => None, + } + } + + fn peeled(v: &Self::Handle) -> Self::Handle { + match v.as_ref() { + Shell::Annotated(b) => b.0.0, + _ => v.clone(), + } + } +} + +impl_value_methods!({'a, D: Domain}, Shell<'a, D>); + +impl<'a, W: Into>, D: Domain> From for Shell<'a, D> { + fn from(w: W) -> Self { + Shell::Atom(w.into()) + } +} + +impl<'a, D: Domain> From>> for Shell<'a, D> { + fn from(vs: Vec>) -> Self { + Shell::Sequence(vs) + } +} + +impl<'a, D: Domain> From>> for Shell<'a, D> { + fn from(vs: Vec>) -> Self { + vs.iter().map(|v| v.wrap()).collect::>().into() + } +} + +impl<'a, D: Domain> From>> for Shell<'a, D> { + fn from(vs: Set>) -> Self { + Shell::Set(vs) + } +} + +impl<'a, D: Domain> From, ShellHandle<'a, D>>> for Shell<'a, D> { + fn from(vs: Map, ShellHandle<'a, D>>) -> Self { + Shell::Dictionary(vs) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[repr(transparent)] +pub struct Record(Vec /* at least one element, for the label */); + +impl Record { + pub fn new(label: V, mut fields: Vec) -> Self { + fields.insert(0, label); + Record(fields) + } + + pub fn _from_vec(v: Vec) -> Self { + if v.is_empty() { panic!("Internal error: empty vec supplied to Record::_from_vec") } + Record(v) + } + + pub fn _vec(&self) -> &Vec { + &self.0 + } +} + +#[derive(Clone)] +pub struct Annotations(Box<(V::Handle, Vec<::Handle>)>); + +impl Annotations { + pub fn new(v: V::Handle, anns: Vec<::Handle>) -> Self { + Self(Box::new((v, anns))) + } +} + +impl Hash for Annotations { + fn hash(&self, state: &mut H) { + self.0.as_ref().0.hash(state) + } +} + +impl PartialEq for Annotations { + fn eq(&self, other: &Self) -> bool { + self.0.as_ref().0.eq(&other.0.as_ref().0) + } +} + +impl Ord for Annotations { + fn cmp(&self, other: &Self) -> Ordering { + self.0.as_ref().0.cmp(&other.0.as_ref().0) + } +} + +impl Eq for Annotations {} + +impl PartialOrd for Annotations { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +pub fn copy_iovalue::Handle>>(v: &V::Handle) -> IOValue { + IOValue::copy::(v, &mut |a| Result::<_, ()>::Ok(copy_iovalue::(a))).unwrap() +} + +pub type IOValueImpl = Shell<'static, IOValue>; + +#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[repr(transparent)] +pub struct IOValue(ShellHandle<'static, IOValue>); +unsafe impl TransparentWrapper> for IOValue {} + +impl Domain for IOValue { + type Decode = IOValueDomainCodec; + type Encode = IOValueDomainCodec; +} + +impl Debug for IOValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + IOValue::peel_ref(self).fmt(f) + } +} + +impl IOValue { + pub fn value(&self) -> &IOValueImpl { + self.0.as_ref() + } +} + +impl> From for IOValue { + fn from(t: T) -> Self { + IOValue(t.into().wrap()) + } +} + +impl Borrow for IOValue { + fn borrow(&self) -> &IOValueImpl { + self.0.as_ref() + } +} + +impl FromStr for IOValue { + type Err = io::Error; + + fn from_str(s: &str) -> Result { + crate::annotated_iovalue_from_str(s) + } +} + +impl From<::Handle> for IOValue { + fn from(h: ::Handle) -> Self { + TransparentWrapper::wrap(h) + } +} + +impl<'a> From<&'a ::Handle> for &'a IOValue { + fn from(h: &'a ::Handle) -> Self { + TransparentWrapper::wrap_ref(h) + } +} + +impl From for ::Handle { + fn from(i: IOValue) -> Self { + IOValue::peel(i) + } +} + +impl<'a> From<&'a IOValue> for &'a ::Handle { + fn from(i: &'a IOValue) -> Self { + IOValue::peel_ref(i) + } +} + +impl ValueImpl for IOValue { + type Handle = IOValue; + type Embedded = IOValue; + type Mapped = Shell<'static, E>; + type Items<'i> = std::slice::Iter<'i, Self::Handle> where Self: 'i; + type Entries<'i> = std::collections::btree_map::Iter<'i, Self::Handle, Self::Handle> where Self: 'i; + type IOValueImpl = IOValue; + + fn wrap(self) -> Self::Handle { + self + } + + fn value_class(&self) -> ValueClass { + self.value().value_class() + } + + fn as_boolean(&self) -> Option { + self.value().as_boolean() + } + + fn as_float(&self) -> Option { + self.value().as_float() + } + + fn as_double(&self) -> Option { + self.value().as_double() + } + + fn as_signed_integer(&self) -> Option> { + self.value().as_signed_integer() + } + + fn as_string(&self) -> Option> { + self.value().as_string() + } + + fn as_bytestring(&self) -> Option> { + self.value().as_bytestring() + } + + fn as_symbol(&self) -> Option> { + self.value().as_symbol() + } + + fn is_record(&self) -> bool { + self.value().is_record() + } + + fn label(&self) -> Self::Handle { + self.value().label().into() + } + + fn is_sequence(&self) -> bool { + self.value().is_sequence() + } + + fn len(&self) -> usize { + self.value().len() + } + + fn index(&self, i: usize) -> Self::Handle { + self.value().index(i).into() + } + + fn iter(&self) -> Self::Items<'_> { + todo!() // self.value().iter() + } + + fn is_set(&self) -> bool { + self.value().is_set() + } + + fn has>(&self, v: &E::Handle) -> bool { + self.value().has::(v) + } + + fn is_dictionary(&self) -> bool { + self.value().is_dictionary() + } + + fn get>(&self, k: &K::Handle) -> Option { + self.value().get::(k).map(|v| v.into()) + } + + fn entries(&self) -> Self::Entries<'_> { + todo!() // self.value().entries() + } + + fn as_embedded(&self) -> Option> { + self.value().as_embedded() + } + + fn annotations(&self) -> Option> { + self.value().annotations() + } + + fn peeled(v: &Self::Handle) -> Self::Handle { + TransparentWrapper::wrap(Shell::peeled(IOValue::peel_ref(v))) + } + + fn copy(w: &E::Handle, f: &mut F) -> Result + where + F: FnMut(&E::Embedded) -> Result { + IOValueImpl::copy::(w, &mut |e| f(e).map(|v| v.into())).map(|v| v.into()) + } + + fn map_embedded(v: &Self::Handle, f: &mut F) -> Result< as ValueImpl>::Handle, Err> + where + F: FnMut(&Self::Embedded) -> Result { + IOValueImpl::map_embedded(v.into(), f) + } +} diff --git a/implementations/rust/preserves/src/writer.rs b/implementations/rust/preserves/src/writer.rs index f83ad67..0dff913 100644 --- a/implementations/rust/preserves/src/writer.rs +++ b/implementations/rust/preserves/src/writer.rs @@ -1,4 +1,5 @@ use num_bigint::BigInt; +use std::borrow::Borrow; use std::io; use crate::AtomClass; @@ -85,7 +86,7 @@ pub fn write_value( for ann in &anns[..] { annotation_b.shift(Some(B::Item::Annotation)); w.boundary(&annotation_b)?; - ann.write(w, &mut IOValueDomainCodec)?; + ann.borrow().write(w, &mut IOValueDomainCodec)?; } annotation_b.shift(Some(B::Item::AnnotatedValue)); w.boundary(&annotation_b)?; @@ -110,11 +111,11 @@ pub fn write_value( w.start_record()?; let mut b = B::start(B::Item::RecordLabel); w.boundary(&b)?; - v.label().write(w, enc)?; + v.label().borrow().write(w, enc)?; for e in v.iter() { b.shift(Some(B::Item::RecordField)); w.boundary(&b)?; - e.write(w, enc)?; + e.borrow().write(w, enc)?; } b.shift(None); w.boundary(&b)?; @@ -126,7 +127,7 @@ pub fn write_value( for e in v.iter() { b.shift(Some(B::Item::SequenceValue)); w.boundary(&b)?; - e.write(w, enc)?; + e.borrow().write(w, enc)?; } b.shift(None); w.boundary(&b)?; @@ -138,7 +139,7 @@ pub fn write_value( for e in v.iter() { b.shift(Some(B::Item::SetValue)); w.boundary(&b)?; - e.write(w, enc)?; + e.borrow().write(w, enc)?; } b.shift(None); w.boundary(&b)?; @@ -150,10 +151,10 @@ pub fn write_value( for (k, v) in v.entries() { b.shift(Some(B::Item::DictionaryKey)); w.boundary(&b)?; - k.write(w, enc)?; + k.borrow().write(w, enc)?; b.shift(Some(B::Item::DictionaryValue)); w.boundary(&b)?; - v.write(w, enc)?; + v.borrow().write(w, enc)?; } b.shift(None); w.boundary(&b)?; @@ -162,7 +163,7 @@ pub fn write_value( } ValueClass::Embedded => { w.start_embedded()?; - enc.encode_embedded(w, &v.embedded())?; + enc.encode_embedded(w, &v.as_embedded().unwrap())?; w.end_embedded()? } }