Experimental deserialization direct from Reader

This commit is contained in:
Tony Garnock-Jones 2021-07-21 21:52:20 +02:00
parent 6d9ed94065
commit cae254ef21
16 changed files with 1489 additions and 168 deletions

View File

@ -11,10 +11,9 @@ license = "Apache-2.0"
[dependencies]
preserves = { path = "../preserves", version = "0.15.0" }
structopt = "0.3.14"
glob = "0.3.0"
regex = "1.5.4"
convert_case = "0.4.0"
glob = "0.3.0"
lazy_static = "1.4.0"
regex = "1.5.4"
structopt = "0.3.14"
thiserror = "1.0"

View File

@ -1,11 +0,0 @@
use crate::*;
use crate::syntax::block::Item;
use crate::syntax::block::constructors::*;
pub fn push_let(body: &mut Vec<Item>, name: Item, expr: Item) {
body.push(item(seq!["let ", name, " = ", expr, ";"]))
}
pub fn push_let_mut(body: &mut Vec<Item>, name: Item, expr: Item) {
body.push(item(seq!["let mut ", name, " = ", expr, ";"]))
}

View File

@ -1,5 +1,6 @@
use crate::*;
use crate::syntax::block::Item;
use crate::syntax::block::escape_string;
use crate::syntax::block::constructors::*;
use crate::gen::schema::*;
@ -22,6 +23,7 @@ pub enum ModuleContextMode {
}
pub struct ModuleContext<'m> {
pub module_path: ModulePath,
pub config: &'m CompilerConfig,
pub literals: Map<_Any, String>,
pub typedefs: Vec<Item>,
@ -30,9 +32,11 @@ pub struct ModuleContext<'m> {
}
pub struct FunctionContext<'a, 'm> {
pub error_context: String,
pub m: &'a mut ModuleContext<'m>,
pub temp_counter: usize,
pub captures: Vec<Capture>,
pub capture_mode: CaptureMode,
}
pub struct Capture {
@ -41,13 +45,19 @@ pub struct Capture {
pub source_expr: String,
}
pub enum CaptureMode {
Definite,
Indefinite(Vec<Item>),
}
lazy_static! {
static ref ID_RE: regex::Regex = regex::Regex::new(r"^[a-zA-Z][a-zA-Z_0-9]*$").unwrap();
}
impl<'m> ModuleContext<'m> {
pub fn new(config: &'m CompilerConfig) -> Self {
pub fn new(config: &'m CompilerConfig, module_path: &ModulePath) -> Self {
ModuleContext {
module_path: module_path.to_owned(),
config: config,
literals: Map::new(),
typedefs: Vec::new(),
@ -73,8 +83,8 @@ impl<'m> ModuleContext<'m> {
self.typedefs.push(i)
}
pub fn define_function<F: FnOnce(FunctionContext) -> Item>(&mut self, f: F) {
let i = f(FunctionContext::new(self));
pub fn define_function<F: FnOnce(FunctionContext) -> Item>(&mut self, error_context: &str, f: F) {
let i = f(FunctionContext::new(self, error_context));
self.functiondefs.push(i)
}
@ -111,11 +121,13 @@ impl<'m> ModuleContext<'m> {
}
impl<'a, 'm> FunctionContext<'a, 'm> {
pub fn new(m: &'a mut ModuleContext<'m>) -> Self {
pub fn new(m: &'a mut ModuleContext<'m>, error_context: &str) -> Self {
FunctionContext {
error_context: error_context.to_owned(),
m: m,
temp_counter: 0,
captures: Vec::new(),
capture_mode: CaptureMode::Definite,
}
}
@ -123,7 +135,12 @@ impl<'a, 'm> FunctionContext<'a, 'm> {
self.captures.push(Capture {
field_name: field_name,
ty: ty,
source_expr: source_expr,
source_expr: match self.capture_mode {
CaptureMode::Definite =>
source_expr,
CaptureMode::Indefinite(_) =>
format!("{}.ok_or_else(|| {:?})?", source_expr, self.conformance_err_code()),
}
})
}
@ -142,6 +159,29 @@ impl<'a, 'm> FunctionContext<'a, 'm> {
format!("_tmp{}", i)
}
pub fn declare_compound(&self, body: &mut Vec<Item>, name: &str, init_expr: Item) {
body.push(item(seq!["let mut ", name.to_owned(), " = ", init_expr, ";"]));
}
pub fn define_atom(&mut self, body: &mut Vec<Item>, name: &str, val_expr: Item) {
body.push(match &mut self.capture_mode {
CaptureMode::Definite => item(seq!["let ", name.to_owned(), " = ", val_expr, ";"]),
CaptureMode::Indefinite(items) => {
items.push(item(seq!["let mut ", name.to_owned(), " = None;"]));
item(seq![name.to_owned(), " = Some(", val_expr, ");"])
}
})
}
pub fn with_indefinite_mode<F: FnOnce(&mut Self) -> ()>(&mut self, f: F) -> Vec<Item> {
let saved_mode = std::mem::replace(&mut self.capture_mode, CaptureMode::Indefinite(Vec::new()));
f(self);
match std::mem::replace(&mut self.capture_mode, saved_mode) {
CaptureMode::Definite => panic!("corrupt capture_mode"),
CaptureMode::Indefinite(declarations) => declarations,
}
}
pub fn branch<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R {
let saved_temp_counter = self.temp_counter;
let saved_capture_count = self.captures.len();
@ -150,4 +190,13 @@ impl<'a, 'm> FunctionContext<'a, 'm> {
self.captures.truncate(saved_capture_count);
result
}
pub fn err_code(&self) -> Item {
return item(seq!["Err", parens![self.conformance_err_code()]]);
}
pub fn conformance_err_code(&self) -> Item {
return item(seq!["_support::ParseError::conformance_error", parens![
escape_string(&(self.m.module_path.0.join(".") + "." + &self.error_context))]]);
}
}

View File

@ -1,9 +1,9 @@
pub mod types;
pub mod names;
pub mod context;
pub mod names;
pub mod parsers;
pub mod readers;
pub mod types;
pub mod unparsers;
pub mod codegen;
use crate::*;
use crate::gen::schema::*;
@ -115,7 +115,7 @@ pub fn compile(config: &CompilerConfig) -> io::Result<()> {
let module_name = names::render_modname(&module_name);
output_path.set_file_name(format!("{}.rs", module_name));
DirBuilder::new().recursive(true).create(output_path.parent().unwrap())?;
let mut m = context::ModuleContext::new(config);
let mut m = context::ModuleContext::new(config, &ModulePath(k.clone()));
let mut modes: Vec<context::ModuleContextMode> =
vec![context::ModuleContextMode::TargetAny];
@ -144,6 +144,7 @@ pub fn compile(config: &CompilerConfig) -> io::Result<()> {
parsers::gen_definition_parser(&mut m, n, d);
unparsers::gen_definition_unparser(&mut m, n, d);
}
readers::gen_definition_reader(&mut m, n, d);
}
//---------------------------------------------------------------------------
@ -157,6 +158,7 @@ pub fn compile(config: &CompilerConfig) -> io::Result<()> {
lines.push("use preserves::value::Domain;".to_owned());
lines.push("use preserves::value::NestedValue;".to_owned());
lines.push(format!("use {}::support as _support;", &config.support_crate));
lines.push("use _support::Deserialize;".to_owned());
lines.push("".to_owned());
for mode in &modes {

View File

@ -3,13 +3,13 @@ use crate::gen::schema::*;
use crate::syntax::block::Item;
use crate::syntax::block::constructors::*;
use super::codegen::*;
use super::context::{ModuleContextMode, ModuleContext, FunctionContext};
use super::names;
use super::types::*;
pub fn gen_definition_parser(m: &mut ModuleContext, n: &str, d: &Definition) {
m.define_function(
n,
|mut ctxt| {
let mut body = vec![];
@ -22,6 +22,7 @@ pub fn gen_definition_parser(m: &mut ModuleContext, n: &str, d: &Definition) {
names::render_fieldname(n), "_", names::render_fieldname(name)];
let ctorname = item(name![names::render_constructor(n), names::render_constructor(name)]);
ctxt.m.define_function(
&(n.to_owned() + "::" + name),
|mut ctxt| {
let mut body = Vec::new();
let dest = pattern_parser(&mut ctxt, pat, "value", None, &mut body);
@ -33,7 +34,7 @@ pub fn gen_definition_parser(m: &mut ModuleContext, n: &str, d: &Definition) {
});
body.push(item(seq!["if let Ok(r) = ", fname, "(value) { return Ok(r); }"]));
}
body.push(item(seq!["Err(_support::ParseError::ConformanceError)"]));
body.push(item(seq![ctxt.err_code()]));
}
Definition::And { pattern_0, pattern_1, pattern_n } => {
let mut ps = vec![&**pattern_0, &**pattern_1];
@ -108,9 +109,9 @@ fn simple_pattern_parser(
SimplePattern::Any => {
match ctxt.m.mode {
ModuleContextMode::TargetIOValue =>
push_let(body, item(dest.to_owned()), item(seq!["_support::decode_embedded", parens![src.to_owned()], "?"])),
ctxt.define_atom(body, &dest, item(seq!["_support::decode_embedded", parens![src.to_owned()], "?"])),
ModuleContextMode::TargetAny =>
push_let(body, item(dest.to_owned()), item(src.to_owned())),
ctxt.define_atom(body, &dest, item(src.to_owned())),
}
dest
},
@ -124,26 +125,26 @@ fn simple_pattern_parser(
AtomKind::ByteString => "to_bytestring",
AtomKind::Symbol => "to_symbol",
};
push_let(body, item(dest.to_owned()), item(seq![src.to_owned(), ".value().", converter, "()?"]));
ctxt.define_atom(body, &dest, item(seq![src.to_owned(), ".value().", converter, "()?"]));
dest
},
SimplePattern::Embedded { .. } => {
match ctxt.m.mode {
ModuleContextMode::TargetIOValue =>
push_let(body, item(dest.to_owned()), item(seq![
ctxt.define_atom(body, &dest, item(seq![
"std::sync::Arc::new(_Dom::try_from",
parens![seq![src.to_owned(), ".value().to_embedded()?"]],
"?)"])),
ModuleContextMode::TargetAny =>
push_let(body, item(dest.to_owned()), item(seq![
ctxt.define_atom(body, &dest, item(seq![
parens![seq![src.to_owned(), ".value().to_embedded()?"]]])),
}
dest
},
SimplePattern::Lit { value } => {
body.push(item(seq!["if ", src.to_owned(), " != ", ctxt.m.define_literal(value),
" { return Err(_support::ParseError::ConformanceError); }"]));
push_let(body, item(dest.to_owned()), item("()"));
" { return ", ctxt.err_code(), "; }"]));
ctxt.define_atom(body, &dest, item("()"));
dest
},
SimplePattern::Seqof { pattern } => {
@ -153,7 +154,7 @@ fn simple_pattern_parser(
let item_dest = simple_pattern_parser(ctxt, pattern, &tmp, None, &mut inner);
inner.push(item(seq![dest.to_owned(), ".push(",
store_wrap(true, &field_type(pattern), &item_dest), ");"]));
push_let_mut(body, item(dest.to_owned()), item("std::vec::Vec::new()"));
ctxt.declare_compound(body, &dest, item("std::vec::Vec::new()"));
body.push(item(seq!["for ", tmp.to_owned(),
" in &", src.to_owned(), brackets![seq![n.to_string() , ".."]],
" ", block(inner)]));
@ -165,7 +166,7 @@ fn simple_pattern_parser(
let item_dest = simple_pattern_parser(ctxt, pattern, &tmp, None, &mut inner);
inner.push(item(seq![dest.to_owned(), ".insert(",
store_wrap(true, &field_type(pattern), &item_dest), ");"]));
push_let_mut(body, item(dest.to_owned()), item("preserves::value::Set::new()"));
ctxt.declare_compound(body, &dest, item("preserves::value::Set::new()"));
body.push(item(seq!["for ", tmp.to_owned(),
" in ", src.to_owned(), ".value().to_set()?",
" ", block(inner)]));
@ -181,7 +182,7 @@ fn simple_pattern_parser(
dest.to_owned(), ".insert(",
store_wrap(true, &field_type(key), &key_dest), ", ",
store_wrap(true, &field_type(value), &value_dest), ");"]));
push_let_mut(body, item(dest.to_owned()), item("preserves::value::Map::new()"));
ctxt.declare_compound(body, &dest, item("preserves::value::Map::new()"));
body.push(item(seq!["for (", tmp_key.to_owned(), ", ", tmp_value.to_owned(), ")",
" in ", src.to_owned(), ".value().to_dictionary()?",
" ", block(inner)]));
@ -189,9 +190,9 @@ fn simple_pattern_parser(
},
SimplePattern::Ref(r) => {
let tf = name![ctxt.m.render_ref(&**r), "try_from"];
push_let(body,
item(dest.to_owned()),
item(seq![tf, parens![seq![src.to_owned()]], "?"]));
ctxt.define_atom(body,
&dest,
item(seq![tf, parens![seq![src.to_owned()]], "?"]));
dest
},
}
@ -207,9 +208,7 @@ fn sequenceify(
Some(n) => (src.to_owned(), n),
None => {
let tmp = ctxt.gentempname();
push_let(body,
item(tmp.to_owned()),
item(seq![src.to_owned(), ".value().to_sequence()?"]));
ctxt.define_atom(body, &tmp, item(seq![src.to_owned(), ".value().to_sequence()?"]));
(tmp, 0)
}
}
@ -228,7 +227,7 @@ fn fixed_sequence_parser(
body.push(item(seq!["if ", src.to_owned(), ".len()",
if base > 0 { seq![" - ", base.to_string()] } else { seq![] },
" < ", required_count.to_string(),
" { return Err(_support::ParseError::ConformanceError); }"]));
" { return ", ctxt.err_code(), "; }"]));
}
for p in ps {
named_pattern_parser(ctxt, p, &format!("(&{}[{}])", src, i), None, body);
@ -270,7 +269,7 @@ fn pattern_parser(
match &**c {
CompoundPattern::Rec { label, fields } => {
let rtmp = ctxt.gentempname();
push_let(body, item(rtmp.to_owned()), item(seq![src.to_owned(), ".value().to_record(None)?"]));
ctxt.define_atom(body, &rtmp, item(seq![src.to_owned(), ".value().to_record(None)?"]));
named_pattern_parser(ctxt, &**label, &format!("{}.label()", rtmp), None, body);
named_pattern_parser(ctxt, &**fields, &format!("{}.fields()", rtmp), Some(0), body);
},
@ -285,12 +284,13 @@ fn pattern_parser(
},
CompoundPattern::Dict { entries } => {
let dtmp = ctxt.gentempname();
push_let(body, item(dtmp.to_owned()), item(seq![src.to_owned(), ".value().to_dictionary()?"]));
ctxt.define_atom(body, &dtmp, item(seq![src.to_owned(), ".value().to_dictionary()?"]));
for (key_lit, value_pat) in entries.0.iter() {
let vtmp = ctxt.gentempname();
push_let(body, item(vtmp.to_owned()), item(seq![
let init_expr = item(seq![
dtmp.to_owned(), ".get", parens![ctxt.m.define_literal(key_lit)],
".ok_or(_support::ParseError::ConformanceError)?"]));
".ok_or_else(|| ", ctxt.conformance_err_code(), ")?"]);
ctxt.define_atom(body, &vtmp, init_expr);
named_pattern_parser(ctxt, &promote(value_pat), &vtmp, None, body);
}
}

View File

@ -0,0 +1,412 @@
use crate::*;
use crate::gen::schema::*;
use crate::syntax::block::Item;
use crate::syntax::block::escape_string;
use crate::syntax::block::escape_bytes;
use crate::syntax::block::constructors::*;
use preserves::value::AtomClass;
use preserves::value::CompoundClass;
use preserves::value::NestedValue;
use preserves::value::ValueClass;
use super::context::{ModuleContext, FunctionContext};
use super::names;
use super::types::*;
pub fn gen_definition_reader(m: &mut ModuleContext, n: &str, d: &Definition) {
m.define_function(
n,
|mut ctxt| {
let mut body = vec![];
match d {
Definition::Or { pattern_0, pattern_1, pattern_n } => {
let mut ps = vec![&**pattern_0, &**pattern_1];
ps.extend(pattern_n);
ctxt.define_atom(&mut body, "_mark", item("r.mark()?"));
for NamedAlternative { variant_label: name, pattern: pat } in ps {
let fname = seq![ctxt.m.target_prefix(), "read_",
names::render_fieldname(n), "_", names::render_fieldname(name)];
let ctorname = item(name![names::render_constructor(n), names::render_constructor(name)]);
ctxt.m.define_function(
&(n.to_owned() + "::" + name),
|mut ctxt| {
let mut body = Vec::new();
let dest = pattern_reader(&mut ctxt, pat, false, &mut body);
let dest = dest.as_ref().map(String::as_str);
construct(&ctxt, ctorname, false, &pattern_type(pat), dest, &mut body);
item(seq![
"fn ", fname.clone(), anglebrackets![
"'de",
"R: _support::Reader<'de, _Ptr, _Any>"],
"(r: &mut R) -> ",
"std::result::Result<", names::render_constructor(n), ", _support::ParseError> ",
block(body)])
});
body.push(item(seq![
"match ", fname, "(r) { ",
"Err(e) if e.is_conformance_error() => r.restore(&_mark)?, ",
"result => return result }"]));
}
body.push(item(seq![ctxt.err_code()]));
}
Definition::And { pattern_0, pattern_1, pattern_n } => {
let mut ps = vec![&**pattern_0, &**pattern_1];
ps.extend(pattern_n);
for e in &ps {
named_pattern_reader(&mut ctxt, e, false, &mut body);
}
construct(&ctxt, item(names::render_constructor(n)), true, &record_type(&ps), None, &mut body);
}
Definition::Pattern(p) => {
let dest = pattern_reader(&mut ctxt, p, false, &mut body);
let dest = dest.as_ref().map(String::as_str);
construct(&ctxt, item(names::render_constructor(n)), true, &pattern_type(p), dest, &mut body);
}
}
item(seq![
"impl", anglebrackets!["'de", "R: _support::Reader<'de, _Ptr, _Any>"], " ",
"_support::Deserialize", anglebrackets!["'de", "_Ptr", "_Any", "R"], " ",
"for ", names::render_constructor(n), " ", block![
seq!["fn deserialize(r: &mut R) -> ",
"std::result::Result<Self, _support::ParseError> ",
block(body)]]])
});
}
fn construct(
ctxt: &FunctionContext,
ctorname: Item,
is_struct: bool,
ty: &TSimple,
dest: Option<&str>,
body: &mut Vec<Item>,
) {
match ty {
TSimple::Field(TField::Unit) =>
body.push(item(seq!["Ok(", ctorname, ")"])),
TSimple::Field(fieldty) =>
body.push(item(seq!["Ok(", ctorname, parens![store_wrap(is_struct, fieldty, dest.unwrap())], ")"])),
TSimple::Record(_) =>
body.push(item(seq!["Ok(", ctorname, " ", braces(
ctxt.captures.iter().map(
|c| item(seq![c.field_name.clone(), ": ", store_wrap(is_struct, &c.ty, &c.source_expr)])).collect()),
")"])),
}
}
fn store_wrap(is_struct: bool, ty: &TField, expr: &str) -> String {
match ty {
TField::Unit
| TField::Array(_)
| TField::Set(_)
| TField::Map(_, _) => expr.to_owned(),
TField::Ref(_) =>
if is_struct {
expr.to_owned()
} else {
format!("std::boxed::Box::new({})", expr)
},
TField::Base(_) => expr.to_owned(),
}
}
fn group_by<T, K, Key>(mut items: Vec<T>, mut key: Key) -> Vec<(K, Vec<T>)>
where
K: Ord + Clone,
Key: FnMut(&T) -> K,
{
let mut result = Vec::new();
let mut current_key: Option<K> = None;
let mut buf = Vec::new();
items.sort_by(|a, b| key(a).cmp(&key(b)));
for (k, v) in items.into_iter().map(|t| (key(&t), t)) {
match current_key.cmp(&Some(k.clone())) {
std::cmp::Ordering::Equal => (),
std::cmp::Ordering::Less |
std::cmp::Ordering::Greater => {
if let Some(k) = current_key {
result.push((k, std::mem::take(&mut buf)));
}
current_key = Some(k);
}
}
buf.push(v)
}
if let Some(k) = current_key {
result.push((k.clone(), std::mem::take(&mut buf)));
}
result
}
type LiteralContinuation = Box<dyn FnOnce(&mut FunctionContext, &mut Vec<Item>) -> ()>;
type LiteralCases = Vec<(_Any, LiteralContinuation)>;
type LiteralSeqCases = Vec<(Vec<_Any>, LiteralContinuation)>;
fn read_expected_literal_seqs(
ctxt: &mut FunctionContext,
body: &mut Vec<Item>,
possibilities: LiteralSeqCases,
) {
let grouped = group_by(possibilities, |(vs, _f)| if vs.is_empty() {
None
} else {
Some(vs[0].clone())
});
let mut cases = Vec::new();
let mut nested: LiteralCases = Vec::new();
for (head, group) in grouped.into_iter() {
match head {
None => {
let mut inner = Vec::new();
group.into_iter().next().unwrap().1(ctxt, &mut inner);
cases.push(item(seq!["preserves::value::Token::End => ", block(inner)]));
},
Some(h) => {
let tails = group.into_iter().map(|(mut vs, f)| {
vs.remove(0);
(vs, f)
}).collect();
nested.push((h, Box::new(|ctxt: &mut FunctionContext, b: &'_ mut Vec<Item>| {
read_expected_literal_seqs(ctxt, b, tails)
})));
}
}
}
cases.extend(read_expected_literals_cases(ctxt, nested));
body.push(item(seq!["match r.next_token(false)? ", block(cases)]));
}
fn read_expected_literals_cases(
ctxt: &mut FunctionContext,
possibilities: LiteralCases,
) -> Vec<Item> {
let grouped = group_by(possibilities, |(v, _f)| v.value_class());
let mut cases = grouped.into_iter().map(|(n, group)| {
match n {
ValueClass::Atomic(cls) => {
let mut subcases = Vec::new();
for p in group {
let mut inner = Vec::new();
p.1(ctxt, &mut inner);
subcases.push(item(seq![
format!("preserves::value::Value::{:?}(w)", cls),
match cls {
AtomClass::Boolean => match p.0.value().to_boolean().unwrap() {
true => " if *w".to_owned(),
false => " if !*w".to_owned(),
},
AtomClass::Float |
AtomClass::Double =>
format!(" if w.0 == {:?}", p.0),
AtomClass::SignedInteger =>
format!(" if *w == ({:?}).into()", p.0),
AtomClass::String =>
format!(" if w == {}", escape_string(p.0.value().to_string().unwrap())),
AtomClass::ByteString =>
format!(" if w == {}", escape_bytes(p.0.value().to_bytestring().unwrap())),
AtomClass::Symbol =>
format!(" if w == {}", escape_string(p.0.value().to_symbol().unwrap())),
},
" => ",
block(inner)]));
}
subcases.push(item(seq!["_ => return ", ctxt.err_code(), "?,"]));
item(seq!["preserves::value::Token::Atom(v) => match v.value() ", block(subcases)])
}
ValueClass::Compound(CompoundClass::Record) => {
let mut subcases = Vec::new();
read_expected_literal_seqs(ctxt, &mut subcases, group.into_iter().map(|(v, f)| {
let r = v.value().to_record(None).unwrap();
(r.0.clone(), f)
}).collect());
item(seq![
"preserves::value::Token::Compound(preserves::value::CompoundClass::Record) => ",
block(subcases)])
}
ValueClass::Compound(CompoundClass::Sequence) => {
let mut subcases = Vec::new();
read_expected_literal_seqs(ctxt, &mut subcases, group.into_iter().map(|(v, f)| {
let s = v.value().to_sequence().unwrap().clone();
(s, f)
}).collect());
item(seq![
"preserves::value::Token::Compound(preserves::value::CompoundClass::Sequence) => ",
block(subcases)])
}
ValueClass::Compound(CompoundClass::Set) => {
panic!("Sets in literal constants in Schema not yet supported");
}
ValueClass::Compound(CompoundClass::Dictionary) => {
panic!("Dictionaries in literal constants in Schema not yet supported");
}
ValueClass::Embedded => {
panic!("Embedded values in literal constants in Schema not yet supported");
}
}
}).collect::<Vec<_>>();
cases.push(item(seq!["_ => return ", ctxt.err_code(), "?,"]));
cases
}
fn read_expected_literals(
ctxt: &mut FunctionContext,
body: &mut Vec<Item>,
possibilities: LiteralCases,
) {
let cases = read_expected_literals_cases(ctxt, possibilities);
body.push(item(seq!["match r.next_token(false)? ", block(cases)]));
}
fn simple_pattern_reader(
ctxt: &mut FunctionContext,
p: &SimplePattern,
in_sequence: bool,
body: &mut Vec<Item>,
) -> String {
let dest = ctxt.gentempname();
match p {
SimplePattern::Any => {
ctxt.define_atom(body, &dest, item("r.demand_next(false)?"));
dest
},
SimplePattern::Atom { atom_kind: k } => {
let reader = match &**k {
AtomKind::Boolean => "r.next_boolean()?",
AtomKind::Float => "r.next_float()?",
AtomKind::Double => "r.next_double()?",
AtomKind::SignedInteger => "r.next_signedinteger()?",
AtomKind::String => "r.next_str()?.into_owned()",
AtomKind::ByteString => "r.next_bytestring()?.into_owned()",
AtomKind::Symbol => "r.next_symbol()?.into_owned()",
};
ctxt.define_atom(body, &dest, item(reader.to_owned()));
dest
},
SimplePattern::Embedded { .. } => {
body.push(item("r.open_embedded()?;"));
ctxt.define_atom(body, &dest, item("r.demand_next(false)?.value().to_embedded()?.clone()"));
body.push(item("r.close_embedded()?;"));
dest
},
SimplePattern::Lit { value } => {
let f = Box::new(|_ctxt: &mut FunctionContext, _: &'_ mut Vec<Item>| ());
read_expected_literals(ctxt, body, vec![(value.clone(), f)]);
ctxt.define_atom(body, &dest, item("()"));
dest
},
SimplePattern::Seqof { pattern } => {
if !in_sequence {
body.push(item("r.open_sequence()?;"));
}
let mut inner = Vec::new();
let item_dest = simple_pattern_reader(ctxt, pattern, false, &mut inner);
inner.push(item(seq![dest.to_owned(), ".push(",
store_wrap(true, &field_type(pattern), &item_dest), ");"]));
ctxt.declare_compound(body, &dest, item("std::vec::Vec::new()"));
body.push(item(seq!["while !(r.close_compound()?) ", block(inner)]));
dest
},
SimplePattern::Setof { pattern } => {
body.push(item("r.open_set()?;"));
let mut inner = Vec::new();
let item_dest = simple_pattern_reader(ctxt, pattern, false, &mut inner);
inner.push(item(seq![dest.to_owned(), ".insert(",
store_wrap(true, &field_type(pattern), &item_dest), ");"]));
ctxt.declare_compound(body, &dest, item("preserves::value::Set::new()"));
body.push(item(seq!["while !(r.close_compound()?) ", block(inner)]));
dest
},
SimplePattern::Dictof { key, value } => {
body.push(item("r.open_dictionary()?;"));
let mut inner = Vec::new();
let key_dest = simple_pattern_reader(ctxt, key, false, &mut inner);
let value_dest = simple_pattern_reader(ctxt, value, false, &mut inner);
inner.push(item(seq![
dest.to_owned(), ".insert(",
store_wrap(true, &field_type(key), &key_dest), ", ",
store_wrap(true, &field_type(value), &value_dest), ");"]));
ctxt.declare_compound(body, &dest, item("preserves::value::Map::new()"));
body.push(item(seq!["while !(r.close_compound()?) ", block(inner)]));
dest
},
SimplePattern::Ref(r) => {
let tf = name![ctxt.m.render_ref(&**r), "deserialize"];
ctxt.define_atom(body, &dest, item(seq![tf, "(r)?"]));
dest
},
}
}
fn named_pattern_reader(
ctxt: &mut FunctionContext,
p: &NamedPattern,
in_sequence: bool,
body: &mut Vec<Item>,
) {
match p {
NamedPattern::Anonymous(p) => {
pattern_reader(ctxt, p, in_sequence, body);
},
NamedPattern::Named(b) => {
let Binding { name, pattern} = &**b;
let dest = simple_pattern_reader(ctxt, pattern, in_sequence, body);
let capture_ty = field_type(pattern);
ctxt.capture(names::render_fieldname(name), capture_ty, dest);
}
}
}
fn pattern_reader(
ctxt: &mut FunctionContext,
p: &Pattern,
in_sequence: bool,
body: &mut Vec<Item>,
) -> Option<String> {
match p {
Pattern::SimplePattern(s) =>
Some(simple_pattern_reader(ctxt, s, in_sequence, body)),
Pattern::CompoundPattern(c) => {
match &**c {
CompoundPattern::Rec { label, fields } => {
body.push(item("r.open_record(None)?;"));
named_pattern_reader(ctxt, &**label, false, body);
named_pattern_reader(ctxt, &**fields, true, body);
},
CompoundPattern::Tuple { patterns } => {
if !in_sequence {
body.push(item("r.open_sequence()?;"));
}
for p in patterns { named_pattern_reader(ctxt, p, false, body); }
body.push(item("r.ensure_complete()?;"));
},
CompoundPattern::TuplePrefix { fixed, variable } => {
if !in_sequence {
body.push(item("r.open_sequence()?;"));
}
for p in fixed { named_pattern_reader(ctxt, p, false, body); }
named_pattern_reader(ctxt, &promote(variable), true, body);
},
CompoundPattern::Dict { entries } => {
body.push(item("r.open_dictionary()?;"));
let mut inner = Vec::new();
body.extend(ctxt.with_indefinite_mode(|ctxt| {
read_expected_literals(ctxt, &mut inner, entries.0.iter().map(move |(key_lit, value_pat)| {
let value_pat = value_pat.clone();
let f: LiteralContinuation = Box::new(
move |ctxt: &mut FunctionContext, innerinner: &mut Vec<Item>| {
named_pattern_reader(ctxt, &promote(&value_pat), false, innerinner);
innerinner.push(item("continue;"));
});
(key_lit.clone(), f)
}).collect());
}));
body.push(item(seq!["while !(r.close_compound()?) ", block(inner)]));
}
}
None
},
}
}

View File

@ -6,7 +6,6 @@ use crate::syntax::block::{Emittable, Item};
use std::cell::Cell;
use std::rc::Rc;
use super::codegen::*;
use super::context::{ModuleContextMode, ModuleContext, FunctionContext};
use super::names;
use super::types::*;
@ -52,6 +51,7 @@ fn normal_src(src: String, is_struct: bool) -> ValueContext {
pub fn gen_definition_unparser(m: &mut ModuleContext, n: &str, d: &Definition) {
m.define_function(
n,
|mut ctxt| {
let mut body = Vec::new();
@ -70,13 +70,13 @@ pub fn gen_definition_unparser(m: &mut ModuleContext, n: &str, d: &Definition) {
let mut ps = vec![&**pattern_0, &**pattern_1];
ps.extend(pattern_n);
let (patpat, vc) = destruct(&mut ctxt, item(names::render_constructor(n)), true, &record_type(&ps));
push_let(&mut body, item(patpat), item("value"));
body.push(item(seq!["let ", patpat, " = value;"]));
body.push(item(seq!["preserves::value::merge(vec!", brackets(ps.iter().map(
|p| named_pattern_unparser(&mut ctxt, p, &vc)).collect()), ")"]));
}
Definition::Pattern(p) => {
let (patpat, vc) = destruct(&mut ctxt, item(names::render_constructor(n)), true, &pattern_type(p));
push_let(&mut body, item(patpat), item("value"));
body.push(item(seq!["let ", patpat, " = value;"]));
body.push(pattern_unparser(&mut ctxt, p, &vc));
}
}
@ -217,11 +217,11 @@ fn pattern_unparser(
CompoundPattern::Rec { label, fields } => {
let rtmp = ctxt.gentempname();
let mut body = Vec::new();
push_let_mut(&mut body,
item(rtmp.to_owned()),
item(seq!["preserves::value::Record(vec![",
named_pattern_unparser(ctxt, label, &normal_none(vc.is_struct)),
"])"]));
let init_expr = item(seq![
"preserves::value::Record(vec![",
named_pattern_unparser(ctxt, label, &normal_none(vc.is_struct)),
"])"]);
ctxt.declare_compound(&mut body, &rtmp, init_expr);
named_pattern_unparser(ctxt, fields, &ValueContext {
src: None,
sink: ValueSink::Fields(Rc::new(Cell::new(Some(FieldsSink {
@ -247,9 +247,9 @@ fn pattern_unparser(
})
},
CompoundPattern::Dict { entries } => {
let dtmp = item(ctxt.gentempname());
let dtmp = ctxt.gentempname();
let mut body = Vec::new();
push_let_mut(&mut body, dtmp.clone(), item("preserves::value::Map::new()"));
ctxt.declare_compound(&mut body, &dtmp, item("preserves::value::Map::new()"));
for (key_lit, value_pat) in entries.0.iter() {
body.push(item(seq![dtmp.clone(), ".insert", parens![
seq![parens![ctxt.m.define_literal(key_lit)], ".clone()"],
@ -271,13 +271,13 @@ fn sequenceify<'a>(
ValueContext { sink: ValueSink::Fields(fields_sink), .. } =>
(**fields_sink).take().unwrap(),
_ => {
let rtmp = item(ctxt.gentempname());
let rtmp = ctxt.gentempname();
let mut body = Vec::new();
push_let_mut(&mut body, rtmp.clone(), item("vec![]"));
ctxt.declare_compound(&mut body, &rtmp, item("std::vec::Vec::new()"));
FieldsSink {
finish: item(seq![
"preserves::value::Value::Sequence", parens![rtmp.clone()], ".wrap()"]),
vec_expr: rtmp,
vec_expr: item(rtmp),
body: body,
}
}

View File

@ -1 +1 @@
pub mod schema;
pub mod schema;

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,7 @@
pub use lazy_static::lazy_static;
pub use preserves::value::Reader;
use preserves::value::ArcValue;
use preserves::value::Domain;
use preserves::value::Embeddable;
@ -13,6 +15,15 @@ use std::convert::TryFrom;
use std::io;
use std::sync::Arc;
use thiserror::Error;
pub trait Deserialize<'de, D: Embeddable, N: NestedValue<D>, R: Reader<'de, D, N>>
where
Self: Sized
{
fn deserialize(r: &mut R) -> Result<Self, ParseError>;
}
pub fn decode_lit<D: Embeddable, N: NestedValue<D>>(bs: &[u8]) -> io::Result<N> {
preserves::value::packed::from_bytes(bs, NoEmbeddedDomainCodec)
}
@ -36,46 +47,35 @@ where
&mut |d| Ok(Value::Embedded(IOValue::from(d)))).unwrap()
}
#[derive(Debug)]
#[derive(Error, Debug)]
pub enum ParseError {
ConformanceError,
IO(io::Error),
Preserves(preserves::error::Error),
#[error("Input not conformant with Schema: {0}")]
ConformanceError(&'static str),
#[error(transparent)]
Preserves(#[from] preserves::error::Error),
}
const INPUT_NOT_CONFORMANT: &str = "Input not conformant with Schema";
impl std::fmt::Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
match self {
ParseError::ConformanceError => write!(f, "{}", INPUT_NOT_CONFORMANT),
ParseError::IO(e) => e.fmt(f),
ParseError::Preserves(e) => e.fmt(f),
}
}
}
impl std::error::Error for ParseError {}
impl From<io::Error> for ParseError {
fn from(v: io::Error) -> Self {
ParseError::IO(v)
}
}
impl From<preserves::error::Error> for ParseError {
fn from(v: preserves::error::Error) -> Self {
ParseError::Preserves(v)
preserves::error::Error::from(v).into()
}
}
impl From<ParseError> for io::Error {
fn from(v: ParseError) -> Self {
match v {
ParseError::ConformanceError =>
io::Error::new(io::ErrorKind::InvalidData, INPUT_NOT_CONFORMANT),
ParseError::IO(e) => e,
ParseError::ConformanceError(_) => io::Error::new(io::ErrorKind::InvalidData, v),
ParseError::Preserves(e) => e.into(),
}
}
}
impl ParseError {
pub fn conformance_error(context: &'static str) -> Self {
ParseError::ConformanceError(context)
}
pub fn is_conformance_error(&self) -> bool {
return if let ParseError::ConformanceError(_) = self { true } else { false }
}
}

View File

@ -1,3 +1,4 @@
use std::fmt::Write;
use std::str;
pub const DEFAULT_WIDTH: usize = 80;
@ -171,6 +172,39 @@ impl std::fmt::Debug for Grouping {
//---------------------------------------------------------------------------
pub fn escape_string(s: &str) -> String {
let mut buf = String::new();
buf.push('"');
for c in s.chars() {
match c {
'\\' => buf.push_str("\\\\"),
'"' => buf.push_str("\\\""),
_ if c >= ' ' && c <= '~' => buf.push(c),
_ => write!(&mut buf, "\\u{{{:x}}}", c as i32).expect("no IO errors building a string"),
}
}
buf.push('"');
buf
}
pub fn escape_bytes(bs: &[u8]) -> String {
let mut buf = String::new();
buf.push_str("b\"");
for b in bs {
let c = *b as char;
match c {
'\\' => buf.push_str("\\\\"),
'"' => buf.push_str("\\\""),
_ if c >= ' ' && c <= '~' => buf.push(c),
_ => write!(&mut buf, "\\x{{{:02x}}}", b).expect("no IO errors building a string"),
}
}
buf.push('"');
buf
}
//---------------------------------------------------------------------------
pub mod constructors {
use super::Sequence;
use super::Grouping;

View File

@ -2,6 +2,7 @@ use serde::Deserialize;
use serde::de::{Visitor, SeqAccess, MapAccess, EnumAccess, VariantAccess, DeserializeSeed};
use std::borrow::Cow;
use std::io;
use std::marker::PhantomData;
use super::value::{IOValue, IOValueDomainCodec, PackedReader};
@ -24,7 +25,7 @@ where
from_reader(&mut PackedReader::new(&mut BytesBinarySource::new(bytes), IOValueDomainCodec))
}
pub fn from_read<'de, 'r, IOR: std::io::Read, T>(read: &'r mut IOR) ->
pub fn from_read<'de, 'r, IOR: io::Read + io::Seek, T>(read: &'r mut IOR) ->
Result<T>
where
T: Deserialize<'de>

View File

@ -21,8 +21,11 @@ pub use reader::BytesBinarySource;
pub use reader::ConfiguredReader;
pub use reader::IOBinarySource;
pub use reader::Reader;
pub use reader::Token;
pub use repr::AnnotatedValue;
pub use repr::ArcValue;
pub use repr::AtomClass;
pub use repr::CompoundClass;
pub use repr::Domain;
pub use repr::Double;
pub use repr::Embeddable;
@ -36,6 +39,7 @@ pub use repr::Record;
pub use repr::Set;
pub use repr::UnwrappedIOValue;
pub use repr::Value;
pub use repr::ValueClass;
pub use ser::Serializer;
pub use ser::to_value;
pub use writer::Writer;

View File

@ -11,6 +11,7 @@ use std::marker::PhantomData;
use super::constants::Tag;
use super::super::{
CompoundClass,
DomainDecode,
Embeddable,
Map,
@ -20,6 +21,7 @@ use super::super::{
Value,
reader::{
Token,
BinarySource,
ConfiguredReader,
Reader,
@ -39,6 +41,13 @@ impl<'de, 'src, D: Embeddable, N: NestedValue<D>, Dec: DomainDecode<D>, S: Binar
BinarySource<'de>
for PackedReader<'de, 'src, D, N, Dec, S>
{
type Mark = S::Mark;
fn mark(&mut self) -> io::Result<Self::Mark> {
self.source.mark()
}
fn restore(&mut self, mark: &Self::Mark) -> io::Result<()> {
self.source.restore(mark)
}
fn skip(&mut self) -> io::Result<()> {
self.source.skip()
}
@ -222,6 +231,24 @@ impl<'de, 'src, D: Embeddable, N: NestedValue<D>, Dec: DomainDecode<D>, S: Binar
_ => Err(self.expected(ExpectedKind::SignedInteger))
}
}
fn gather_annotations(&mut self) -> io::Result<Vec<N>> {
let mut annotations = vec![self.demand_next(true)?];
while Tag::try_from(self.peek()?)? == Tag::Annotation {
self.skip()?;
annotations.push(self.demand_next(true)?);
}
Ok(annotations)
}
fn skip_annotations(&mut self) -> io::Result<()> {
self.skip_value()?;
while Tag::try_from(self.peek()?)? == Tag::Annotation {
self.skip()?;
self.skip_value()?;
}
Ok(())
}
}
impl<'de, 'src, D: Embeddable, N: NestedValue<D>, Dec: DomainDecode<D>, S: BinarySource<'de>>
@ -249,20 +276,12 @@ impl<'de, 'src, D: Embeddable, N: NestedValue<D>, Dec: DomainDecode<D>, S: Binar
}
Tag::Annotation => {
if read_annotations {
let mut annotations = vec![self.demand_next(read_annotations)?];
while Tag::try_from(self.peek()?)? == Tag::Annotation {
self.skip()?;
annotations.push(self.demand_next(read_annotations)?);
}
let mut annotations = self.gather_annotations()?;
let (existing_annotations, v) = self.demand_next(read_annotations)?.pieces();
annotations.extend_from_slice(existing_annotations.slice());
N::wrap(Annotations::new(Some(annotations)), v)
} else {
self.skip_value()?;
while Tag::try_from(self.peek()?)? == Tag::Annotation {
self.skip()?;
self.skip_value()?;
}
self.skip_annotations()?;
self.demand_next(read_annotations)?
}
}
@ -373,6 +392,64 @@ impl<'de, 'src, D: Embeddable, N: NestedValue<D>, Dec: DomainDecode<D>, S: Binar
Ok(())
}
type Mark = S::Mark;
fn mark(&mut self) -> io::Result<Self::Mark> {
self.source.mark()
}
fn restore(&mut self, mark: &Self::Mark) -> io::Result<()> {
self.source.restore(mark)
}
fn next_token(&mut self, read_embedded_annotations: bool) -> io::Result<Token<D, N>> {
loop {
return Ok(match Tag::try_from(self.peek()?)? {
Tag::Embedded => {
self.skip()?;
Token::Embedded(self.decode_embedded.decode_embedded(
self.source,
read_embedded_annotations)?)
}
Tag::False |
Tag::True |
Tag::Float |
Tag::Double |
Tag::SmallInteger(_) |
Tag::MediumInteger(_) |
Tag::SignedInteger |
Tag::String |
Tag::ByteString |
Tag::Symbol =>
Token::Atom(self.demand_next(false)?),
Tag::Record => { self.skip()?; Token::Compound(CompoundClass::Record) }
Tag::Sequence => { self.skip()?; Token::Compound(CompoundClass::Sequence) }
Tag::Set => { self.skip()?; Token::Compound(CompoundClass::Set) }
Tag::Dictionary => { self.skip()?; Token::Compound(CompoundClass::Dictionary) }
Tag::End => { self.skip()?; Token::End }
Tag::Annotation => {
self.skip()?;
self.skip_annotations()?;
continue
}
})
}
}
fn next_annotations_and_token(&mut self) -> io::Result<(Vec<N>, Token<D, N>)> {
match Tag::try_from(self.peek()?)? {
Tag::Annotation => {
self.skip()?;
let annotations = self.gather_annotations()?;
Ok((annotations, self.next_token(true)?))
}
_ => Ok((Vec::new(), self.next_token(true)?)),
}
}
fn next_boolean(&mut self) -> ReaderResult<bool> {
match self.peek_next_nonannotation_tag()? {
Tag::False => { self.skip()?; Ok(false) }
@ -381,6 +458,26 @@ impl<'de, 'src, D: Embeddable, N: NestedValue<D>, Dec: DomainDecode<D>, S: Binar
}
}
fn next_signedinteger(&mut self) -> ReaderResult<SignedInteger> {
let tag = self.peek_next_nonannotation_tag()?;
match tag {
Tag::SmallInteger(v) => {
self.skip()?;
Ok(SignedInteger::from(v as i32))
}
Tag::MediumInteger(count) => {
self.skip()?;
Ok(self.read_signed_integer(count.into())?)
}
Tag::SignedInteger => {
self.skip()?;
let count = self.varint()?;
Ok(self.read_signed_integer(count)?)
}
_ => Err(self.expected(ExpectedKind::SignedInteger))
}
}
fn next_i8(&mut self) -> ReaderResult<i8> { self.next_signed(|n| n.to_i8()) }
fn next_i16(&mut self) -> ReaderResult<i16> { self.next_signed(|n| n.to_i16()) }
fn next_i32(&mut self) -> ReaderResult<i32> { self.next_signed(|n| n.to_i32()) }

View File

@ -4,10 +4,25 @@ use std::borrow::Cow;
use std::io;
use std::marker::PhantomData;
use super::{DomainDecode, Embeddable, IOValue, IOValueDomainCodec, NestedValue};
use super::DomainDecode;
use super::Double;
use super::Embeddable;
use super::Float;
use super::IOValue;
use super::IOValueDomainCodec;
use super::NestedValue;
use super::CompoundClass;
use super::signed_integer::SignedInteger;
pub type ReaderResult<T> = std::result::Result<T, error::Error>;
pub enum Token<D: Embeddable, N: NestedValue<D>> {
Embedded(D),
Atom(N),
Compound(CompoundClass),
End,
}
pub trait Reader<'de, D: Embeddable, N: NestedValue<D>> {
fn next(&mut self, read_annotations: bool) -> io::Result<Option<N>>;
fn open_record(&mut self, arity: Option<usize>) -> ReaderResult<()>;
@ -19,6 +34,13 @@ pub trait Reader<'de, D: Embeddable, N: NestedValue<D>> {
fn open_embedded(&mut self) -> ReaderResult<()>;
fn close_embedded(&mut self) -> ReaderResult<()>;
type Mark;
fn mark(&mut self) -> io::Result<Self::Mark>;
fn restore(&mut self, mark: &Self::Mark) -> io::Result<()>;
fn next_token(&mut self, read_embedded_annotations: bool) -> io::Result<Token<D, N>>;
fn next_annotations_and_token(&mut self) -> io::Result<(Vec<N>, Token<D, N>)>;
//---------------------------------------------------------------------------
fn skip_value(&mut self) -> io::Result<()> {
@ -31,7 +53,22 @@ pub trait Reader<'de, D: Embeddable, N: NestedValue<D>> {
self.next(read_annotations)?.ok_or_else(io_eof)
}
fn next_boolean(&mut self) -> ReaderResult<bool> { self.demand_next(false)?.value().to_boolean() }
fn next_boolean(&mut self) -> ReaderResult<bool> {
self.demand_next(false)?.value().to_boolean()
}
fn next_float(&mut self) -> ReaderResult<Float> {
Ok(self.demand_next(false)?.value().to_float()?.to_owned())
}
fn next_double(&mut self) -> ReaderResult<Double> {
Ok(self.demand_next(false)?.value().to_double()?.to_owned())
}
fn next_signedinteger(&mut self) -> ReaderResult<SignedInteger> {
Ok(self.demand_next(false)?.value().to_signedinteger()?.to_owned())
}
fn next_i8(&mut self) -> ReaderResult<i8> { self.demand_next(false)?.value().to_i8() }
fn next_u8(&mut self) -> ReaderResult<u8> { self.demand_next(false)?.value().to_u8() }
fn next_i16(&mut self) -> ReaderResult<i16> { self.demand_next(false)?.value().to_i16() }
@ -156,10 +193,32 @@ impl<'r, 'de, D: Embeddable, N: NestedValue<D>, R: Reader<'de, D, N>>
fn close_embedded(&mut self) -> ReaderResult<()> {
(*self).close_embedded()
}
type Mark = R::Mark;
fn mark(&mut self) -> io::Result<Self::Mark> {
(*self).mark()
}
fn restore(&mut self, mark: &Self::Mark) -> io::Result<()> {
(*self).restore(mark)
}
fn next_token(&mut self, read_embedded_annotations: bool) -> io::Result<Token<D, N>> {
(*self).next_token(read_embedded_annotations)
}
fn next_annotations_and_token(&mut self) -> io::Result<(Vec<N>, Token<D, N>)> {
(*self).next_annotations_and_token()
}
}
pub trait BinarySource<'de>: Sized {
type Mark;
fn mark(&mut self) -> io::Result<Self::Mark>;
fn restore(&mut self, mark: &Self::Mark) -> io::Result<()>;
fn skip(&mut self) -> io::Result<()>;
fn peek(&mut self) -> io::Result<u8>;
fn readbytes(&mut self, count: usize) -> io::Result<Cow<'de, [u8]>>;
@ -179,18 +238,30 @@ pub trait BinarySource<'de>: Sized {
}
}
pub struct IOBinarySource<'a, R: io::Read> {
pub struct IOBinarySource<'a, R: io::Read + io::Seek> {
pub read: &'a mut R,
pub buf: Option<u8>,
}
impl<'a, R: io::Read> IOBinarySource<'a, R> {
impl<'a, R: io::Read + io::Seek> IOBinarySource<'a, R> {
pub fn new(read: &'a mut R) -> Self {
IOBinarySource { read, buf: None }
}
}
impl<'de, 'a, R: io::Read> BinarySource<'de> for IOBinarySource<'a, R> {
impl<'de, 'a, R: io::Read + io::Seek> BinarySource<'de> for IOBinarySource<'a, R> {
type Mark = u64;
fn mark(&mut self) -> io::Result<Self::Mark> {
Ok(self.read.stream_position()? - (if self.buf.is_some() { 1 } else { 0 }))
}
fn restore(&mut self, mark: &Self::Mark) -> io::Result<()> {
self.read.seek(io::SeekFrom::Start(*mark))?;
self.buf = None;
Ok(())
}
fn skip(&mut self) -> io::Result<()> {
if self.buf.is_none() { unreachable!(); }
self.buf = None;
@ -239,6 +310,17 @@ impl<'de> BytesBinarySource<'de> {
}
impl<'de> BinarySource<'de> for BytesBinarySource<'de> {
type Mark = usize;
fn mark(&mut self) -> io::Result<Self::Mark> {
Ok(self.index)
}
fn restore(&mut self, mark: &Self::Mark) -> io::Result<()> {
self.index = *mark;
Ok(())
}
fn skip(&mut self) -> io::Result<()> {
if self.index >= self.bytes.len() { unreachable!(); }
self.index += 1;

View File

@ -42,6 +42,10 @@ pub trait NestedValue<D: Embeddable>: Sized + Debug + Clone + Eq + Hash + Ord {
fn pieces(self) -> (Annotations<Self, D>, Value<Self, D>);
fn value_owned(self) -> Value<Self, D>;
fn value_class(&self) -> ValueClass {
self.value().value_class()
}
fn debug_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for ann in self.annotations().slice() {
write!(f, "@{:?} ", ann)?;
@ -85,6 +89,35 @@ pub enum Value<N, D> where N: NestedValue<D>, D: Embeddable {
Embedded(D),
}
/// The kinds of `Value` from the specification.
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum ValueClass {
Atomic(AtomClass),
Compound(CompoundClass),
Embedded,
}
/// The kinds of `Atom` from the specification.
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum AtomClass {
Boolean,
Float,
Double,
SignedInteger,
String,
ByteString,
Symbol,
}
/// The kinds of `Compound` from the specification.
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum CompoundClass {
Record,
Sequence,
Set,
Dictionary,
}
/// Single-precision IEEE 754 Value
#[derive(Clone, Debug)]
pub struct Float(pub f32);
@ -299,6 +332,23 @@ impl<N: NestedValue<D>, D: Embeddable> Value<N, D> {
N::wrap(Annotations::empty(), self)
}
fn value_class(&self) -> ValueClass {
match self {
Value::Boolean(_) => ValueClass::Atomic(AtomClass::Boolean),
Value::Float(_) => ValueClass::Atomic(AtomClass::Float),
Value::Double(_) => ValueClass::Atomic(AtomClass::Double),
Value::SignedInteger(_) => ValueClass::Atomic(AtomClass::SignedInteger),
Value::String(_) => ValueClass::Atomic(AtomClass::String),
Value::ByteString(_) => ValueClass::Atomic(AtomClass::ByteString),
Value::Symbol(_) => ValueClass::Atomic(AtomClass::Symbol),
Value::Record(_) => ValueClass::Compound(CompoundClass::Record),
Value::Sequence(_) => ValueClass::Compound(CompoundClass::Sequence),
Value::Set(_) => ValueClass::Compound(CompoundClass::Set),
Value::Dictionary(_) => ValueClass::Compound(CompoundClass::Dictionary),
Value::Embedded(_) => ValueClass::Embedded,
}
}
fn expected(&self, k: ExpectedKind) -> Error {
Error::Expected(k, Received::ReceivedOtherValue(format!("{:?}", self.clone().wrap())))
}