Text I/O
This commit is contained in:
parent
1121da0b75
commit
228f34c699
|
@ -8,7 +8,7 @@ pub mod reader;
|
|||
pub mod repr;
|
||||
pub mod signed_integer;
|
||||
pub mod source;
|
||||
// pub mod text;
|
||||
pub mod text;
|
||||
pub mod types;
|
||||
pub mod writer;
|
||||
|
||||
|
@ -26,6 +26,7 @@ pub use repr::Bytes;
|
|||
pub use repr::Embedded;
|
||||
pub use repr::IOValue;
|
||||
pub use repr::Map;
|
||||
pub use repr::PlainValue;
|
||||
pub use repr::NoValue;
|
||||
pub use repr::Record;
|
||||
pub use repr::Set;
|
||||
|
@ -37,16 +38,17 @@ pub use signed_integer::SignedInteger;
|
|||
pub use source::BinarySource;
|
||||
pub use source::BytesBinarySource;
|
||||
pub use source::IOBinarySource;
|
||||
// pub use text::TextReader;
|
||||
// pub use text::TextWriter;
|
||||
// pub use text::annotated_from_str;
|
||||
// pub use text::annotated_iovalue_from_str;
|
||||
// pub use text::from_str;
|
||||
// pub use text::iovalue_from_str;
|
||||
pub use text::TextReader;
|
||||
pub use text::TextWriter;
|
||||
pub use text::annotated_from_str;
|
||||
pub use text::annotated_iovalue_from_str;
|
||||
pub use text::from_str;
|
||||
pub use text::iovalue_from_str;
|
||||
pub use types::AtomClass;
|
||||
pub use types::CompoundClass;
|
||||
pub use types::ValueClass;
|
||||
pub use writer::Writer;
|
||||
pub use writer::write_value;
|
||||
|
||||
#[cfg(test)]
|
||||
mod demo {
|
||||
|
@ -57,16 +59,17 @@ mod demo {
|
|||
}
|
||||
|
||||
#[test] fn a() {
|
||||
let l = Symbol::new("label");
|
||||
let r = Record::new(owned::<NoValue, _>(l.clone()), vec![owned(1), owned(2), owned(3)]);
|
||||
let r2 = Record::new(owned::<NoValue, _>(l), vec![owned(1), owned(2), owned(4)]);
|
||||
let l: PlainValue<NoValue> = "label".parse().unwrap();
|
||||
let r = Record::new(l.value_clone(), vec![owned(1), owned(2), owned(3)]);
|
||||
let r2 = Record::new(l, vec![owned(1), owned(2), owned(4)]);
|
||||
|
||||
let mut v: Map<Box<dyn Value<NoValue>>, String> = Map::new();
|
||||
v.insert(Box::new("abc"), "def".to_owned());
|
||||
v.insert(Box::new(123), "xyz".to_owned());
|
||||
v.insert(Box::new(vec![1, 2, 3]), "www".to_owned());
|
||||
v.insert(Box::new(r2), "bbb".to_owned());
|
||||
v.insert(Box::new(r), "aaa".to_owned());
|
||||
let mut v: Map<PlainValue<NoValue>, PlainValue<NoValue>> = Map::new();
|
||||
v.insert("\"abc\"".parse().unwrap(), "def".parse().unwrap());
|
||||
v.insert("abc".parse().unwrap(), "DEF".parse().unwrap());
|
||||
v.insert(owned(123), "xyz".parse().unwrap());
|
||||
v.insert(owned(vec![1, 2, 3]), "{a: 1, b: 2}".parse().unwrap());
|
||||
v.insert(owned(r2), "bbb".parse().unwrap());
|
||||
v.insert(owned(r), "<foo bar zot>".parse().unwrap());
|
||||
let w: &dyn Value<NoValue> = &v;
|
||||
println!("GETw abc {:?}", w.get(&"abc"));
|
||||
println!("GETw 123 {:?}", w.get(&123));
|
||||
|
@ -75,15 +78,16 @@ mod demo {
|
|||
println!("GETv 123 {:?}", v.get(value(&123)));
|
||||
println!("GETv qqq {:?}", v.get(value(&"qqq")));
|
||||
for (kk, vv) in w.entries() {
|
||||
println!("{:?} {:?} ==> {:?} {:?}", kk.value_class(), kk, vv.value_class(), vv);
|
||||
println!("{:#?} ==> {:#?}", kk, vv);
|
||||
}
|
||||
|
||||
// {
|
||||
// use std::io::BufRead;
|
||||
// for line in std::io::stdin().lock().lines() {
|
||||
// let line = line.unwrap();
|
||||
// let val = w.get(&line);
|
||||
// println!("{:?} ==> {:?} == {:?}", line, val, getit(&v, &line));
|
||||
// let key = line.parse::<PlainValue<NoValue>>().unwrap();
|
||||
// let val = w.get(&key);
|
||||
// println!("{:?} == {:?} ==> {:?} == {:?}", line, &key, val, getit(&v, &line));
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -6,13 +6,14 @@ use std::fmt::Debug;
|
|||
use std::hash::{Hash, Hasher};
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
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::AtomClass;
|
||||
use crate::{AtomClass, TextWriter, DefaultDomainCodec, write_value};
|
||||
use crate::CompoundClass;
|
||||
use crate::Domain;
|
||||
use crate::SignedInteger;
|
||||
|
@ -23,11 +24,15 @@ use crate::domain::{NoEmbeddedDomainCodec, DomainEncode, IOValueDomainCodec};
|
|||
|
||||
use super::float::{eq_f32, eq_f64, cmp_f32, cmp_f64};
|
||||
|
||||
/// Atomic values from the specification.
|
||||
pub trait Value<D: Domain>: Debug {
|
||||
fn write(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode<D>) -> io::Result<()>;
|
||||
pub type PlainValue<'a, D = IOValue> = Box<dyn Value<D> + 'a>;
|
||||
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static;
|
||||
/// Atomic values from the specification.
|
||||
pub trait Value<D: Domain> {
|
||||
fn write(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode<D>) -> io::Result<()> {
|
||||
write_value(w, self, enc)
|
||||
}
|
||||
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static;
|
||||
fn value_class(&self) -> ValueClass;
|
||||
|
||||
fn as_boolean(&self) -> Option<bool> { None }
|
||||
|
@ -66,7 +71,7 @@ pub fn value<D: Domain, V: Value<D>>(v: &V) -> &dyn Value<D> {
|
|||
v
|
||||
}
|
||||
|
||||
pub fn owned<D: Domain, V: Value<D> + 'static>(v: V) -> Box<dyn Value<D>> {
|
||||
pub fn owned<D: Domain, V: Value<D> + 'static>(v: V) -> PlainValue<'static, D> {
|
||||
Box::new(v)
|
||||
}
|
||||
|
||||
|
@ -74,9 +79,15 @@ pub fn iovalue<V: Value<IOValue> + 'static>(v: V) -> IOValue {
|
|||
IOValue(Arc::new(v))
|
||||
}
|
||||
|
||||
impl<'a, D: Domain + 'static> From<&'a dyn Value<D>> for PlainValue<'static, D> {
|
||||
fn from(v: &'a dyn Value<D>) -> Self {
|
||||
v.value_clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, D: Domain, V: Value<D> + ?Sized> Value<D> for &'a V {
|
||||
fn write(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode<D>) -> io::Result<()> { (*self).write(w, enc) }
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static { (*self).value_clone() }
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static { (*self).value_clone() }
|
||||
fn value_class(&self) -> ValueClass { (*self).value_class() }
|
||||
fn as_boolean(&self) -> Option<bool> { (*self).as_boolean() }
|
||||
fn as_float(&self) -> Option<f32> { (*self).as_float() }
|
||||
|
@ -102,9 +113,9 @@ impl<'a, D: Domain, V: Value<D> + ?Sized> Value<D> for &'a V {
|
|||
fn annotations(&self) -> Option<&[IOValue]> { (*self).annotations() }
|
||||
}
|
||||
|
||||
impl<D: Domain> Value<D> for Box<dyn Value<D>> {
|
||||
impl<'a, D: Domain> Value<D> for PlainValue<'a, D> {
|
||||
fn write(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode<D>) -> io::Result<()> { self.as_ref().write(w, enc) }
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static { self.as_ref().value_clone() }
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static { self.as_ref().value_clone() }
|
||||
fn value_class(&self) -> ValueClass { self.as_ref().value_class() }
|
||||
fn as_boolean(&self) -> Option<bool> { self.as_ref().as_boolean() }
|
||||
fn as_float(&self) -> Option<f32> { self.as_ref().as_float() }
|
||||
|
@ -130,6 +141,20 @@ impl<D: Domain> Value<D> for Box<dyn Value<D>> {
|
|||
fn annotations(&self) -> Option<&[IOValue]> { self.as_ref().annotations() }
|
||||
}
|
||||
|
||||
impl<'a, D: Domain> Debug for dyn Value<D> + 'a {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
TextWriter::fmt_value(f, &mut DefaultDomainCodec, self).map_err(|_| std::fmt::Error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Err: Into<io::Error>, D: Domain + FromStr<Err = Err> + 'static> FromStr for PlainValue<'a, D> {
|
||||
type Err = io::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
crate::from_str(s, &mut DefaultDomainCodec)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, D: Domain> Hash for dyn Value<D> + 'a {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
match self.value_class() {
|
||||
|
@ -308,7 +333,7 @@ pub enum Atom<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Atom<'a> {
|
||||
pub fn into_value<D: Domain>(self) -> Box<dyn Value<D>> {
|
||||
pub fn into_value<D: Domain>(self) -> PlainValue<'static, D> {
|
||||
match self {
|
||||
Atom::Boolean(b) => Box::new(b),
|
||||
Atom::Float(f) => Box::new(f),
|
||||
|
@ -321,6 +346,20 @@ impl<'a> Atom<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
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, D: Domain> Value<D> for Atom<'a> {
|
||||
fn write(&self, w: &mut dyn Writer, _enc: &mut dyn DomainEncode<D>) -> io::Result<()> {
|
||||
match self {
|
||||
|
@ -334,20 +373,12 @@ impl<'a, D: Domain> Value<D> for Atom<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static {
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static {
|
||||
self.clone().into_value()
|
||||
}
|
||||
|
||||
fn value_class(&self) -> ValueClass {
|
||||
ValueClass::Atomic(match self {
|
||||
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,
|
||||
})
|
||||
ValueClass::Atomic(self.into())
|
||||
}
|
||||
|
||||
fn as_boolean(&self) -> Option<bool> {
|
||||
|
@ -388,22 +419,30 @@ impl Domain for NoValue {
|
|||
type Encode = NoEmbeddedDomainCodec;
|
||||
}
|
||||
|
||||
impl FromStr for NoValue {
|
||||
type Err = io::Error;
|
||||
|
||||
fn from_str(_s: &str) -> Result<Self, Self::Err> {
|
||||
Err(io::Error::new(io::ErrorKind::Unsupported, "Embedded values not supported here"))
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Domain> Value<D> for NoValue {
|
||||
fn write(&self, _w: &mut dyn Writer, _enc: &mut dyn DomainEncode<D>) -> io::Result<()> { unreachable!() }
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static { unreachable!() }
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static { unreachable!() }
|
||||
fn value_class(&self) -> ValueClass { unreachable!() }
|
||||
}
|
||||
|
||||
impl<D: Domain> Value<D> for bool {
|
||||
fn write(&self, w: &mut dyn Writer, __enc: &mut dyn DomainEncode<D>) -> io::Result<()> { w.write_bool(*self) }
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static { Box::new(*self) }
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static { Box::new(*self) }
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::Boolean) }
|
||||
fn as_boolean(&self) -> Option<bool> { Some(*self) }
|
||||
}
|
||||
|
||||
impl<D: Domain> Value<D> for u64 {
|
||||
fn write(&self, w: &mut dyn Writer, _enc: &mut dyn DomainEncode<D>) -> io::Result<()> { w.write_u64(*self) }
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static { Box::new(*self) }
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static { Box::new(*self) }
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::SignedInteger) }
|
||||
fn as_signed_integer(&self) -> Option<SignedInteger> {
|
||||
Some((*self).into())
|
||||
|
@ -412,7 +451,7 @@ impl<D: Domain> Value<D> for u64 {
|
|||
|
||||
impl<D: Domain> Value<D> for SignedInteger {
|
||||
fn write(&self, w: &mut dyn Writer, _enc: &mut dyn DomainEncode<D>) -> io::Result<()> { w.write_signed_integer(self) }
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static { Box::new(self.clone()) }
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static { Box::new(self.clone()) }
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::SignedInteger) }
|
||||
fn as_signed_integer(&self) -> Option<SignedInteger> {
|
||||
Some(self.clone())
|
||||
|
@ -421,7 +460,7 @@ impl<D: Domain> Value<D> for SignedInteger {
|
|||
|
||||
impl<D: Domain> Value<D> for f32 {
|
||||
fn write(&self, w: &mut dyn Writer, _enc: &mut dyn DomainEncode<D>) -> io::Result<()> { w.write_f32(*self) }
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static { Box::new(*self) }
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static { Box::new(*self) }
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::Float) }
|
||||
fn as_float(&self) -> Option<f32> { Some(*self) }
|
||||
fn as_double(&self) -> Option<f64> { Some(*self as f64) }
|
||||
|
@ -429,7 +468,7 @@ impl<D: Domain> Value<D> for f32 {
|
|||
|
||||
impl<D: Domain> Value<D> for f64 {
|
||||
fn write(&self, w: &mut dyn Writer, _enc: &mut dyn DomainEncode<D>) -> io::Result<()> { w.write_f64(*self) }
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static { Box::new(*self) }
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static { Box::new(*self) }
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::Float) }
|
||||
fn as_float(&self) -> Option<f32> { Some(*self as f32) }
|
||||
fn as_double(&self) -> Option<f64> { Some(*self) }
|
||||
|
@ -437,14 +476,14 @@ impl<D: Domain> Value<D> for f64 {
|
|||
|
||||
impl<D: Domain> Value<D> for str {
|
||||
fn write(&self, w: &mut dyn Writer, _enc: &mut dyn DomainEncode<D>) -> io::Result<()> { w.write_string(self) }
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static { Box::new(self.to_owned()) }
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static { Box::new(self.to_owned()) }
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::String) }
|
||||
fn as_string(&self) -> Option<Cow<'_, str>> { Some(Cow::Borrowed(self)) }
|
||||
}
|
||||
|
||||
impl<D: Domain> Value<D> for String {
|
||||
fn write(&self, w: &mut dyn Writer, _enc: &mut dyn DomainEncode<D>) -> io::Result<()> { w.write_string(self) }
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static { Box::new(self.clone()) }
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static { Box::new(self.clone()) }
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::String) }
|
||||
fn as_string(&self) -> Option<Cow<'_, str>> { Some(Cow::Borrowed(self)) }
|
||||
}
|
||||
|
@ -455,24 +494,24 @@ pub struct Bytes<T: AsRef<[u8]>>(T);
|
|||
|
||||
impl<T: AsRef<[u8]> + Debug, D: Domain> Value<D> for Bytes<T> {
|
||||
fn write(&self, w: &mut dyn Writer, _enc: &mut dyn DomainEncode<D>) -> io::Result<()> { w.write_bytes(self.0.as_ref()) }
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static { Box::new(Bytes(self.0.as_ref().to_owned())) }
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static { Box::new(Bytes(self.0.as_ref().to_owned())) }
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::ByteString) }
|
||||
fn as_bytestring(&self) -> Option<Cow<'_, [u8]>> { Some(Cow::Borrowed(self.0.as_ref())) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
#[repr(transparent)]
|
||||
pub struct Symbol<T: AsRef<str> + Debug>(T);
|
||||
pub struct Symbol<T: AsRef<str> + Debug = String>(T);
|
||||
|
||||
impl<T: AsRef<str> + Debug> Symbol<T> {
|
||||
pub fn new(t: T) -> Self {
|
||||
Symbol(t)
|
||||
pub fn new<R: Into<T>>(t: R) -> Self {
|
||||
Symbol(t.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<str> + Debug, D: Domain> Value<D> for Symbol<T> {
|
||||
fn write(&self, w: &mut dyn Writer, _enc: &mut dyn DomainEncode<D>) -> io::Result<()> { w.write_symbol(self.0.as_ref()) }
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static { Box::new(Symbol(self.0.as_ref().to_owned())) }
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static { Box::new(Symbol(self.0.as_ref().to_owned())) }
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::Symbol) }
|
||||
fn as_symbol(&self) -> Option<Cow<'_, str>> { Some(Cow::Borrowed(self.0.as_ref())) }
|
||||
}
|
||||
|
@ -513,7 +552,7 @@ impl<D: Domain, V: Value<D>> Value<D> for Record<V> {
|
|||
w.end_record()
|
||||
}
|
||||
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static {
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static {
|
||||
Box::new(Record(self.0.iter().map(|v| v.value_clone()).collect()))
|
||||
}
|
||||
|
||||
|
@ -532,7 +571,7 @@ impl<D: Domain, V: Value<D>> Value<D> for Vec<V> {
|
|||
(&self[..]).write(w, enc)
|
||||
}
|
||||
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static {
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static {
|
||||
(&self[..]).value_clone()
|
||||
}
|
||||
|
||||
|
@ -559,7 +598,7 @@ impl<D: Domain, V: Value<D>> Value<D> for [V] {
|
|||
w.end_sequence()
|
||||
}
|
||||
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static {
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static {
|
||||
Box::new(self.iter().map(|v| v.value_clone()).collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
|
@ -572,7 +611,7 @@ impl<D: Domain, V: Value<D>> Value<D> for [V] {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'e, D: Domain, E: for<'a> Borrow<Key<'a, D>> + Debug + Ord + 'e> Value<D> for Set<E> {
|
||||
impl<'e, D: Domain, E: for<'a> Borrow<Key<'a, D>> + Ord + 'e> Value<D> for Set<E> {
|
||||
fn write(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode<D>) -> io::Result<()> {
|
||||
w.start_set()?;
|
||||
let mut b = B::Type::default();
|
||||
|
@ -586,7 +625,7 @@ impl<'e, D: Domain, E: for<'a> Borrow<Key<'a, D>> + Debug + Ord + 'e> Value<D> f
|
|||
w.end_set()
|
||||
}
|
||||
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static {
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static {
|
||||
Box::new(self.iter().map(|v| Key::peel_ref(&v.borrow()).value_clone()).collect::<Set<_>>())
|
||||
}
|
||||
|
||||
|
@ -620,7 +659,7 @@ impl<'a, 'b: 'a, D: Domain> Borrow<Key<'a, D>> for &'b (dyn Value<D> + 'b) {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'k, D: Domain, V: Value<D>, K: for<'a> Borrow<Key<'a, D>> + Debug + Ord + 'k> Value<D>
|
||||
impl<'k, D: Domain, V: Value<D>, K: for<'a> Borrow<Key<'a, D>> + Ord + 'k> Value<D>
|
||||
for Map<K, V>
|
||||
{
|
||||
fn write(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode<D>) -> io::Result<()> {
|
||||
|
@ -639,7 +678,7 @@ impl<'k, D: Domain, V: Value<D>, K: for<'a> Borrow<Key<'a, D>> + Debug + Ord + '
|
|||
w.end_dictionary()
|
||||
}
|
||||
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static {
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static {
|
||||
Box::new(Value::entries(self).map(|(k, v)| (k.value_clone(), v.value_clone())).collect::<Map<_, _>>())
|
||||
}
|
||||
|
||||
|
@ -663,8 +702,8 @@ impl<'k, D: Domain, V: Value<D>, K: for<'a> Borrow<Key<'a, D>> + Debug + Ord + '
|
|||
pub struct Embedded<D: Domain>(D);
|
||||
|
||||
impl<D: Domain> Embedded<D> {
|
||||
pub fn new(d: D) -> Self {
|
||||
Embedded(d)
|
||||
pub fn new<E: Into<D>>(d: E) -> Self {
|
||||
Embedded(d.into())
|
||||
}
|
||||
|
||||
pub fn embedded_value(&self) -> &D {
|
||||
|
@ -683,7 +722,7 @@ impl<D: Domain> Value<D> for Embedded<D> {
|
|||
w.end_embedded()
|
||||
}
|
||||
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static { Box::new(self.clone()) }
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static { Box::new(self.clone()) }
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Embedded }
|
||||
fn is_embedded(&self) -> bool { true }
|
||||
fn embedded(&self) -> Cow<'_, D> { Cow::Borrowed(&self.0) }
|
||||
|
@ -723,7 +762,7 @@ impl<D: Domain, V: Value<D>> Value<D> for Annotations<D, V> {
|
|||
}
|
||||
}
|
||||
|
||||
fn value_clone(&self) -> Box<dyn Value<D>> where D: 'static {
|
||||
fn value_clone(&self) -> PlainValue<'static, D> where D: 'static {
|
||||
Box::new(Annotations(self.0.value_clone(),
|
||||
self.1.iter().map(|v| v.value_clone().into()).collect(),
|
||||
PhantomData))
|
||||
|
@ -780,17 +819,31 @@ impl<D: Domain, V: Value<D>> Ord for Annotations<D, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, Hash, PartialOrd, Ord)]
|
||||
#[derive(Clone, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct IOValue(Arc<dyn Value<IOValue>>);
|
||||
|
||||
impl Debug for IOValue {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
value(self).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for IOValue {
|
||||
type Err = io::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
crate::iovalue_from_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for IOValue {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
&self.0 == &other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<dyn Value<IOValue>>> for IOValue {
|
||||
fn from(b: Box<dyn Value<IOValue>>) -> Self {
|
||||
impl From<PlainValue<'static, IOValue>> for IOValue {
|
||||
fn from(b: PlainValue<'static, IOValue>) -> Self {
|
||||
IOValue(Arc::from(b))
|
||||
}
|
||||
}
|
||||
|
@ -803,7 +856,7 @@ impl<'a> Borrow<Key<'a, IOValue>> for IOValue {
|
|||
|
||||
impl Value<IOValue> for IOValue {
|
||||
fn write(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode<IOValue>) -> io::Result<()> { self.0.write(w, enc) }
|
||||
fn value_clone(&self) -> Box<dyn Value<IOValue>> { Box::new(self.clone()) }
|
||||
fn value_clone(&self) -> PlainValue<'static, IOValue> { Box::new(self.clone()) }
|
||||
fn value_class(&self) -> ValueClass { self.0.value_class() }
|
||||
fn as_boolean(&self) -> Option<bool> { self.0.as_boolean() }
|
||||
fn as_float(&self) -> Option<f32> { self.0.as_float() }
|
||||
|
|
|
@ -31,9 +31,9 @@ pub trait BinarySource<'de>: Sized {
|
|||
super::PackedReader::new(self)
|
||||
}
|
||||
|
||||
// fn text(&mut self) -> super::TextReader<'de, '_, Self> {
|
||||
// super::TextReader::new(self)
|
||||
// }
|
||||
fn text(&mut self) -> super::TextReader<'de, '_, Self> {
|
||||
super::TextReader::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -6,6 +6,7 @@ pub mod writer;
|
|||
pub use reader::TextReader;
|
||||
pub use writer::TextWriter;
|
||||
|
||||
use crate::BinarySource;
|
||||
use crate::BytesBinarySource;
|
||||
use crate::Domain;
|
||||
use crate::DomainDecode;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::Atom;
|
||||
use crate::ValueClass;
|
||||
use crate::error::Error;
|
||||
use crate::error::ExpectedKind;
|
||||
use crate::error::io_eof;
|
||||
|
@ -6,25 +7,41 @@ use crate::error::io_eof;
|
|||
use crate::hex;
|
||||
|
||||
use crate::CompoundClass;
|
||||
use crate::Domain;
|
||||
use crate::DomainDecode;
|
||||
use crate::Map;
|
||||
use crate::Reader;
|
||||
use crate::Record;
|
||||
use crate::Set;
|
||||
use crate::Value;
|
||||
use crate::boundary as B;
|
||||
use crate::reader::NextToken;
|
||||
use crate::reader::ReaderResult;
|
||||
use crate::source::BinarySource;
|
||||
|
||||
use num::bigint::BigInt;
|
||||
use num_bigint::BigInt;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::io;
|
||||
use std::iter::FromIterator;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
enum Classification {
|
||||
Atom(Atom<'static>),
|
||||
Compound(CompoundClass),
|
||||
Embedded,
|
||||
CommentAnnotation,
|
||||
OrdinaryAnnotation,
|
||||
}
|
||||
|
||||
impl<'r> From<&'r Classification> for NextToken {
|
||||
fn from(c: &'r Classification) -> Self {
|
||||
match c {
|
||||
Classification::Atom(a) => NextToken::Value(ValueClass::Atomic(a.into())),
|
||||
Classification::Compound(c) => NextToken::Value(ValueClass::Compound(c.clone())),
|
||||
Classification::Embedded => NextToken::Value(ValueClass::Embedded),
|
||||
Classification::CommentAnnotation |
|
||||
Classification::OrdinaryAnnotation => NextToken::Annotation,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TextReader<'de, 'src, S: BinarySource<'de>> {
|
||||
pub source: &'src mut S,
|
||||
classification_cache: Option<Classification>,
|
||||
phantom: PhantomData<&'de ()>,
|
||||
}
|
||||
|
||||
|
@ -33,6 +50,7 @@ impl<'de, 'src, S: BinarySource<'de>> TextReader<'de, 'src, S>
|
|||
pub fn new(source: &'src mut S) -> Self {
|
||||
TextReader {
|
||||
source,
|
||||
classification_cache: None,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +107,7 @@ impl<'de, 'src, S: BinarySource<'de>> TextReader<'de, 'src, S>
|
|||
}
|
||||
}
|
||||
|
||||
fn read_intpart(&mut self, mut bs: Vec<u8>, c: u8) -> io::Result<Atom<'de>> {
|
||||
fn read_intpart(&mut self, mut bs: Vec<u8>, c: u8) -> io::Result<Atom<'static>> {
|
||||
match c {
|
||||
b'0' => {
|
||||
bs.push(c);
|
||||
|
@ -102,7 +120,7 @@ impl<'de, 'src, S: BinarySource<'de>> TextReader<'de, 'src, S>
|
|||
}
|
||||
}
|
||||
|
||||
fn read_fracexp(&mut self, mut bs: Vec<u8>) -> io::Result<Atom<'de>> {
|
||||
fn read_fracexp(&mut self, mut bs: Vec<u8>) -> io::Result<Atom<'static>> {
|
||||
let mut is_float = false;
|
||||
match self.peek_noeof() {
|
||||
Ok(b'.') => {
|
||||
|
@ -122,7 +140,7 @@ impl<'de, 'src, S: BinarySource<'de>> TextReader<'de, 'src, S>
|
|||
}
|
||||
}
|
||||
|
||||
fn read_sign_and_exp(&mut self, mut bs: Vec<u8>) -> io::Result<Atom<'de>> {
|
||||
fn read_sign_and_exp(&mut self, mut bs: Vec<u8>) -> io::Result<Atom<'static>> {
|
||||
match self.peek_noeof()? {
|
||||
b'+' | b'-' => bs.push(self.next_byte()?),
|
||||
_ => (),
|
||||
|
@ -132,7 +150,7 @@ impl<'de, 'src, S: BinarySource<'de>> TextReader<'de, 'src, S>
|
|||
self.finish_number(bs, true)
|
||||
}
|
||||
|
||||
fn finish_number(&mut self, bs: Vec<u8>, is_float: bool) -> io::Result<Atom<'de>> {
|
||||
fn finish_number(&mut self, bs: Vec<u8>, is_float: bool) -> io::Result<Atom<'static>> {
|
||||
let s = self.decode_utf8(bs)?;
|
||||
if is_float {
|
||||
match self.peek_noeof() {
|
||||
|
@ -150,7 +168,7 @@ impl<'de, 'src, S: BinarySource<'de>> TextReader<'de, 'src, S>
|
|||
} else {
|
||||
Ok(Atom::SignedInteger(s.parse::<BigInt>().map_err(
|
||||
|_| self.syntax_error(&format!(
|
||||
"Invalid signed-integer number: {:?}", s)))?))
|
||||
"Invalid signed-integer number: {:?}", s)))?.into()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,23 +269,23 @@ impl<'de, 'src, S: BinarySource<'de>> TextReader<'de, 'src, S>
|
|||
self.decode_utf8(raw)
|
||||
}
|
||||
|
||||
fn read_literal_binary(&mut self) -> io::Result<Atom<'de>> {
|
||||
Ok(Atom::Bytes(&self.read_stringlike(
|
||||
fn read_literal_binary(&mut self) -> io::Result<Atom<'static>> {
|
||||
Ok(Atom::ByteString(Cow::Owned(self.read_stringlike(
|
||||
Vec::new(),
|
||||
|_r, bs, b| Ok(bs.push(b)),
|
||||
b'"',
|
||||
b'x',
|
||||
|r, bs| Ok(bs.push(r.hexnum(2)? as u8)))?[..]))
|
||||
|r, bs| Ok(bs.push(r.hexnum(2)? as u8)))?)))
|
||||
}
|
||||
|
||||
fn read_hex_binary(&mut self) -> io::Result<Atom<'de>> {
|
||||
fn read_hex_binary(&mut self) -> io::Result<Atom<'static>> {
|
||||
let mut s = String::new();
|
||||
loop {
|
||||
self.skip_whitespace();
|
||||
let c1 = self.next_byte()? as char;
|
||||
if c1 == '"' {
|
||||
let bs = hex::HexParser::Strict.decode(&s).unwrap();
|
||||
return Ok(Atom::Bytes(&bs[..]));
|
||||
return Ok(Atom::ByteString(Cow::Owned(bs)));
|
||||
}
|
||||
let c2 = self.next_byte()? as char;
|
||||
if !(c1.is_digit(16) && c2.is_digit(16)) {
|
||||
|
@ -278,7 +296,7 @@ impl<'de, 'src, S: BinarySource<'de>> TextReader<'de, 'src, S>
|
|||
}
|
||||
}
|
||||
|
||||
fn read_base64_binary(&mut self) -> io::Result<Atom<'de>> {
|
||||
fn read_base64_binary(&mut self) -> io::Result<Atom<'static>> {
|
||||
let mut bs = Vec::new();
|
||||
loop {
|
||||
self.skip_whitespace();
|
||||
|
@ -286,7 +304,7 @@ impl<'de, 'src, S: BinarySource<'de>> TextReader<'de, 'src, S>
|
|||
if c == b']' {
|
||||
let bs = base64::decode_config(&self.decode_utf8(bs)?, base64::STANDARD_NO_PAD)
|
||||
.map_err(|_| self.syntax_error("Invalid base64 character"))?;
|
||||
return Ok(Atom::Bytes(&bs[..]));
|
||||
return Ok(Atom::ByteString(Cow::Owned(bs)));
|
||||
}
|
||||
if c == b'-' { c = b'+'; }
|
||||
if c == b'_' { c = b'/'; }
|
||||
|
@ -295,7 +313,7 @@ impl<'de, 'src, S: BinarySource<'de>> TextReader<'de, 'src, S>
|
|||
}
|
||||
}
|
||||
|
||||
fn read_raw_symbol(&mut self, mut bs: Vec<u8>) -> io::Result<Atom<'de>> {
|
||||
fn read_raw_symbol(&mut self, mut bs: Vec<u8>) -> io::Result<Atom<'static>> {
|
||||
loop {
|
||||
let c = match self.peek()? {
|
||||
None => b' ',
|
||||
|
@ -305,7 +323,7 @@ impl<'de, 'src, S: BinarySource<'de>> TextReader<'de, 'src, S>
|
|||
match c {
|
||||
b'(' | b')' | b'{' | b'}' | b'[' | b']' | b'<' | b'>' |
|
||||
b'"' | b';' | b',' | b'@' | b'#' | b':' | b'|' | b' ' =>
|
||||
return Ok(Atom::Symbol(&self.decode_utf8(bs)?)),
|
||||
return Ok(Atom::Symbol(Cow::Owned(self.decode_utf8(bs)?))),
|
||||
c => {
|
||||
self.skip()?;
|
||||
bs.push(c)
|
||||
|
@ -313,142 +331,120 @@ impl<'de, 'src, S: BinarySource<'de>> TextReader<'de, 'src, S>
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_classification(&mut self) -> io::Result<Classification> {
|
||||
self.skip_whitespace();
|
||||
let c = match self.peek()? {
|
||||
None => Err(io_eof())?,
|
||||
Some(c) => c,
|
||||
};
|
||||
self.skip()?;
|
||||
|
||||
Ok(match c {
|
||||
b'-' => {
|
||||
let c1 = self.next_byte()?;
|
||||
Classification::Atom(self.read_intpart(vec![b'-'], c1)?)
|
||||
}
|
||||
b'0' | b'1' | b'2' | b'3' | b'4' | b'5' | b'6' | b'7' | b'8' | b'9' => {
|
||||
Classification::Atom(self.read_intpart(Vec::new(), c)?)
|
||||
}
|
||||
b'"' => Classification::Atom(Atom::String(Cow::Owned(self.read_string(b'"')?))),
|
||||
b'|' => Classification::Atom(Atom::Symbol(Cow::Owned(self.read_string(b'|')?))),
|
||||
b':' => Err(self.syntax_error("Unexpected key/value separator between items"))?,
|
||||
b';' => Classification::CommentAnnotation,
|
||||
b'@' => Classification::OrdinaryAnnotation,
|
||||
b'#' => {
|
||||
match self.next_byte()? {
|
||||
b'f' => Classification::Atom(Atom::Boolean(false)),
|
||||
b't' => Classification::Atom(Atom::Boolean(true)),
|
||||
b'{' => Classification::Compound(CompoundClass::Set),
|
||||
b'"' => Classification::Atom(self.read_literal_binary()?),
|
||||
b'x' => if self.next_byte()? == b'"' {
|
||||
Classification::Atom(self.read_hex_binary()?)
|
||||
} else {
|
||||
Err(self.syntax_error("Expected open-quote at start of hex ByteString"))?
|
||||
},
|
||||
b'[' => Classification::Atom(self.read_base64_binary()?),
|
||||
b'=' => {
|
||||
todo!("Remove machine text syntax")
|
||||
}
|
||||
b'!' => Classification::Embedded,
|
||||
other => Err(self.syntax_error(&format!("Invalid # syntax: {:?}", other)))?,
|
||||
}
|
||||
}
|
||||
b'<' => Classification::Compound(CompoundClass::Record),
|
||||
b'[' => Classification::Compound(CompoundClass::Sequence),
|
||||
b'{' => Classification::Compound(CompoundClass::Dictionary),
|
||||
b'>' => Err(self.syntax_error("Unexpected >"))?,
|
||||
b']' => Err(self.syntax_error("Unexpected ]"))?,
|
||||
b'}' => Err(self.syntax_error("Unexpected }"))?,
|
||||
other => Classification::Atom(self.read_raw_symbol(vec![other])?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'src, S: BinarySource<'de>> Reader<'de> for TextReader<'de, 'src, S>
|
||||
{
|
||||
fn peek_class(&mut self) -> io::Result<Option<crate::reader::NextToken>> {
|
||||
self.skip_whitespace();
|
||||
let c = match self.peek()? {
|
||||
None => return Ok(None),
|
||||
Some(c) => c,
|
||||
};
|
||||
XX Ok(Some(match c {
|
||||
b'-' => {
|
||||
self.skip()?;
|
||||
let c1 = self.next_byte()?;
|
||||
self.read_intpart(vec![b'-'], c1)?
|
||||
}
|
||||
b'0' | b'1' | b'2' | b'3' | b'4' | b'5' | b'6' | b'7' | b'8' | b'9' => {
|
||||
self.skip()?;
|
||||
self.read_intpart(Vec::new(), c)?
|
||||
}
|
||||
b'"' => {
|
||||
self.skip()?;
|
||||
N::new(self.read_string(b'"')?)
|
||||
}
|
||||
b'|' => {
|
||||
self.skip()?;
|
||||
N::symbol(&self.read_string(b'|')?)
|
||||
}
|
||||
b';' | b'@' => {
|
||||
if read_annotations {
|
||||
let mut annotations = self.gather_annotations(decode_embedded)?;
|
||||
let av: N = self.demand_next_domain(read_annotations, decode_embedded)?;
|
||||
let (existing_annotations, v) = av.pieces();
|
||||
if let Some(vs) = existing_annotations {
|
||||
annotations.extend_from_slice(&vs[..]);
|
||||
}
|
||||
N::wrap(Some(Box::new(annotations)), v)
|
||||
} else {
|
||||
self.skip_annotations()?;
|
||||
self.demand_next_domain(read_annotations, decode_embedded)?
|
||||
}
|
||||
}
|
||||
b':' => {
|
||||
return Err(self.syntax_error("Unexpected key/value separator between items"));
|
||||
}
|
||||
b'#' => {
|
||||
self.skip()?;
|
||||
match self.next_byte()? {
|
||||
b'f' => N::new(false),
|
||||
b't' => N::new(true),
|
||||
b'{' => N::new(Set::from_iter(self.upto(b'}', read_annotations, decode_embedded)?.into_iter())),
|
||||
b'"' => self.read_literal_binary()?,
|
||||
b'x' => if self.next_byte()? == b'"' {
|
||||
self.read_hex_binary()?
|
||||
} else {
|
||||
return Err(self.syntax_error("Expected open-quote at start of hex ByteString"));
|
||||
},
|
||||
b'[' => self.read_base64_binary()?,
|
||||
b'=' => {
|
||||
let bs_val = self.next_iovalue(true)?;
|
||||
if let Some(anns) = bs_val.annotations() {
|
||||
if anns.len() > 0 {
|
||||
return Err(self.syntax_error("Annotations not permitted after #="));
|
||||
}
|
||||
}
|
||||
match bs_val.value().as_bytestring() {
|
||||
None =>
|
||||
return Err(self.syntax_error("ByteString must follow #=")),
|
||||
Some(bs) =>
|
||||
crate::value::BytesBinarySource::new(bs)
|
||||
.packed()
|
||||
.demand_next_domain(read_annotations, decode_embedded)?
|
||||
}
|
||||
}
|
||||
b'!' => Value::Embedded(decode_embedded.decode_embedded(self, read_annotations)?).wrap(),
|
||||
other => return Err(self.syntax_error(&format!("Invalid # syntax: {:?}", other))),
|
||||
}
|
||||
}
|
||||
b'<' => {
|
||||
self.skip()?;
|
||||
let vs = self.upto(b'>', read_annotations, decode_embedded)?;
|
||||
if vs.is_empty() {
|
||||
return Err(self.syntax_error("Missing record label"));
|
||||
}
|
||||
Value::Record(Record(vs)).wrap()
|
||||
}
|
||||
b'[' => {
|
||||
self.skip()?;
|
||||
N::new(self.upto(b']', read_annotations, decode_embedded)?)
|
||||
}
|
||||
b'{' => {
|
||||
self.skip()?;
|
||||
self.read_dictionary(read_annotations, decode_embedded)?
|
||||
}
|
||||
b'>' => return Err(self.syntax_error("Unexpected >")),
|
||||
b']' => return Err(self.syntax_error("Unexpected ]")),
|
||||
b'}' => return Err(self.syntax_error("Unexpected }")),
|
||||
other => {
|
||||
self.skip()?;
|
||||
self.read_raw_symbol(vec![other])?
|
||||
}
|
||||
}))
|
||||
fn peek_class(&mut self) -> io::Result<Option<NextToken>> {
|
||||
if let Some(a) = &self.classification_cache {
|
||||
Ok(Some(a.into()))
|
||||
} else {
|
||||
let a = self.read_classification()?;
|
||||
let result = (&a).into();
|
||||
self.classification_cache = Some(a);
|
||||
Ok(Some(result))
|
||||
}
|
||||
}
|
||||
|
||||
fn next_atom(&mut self) -> ReaderResult<Atom<'de>> {
|
||||
self.skip_annotations()?;
|
||||
|
||||
let a = self.classification_cache.take().map_or_else(
|
||||
|| self.read_classification(),
|
||||
|c| Ok(c))?;
|
||||
|
||||
match a {
|
||||
Classification::Atom(a) => Ok(a),
|
||||
Classification::Compound(_) => Err(self.syntax_error("Unexpected compound value"))?,
|
||||
Classification::Embedded => Err(self.syntax_error("Unexpected embedded value"))?,
|
||||
Classification::CommentAnnotation | Classification::OrdinaryAnnotation =>
|
||||
unreachable!("Annotations are supposed to have been skipped already"),
|
||||
}
|
||||
}
|
||||
|
||||
fn open_record(&mut self) -> ReaderResult<()> {
|
||||
self.skip_annotations()?;
|
||||
if self.peek()? != Some(b'<') { return Err(Error::Expected(ExpectedKind::Record)); }
|
||||
self.skip()?;
|
||||
if self.peek_class()? != Some(NextToken::Value(ValueClass::Compound(CompoundClass::Record))) {
|
||||
return Err(Error::Expected(ExpectedKind::Record));
|
||||
}
|
||||
self.classification_cache = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn open_sequence(&mut self) -> ReaderResult<()> {
|
||||
self.skip_annotations()?;
|
||||
if self.peek()? != Some(b'[') { return Err(Error::Expected(ExpectedKind::Sequence)); }
|
||||
self.skip()?;
|
||||
if self.peek_class()? != Some(NextToken::Value(ValueClass::Compound(CompoundClass::Sequence))) {
|
||||
return Err(Error::Expected(ExpectedKind::Sequence));
|
||||
}
|
||||
self.classification_cache = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn open_set(&mut self) -> ReaderResult<()> {
|
||||
self.skip_annotations()?;
|
||||
let mark = self.mark()?;
|
||||
match self.next_byte()? {
|
||||
b'#' => match self.next_byte()? {
|
||||
b'{' => return Ok(()),
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
if self.peek_class()? != Some(NextToken::Value(ValueClass::Compound(CompoundClass::Set))) {
|
||||
return Err(Error::Expected(ExpectedKind::Set));
|
||||
}
|
||||
self.restore(&mark)?;
|
||||
Err(Error::Expected(ExpectedKind::Set))
|
||||
self.classification_cache = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn open_dictionary(&mut self) -> ReaderResult<()> {
|
||||
self.skip_annotations()?;
|
||||
if self.peek()? != Some(b'{') { return Err(Error::Expected(ExpectedKind::Dictionary)); }
|
||||
self.skip()?;
|
||||
if self.peek_class()? != Some(NextToken::Value(ValueClass::Compound(CompoundClass::Dictionary))) {
|
||||
return Err(Error::Expected(ExpectedKind::Dictionary));
|
||||
}
|
||||
self.classification_cache = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -486,58 +482,47 @@ XX Ok(Some(match c {
|
|||
|
||||
fn open_embedded(&mut self) -> ReaderResult<()> {
|
||||
self.skip_annotations()?;
|
||||
let mark = self.mark()?;
|
||||
match self.next_byte()? {
|
||||
b'#' => match self.next_byte()? {
|
||||
b'!' => return Ok(()),
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
if self.peek_class()? != Some(NextToken::Value(ValueClass::Embedded)) {
|
||||
return Err(Error::Expected(ExpectedKind::Embedded));
|
||||
}
|
||||
self.restore(&mark)?;
|
||||
Err(Error::Expected(ExpectedKind::Embedded))
|
||||
self.classification_cache = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn close_embedded(&mut self) -> ReaderResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
type Mark = S::Mark;
|
||||
|
||||
fn mark(&mut self) -> io::Result<Self::Mark> {
|
||||
fn mark(&mut self) -> io::Result<usize> {
|
||||
if self.classification_cache.is_some() {
|
||||
panic!("Cannot mark with full classification_cache");
|
||||
}
|
||||
self.source.mark()
|
||||
}
|
||||
|
||||
fn restore(&mut self, mark: &Self::Mark) -> io::Result<()> {
|
||||
fn restore(&mut self, mark: usize) -> io::Result<()> {
|
||||
self.classification_cache = None;
|
||||
self.source.restore(mark)
|
||||
}
|
||||
|
||||
fn next_token<D: Domain, Dec: DomainDecode<D>>(
|
||||
&mut self,
|
||||
read_embedded_annotations: bool,
|
||||
decode_embedded: &mut Dec,
|
||||
) -> io::Result<Token<D>> {
|
||||
self.skip_annotations()?;
|
||||
let mark = self.mark()?;
|
||||
Ok(match self.next_byte()? {
|
||||
b'<' => Token::Compound(CompoundClass::Record),
|
||||
b'[' => Token::Compound(CompoundClass::Sequence),
|
||||
b'{' => Token::Compound(CompoundClass::Dictionary),
|
||||
b'>' => Token::End,
|
||||
b']' => Token::End,
|
||||
b'}' => Token::End,
|
||||
b'#' => match self.next_byte()? {
|
||||
b'!' => Token::Embedded(decode_embedded.decode_embedded(self, read_embedded_annotations)?),
|
||||
b'{' => Token::Compound(CompoundClass::Set),
|
||||
_ => {
|
||||
self.restore(&mark)?;
|
||||
Token::Atom(self.demand_next_domain(false, decode_embedded)?)
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
self.restore(&mark)?;
|
||||
Token::Atom(self.demand_next_domain(false, decode_embedded)?)
|
||||
fn open_annotation(&mut self) -> ReaderResult<()> {
|
||||
let _ = self.peek_class()?;
|
||||
match self.classification_cache {
|
||||
None => unreachable!("peek_class should have primed the cache"),
|
||||
Some(Classification::CommentAnnotation) => {
|
||||
self.classification_cache = Some(Classification::Atom(
|
||||
Atom::String(Cow::Owned(self.comment_line()?))));
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
Some(Classification::OrdinaryAnnotation) => {
|
||||
self.classification_cache = None;
|
||||
Ok(())
|
||||
}
|
||||
Some(_) => Err(Error::Expected(ExpectedKind::Annotation))?,
|
||||
}
|
||||
}
|
||||
|
||||
fn close_annotation(&mut self) -> ReaderResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use crate::value::DomainEncode;
|
||||
use crate::value::IOValue;
|
||||
use crate::value::IOValueDomainCodec;
|
||||
use crate::value::NestedValue;
|
||||
use crate::value::Writer;
|
||||
use crate::Domain;
|
||||
use crate::DomainEncode;
|
||||
use crate::IOValue;
|
||||
use crate::IOValueDomainCodec;
|
||||
use crate::Value;
|
||||
use crate::Writer;
|
||||
|
||||
use num::bigint::BigInt;
|
||||
use num_bigint::BigInt;
|
||||
|
||||
use std::io;
|
||||
|
||||
|
@ -32,25 +33,25 @@ impl std::default::Default for CommaStyle {
|
|||
}
|
||||
|
||||
impl TextWriter<&mut Vec<u8>> {
|
||||
pub fn fmt_value<N: NestedValue, Enc: DomainEncode<N::Embedded>>(
|
||||
pub fn fmt_value<D: Domain, Enc: DomainEncode<D>>(
|
||||
f: &mut std::fmt::Formatter<'_>,
|
||||
enc: &mut Enc,
|
||||
v: &crate::value::Value<N>,
|
||||
v: &dyn Value<D>,
|
||||
) -> io::Result<()> {
|
||||
let mut buf: Vec<u8> = Vec::new();
|
||||
let mut w = TextWriter::new(&mut buf);
|
||||
if f.alternate() { w.indentation = 4 }
|
||||
w.write_value(enc, v)?;
|
||||
v.write(&mut w, enc)?;
|
||||
f.write_str(std::str::from_utf8(&buf).expect("valid UTF-8 from TextWriter")).map_err(
|
||||
|_| io::Error::new(io::ErrorKind::Other, "could not append to Formatter"))
|
||||
}
|
||||
|
||||
pub fn encode<N: NestedValue, Enc: DomainEncode<N::Embedded>>(
|
||||
pub fn encode<D: Domain, Enc: DomainEncode<D>>(
|
||||
enc: &mut Enc,
|
||||
v: &N,
|
||||
v: &dyn Value<D>,
|
||||
) -> io::Result<String> {
|
||||
let mut buf: Vec<u8> = Vec::new();
|
||||
TextWriter::new(&mut buf).write(enc, v)?;
|
||||
v.write(&mut TextWriter::new(&mut buf), enc)?;
|
||||
Ok(String::from_utf8(buf).expect("valid UTF-8 from TextWriter"))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
use num_bigint::BigInt;
|
||||
use std::io;
|
||||
|
||||
use crate::AtomClass;
|
||||
use crate::CompoundClass;
|
||||
use crate::Domain;
|
||||
use crate::DomainEncode;
|
||||
use crate::IOValueDomainCodec;
|
||||
use crate::SignedInteger;
|
||||
use crate::ValueClass;
|
||||
use crate::boundary as B;
|
||||
use crate::signed_integer::SignedIntegerRepr;
|
||||
use crate::Value;
|
||||
|
||||
pub trait Writer {
|
||||
fn boundary(&mut self, b: &B::Type) -> io::Result<()>;
|
||||
|
@ -60,3 +67,103 @@ pub trait Writer {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_value<D: Domain, V: Value<D>>(
|
||||
w: &mut dyn Writer,
|
||||
v: V,
|
||||
enc: &mut dyn DomainEncode<D>,
|
||||
) -> io::Result<()> {
|
||||
let annotations = v.annotations();
|
||||
let mut annotation_b = B::Type::default();
|
||||
|
||||
if let Some(anns) = annotations {
|
||||
w.start_annotations()?;
|
||||
for ann in anns {
|
||||
annotation_b.shift(Some(B::Item::Annotation));
|
||||
w.boundary(&annotation_b)?;
|
||||
ann.write(w, &mut IOValueDomainCodec)?;
|
||||
}
|
||||
annotation_b.shift(Some(B::Item::AnnotatedValue));
|
||||
w.boundary(&annotation_b)?;
|
||||
}
|
||||
|
||||
match v.value_class() {
|
||||
ValueClass::Atomic(a) => match a {
|
||||
AtomClass::Boolean => w.write_bool(v.as_boolean().unwrap())?,
|
||||
AtomClass::Float => w.write_f32(v.as_float().unwrap())?,
|
||||
AtomClass::Double => w.write_f64(v.as_double().unwrap())?,
|
||||
AtomClass::SignedInteger => w.write_signed_integer(&v.as_signed_integer().unwrap())?,
|
||||
AtomClass::String => w.write_string(&v.as_string().unwrap())?,
|
||||
AtomClass::ByteString => w.write_bytes(&v.as_bytestring().unwrap())?,
|
||||
AtomClass::Symbol => w.write_symbol(&v.as_symbol().unwrap())?,
|
||||
}
|
||||
ValueClass::Compound(c) => match c {
|
||||
CompoundClass::Record => {
|
||||
w.start_record()?;
|
||||
let mut b = B::start(B::Item::RecordLabel);
|
||||
w.boundary(&b)?;
|
||||
v.label().write(w, enc)?;
|
||||
for e in v.iter() {
|
||||
b.shift(Some(B::Item::RecordField));
|
||||
w.boundary(&b)?;
|
||||
e.write(w, enc)?;
|
||||
}
|
||||
b.shift(None);
|
||||
w.boundary(&b)?;
|
||||
w.end_record()?
|
||||
}
|
||||
CompoundClass::Sequence => {
|
||||
w.start_sequence()?;
|
||||
let mut b = B::Type::default();
|
||||
for e in v.iter() {
|
||||
b.shift(Some(B::Item::SequenceValue));
|
||||
w.boundary(&b)?;
|
||||
e.write(w, enc)?;
|
||||
}
|
||||
b.shift(None);
|
||||
w.boundary(&b)?;
|
||||
w.end_sequence()?
|
||||
}
|
||||
CompoundClass::Set => {
|
||||
w.start_set()?;
|
||||
let mut b = B::Type::default();
|
||||
for e in v.iter() {
|
||||
b.shift(Some(B::Item::SetValue));
|
||||
w.boundary(&b)?;
|
||||
e.write(w, enc)?;
|
||||
}
|
||||
b.shift(None);
|
||||
w.boundary(&b)?;
|
||||
w.end_set()?
|
||||
}
|
||||
CompoundClass::Dictionary => {
|
||||
w.start_dictionary()?;
|
||||
let mut b = B::Type::default();
|
||||
for (k, v) in v.entries() {
|
||||
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()?
|
||||
}
|
||||
}
|
||||
ValueClass::Embedded => {
|
||||
w.start_embedded()?;
|
||||
enc.encode_embedded(w, &v.embedded())?;
|
||||
w.end_embedded()?
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(_) = annotations {
|
||||
annotation_b.shift(None);
|
||||
w.boundary(&annotation_b)?;
|
||||
w.end_annotations()?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue