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<()> {
|
||||
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)?;
|
||||
println!("(via generic decoding) {}: {:?}", kind, fruits1);
|
||||
|
|
|
@ -19,6 +19,17 @@ mod 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> {
|
||||
Ok(match v {
|
||||
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)]
|
||||
mod serde_tests {
|
||||
use crate::symbol::Symbol;
|
||||
|
|
|
@ -4,6 +4,7 @@ use super::BinarySource;
|
|||
use super::BytesBinarySource;
|
||||
use super::Embeddable;
|
||||
use super::IOValue;
|
||||
use super::NestedValue;
|
||||
use super::Reader;
|
||||
use super::Writer;
|
||||
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;
|
||||
|
||||
impl DomainDecode<IOValue> for IOValueDomainCodec {
|
||||
|
|
|
@ -17,6 +17,8 @@ pub use de::from_value;
|
|||
pub use domain::DomainDecode;
|
||||
pub use domain::DomainEncode;
|
||||
pub use domain::DomainParse;
|
||||
pub use domain::DebugDomainEncode;
|
||||
pub use domain::FromStrDomainParse;
|
||||
pub use domain::IOValueDomainCodec;
|
||||
pub use domain::NoEmbeddedDomainCodec;
|
||||
pub use domain::ViaCodec;
|
||||
|
|
|
@ -7,6 +7,7 @@ use std::convert::TryFrom;
|
|||
use std::convert::TryInto;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::io;
|
||||
use std::ops::Index;
|
||||
use std::ops::IndexMut;
|
||||
use std::string::String;
|
||||
|
@ -16,14 +17,29 @@ use std::vec::Vec;
|
|||
pub use std::collections::BTreeSet as Set;
|
||||
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::text;
|
||||
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 {}
|
||||
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 {
|
||||
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> 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 {
|
||||
match self {
|
||||
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),
|
||||
Value::SignedInteger(v) => write!(f, "{}", v),
|
||||
Value::String(v) => write!(f, "{:?}", v), // TODO: proper escaping!
|
||||
Value::ByteString(v) => {
|
||||
f.write_str("#x\"")?;
|
||||
for b in v { write!(f, "{:02x}", b)? }
|
||||
f.write_str("\"")
|
||||
}
|
||||
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),
|
||||
}
|
||||
TextWriter::fmt_value(f, &mut DebugDomainEncode, self).map_err(|_| std::fmt::Error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Err: Into<io::Error>, D: Embeddable + std::str::FromStr<Err = Err>, N: NestedValue<Embedded = D>>
|
||||
std::str::FromStr for Value<N>
|
||||
{
|
||||
type Err = io::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(text::from_str::<N, _>(s, FromStrDomainParse)?.value_owned())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1432,7 +1420,11 @@ impl<D: Embeddable> Debug for ArcValue<D> {
|
|||
pub struct IOValue(Arc<AnnotatedValue<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 {
|
||||
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 {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||
super::magic::output_value(serializer, self.clone())
|
||||
|
|
|
@ -29,11 +29,24 @@ pub struct TextWriter<W: io::Write> {
|
|||
|
||||
impl std::default::Default for CommaStyle {
|
||||
fn default() -> Self {
|
||||
CommaStyle::None
|
||||
CommaStyle::Separating
|
||||
}
|
||||
}
|
||||
|
||||
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>>(
|
||||
enc: &mut Enc,
|
||||
v: &N,
|
||||
|
|
Loading…
Reference in New Issue