Parsing and reading via TextReader/TextWriter
This commit is contained in:
parent
a1043f406c
commit
52de025c21
|
@ -34,7 +34,7 @@ enum Variety {
|
||||||
|
|
||||||
fn try_file(kind: &str, path: &str) -> io::Result<()> {
|
fn try_file(kind: &str, path: &str) -> io::Result<()> {
|
||||||
let fruits_value = IOBinarySource::new(&mut File::open(path)?).packed_iovalues().demand_next(true)?;
|
let fruits_value = IOBinarySource::new(&mut File::open(path)?).packed_iovalues().demand_next(true)?;
|
||||||
println!("{:?}", fruits_value);
|
println!("{:#?}", fruits_value);
|
||||||
|
|
||||||
let fruits1: Vec<Fruit> = value::de::from_value(&fruits_value)?;
|
let fruits1: Vec<Fruit> = value::de::from_value(&fruits_value)?;
|
||||||
println!("(via generic decoding) {}: {:?}", kind, fruits1);
|
println!("(via generic decoding) {}: {:?}", kind, fruits1);
|
||||||
|
|
|
@ -19,6 +19,17 @@ mod dom {
|
||||||
|
|
||||||
impl Domain for Dom {}
|
impl Domain for Dom {}
|
||||||
|
|
||||||
|
impl std::str::FromStr for Dom {
|
||||||
|
type Err = io::Error;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"One" => Ok(Dom::One),
|
||||||
|
"Two" => Ok(Dom::Two),
|
||||||
|
_ => Err(io::Error::new(io::ErrorKind::Other, "cannot parse preserves test domain")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn dom_as_preserves(v: &Dom) -> io::Result<UnwrappedIOValue> {
|
fn dom_as_preserves(v: &Dom) -> io::Result<UnwrappedIOValue> {
|
||||||
Ok(match v {
|
Ok(match v {
|
||||||
Dom::One => Value::bytestring(vec![255, 255, 255, 255]),
|
Dom::One => Value::bytestring(vec![255, 255, 255, 255]),
|
||||||
|
@ -366,6 +377,48 @@ mod decoder_tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod formatting_tests {
|
||||||
|
use super::dom::Dom;
|
||||||
|
use super::value::ArcValue;
|
||||||
|
use super::value::IOValue;
|
||||||
|
use super::value::Value;
|
||||||
|
|
||||||
|
#[test] fn format_debug_and_parse() {
|
||||||
|
let v = "[1, {z: 2, a: #!\"One\"}, 3]".parse::<Value<ArcValue<Dom>>>().unwrap();
|
||||||
|
assert_eq!(format!("{:?}", &v), "[1, {a: #!\"One\", z: 2}, 3]");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test] fn format_pretty_debug_and_parse() {
|
||||||
|
let v = "[1, {z: 2, a: #!\"One\"}, 3]".parse::<Value<ArcValue<Dom>>>().unwrap();
|
||||||
|
assert_eq!(format!("{:#?}", &v), concat!(
|
||||||
|
"[\n",
|
||||||
|
" 1,\n",
|
||||||
|
" {\n",
|
||||||
|
" a: #!\"One\",\n",
|
||||||
|
" z: 2\n",
|
||||||
|
" },\n",
|
||||||
|
" 3\n",
|
||||||
|
"]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test] fn iovalue_parse() {
|
||||||
|
let v = "[1 @{a:b c:d} @\"foo\" #![2 3] 4]".parse::<IOValue>().unwrap();
|
||||||
|
assert_eq!(format!("{:#?}", &v), concat!(
|
||||||
|
"[\n",
|
||||||
|
" 1,\n",
|
||||||
|
" @{\n",
|
||||||
|
" a: b,\n",
|
||||||
|
" c: d\n",
|
||||||
|
" } @\"foo\" #![\n",
|
||||||
|
" 2,\n",
|
||||||
|
" 3\n",
|
||||||
|
" ],\n",
|
||||||
|
" 4\n",
|
||||||
|
"]"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod serde_tests {
|
mod serde_tests {
|
||||||
use crate::symbol::Symbol;
|
use crate::symbol::Symbol;
|
||||||
|
|
|
@ -4,6 +4,7 @@ use super::BinarySource;
|
||||||
use super::BytesBinarySource;
|
use super::BytesBinarySource;
|
||||||
use super::Embeddable;
|
use super::Embeddable;
|
||||||
use super::IOValue;
|
use super::IOValue;
|
||||||
|
use super::NestedValue;
|
||||||
use super::Reader;
|
use super::Reader;
|
||||||
use super::Writer;
|
use super::Writer;
|
||||||
use super::packed;
|
use super::packed;
|
||||||
|
@ -50,6 +51,22 @@ impl<'a, D: Embeddable, T: DomainDecode<D>> DomainDecode<D> for &'a mut T {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct DebugDomainEncode;
|
||||||
|
|
||||||
|
impl<D: Embeddable> DomainEncode<D> for DebugDomainEncode {
|
||||||
|
fn encode_embedded<W: Writer>(&mut self, w: &mut W, d: &D) -> io::Result<()> {
|
||||||
|
d.debug_encode(w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FromStrDomainParse;
|
||||||
|
|
||||||
|
impl<Err: Into<io::Error>, D: Embeddable + std::str::FromStr<Err = Err>> DomainParse<D> for FromStrDomainParse {
|
||||||
|
fn parse_embedded(&mut self, v: &IOValue) -> io::Result<D> {
|
||||||
|
Ok(D::from_str(v.value().to_string()?).map_err(|e| e.into())?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct IOValueDomainCodec;
|
pub struct IOValueDomainCodec;
|
||||||
|
|
||||||
impl DomainDecode<IOValue> for IOValueDomainCodec {
|
impl DomainDecode<IOValue> for IOValueDomainCodec {
|
||||||
|
|
|
@ -17,6 +17,8 @@ pub use de::from_value;
|
||||||
pub use domain::DomainDecode;
|
pub use domain::DomainDecode;
|
||||||
pub use domain::DomainEncode;
|
pub use domain::DomainEncode;
|
||||||
pub use domain::DomainParse;
|
pub use domain::DomainParse;
|
||||||
|
pub use domain::DebugDomainEncode;
|
||||||
|
pub use domain::FromStrDomainParse;
|
||||||
pub use domain::IOValueDomainCodec;
|
pub use domain::IOValueDomainCodec;
|
||||||
pub use domain::NoEmbeddedDomainCodec;
|
pub use domain::NoEmbeddedDomainCodec;
|
||||||
pub use domain::ViaCodec;
|
pub use domain::ViaCodec;
|
||||||
|
|
|
@ -7,6 +7,7 @@ use std::convert::TryFrom;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::io;
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
use std::ops::IndexMut;
|
use std::ops::IndexMut;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
|
@ -16,14 +17,29 @@ use std::vec::Vec;
|
||||||
pub use std::collections::BTreeSet as Set;
|
pub use std::collections::BTreeSet as Set;
|
||||||
pub use std::collections::BTreeMap as Map;
|
pub use std::collections::BTreeMap as Map;
|
||||||
|
|
||||||
|
use super::DebugDomainEncode;
|
||||||
|
use super::FromStrDomainParse;
|
||||||
|
use super::IOValueDomainCodec;
|
||||||
|
use super::TextWriter;
|
||||||
|
use super::Writer;
|
||||||
use super::signed_integer::SignedInteger;
|
use super::signed_integer::SignedInteger;
|
||||||
|
use super::text;
|
||||||
use crate::error::{Error, ExpectedKind, Received};
|
use crate::error::{Error, ExpectedKind, Received};
|
||||||
|
|
||||||
pub trait Domain: Sized + Debug + Eq + Hash + Ord {}
|
pub trait Domain: Sized + Debug + Eq + Hash + Ord {
|
||||||
|
fn debug_encode<W: Writer>(&self, w: &mut W) -> io::Result<()> {
|
||||||
|
w.write_string(&format!("{:?}", self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Embeddable: Domain + Clone {}
|
pub trait Embeddable: Domain + Clone {}
|
||||||
impl<T> Embeddable for T where T: Domain + Clone {}
|
impl<T> Embeddable for T where T: Domain + Clone {}
|
||||||
|
|
||||||
impl<D: Domain> Domain for Arc<D> {}
|
impl<D: Domain> Domain for Arc<D> {
|
||||||
|
fn debug_encode<W: Writer>(&self, w: &mut W) -> io::Result<()> {
|
||||||
|
self.as_ref().debug_encode(w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait NestedValue: Sized + Debug + Clone + Eq + Hash + Ord {
|
pub trait NestedValue: Sized + Debug + Clone + Eq + Hash + Ord {
|
||||||
type Embedded: Embeddable;
|
type Embedded: Embeddable;
|
||||||
|
@ -312,46 +328,18 @@ impl<N: NestedValue> From<Set<N>> for Value<N> { fn from(v: Set<N>) -> Self { Va
|
||||||
impl<N: NestedValue> From<Map<N, N>> for Value<N> { fn from(v: Map<N, N>) -> Self { Value::Dictionary(v) } }
|
impl<N: NestedValue> From<Map<N, N>> for Value<N> { fn from(v: Map<N, N>) -> Self { Value::Dictionary(v) } }
|
||||||
|
|
||||||
impl<N: NestedValue> Debug for Value<N> {
|
impl<N: NestedValue> Debug for Value<N> {
|
||||||
// Not *quite* a formatter for the Preserves text syntax, since it
|
|
||||||
// doesn't escape strings/symbols properly.
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
TextWriter::fmt_value(f, &mut DebugDomainEncode, self).map_err(|_| std::fmt::Error)
|
||||||
Value::Boolean(false) => f.write_str("#f"),
|
}
|
||||||
Value::Boolean(true) => f.write_str("#t"),
|
}
|
||||||
Value::Float(Float(v)) => write!(f, "{:?}f", v),
|
|
||||||
Value::Double(Double(v)) => write!(f, "{:?}", v),
|
impl<Err: Into<io::Error>, D: Embeddable + std::str::FromStr<Err = Err>, N: NestedValue<Embedded = D>>
|
||||||
Value::SignedInteger(v) => write!(f, "{}", v),
|
std::str::FromStr for Value<N>
|
||||||
Value::String(v) => write!(f, "{:?}", v), // TODO: proper escaping!
|
{
|
||||||
Value::ByteString(v) => {
|
type Err = io::Error;
|
||||||
f.write_str("#x\"")?;
|
|
||||||
for b in v { write!(f, "{:02x}", b)? }
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
f.write_str("\"")
|
Ok(text::from_str::<N, _>(s, FromStrDomainParse)?.value_owned())
|
||||||
}
|
|
||||||
Value::Symbol(v) => {
|
|
||||||
// TODO: proper escaping!
|
|
||||||
if v.is_empty() {
|
|
||||||
f.write_str("||")
|
|
||||||
} else {
|
|
||||||
write!(f, "{}", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Value::Record(r) => {
|
|
||||||
f.write_str("<")?;
|
|
||||||
r.label().fmt(f)?;
|
|
||||||
for v in r.fields() {
|
|
||||||
f.write_str(" ")?;
|
|
||||||
v.fmt(f)?;
|
|
||||||
}
|
|
||||||
f.write_str(">")
|
|
||||||
}
|
|
||||||
Value::Sequence(v) => v.fmt(f),
|
|
||||||
Value::Set(v) => {
|
|
||||||
f.write_str("#")?;
|
|
||||||
f.debug_set().entries(v.iter()).finish()
|
|
||||||
}
|
|
||||||
Value::Dictionary(v) => f.debug_map().entries(v.iter()).finish(),
|
|
||||||
Value::Embedded(d) => write!(f, "#!{:?}", d),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1432,7 +1420,11 @@ impl<D: Embeddable> Debug for ArcValue<D> {
|
||||||
pub struct IOValue(Arc<AnnotatedValue<IOValue>>);
|
pub struct IOValue(Arc<AnnotatedValue<IOValue>>);
|
||||||
pub type UnwrappedIOValue = Value<IOValue>;
|
pub type UnwrappedIOValue = Value<IOValue>;
|
||||||
|
|
||||||
impl Domain for IOValue {}
|
impl Domain for IOValue {
|
||||||
|
fn debug_encode<W: Writer>(&self, w: &mut W) -> io::Result<()> {
|
||||||
|
w.write(&mut IOValueDomainCodec, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl NestedValue for IOValue {
|
impl NestedValue for IOValue {
|
||||||
type Embedded = Self;
|
type Embedded = Self;
|
||||||
|
@ -1475,6 +1467,13 @@ impl Debug for IOValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::str::FromStr for IOValue {
|
||||||
|
type Err = io::Error;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
text::annotated_iovalue_from_str(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl serde::Serialize for IOValue {
|
impl serde::Serialize for IOValue {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||||
super::magic::output_value(serializer, self.clone())
|
super::magic::output_value(serializer, self.clone())
|
||||||
|
|
|
@ -29,11 +29,24 @@ pub struct TextWriter<W: io::Write> {
|
||||||
|
|
||||||
impl std::default::Default for CommaStyle {
|
impl std::default::Default for CommaStyle {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
CommaStyle::None
|
CommaStyle::Separating
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextWriter<&mut Vec<u8>> {
|
impl TextWriter<&mut Vec<u8>> {
|
||||||
|
pub fn fmt_value<N: NestedValue, Enc: DomainEncode<N::Embedded>>(
|
||||||
|
f: &mut std::fmt::Formatter<'_>,
|
||||||
|
enc: &mut Enc,
|
||||||
|
v: &crate::value::Value<N>,
|
||||||
|
) -> 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)?;
|
||||||
|
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<N: NestedValue, Enc: DomainEncode<N::Embedded>>(
|
||||||
enc: &mut Enc,
|
enc: &mut Enc,
|
||||||
v: &N,
|
v: &N,
|
||||||
|
|
Loading…
Reference in New Issue