Experimental deserialization direct from Reader
This commit is contained in:
parent
6d9ed94065
commit
cae254ef21
|
@ -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"
|
||||
|
|
|
@ -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, ";"]))
|
||||
}
|
|
@ -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))]]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
},
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
pub mod schema;
|
||||
pub mod schema;
|
File diff suppressed because it is too large
Load Diff
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()) }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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())))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue