Remove split-out Rust implementation

This commit is contained in:
Tony Garnock-Jones 2024-01-28 15:18:08 +01:00
parent be32f9b7c8
commit 1798e64615
90 changed files with 25 additions and 18266 deletions

View File

@ -22,4 +22,3 @@ test-all:
(cd implementations/javascript; npm test) (cd implementations/javascript; npm test)
(cd implementations/python; make test) (cd implementations/python; make test)
(cd implementations/racket/preserves; make testonly) (cd implementations/racket/preserves; make testonly)
(cd implementations/rust; cargo test)

View File

@ -38,14 +38,14 @@ automatic, perfect-fidelity conversion between syntaxes.
#### Implementations of the data model, plus Preserves textual and binary transfer syntax #### Implementations of the data model, plus Preserves textual and binary transfer syntax
| Language[^pre-alpha-implementations] | Code | Package | Docs | | Language[^pre-alpha-implementations] | Code | Package | Docs |
|-----------------------|------------------------------------------------------------------------------|--------------------------------------------------------------------------------|-------------------------------------------| |--------------------------------------|------------------------------------------------------------------------------|--------------------------------------------------------------------------------|-------------------------------------------|
| Nim | [git.syndicate-lang.org](https://git.syndicate-lang.org/ehmry/preserves-nim) | | | | Nim | [git.syndicate-lang.org](https://git.syndicate-lang.org/ehmry/preserves-nim) | | |
| Python | [preserves.dev]({{page.projecttree}}/implementations/python/) | [`pip install preserves`](https://pypi.org/project/preserves/) | [docs](python/latest/) | | Python | [preserves.dev]({{page.projecttree}}/implementations/python/) | [`pip install preserves`](https://pypi.org/project/preserves/) | [docs](python/latest/) |
| Racket | [preserves.dev]({{page.projecttree}}/implementations/racket/preserves/) | [`raco pkg install preserves`](https://pkgs.racket-lang.org/package/preserves) | | | Racket | [preserves.dev]({{page.projecttree}}/implementations/racket/preserves/) | [`raco pkg install preserves`](https://pkgs.racket-lang.org/package/preserves) | |
| Rust | [preserves.dev]({{page.projecttree}}/implementations/rust/) | [`cargo add preserves`](https://crates.io/crates/preserves) | [docs](https://docs.rs/preserves/latest/) | | Rust | [preserves.dev](https://gitlab.com/preserves/preserves-rs/) | [`cargo add preserves`](https://crates.io/crates/preserves) | [docs](https://docs.rs/preserves/latest/) |
| Squeak Smalltalk | [SqueakSource](https://squeaksource.com/Preserves.html) | `Installer ss project: 'Preserves';`<br>`  install: 'Preserves'` | | | Squeak Smalltalk | [SqueakSource](https://squeaksource.com/Preserves.html) | `Installer ss project: 'Preserves';`<br>`  install: 'Preserves'` | |
| TypeScript/JavaScript | [preserves.dev]({{page.projecttree}}/implementations/javascript/) | [`yarn add @preserves/core`](https://www.npmjs.com/package/@preserves/core) | | | TypeScript/JavaScript | [preserves.dev]({{page.projecttree}}/implementations/javascript/) | [`yarn add @preserves/core`](https://www.npmjs.com/package/@preserves/core) | |
[^pre-alpha-implementations]: Pre-alpha implementations also exist for [^pre-alpha-implementations]: Pre-alpha implementations also exist for
[C]({{page.projecttree}}/implementations/c/) and [C]({{page.projecttree}}/implementations/c/) and

View File

@ -31,7 +31,6 @@ fi
# Ensure that various copies of schema.prs, schema.bin, path.bin, # Ensure that various copies of schema.prs, schema.bin, path.bin,
# samples.pr and samples.bin are in fact identical. # samples.pr and samples.bin are in fact identical.
${COMMAND} path/path.bin implementations/python/preserves/path.prb ${COMMAND} path/path.bin implementations/python/preserves/path.prb
${COMMAND} path/path.bin implementations/rust/preserves-path/path.bin
${COMMAND} schema/schema.bin implementations/python/preserves/schema.prb ${COMMAND} schema/schema.bin implementations/python/preserves/schema.prb
${COMMAND} schema/schema.prs implementations/racket/preserves/preserves-schema/schema.prs ${COMMAND} schema/schema.prs implementations/racket/preserves/preserves-schema/schema.prs
@ -40,11 +39,4 @@ ${COMMAND} tests/samples.bin implementations/python/tests/samples.bin
${COMMAND} tests/samples.pr implementations/python/tests/samples.pr ${COMMAND} tests/samples.pr implementations/python/tests/samples.pr
${COMMAND} tests/samples.pr implementations/racket/preserves/preserves/tests/samples.pr ${COMMAND} tests/samples.pr implementations/racket/preserves/preserves/tests/samples.pr
${COMMAND} _includes/what-is-preserves.md implementations/rust/preserves/doc/what-is-preserves.md
${COMMAND} _includes/cheatsheet-binary-plaintext.md implementations/rust/preserves/doc/cheatsheet-binary-plaintext.md
${COMMAND} _includes/cheatsheet-text-plaintext.md implementations/rust/preserves/doc/cheatsheet-text-plaintext.md
${COMMAND} _includes/value-grammar.md implementations/rust/preserves/doc/value-grammar.md
${COMMAND} _includes/what-is-preserves-schema.md implementations/rust/preserves-schema/doc/what-is-preserves-schema.md
[ -z "$failed" ] [ -z "$failed" ]

View File

@ -13,9 +13,9 @@ Here you may find:
- [racket](racket/), an implementation for Racket 7.x and newer - [racket](racket/), an implementation for Racket 7.x and newer
(though older Rackets may also work with it). (though older Rackets may also work with it).
- [rust](rust/), an implementation for Rust that interoperates with
serde.
Other implementations are also available: Other implementations are also available:
- [Preserves for Rust](https://gitlab.com/preserves/preserves-rs/), an implementation for Rust
that interoperates with serde.
- [Preserves for Squeak Smalltalk](https://squeaksource.com/Preserves.html) - [Preserves for Squeak Smalltalk](https://squeaksource.com/Preserves.html)

View File

@ -1,3 +0,0 @@
Cargo.lock
scratch/
target/

View File

@ -1,15 +0,0 @@
[workspace]
exclude = [
"examples/schema-no-build",
]
members = [
"preserves",
"preserves-path",
"preserves-schema",
"preserves-schema-macros",
"preserves-tools",
]
[profile.bench]
debug = true

View File

@ -1,41 +0,0 @@
# Use cargo release to manage publication and versions etc.
#
# cargo install cargo-release
all:
cargo build --all-targets
doc:
cargo doc --workspace
x86_64-binary: x86_64-binary-release
x86_64-binary-release:
cross build --target=x86_64-unknown-linux-musl --release --all-targets
armv7-binary: armv7-binary-release
armv7-binary-release:
cross build --target=armv7-unknown-linux-musleabihf --release --all-targets
aarch64-binary: aarch64-binary-release
aarch64-binary-release:
cross build --target=aarch64-unknown-linux-musl --release --all-targets
test:
cargo test
test-all:
cargo test --all-targets
ws-bump:
cargo workspaces version \
--no-global-tag \
--individual-tag-prefix 'rust-%n@' \
--allow-branch 'main' \
--ignore-changes '../*'
ws-publish:
cargo workspaces publish \
--from-git

View File

@ -0,0 +1,13 @@
# Split out to separate repository
The Rust implementation of Preserves has been split out into a separate git repository,
<https://gitlab.com/preserves/preserves-rs>.
The final released versions that were here were
- `preserves` v4.992.2,
- `preserves-schema` v5.992.0,
- `preserves-tools` v4.992.2, and
- `preserves-path` v5.992.0.
Subsequent releases live in the other repository.

View File

@ -1,10 +0,0 @@
[package]
name = "schema-no-build"
version = "0.1.0"
edition = "2021"
[dependencies]
lazy_static = "1"
preserves = { path = "../../preserves" }
preserves-schema = { path = "../../preserves-schema" }
preserves-schema-macros = { path = "../../preserves-schema-macros" }

View File

@ -1,27 +0,0 @@
use preserves::value::IOValue;
use preserves_schema_macros::compile_preserves_schemas;
compile_preserves_schemas!(
crate::schemas,
load("<CARGO_MANIFEST_DIR>/../../../../path/path.bin"),
external_module(EntityRef = crate::demo_entity_ref),
);
pub mod demo_entity_ref {
use preserves::value::IOValue;
pub type Cap = IOValue;
}
preserves_schema::define_language!(language(): Language<IOValue> {
demo: crate::schemas::Language,
});
fn main() {
use crate::schemas::path::*;
use preserves::value::NestedValue;
use preserves_schema::support::Unparse;
println!("Hello, world! {:?}", (Filter::Compare {
op: Box::new(Comparison::Eq),
literal: IOValue::new(123),
}).unparse(language()));
}

View File

@ -1,23 +0,0 @@
[package]
name = "preserves-path"
version = "5.993.0"
authors = ["Tony Garnock-Jones <tonyg@leastfixedpoint.com>"]
edition = "2018"
description = "Implementation of preserves-path, a query language for Preserves documents."
homepage = "https://preserves.dev/"
repository = "https://gitlab.com/preserves/preserves"
license = "Apache-2.0"
[build-dependencies]
preserves-schema = { path = "../preserves-schema", version = "5.993.0"}
[dependencies]
preserves = { path = "../preserves", version = "4.993.0"}
preserves-schema = { path = "../preserves-schema", version = "5.993.0"}
num = "0.4"
regex = "1.5"
thiserror = "1.0"
[package.metadata.workspaces]
independent = true

View File

@ -1,18 +0,0 @@
use preserves_schema::compiler::*;
use std::io::Error;
use std::path::PathBuf;
fn main() -> Result<(), Error> {
let buildroot = PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
let mut gen_dir = buildroot.clone();
gen_dir.push("src/schemas");
let mut c = CompilerConfig::new("crate::schemas".to_owned());
let inputs = expand_inputs(&vec!["path.bin".to_owned()])?;
c.load_schemas_and_bundles(&inputs, &vec![])?;
compile(&c, &mut CodeCollector::files(gen_dir))
}

View File

@ -1,7 +0,0 @@
´³schema·³version°³ definitions·³Axis´³orµµ±values´³rec´³lit³values„´³tupleµ„„„„µ± descendants´³rec´³lit³ descendants„´³tupleµ„„„„µ±at´³rec´³lit³at„´³tupleµ´³named³key³any„„„„„µ±label´³rec´³lit³label„´³tupleµ„„„„µ±keys´³rec´³lit³keys„´³tupleµ„„„„µ±length´³rec´³lit³length„´³tupleµ„„„„µ± annotations´³rec´³lit³ annotations„´³tupleµ„„„„µ±embedded´³rec´³lit³embedded„´³tupleµ„„„„µ±parse´³rec´³lit³parse„´³tupleµ´³named³module´³seqof´³atom³Symbol„„„´³named³name´³atom³Symbol„„„„„„µ±unparse´³rec´³lit³unparse„´³tupleµ´³named³module´³seqof´³atom³Symbol„„„´³named³name´³atom³Symbol„„„„„„„„³Step´³orµµ±Axis´³refµ„³Axis„„µ±Filter´³refµ„³Filter„„µ±Function´³refµ„³Function„„„„³Filter´³orµµ±nop´³rec´³lit³nop„´³tupleµ„„„„µ±compare´³rec´³lit³compare„´³tupleµ´³named³op´³refµ„³
Comparison„„´³named³literal³any„„„„„µ±regex´³rec´³lit³regex„´³tupleµ´³named³regex´³atom³String„„„„„„µ±test´³rec´³lit³test„´³tupleµ´³named³pred´³refµ„³ Predicate„„„„„„µ±real´³rec´³lit³real„´³tupleµ„„„„µ±int´³rec´³lit³int„´³tupleµ„„„„µ±kind´³rec´³lit³kind„´³tupleµ´³named³kind´³refµ„³ ValueKind„„„„„„„„³Function´³rec´³lit³count„´³tupleµ´³named³selector´³refµ„³Selector„„„„„³Selector´³seqof´³refµ„³Step„„³ Predicate´³orµµ±Selector´³refµ„³Selector„„µ±not´³rec´³lit³not„´³tupleµ´³named³pred´³refµ„³ Predicate„„„„„„µ±or´³rec´³lit³or„´³tupleµ´³named³preds´³seqof´³refµ„³ Predicate„„„„„„„µ±and´³rec´³lit³and„´³tupleµ´³named³preds´³seqof´³refµ„³ Predicate„„„„„„„„„³ ValueKind´³orµµ±Boolean´³lit³Boolean„„µ±Double´³lit³Double„„µ± SignedInteger´³lit³ SignedInteger„„µ±String´³lit³String„„µ±
ByteString´³lit³
ByteString„„µ±Symbol´³lit³Symbol„„µ±Record´³lit³Record„„µ±Sequence´³lit³Sequence„„µ±Set´³lit³Set„„µ±
Dictionary´³lit³
Dictionary„„µ±Embedded´³lit³Embedded„„„„³
Comparison´³orµµ±eq´³lit³eq„„µ±ne´³lit³ne„„µ±lt´³lit³lt„„µ±ge´³lit³ge„„µ±gt´³lit³gt„„µ±le´³lit³le„„„„„³ embeddedType€„„

View File

@ -1,52 +0,0 @@
use preserves::value::IOValue;
use preserves_schema::compiler::load_schema_or_bundle;
use preserves_schema::gen::schema::Definition;
use std::io;
#[derive(Default)]
pub struct Env(pub preserves_schema::support::interpret::Env<IOValue>);
pub struct Context<'a> {
pub env: &'a Env,
path: Vec<IOValue>,
}
impl<'a> Context<'a> {
pub fn new(env: &'a Env) -> Self {
Context {
env,
path: Vec::new(),
}
}
pub fn with_path_step<R, F: FnOnce(&mut Self) -> R>(&mut self, v: &IOValue, f: F) -> R {
self.path.push(v.clone());
let result = f(self);
self.path.pop();
result
}
}
impl Env {
pub fn new() -> Self {
Default::default()
}
pub fn load_bundle(&mut self, filename: &std::path::PathBuf) -> io::Result<bool> {
load_schema_or_bundle(&mut self.0, filename)
}
pub fn lookup_definition(
&self,
module: &Vec<String>,
name: &str,
) -> Option<&Definition<IOValue>> {
self.0.get(module).and_then(|s| s.definitions.0.get(name))
}
pub fn to_context(&self) -> Context {
Context::new(self)
}
}

View File

@ -1,17 +0,0 @@
use std::io;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum CompilationError {
#[error(transparent)]
IoError(#[from] io::Error),
#[error("Cannot mix binary operators")]
MixedOperators,
#[error("Invalid step")]
InvalidStep,
#[error("Undefined schema definition name: {0}")]
UndefinedSchemaDefinitionName(String),
#[error(transparent)]
RegexError(#[from] regex::Error),
}

View File

@ -1,24 +0,0 @@
pub mod context;
pub mod error;
pub mod parse;
pub mod predicate;
pub mod schemas {
include!(concat!(env!("OUT_DIR"), "/src/schemas/mod.rs"));
}
pub mod step;
pub use context::Context;
pub use context::Env;
pub use error::CompilationError;
pub use parse::parse_predicate;
pub use parse::parse_selector;
pub use schemas::path::Predicate;
pub use schemas::path::Selector;
pub use schemas::path::Step;
pub use step::Node;

View File

@ -1,322 +0,0 @@
use crate::context::Env;
use crate::schemas::path;
use crate::step::Node;
use crate::CompilationError;
use preserves::value::BinarySource;
use preserves::value::BytesBinarySource;
use preserves::value::IOValue;
use preserves::value::NestedValue;
use preserves::value::Reader;
use std::iter::Iterator;
#[derive(Debug)]
enum Binop {
Union,
Intersection,
}
fn split_values_by_symbol<'a>(tokens: &'a [IOValue], separator: &str) -> Vec<&'a [IOValue]> {
tokens
.split(|t| matches!(t.value().as_symbol(), Some(s) if s == separator))
.collect()
}
fn split_binop(tokens: &[IOValue]) -> Result<(Vec<&[IOValue]>, Option<Binop>), CompilationError> {
let union_pieces = split_values_by_symbol(&tokens, "+");
let intersection_pieces = split_values_by_symbol(&tokens, "&");
match (union_pieces.len(), intersection_pieces.len()) {
(1, 1) => Ok((union_pieces, None)),
(_, 1) => Ok((union_pieces, Some(Binop::Union))),
(1, _) => Ok((intersection_pieces, Some(Binop::Intersection))),
_ => Err(CompilationError::MixedOperators),
}
}
pub fn parse_selector(env: &Env, tokens: &[IOValue]) -> Result<path::Selector, CompilationError> {
let mut steps = Vec::new();
let mut tokens = tokens;
while let Some((s, remaining)) = parse_step(env, tokens)? {
steps.push(s);
tokens = remaining;
}
Ok(path::Selector(steps))
}
pub fn parse_predicate(env: &Env, tokens: &[IOValue]) -> Result<path::Predicate, CompilationError> {
let (pieces, binop) = split_binop(tokens)?;
match binop {
None => parse_non_binop(env, &pieces[0]),
Some(o) => {
let preds = pieces
.into_iter()
.map(|ts| parse_non_binop(env, &ts))
.collect::<Result<_, _>>()?;
Ok(match o {
Binop::Union => path::Predicate::Or { preds },
Binop::Intersection => path::Predicate::And { preds },
})
}
}
}
fn parse_non_binop(env: &Env, tokens: &[IOValue]) -> Result<path::Predicate, CompilationError> {
if !tokens.is_empty() {
let t = tokens[0].value();
if let Some("!") = t.as_symbol().map(|s| s.as_str()) {
return Ok(path::Predicate::Not {
pred: Box::new(parse_non_binop(env, &tokens[1..])?),
});
}
}
Ok(path::Predicate::Selector(Box::new(parse_selector(
env, tokens,
)?)))
}
fn parse_schema_definition_name(
env: &Env,
token: &IOValue,
) -> Result<(Vec<String>, String), CompilationError> {
let defpath = token
.value()
.to_symbol()
.map_err(|_| CompilationError::InvalidStep)?;
let mut module: Vec<String> = defpath.split('.').map(|s| s.to_string()).collect();
let name = module
.pop()
.expect("at least one element in the Schema name");
match env.lookup_definition(&module, &name) {
Some(_) => Ok((module, name)),
None => Err(CompilationError::UndefinedSchemaDefinitionName(format!(
"{:?}",
token
))),
}
}
fn parse_step<'a>(
env: &Env,
tokens: &'a [IOValue],
) -> Result<Option<(path::Step, &'a [IOValue])>, CompilationError> {
if tokens.is_empty() {
return Ok(None);
}
let remainder = &tokens[1..];
if tokens[0].value().is_sequence() {
return Ok(Some((
path::Step::Filter(Box::new(path::Filter::Test {
pred: Box::new(parse_predicate(
env,
tokens[0].value().as_sequence().unwrap(),
)?),
})),
remainder,
)));
}
match tokens[0].value().as_record(None) {
None => (),
Some(r) => match r.label().value().as_symbol() {
None => return Err(CompilationError::InvalidStep),
Some(t) => match t.as_str() {
"count" => {
return Ok(Some((
path::Step::Function(Box::new(path::Function {
selector: parse_selector(env, r.fields())?,
})),
remainder,
)))
}
_ => return Err(CompilationError::InvalidStep),
},
},
}
match tokens[0].value().as_symbol() {
None => return Err(CompilationError::InvalidStep),
Some(t) => match t.as_str() {
"/" => Ok(Some((
path::Step::Axis(Box::new(path::Axis::Values)),
remainder,
))),
"//" => Ok(Some((
path::Step::Axis(Box::new(path::Axis::Descendants)),
remainder,
))),
"." => {
let (key, remainder) = pop_step_arg(remainder)?;
Ok(Some((
path::Step::Axis(Box::new(path::Axis::At { key })),
remainder,
)))
}
".^" => Ok(Some((
path::Step::Axis(Box::new(path::Axis::Label)),
remainder,
))),
".keys" => Ok(Some((
path::Step::Axis(Box::new(path::Axis::Keys)),
remainder,
))),
".length" => Ok(Some((
path::Step::Axis(Box::new(path::Axis::Length)),
remainder,
))),
".annotations" => Ok(Some((
path::Step::Axis(Box::new(path::Axis::Annotations)),
remainder,
))),
".embedded" => Ok(Some((
path::Step::Axis(Box::new(path::Axis::Embedded)),
remainder,
))),
"%" => {
let (defpath, remainder) = pop_step_arg(remainder)?;
let (module, name) = parse_schema_definition_name(env, &defpath)?;
Ok(Some((
path::Step::Axis(Box::new(path::Axis::Parse { module, name })),
remainder,
)))
}
"%-" => {
let (defpath, remainder) = pop_step_arg(remainder)?;
let (module, name) = parse_schema_definition_name(env, &defpath)?;
Ok(Some((
path::Step::Axis(Box::new(path::Axis::Unparse { module, name })),
remainder,
)))
}
"*" => Ok(Some((
path::Step::Filter(Box::new(path::Filter::Nop)),
remainder,
))),
"eq" | "=" => parse_comparison(remainder, path::Comparison::Eq),
"ne" | "!=" => parse_comparison(remainder, path::Comparison::Ne),
"lt" => parse_comparison(remainder, path::Comparison::Lt),
"gt" => parse_comparison(remainder, path::Comparison::Gt),
"le" => parse_comparison(remainder, path::Comparison::Le),
"ge" => parse_comparison(remainder, path::Comparison::Ge),
"re" | "=r" => {
let (regex_val, remainder) = pop_step_arg(remainder)?;
let regex = regex_val
.value()
.to_string()
.map_err(|_| CompilationError::InvalidStep)?
.clone();
let _ = regex::Regex::new(&regex)?;
Ok(Some((
path::Step::Filter(Box::new(path::Filter::Regex { regex })),
remainder,
)))
}
"^" => {
let (literal, remainder) = pop_step_arg(remainder)?;
Ok(Some((
path::Step::Filter(Box::new(path::Filter::Test {
pred: Box::new(path::Predicate::Selector(Box::new(path::Selector(vec![
path::Step::Axis(Box::new(path::Axis::Label)),
path::Step::Filter(Box::new(path::Filter::Compare {
op: Box::new(path::Comparison::Eq),
literal,
})),
])))),
})),
remainder,
)))
}
"~real" => Ok(Some((
path::Step::Filter(Box::new(path::Filter::Real)),
remainder,
))),
"~int" => Ok(Some((
path::Step::Filter(Box::new(path::Filter::Int)),
remainder,
))),
"bool" => Ok(Some((
path::Step::from(path::ValueKind::Boolean),
remainder,
))),
"double" => Ok(Some((path::Step::from(path::ValueKind::Double), remainder))),
"int" => Ok(Some((
path::Step::from(path::ValueKind::SignedInteger),
remainder,
))),
"string" => Ok(Some((path::Step::from(path::ValueKind::String), remainder))),
"bytes" => Ok(Some((
path::Step::from(path::ValueKind::ByteString),
remainder,
))),
"symbol" => Ok(Some((path::Step::from(path::ValueKind::Symbol), remainder))),
"rec" => Ok(Some((path::Step::from(path::ValueKind::Record), remainder))),
"seq" => Ok(Some((
path::Step::from(path::ValueKind::Sequence),
remainder,
))),
"set" => Ok(Some((path::Step::from(path::ValueKind::Set), remainder))),
"dict" => Ok(Some((
path::Step::from(path::ValueKind::Dictionary),
remainder,
))),
"embedded" => Ok(Some((
path::Step::from(path::ValueKind::Embedded),
remainder,
))),
_ => Err(CompilationError::InvalidStep),
},
}
}
impl From<path::ValueKind> for path::Step {
fn from(k: path::ValueKind) -> Self {
path::Step::Filter(Box::new(path::Filter::Kind { kind: Box::new(k) }))
}
}
fn pop_step_arg(tokens: &[IOValue]) -> Result<(IOValue, &[IOValue]), CompilationError> {
if tokens.is_empty() {
return Err(CompilationError::InvalidStep);
}
Ok((tokens[0].clone(), &tokens[1..]))
}
fn parse_comparison(
tokens: &[IOValue],
op: path::Comparison,
) -> Result<Option<(path::Step, &[IOValue])>, CompilationError> {
let (literal, remainder) = pop_step_arg(tokens)?;
Ok(Some((
path::Step::Filter(Box::new(path::Filter::Compare {
op: Box::new(op),
literal,
})),
remainder,
)))
}
impl path::Selector {
pub fn from_str(env: &Env, s: &str) -> Result<Self, CompilationError> {
parse_selector(
env,
&(BytesBinarySource::new(s.as_bytes())
.text_iovalues()
.configured(false)
.collect::<Result<Vec<_>, _>>()?),
)
}
}
impl Node {
pub fn from_str(env: &Env, s: &str) -> Result<Self, CompilationError> {
let expr = path::Selector::from_str(env, s)?;
expr.compile()
}
}

View File

@ -1,68 +0,0 @@
use crate::context::Context;
use crate::schemas::path;
use crate::step::BoolCollector;
use crate::step::Node;
use crate::step::StepMaker;
use crate::CompilationError;
use preserves::value::IOValue;
pub trait Predicate: std::fmt::Debug {
fn test(&mut self, ctxt: &mut Context, value: &IOValue) -> bool;
}
#[derive(Debug)]
pub enum CompiledPredicate {
Selector(Node),
Not(Box<CompiledPredicate>),
Or(Vec<CompiledPredicate>),
And(Vec<CompiledPredicate>),
}
impl path::Predicate {
pub fn compile(&self) -> Result<CompiledPredicate, CompilationError> {
match self {
path::Predicate::Selector(b) => Ok(CompiledPredicate::Selector(
(&**b).connect(BoolCollector::new())?,
)),
path::Predicate::Not { pred } => {
Ok(CompiledPredicate::Not(Box::new((&**pred).compile()?)))
}
path::Predicate::Or { preds } => Ok(CompiledPredicate::Or(
preds.iter().map(Self::compile).collect::<Result<_, _>>()?,
)),
path::Predicate::And { preds } => Ok(CompiledPredicate::And(
preds.iter().map(Self::compile).collect::<Result<_, _>>()?,
)),
}
}
pub fn exec(&self, ctxt: &mut Context, value: &IOValue) -> Result<bool, CompilationError> {
Ok(self.compile()?.test(ctxt, value))
}
}
impl Predicate for CompiledPredicate {
fn test(&mut self, ctxt: &mut Context, value: &IOValue) -> bool {
match self {
CompiledPredicate::Selector(n) => n.test(ctxt, value),
CompiledPredicate::Not(p) => !p.test(ctxt, value),
CompiledPredicate::Or(ps) => {
for p in ps.iter_mut() {
if p.test(ctxt, value) {
return true;
}
}
return false;
}
CompiledPredicate::And(ps) => {
for p in ps.iter_mut() {
if !p.test(ctxt, value) {
return false;
}
}
return true;
}
}
}
}

View File

@ -1,504 +0,0 @@
// Selectors operate on IOValues because the AST includes keys of IOValue type.
// If we could make Schemas produce generics...
use crate::context::Context;
use crate::predicate::CompiledPredicate;
use crate::predicate::Predicate;
use crate::schemas::path;
use crate::CompilationError;
use num::bigint::BigInt;
use num::traits::cast::FromPrimitive;
use num::traits::cast::ToPrimitive;
use preserves::value::AtomClass;
use preserves::value::CompoundClass;
use preserves::value::IOValue;
use preserves::value::NestedValue;
use preserves::value::Value;
use preserves::value::ValueClass;
use preserves_schema::support::interpret;
use std::cell::RefCell;
use std::iter::Iterator;
use std::rc::Rc;
pub trait StepMaker {
fn connect(&self, step: Node) -> Result<Node, CompilationError>;
}
pub trait Step: std::fmt::Debug {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue);
fn finish(&mut self);
fn reset(&mut self) -> Vec<IOValue>;
}
macro_rules! delegate_finish_and_reset {
($self:ident, $target:expr) => {
fn finish(&mut $self) { $target.finish() }
fn reset(&mut $self) -> Vec<IOValue> { $target.reset() }
}
}
#[derive(Clone, Debug)]
pub struct Node(pub Rc<RefCell<dyn Step>>);
#[derive(Debug)]
struct AxisStep {
step: Node,
axis: path::Axis,
}
#[derive(Debug)]
struct CompareStep {
op: path::Comparison,
literal: IOValue,
step: Node,
}
#[derive(Debug)]
struct RegexStep {
regex: regex::Regex,
step: Node,
}
#[derive(Debug)]
struct TestStep {
pred: CompiledPredicate,
step: Node,
}
#[derive(Debug)]
struct RealStep {
step: Node,
}
#[derive(Debug)]
struct IntStep {
step: Node,
}
#[derive(Debug)]
struct VecCollector {
accumulator: Vec<IOValue>,
}
#[derive(Debug)]
pub struct BoolCollector {
seen_value: bool,
}
#[derive(Debug)]
struct KindStep {
kind: ValueClass,
step: Node,
}
#[derive(Debug)]
pub struct CountCollector {
count: usize,
}
#[derive(Debug)]
struct CountStep {
step: Node,
counter: Node,
}
impl Node {
fn new<S: Step + 'static>(s: S) -> Self {
Node(Rc::new(RefCell::new(s)))
}
pub fn test(&self, ctxt: &mut Context, value: &IOValue) -> bool {
!self.exec(ctxt, value).is_empty()
}
pub fn accept(&self, ctxt: &mut Context, value: &IOValue) {
self.0.borrow_mut().accept(ctxt, value)
}
pub fn finish(&self) {
self.0.borrow_mut().finish()
}
pub fn reset(&self) -> Vec<IOValue> {
self.0.borrow_mut().reset()
}
pub fn exec(&self, ctxt: &mut Context, value: &IOValue) -> Vec<IOValue> {
self.accept(ctxt, value);
self.finish();
self.reset()
}
}
impl StepMaker for path::Selector {
fn connect(&self, step: Node) -> Result<Node, CompilationError> {
self.0.connect(step)
}
}
impl<S: StepMaker> StepMaker for Vec<S> {
fn connect(&self, mut step: Node) -> Result<Node, CompilationError> {
for s in self.iter().rev() {
step = s.connect(step)?;
}
Ok(step)
}
}
impl StepMaker for path::Step {
fn connect(&self, step: Node) -> Result<Node, CompilationError> {
match self {
path::Step::Axis(b) => (&**b).connect(step),
path::Step::Filter(b) => (&**b).connect(step),
path::Step::Function(b) => (&**b).connect(step),
}
}
}
impl StepMaker for path::Axis {
fn connect(&self, step: Node) -> Result<Node, CompilationError> {
Ok(Node::new(AxisStep {
step,
axis: self.clone(),
}))
}
}
fn descendants(ctxt: &mut Context, step: &mut Node, v: &IOValue) {
step.accept(ctxt, v);
for c in v.value().children() {
ctxt.with_path_step(&c, |ctxt| descendants(ctxt, step, &c));
}
}
impl Step for AxisStep {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
ctxt.with_path_step(value, |ctxt| match &self.axis {
path::Axis::Values => {
for c in value.value().children() {
self.step.accept(ctxt, &c)
}
}
path::Axis::Descendants => descendants(ctxt, &mut self.step, value),
path::Axis::At { key } => match value.value() {
Value::String(s) | Value::Symbol(s) => step_index(
ctxt,
s.chars(),
&key,
|c| IOValue::new(String::from(c)),
&mut self.step,
),
Value::Record(r) => {
step_index(ctxt, r.fields().iter(), &key, |v| v.clone(), &mut self.step)
}
Value::Sequence(vs) => {
step_index(ctxt, vs.iter(), &key, |v| v.clone(), &mut self.step)
}
Value::Dictionary(d) => {
if let Some(v) = d.get(&key) {
self.step.accept(ctxt, v)
}
}
_ => (),
},
path::Axis::Label => {
if let Some(r) = value.value().as_record(None) {
self.step.accept(ctxt, r.label())
}
}
path::Axis::Keys => match value.value() {
Value::String(s) | Value::Symbol(s) => step_keys(ctxt, s.len(), &mut self.step),
Value::ByteString(bs) => step_keys(ctxt, bs.len(), &mut self.step),
Value::Record(r) => step_keys(ctxt, r.arity(), &mut self.step),
Value::Sequence(vs) => step_keys(ctxt, vs.len(), &mut self.step),
Value::Dictionary(d) => {
for k in d.keys() {
self.step.accept(ctxt, k)
}
}
_ => (),
},
path::Axis::Length => match value.value() {
Value::String(s) | Value::Symbol(s) => {
self.step.accept(ctxt, &IOValue::new(s.len()))
}
Value::ByteString(bs) => self.step.accept(ctxt, &IOValue::new(bs.len())),
Value::Record(r) => self.step.accept(ctxt, &IOValue::new(r.arity())),
Value::Sequence(vs) => self.step.accept(ctxt, &IOValue::new(vs.len())),
Value::Dictionary(d) => self.step.accept(ctxt, &IOValue::new(d.len())),
_ => self.step.accept(ctxt, &IOValue::new(0)),
},
path::Axis::Annotations => {
for c in value.annotations().slice() {
self.step.accept(ctxt, &c)
}
}
path::Axis::Embedded => {
if let Some(d) = value.value().as_embedded() {
self.step.accept(ctxt, d)
}
}
path::Axis::Parse { module, name } => {
if let Some(p) =
interpret::Context::new(&ctxt.env.0).dynamic_parse(module, name, value)
{
self.step.accept(ctxt, &p)
}
}
path::Axis::Unparse { module, name } => {
if let Some(p) =
interpret::Context::new(&ctxt.env.0).dynamic_unparse(module, name, value)
{
self.step.accept(ctxt, &p)
}
}
})
}
delegate_finish_and_reset!(self, self.step);
}
fn step_index<T, Ts: Iterator<Item = T>, F: FnOnce(T) -> IOValue>(
ctxt: &mut Context,
mut vs: Ts,
key: &IOValue,
f: F,
step: &mut Node,
) {
if let Some(i) = key.value().as_usize() {
match vs.nth(i) {
None => (),
Some(v) => step.accept(ctxt, &f(v)),
}
}
}
fn step_keys(ctxt: &mut Context, count: usize, step: &mut Node) {
for i in 0..count {
step.accept(ctxt, &IOValue::new(i))
}
}
impl StepMaker for path::Filter {
fn connect(&self, step: Node) -> Result<Node, CompilationError> {
match self {
path::Filter::Nop => Ok(step),
path::Filter::Compare { op, literal } => Ok(Node::new(CompareStep {
op: (**op).clone(),
literal: literal.clone(),
step,
})),
path::Filter::Regex { regex } => Ok(Node::new(RegexStep {
regex: regex::Regex::new(regex)?,
step,
})),
path::Filter::Test { pred } => Ok(Node::new(TestStep {
pred: (&**pred).compile()?,
step,
})),
path::Filter::Real => Ok(Node::new(RealStep { step })),
path::Filter::Int => Ok(Node::new(IntStep { step })),
path::Filter::Kind { kind } => Ok(Node::new(KindStep {
kind: match &**kind {
path::ValueKind::Boolean => ValueClass::Atomic(AtomClass::Boolean),
path::ValueKind::Double => ValueClass::Atomic(AtomClass::Double),
path::ValueKind::SignedInteger => ValueClass::Atomic(AtomClass::SignedInteger),
path::ValueKind::String => ValueClass::Atomic(AtomClass::String),
path::ValueKind::ByteString => ValueClass::Atomic(AtomClass::ByteString),
path::ValueKind::Symbol => ValueClass::Atomic(AtomClass::Symbol),
path::ValueKind::Record => ValueClass::Compound(CompoundClass::Record),
path::ValueKind::Sequence => ValueClass::Compound(CompoundClass::Sequence),
path::ValueKind::Set => ValueClass::Compound(CompoundClass::Set),
path::ValueKind::Dictionary => ValueClass::Compound(CompoundClass::Dictionary),
path::ValueKind::Embedded => ValueClass::Embedded,
},
step,
})),
}
}
}
impl Step for CompareStep {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
if match self.op {
path::Comparison::Eq => value == &self.literal,
path::Comparison::Ne => value != &self.literal,
path::Comparison::Lt => value < &self.literal,
path::Comparison::Ge => value >= &self.literal,
path::Comparison::Gt => value > &self.literal,
path::Comparison::Le => value <= &self.literal,
} {
self.step.accept(ctxt, value)
}
}
delegate_finish_and_reset!(self, self.step);
}
impl Step for RegexStep {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
match value.value() {
Value::String(s) | Value::Symbol(s) => {
if self.regex.is_match(s) {
self.step.accept(ctxt, value)
}
}
_ => (),
}
}
delegate_finish_and_reset!(self, self.step);
}
impl Step for TestStep {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
if self.pred.test(ctxt, value) {
self.step.accept(ctxt, value)
}
}
delegate_finish_and_reset!(self, self.step);
}
impl Step for RealStep {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
match value.value() {
Value::SignedInteger(i) => {
if let Some(r) = BigInt::from(i).to_f64() {
self.step.accept(ctxt, &IOValue::new(r))
}
}
Value::Double(_) => self.step.accept(ctxt, value),
_ => (),
}
}
delegate_finish_and_reset!(self, self.step);
}
impl Step for IntStep {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
match value.value() {
Value::SignedInteger(_) => self.step.accept(ctxt, value),
Value::Double(d) => {
if let Some(i) = BigInt::from_f64(f64::from(*d)) {
self.step.accept(ctxt, &IOValue::new(i))
}
}
_ => (),
}
}
delegate_finish_and_reset!(self, self.step);
}
impl VecCollector {
fn new() -> Node {
Node::new(VecCollector {
accumulator: Vec::new(),
})
}
}
impl Step for VecCollector {
fn accept(&mut self, _ctxt: &mut Context, value: &IOValue) {
self.accumulator.push(value.clone())
}
fn finish(&mut self) {}
fn reset(&mut self) -> Vec<IOValue> {
std::mem::take(&mut self.accumulator)
}
}
impl BoolCollector {
pub fn new() -> Node {
Node::new(BoolCollector { seen_value: false })
}
}
impl Step for BoolCollector {
fn accept(&mut self, _ctxt: &mut Context, _value: &IOValue) {
self.seen_value = true
}
fn finish(&mut self) {}
fn reset(&mut self) -> Vec<IOValue> {
let result = if self.seen_value {
vec![IOValue::new(true)]
} else {
vec![]
};
self.seen_value = false;
result
}
}
impl Step for KindStep {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
if value.value_class() == self.kind {
self.step.accept(ctxt, value)
}
}
delegate_finish_and_reset!(self, self.step);
}
impl path::Selector {
pub fn compile(&self) -> Result<Node, CompilationError> {
self.connect(VecCollector::new())
}
pub fn exec(
&self,
ctxt: &mut Context,
value: &IOValue,
) -> Result<Vec<IOValue>, CompilationError> {
Ok(self.compile()?.exec(ctxt, value))
}
}
impl StepMaker for path::Function {
fn connect(&self, step: Node) -> Result<Node, CompilationError> {
// For now, there's just one function: `count`.
Ok(Node::new(CountStep {
step,
counter: self.selector.connect(CountCollector::new())?,
}))
}
}
impl CountCollector {
pub fn new() -> Node {
Node::new(CountCollector { count: 0 })
}
}
impl Step for CountCollector {
fn accept(&mut self, _ctxt: &mut Context, _value: &IOValue) {
self.count += 1
}
fn finish(&mut self) {}
fn reset(&mut self) -> Vec<IOValue> {
let result = vec![IOValue::new(self.count)];
self.count = 0;
result
}
}
impl Step for CountStep {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
let count = &self.counter.exec(ctxt, value)[0];
self.step.accept(ctxt, count)
}
delegate_finish_and_reset!(self, self.step);
}

View File

@ -1,23 +0,0 @@
[package]
name = "preserves-schema-macros"
version = "0.993.0"
authors = ["Tony Garnock-Jones <tonyg@leastfixedpoint.com>"]
edition = "2018"
description = "Implementation of Preserves Schema code generation macros for Rust."
homepage = "https://preserves.dev/"
repository = "https://gitlab.com/preserves/preserves"
license = "Apache-2.0"
[lib]
proc-macro = true
[dependencies]
preserves = { path = "../preserves", version = "4.993.0" }
preserves-schema = { path = "../preserves-schema", version = "5.993.0" }
proc-macro2 = { version = "1", features = ["span-locations"] }
quote = "1"
syn = { version = "2", features = ["parsing", "extra-traits", "full"] }
[package.metadata.workspaces]
independent = true

View File

@ -1,227 +0,0 @@
use preserves::value::Map;
use preserves_schema::compiler::*;
use preserves_schema::compiler::types::Purpose;
use preserves_schema::gen::schema::Schema;
use proc_macro2::Span;
use quote::ToTokens;
use quote::quote;
use std::fmt::Display;
use syn::LitStr;
use syn::Token;
use syn::parenthesized;
use syn::parse::Parser;
use syn::punctuated::Punctuated;
mod kw {
use syn::custom_keyword;
custom_keyword!(load);
custom_keyword!(cross_reference);
custom_keyword!(external_module);
}
#[derive(Debug)]
enum Instruction {
Namespace(String),
Load(LitStr),
CrossReference {
namespace: String,
bundle_path: LitStr,
},
ExternalModule {
module_path: ModulePath,
namespace: String,
}
}
fn syn_path_string(p: syn::Path) -> String {
p.to_token_stream().to_string().replace(&[' ', '\t', '\n', '\r'], "")
}
fn syn_litstr_resolve(s: &syn::LitStr) -> String {
let s: String = s.value();
match s.chars().nth(0) {
Some('/') => s.into(),
Some('<') => match &s[1..].split_once('>') {
Some((envvar, remainder)) => match std::env::var(envvar) {
Ok(p) => p + "/" + remainder,
Err(_) => panic!("No such environment variable: {:?}", s),
}
None => panic!("Invalid relative path syntax: {:?}", s),
},
_ => panic!("Invalid path syntax: {:?}", s)
}
}
impl syn::parse::Parse for Instruction {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(kw::load) {
let _: kw::load = input.parse()?;
let content;
let _ = parenthesized!(content in input);
let bundle_path: syn::LitStr = content.parse()?;
Ok(Instruction::Load(bundle_path))
} else if lookahead.peek(kw::cross_reference) {
let _: kw::cross_reference = input.parse()?;
let content;
let _ = parenthesized!(content in input);
let namespace: syn::Path = content.parse()?;
let _: Token![=] = content.parse()?;
let bundle_path: syn::LitStr = content.parse()?;
Ok(Instruction::CrossReference {
namespace: syn_path_string(namespace),
bundle_path,
})
} else if lookahead.peek(kw::external_module) {
let _: kw::external_module = input.parse()?;
let content;
let _ = parenthesized!(content in input);
let module_path = Punctuated::<syn::Ident, syn::Token![.]>::parse_separated_nonempty(&content)?;
let _: Token![=] = content.parse()?;
let namespace: syn::Path = content.parse()?;
Ok(Instruction::ExternalModule {
module_path: module_path.into_iter().map(|p| p.to_string()).collect(),
namespace: syn_path_string(namespace),
})
} else {
let ns: syn::Path = input.parse()?;
Ok(Instruction::Namespace(syn_path_string(ns)))
}
}
}
struct ModuleTree {
own_body: String,
children: Map<String, ModuleTree>,
}
impl Default for ModuleTree {
fn default() -> Self {
ModuleTree {
own_body: String::new(),
children: Map::default(),
}
}
}
impl ModuleTree {
fn build(outputs: Map<Option<ModulePath>, String>) -> Self {
let mut mt = ModuleTree::default();
for (p, c) in outputs.into_iter() {
match p {
None => mt.own_body = c,
Some(k) => {
let mut r = &mut mt;
for e in k { r = mt.children.entry(names::render_modname(&e)).or_default(); }
r.own_body = c;
}
}
}
mt
}
}
impl Display for ModuleTree {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.own_body)?;
for (label, mt) in self.children.iter() {
write!(f, "\npub mod {} {{ ", label)?;
mt.fmt(f)?;
write!(f, "}}")?;
}
Ok(())
}
}
#[proc_macro]
pub fn compile_preserves_schemas(src: proc_macro::TokenStream) -> proc_macro::TokenStream {
let instructions = Punctuated::<Instruction, syn::Token![,]>::parse_terminated
.parse(src)
.expect("valid sequence of compile_preserves_schemas instructions");
let mut namespace = None::<String>;
let mut bundles_to_load = Vec::<LitStr>::new();
let mut bundles_to_xref = Vec::<LitStr>::new();
let mut external_modules = Vec::<ExternalModule>::new();
for i in instructions.into_iter() {
match i {
Instruction::Namespace(n) => {
if namespace.is_some() {
panic!("Only one namespace is permitted")
}
namespace = Some(n)
}
Instruction::Load(p) => bundles_to_load.push(p),
Instruction::ExternalModule { module_path, namespace } => {
external_modules.push(ExternalModule::new(module_path, &namespace));
}
Instruction::CrossReference { namespace, bundle_path } => {
let mut bundle = Map::<ModulePath, Schema>::new();
let is_schema = load_schema_or_bundle(&mut bundle, &syn_litstr_resolve(&bundle_path).into())
.expect("Invalid schema/bundle binary");
bundles_to_xref.push(bundle_path);
for (k, _v) in bundle.into_iter() {
external_modules.push(if is_schema {
ExternalModule::new(k, &namespace)
} else {
let ns = namespace.clone();
let mut pieces = vec![ns.clone()];
pieces.extend(
k.iter().map(|p| names::render_modname(&p)).collect::<Vec<_>>());
ExternalModule::new(k, &pieces.join("::"))
.set_fallback_language_types(
move |v| vec![format!("{}::Language<{}>", ns, v)].into_iter().collect())
});
}
}
}
}
let namespace = namespace.expect("Missing namespace");
let mut dependency_paths = Vec::<syn::LitStr>::new();
let mut c = CompilerConfig::new(namespace.clone());
for b in bundles_to_load.into_iter() {
dependency_paths.push(syn::LitStr::new(&syn_litstr_resolve(&b), Span::call_site()));
load_schema_or_bundle_with_purpose(&mut c.bundle, &syn_litstr_resolve(&b).into(), Purpose::Codegen)
.expect(&b.value());
}
for b in bundles_to_xref.into_iter() {
dependency_paths.push(syn::LitStr::new(&syn_litstr_resolve(&b), Span::call_site()));
load_schema_or_bundle_with_purpose(&mut c.bundle, &syn_litstr_resolve(&b).into(), Purpose::Xref)
.expect(&b.value());
}
for m in external_modules.into_iter() {
c.add_external_module(m);
}
let mut outputs = Map::<Option<ModulePath>, String>::new();
let mut collector = CodeCollector {
emit_mod_declarations: false,
collect_module: CodeModuleCollector::Custom {
collect_output: &mut |p, c| {
outputs.insert(p.cloned(), c.to_owned());
Ok(())
},
},
};
compile(&c, &mut collector).expect("Compilation failed");
let top_module_source = format!(
"pub mod {} {{ {} }}",
names::render_modname(namespace.split("::").last().unwrap()),
ModuleTree::build(outputs));
let top_module: syn::Item = syn::parse_str(&top_module_source)
.expect("Invalid generated code");
quote!{
// TODO: this is ugly, but makes the code depend on the actual schema bundle:
// See https://doc.rust-lang.org/nightly/proc_macro/tracked_path/fn.path.html
// and https://github.com/rust-lang/rust/issues/99515
#( const _: &'static [u8] = include_bytes!(#dependency_paths); )*
#top_module
}.into()
}

View File

@ -1,22 +0,0 @@
[package]
name = "preserves-schema"
version = "5.993.0"
authors = ["Tony Garnock-Jones <tonyg@leastfixedpoint.com>"]
edition = "2018"
description = "Implementation of Preserves Schema code generation and support for Rust."
homepage = "https://preserves.dev/"
repository = "https://gitlab.com/preserves/preserves"
license = "Apache-2.0"
[dependencies]
preserves = { path = "../preserves", version = "4.993.0"}
convert_case = "0.4.0"
glob = "0.3.0"
lazy_static = "1.4.0"
regex = "1.5"
structopt = "0.3.14"
thiserror = "1.0"
[package.metadata.workspaces]
independent = true

View File

@ -1,10 +0,0 @@
all:
@echo please use cargo
regenerate:
cargo run -- \
--prefix crate::gen \
--support-crate crate \
--rustfmt-skip \
-o $(CURDIR)/src/gen \
../../../schema/schema.bin

View File

@ -1,6 +0,0 @@
```shell
cargo add preserves preserves-schema
```
This crate ([`preserves-schema` on crates.io](https://crates.io/crates/preserves-schema)) is an
implementation of [Preserves Schema](https://preserves.dev/preserves-schema.html) for Rust.

View File

@ -1,112 +0,0 @@
# Example
[preserves-schemac]: https://preserves.dev/doc/preserves-schemac.html
[preserves-schema-rs]: https://preserves.dev/doc/preserves-schema-rs.html
Preserves schemas are written in a syntax that (ab)uses [Preserves text
syntax][preserves::value::text] as a kind of S-expression. Schema source code looks like this:
```preserves-schema
version 1 .
Present = <Present @username string> .
Says = <Says @who string @what string> .
UserStatus = <Status @username string @status Status> .
Status = =here / <away @since TimeStamp> .
TimeStamp = string .
```
Conventionally, schema source code is stored in `*.prs` files. In this example, the source code
above is placed in `simpleChatProtocol.prs`.
The Rust code generator for schemas requires not source code, but instances of the [Preserves
metaschema](https://preserves.dev/preserves-schema.html#appendix-metaschema). To compile schema
source code to metaschema instances, use [preserves-schemac][]:
```shell
yarn global add @preserves/schema
preserves-schemac .:simpleChatProtocol.prs > simpleChatProtocol.prb
```
Binary-syntax metaschema instances are conventionally stored in `*.prb` files. If you have a
whole directory tree of `*.prs` files, you can supply just "`.`" without the "`:`"-prefixed
fileglob part.[^converting-metaschema-to-text] See the [preserves-schemac documentation][preserves-schemac].
[^converting-metaschema-to-text]:
Converting the `simpleChatProtocol.prb` file to Preserves text syntax lets us read the
metaschema instance corresponding to the source code:
```shell
cat simpleChatProtocol.prb | preserves-tool convert
```
The result:
```preserves
<bundle {
[
simpleChatProtocol
]: <schema {
definitions: {
Present: <rec <lit Present> <tuple [
<named username <atom String>>
]>>
Says: <rec <lit Says> <tuple [
<named who <atom String>>
<named what <atom String>>
]>>
Status: <or [
[
"here"
<lit here>
]
[
"away"
<rec <lit away> <tuple [
<named since <ref [] TimeStamp>>
]>>
]
]>
TimeStamp: <atom String>
UserStatus: <rec <lit Status> <tuple [
<named username <atom String>>
<named status <ref [] Status>>
]>>
}
embeddedType: #f
version: 1
}>
}>
```
#### Generating Rust code from a schema
Generate Rust definitions corresponding to a metaschema instance with [preserves-schema-rs][].
The best way to use it is to integrate it into your `build.rs` (see [the
docs][preserves-schema-rs]), but you can also use it as a standalone command-line tool.
The following command generates a directory `./rs/chat` containing rust sources for a module
that expects to be called `chat` in Rust code:
```shell
preserves-schema-rs --output-dir rs/chat --prefix chat simpleChatProtocol.prb
```
Representative excerpts from one of the generated files, `./rs/chat/simple_chat_protocol.rs`:
```rust,noplayground
pub struct Present {
pub username: std::string::String
}
pub struct Says {
pub who: std::string::String,
pub what: std::string::String
}
pub struct UserStatus {
pub username: std::string::String,
pub status: Status
}
pub enum Status {
Here,
Away {
since: std::boxed::Box<TimeStamp>
}
}
pub struct TimeStamp(pub std::string::String);
```

View File

@ -1,16 +0,0 @@
A Preserves schema connects Preserves `Value`s to host-language data
structures. Each definition within a schema can be processed by a
compiler to produce
- a simple host-language *type definition*;
- a partial *parsing* function from `Value`s to instances of the
produced type; and
- a total *serialization* function from instances of the type to
`Value`s.
Every parsed `Value` retains enough information to always be able to
be serialized again, and every instance of a host-language data
structure contains, by construction, enough information to be
successfully serialized.

View File

@ -1,64 +0,0 @@
//! Command-line Rust code generator for Preserves Schema. See the documentation at
//! <https://preserves.dev/doc/preserves-schema-rs.html>.
use std::io::Error;
use std::io::ErrorKind;
use std::path::PathBuf;
use structopt::StructOpt;
use preserves_schema::compiler::CodeCollector;
use preserves_schema::compiler::CompilerConfig;
use preserves_schema::compiler::ExternalModule;
use preserves_schema::compiler::compile;
use preserves_schema::compiler::expand_inputs;
#[derive(Clone, StructOpt, Debug)]
struct CommandLine {
#[structopt(short, long)]
output_dir: PathBuf,
#[structopt(short, long)]
prefix: String,
#[structopt(long)]
support_crate: Option<String>,
#[structopt(long)]
module: Vec<String>,
#[structopt(long)]
xref: Vec<String>,
#[structopt(long)]
rustfmt_skip: bool,
input_glob: Vec<String>,
}
fn main() -> Result<(), Error> {
let args = CommandLine::from_args();
let mut config = CompilerConfig::new(args.prefix);
for alias in args.module {
let (modulepath_str, target) = {
let pieces: Vec<&str> = alias.split('=').collect();
if pieces.len() != 2 {
return Err(Error::new(
ErrorKind::InvalidData,
format!("Invalid module alias: {:?}", alias),
));
}
(pieces[0], pieces[1])
};
let modulepath: Vec<String> = modulepath_str.split('.').map(str::to_owned).collect();
config.add_external_module(ExternalModule::new(modulepath, target));
}
if let Some(c) = args.support_crate {
config.support_crate = c;
}
config.rustfmt_skip = args.rustfmt_skip;
config.load_schemas_and_bundles(
&expand_inputs(&args.input_glob)?,
&expand_inputs(&args.xref)?,
)?;
compile(&config, &mut CodeCollector::files(args.output_dir))
}

View File

@ -1,377 +0,0 @@
use crate::gen::schema::*;
use crate::syntax::block::constructors::*;
use crate::syntax::block::escape_string;
use crate::syntax::block::Item;
use crate::*;
use convert_case::{Case, Casing};
use lazy_static::lazy_static;
use preserves::value::IOValue;
use preserves::value::Map;
use preserves::value::NestedValue;
use preserves::value::Value;
use super::names;
use super::types;
use super::types::Purpose;
use super::CompilerConfig;
pub struct BundleContext<'b> {
pub config: &'b CompilerConfig,
pub types: Map<Ref, types::TDefinition>,
pub literals: Map<IOValue, String>,
}
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub enum ModuleContextMode {
TargetModule,
TargetToplevel,
TargetGeneric,
}
pub struct ModuleContext<'m, 'b> {
pub bundle: &'m mut BundleContext<'b>,
pub module_path: ModulePath,
pub schema: &'m Schema,
pub typedefs: Vec<Item>,
pub functiondefs: Vec<Item>,
pub mode: ModuleContextMode,
}
pub struct FunctionContext<'a, 'm, 'b> {
pub error_context: String,
pub m: &'a mut ModuleContext<'m, 'b>,
pub temp_counter: usize,
pub captures: Vec<Capture>,
pub capture_mode: CaptureMode,
}
pub struct Capture {
pub field_name: String,
pub ty: types::TField,
pub source_expr: String,
}
pub enum CaptureMode {
Definite,
Indefinite(Vec<Item>),
}
pub enum RefRenderStyle {
Bare,
Qualified,
}
lazy_static! {
static ref ID_RE: regex::Regex = regex::Regex::new(r"^[a-zA-Z][a-zA-Z_0-9]*$").unwrap();
}
impl<'b> BundleContext<'b> {
pub fn new(config: &'b CompilerConfig) -> Self {
BundleContext {
config,
types: config.build_type_cache(),
literals: Map::new(),
}
}
pub fn any_type(&self) -> &'static str {
"_Value"
}
pub fn lookup_definition(&self, r: &Ref) -> Option<(&Definition, Purpose)> {
self.config
.bundle
.get(&r.module.0)
.and_then(|s| s.0.definitions.0.get(&r.name).map(|d| (d, s.1)))
}
pub fn type_for_name(&self, r: &Ref) -> Option<&types::TDefinition> {
if r.module.0.is_empty() {
panic!(
"BundleContext::type_for_name with module-relative ref {:?}",
r
);
}
let result = self.types.get(r);
if result.is_none() && !self.config.external_modules.contains_key(&r.module.0) {
panic!("Attempted to lookup unknown type {:?}", r)
}
result
}
pub fn define_literal(&mut self, v: &IOValue) -> String {
let prefix = format!("LIT_{}", self.literals.len());
let next_id = match v.value() {
Value::Boolean(b) => prefix + "_" + &b.to_string(),
Value::Symbol(s) => {
if ID_RE.is_match(&s) {
prefix + "_" + s
} else {
prefix
}
}
Value::String(s) => {
if ID_RE.is_match(&s) {
prefix + "_" + s
} else {
prefix
}
}
Value::SignedInteger(n) => prefix + "_" + &n.to_string(),
_ => prefix,
};
let next_id = next_id.to_case(Case::UpperSnake);
format!(
"&<_L as Into<&'a {}>>::into(_ctxt).{}",
self.language_type(),
self.literals.entry(v.clone()).or_insert(next_id)
)
}
pub fn generate_module<F: FnOnce(&mut ModuleContext)>(
&mut self,
path: &Vec<String>,
schema: &Schema,
mode: ModuleContextMode,
items: &mut Map<ModuleContextMode, Vec<Item>>,
f: F,
) {
let mut m = ModuleContext::new(self, &ModulePath(path.clone()), schema, mode);
f(&mut m);
items.entry(mode).or_default().extend(m.extract());
}
pub fn language_struct_name(&self) -> &'static str {
"Language"
}
pub fn language_type_base(&self) -> String {
format!(
"{}::{}",
self.config.fully_qualified_module_prefix.clone(),
self.language_struct_name()
)
}
pub fn language_type(&self) -> String {
format!("{}<{}>", self.language_type_base(), self.any_type())
}
}
impl<'m, 'b> ModuleContext<'m, 'b> {
pub fn new(
bundle: &'m mut BundleContext<'b>,
module_path: &ModulePath,
schema: &'m Schema,
mode: ModuleContextMode,
) -> Self {
ModuleContext {
bundle,
module_path: module_path.to_owned(),
schema,
typedefs: Vec::new(),
functiondefs: Vec::new(),
mode,
}
}
pub fn any_type(&self) -> &'static str {
self.bundle.any_type()
}
pub fn reset_mode(&mut self) {
self.mode = ModuleContextMode::TargetToplevel;
}
pub fn define_literal(&mut self, v: &IOValue) -> String {
self.bundle.define_literal(v)
}
pub fn define_type(&mut self, i: Item) {
self.typedefs.push(i)
}
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)
}
pub fn render_ref(&self, r: &Ref, style: RefRenderStyle) -> Item {
let base = match self.bundle.config.external_modules.get(&r.module.0) {
None => {
if r.module.0.is_empty() {
item(names::render_constructor(&r.name))
} else {
let mut items = Vec::new();
items.push(item(
self.bundle.config.fully_qualified_module_prefix.to_owned(),
));
for p in &r.module.0 {
items.push(item(names::render_modname(p)))
}
items.push(item(names::render_constructor(&r.name)));
item(name(items))
}
}
Some(xm) => item(name![
xm.rust_namespace.clone(),
names::render_constructor(&r.name)
]),
};
let q = self.ref_has_embedded(r);
match style {
RefRenderStyle::Bare => base,
RefRenderStyle::Qualified => {
if q {
item(seq![base, anglebrackets![self.any_type()]])
} else {
base
}
}
}
}
pub fn ref_has_embedded(&self, r: &Ref) -> bool {
let r = r.qualify(&self.module_path);
self.bundle
.type_for_name(&r)
.map(|ty| ty.has_embedded(self.bundle))
.unwrap_or(false)
// ^ TODO: should the "false" be configurable?
}
pub fn parse_unparse_generic_decls(&self, ty: &types::TDefinition) -> Item {
let mut lts = ty.language_types(self.bundle);
lts.insert(self.bundle.language_type());
item(anglebrackets![
"'a",
seq![
"_L: Copy",
seq(lts
.into_iter()
.map(|t| item(seq![" + Into<&'a ", t, ">"]))
.collect())
],
seq![self.any_type(), ": preserves::value::NestedValue + 'a"]
])
}
pub fn extract(&mut self) -> Vec<Item> {
let mut items = std::mem::take(&mut self.typedefs);
items.extend(std::mem::take(&mut self.functiondefs));
items
}
}
impl<'a, 'm, 'b> FunctionContext<'a, 'm, 'b> {
pub fn new(m: &'a mut ModuleContext<'m, 'b>, error_context: &str) -> Self {
FunctionContext {
error_context: error_context.to_owned(),
m,
temp_counter: 0,
captures: Vec::new(),
capture_mode: CaptureMode::Definite,
}
}
pub fn capture(&mut self, field_name: String, ty: types::TField, source_expr: String) {
self.captures.push(Capture {
field_name,
ty,
source_expr: match self.capture_mode {
CaptureMode::Definite => source_expr,
CaptureMode::Indefinite(_) => format!(
"{}.ok_or_else(|| {:?})?",
source_expr,
self.conformance_err_code()
),
},
})
}
pub fn lookup_capture(&self, field_name: &str) -> &Capture {
for c in &self.captures {
if c.field_name == field_name {
return c;
}
}
panic!("No capture for field {:?} available", field_name)
}
pub fn gentempname(&mut self) -> String {
let i = self.temp_counter;
self.temp_counter += 1;
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_definite_mode<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R {
let saved_mode = std::mem::replace(&mut self.capture_mode, CaptureMode::Definite);
let result = f(self);
match std::mem::replace(&mut self.capture_mode, saved_mode) {
CaptureMode::Definite => (),
CaptureMode::Indefinite(_) => panic!("corrupt capture_mode"),
}
result
}
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();
let result = f(self);
self.temp_counter = saved_temp_counter;
self.captures.truncate(saved_capture_count);
result
}
pub fn err_code(&self) -> Item {
return item(seq!["Err", parens![self.conformance_err_code()]]);
}
pub fn fully_qualified_error_context(&self) -> String {
self.m.module_path.0.join(".") + "." + &self.error_context
}
pub fn conformance_err_code(&self) -> Item {
return item(seq![
"_support::ParseError::conformance_error",
parens![escape_string(&self.fully_qualified_error_context())]
]);
}
}

View File

@ -1,46 +0,0 @@
use preserves::value::Set;
use crate::gen::schema::ModulePath;
use crate::gen::schema::Ref;
pub struct WalkState<T> {
pub context: T,
pub module_path: ModulePath,
seen: Set<Ref>,
}
impl<T> WalkState<T> {
pub fn new(context: T, module_path: ModulePath) -> Self {
WalkState {
context,
module_path,
seen: Set::new(),
}
}
pub fn cycle_check<
E,
F: Fn(&T, &Ref) -> Option<E>,
R,
Ks: FnOnce(&mut Self, Option<E>) -> R,
Kf: FnOnce() -> R,
>(
&mut self,
r: &Ref,
step: F,
ks: Ks,
kf: Kf,
) -> R {
let r = r.qualify(&self.module_path);
if self.seen.contains(&r) {
kf()
} else {
self.seen.insert(r.clone());
let maybe_e = step(&self.context, &r);
let saved = std::mem::replace(&mut self.module_path, r.module);
let result = ks(self, maybe_e);
self.module_path = saved;
result
}
}
}

View File

@ -1,636 +0,0 @@
//! Implementation of the Schema-to-Rust compiler; this is the core of the
//! [preserves-schema-rs][] program.
//!
//! See the [documentation for preserves-schema-rs][preserves-schema-rs] for examples of how to
//! use the compiler programmatically from a `build.rs` script, but very briefly, use
//! [preserves-schemac](https://preserves.dev/doc/preserves-schemac.html) to generate a
//! metaschema instance `*.prb` file, and then put something like this in `build.rs`:
//!
//! ```rust,ignore
//! use preserves_schema::compiler::*;
//!
//! const PATH_TO_PRB_FILE: &'static str = "your-metaschema-instance-file.prb";
//!
//! fn main() -> Result<(), std::io::Error> {
//! let buildroot = std::path::PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
//!
//! let mut gen_dir = buildroot.clone();
//! gen_dir.push("src/schemas");
//! let mut c = CompilerConfig::new("crate::schemas".to_owned());
//!
//! let inputs = expand_inputs(&vec![PATH_TO_PRB_FILE.to_owned()])?;
//! c.load_schemas_and_bundles(&inputs, &vec![])?;
//! compile(&c, &mut CodeCollector::files(gen_dir))
//! }
//! ```
//!
//! plus something like this in your `lib.rs` or main program:
//!
//! ```rust,ignore
//! pub mod schemas {
//! include!(concat!(env!("OUT_DIR"), "/src/schemas/mod.rs"));
//! }
//! ```
//!
//! [preserves-schema-rs]: https://preserves.dev/doc/preserves-schema-rs.html
pub mod context;
pub mod cycles;
pub mod names;
pub mod parsers;
pub mod readers;
pub mod types;
pub mod unparsers;
use crate::compiler::context::*;
use crate::compiler::types::Purpose;
use crate::gen::schema;
use crate::gen::schema::*;
use crate::gen::Language;
use crate::syntax::block::constructors::*;
use crate::syntax::block::{Formatter, Item};
use crate::*;
use glob::glob;
use preserves::value::BinarySource;
use preserves::value::BytesBinarySource;
use preserves::value::Map;
use preserves::value::Reader;
use preserves::value::Set;
use std::fs::DirBuilder;
use std::fs::File;
use std::io;
use std::io::Read;
use std::io::Write;
use std::path::PathBuf;
/// Names a Schema module within a (collection of) Schema bundle(s).
pub type ModulePath = Vec<String>;
/// Implement this trait to extend the compiler with custom code generation support. The main
/// code generators are also implemented as plugins.
///
/// For an example of its use outside the core compiler, see [`build.rs` for the `syndicate-rs` project](https://git.syndicate-lang.org/syndicate-lang/syndicate-rs/src/commit/60e6c6badfcbcbccc902994f4f32db6048f60d1f/syndicate/build.rs).
pub trait Plugin: std::fmt::Debug {
/// Use `_module_ctxt` to emit code at a per-module level.
fn generate_module(&self, _module_ctxt: &mut ModuleContext) {}
/// Use `module_ctxt` to emit code at a per-Schema-[Definition] level.
fn generate_definition(
&self,
module_ctxt: &mut ModuleContext,
definition_name: &str,
definition: &Definition,
);
}
pub struct LanguageTypes {
pub fallback: Option<Box<dyn Fn(&str) -> Set<String>>>,
pub definitions: Map<String, Box<dyn Fn(&str) -> Set<String>>>,
}
impl std::fmt::Debug for LanguageTypes {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
f.debug_struct("LanguageTypes")
.field("fallback", &self.fallback.as_ref().map(|f| f("_")))
.field(
"definitions",
&self
.definitions
.iter()
.map(|(k, f)| (k.clone(), f("_")))
.collect::<Map<String, Set<String>>>(),
)
.finish()
}
}
#[derive(Debug)]
pub struct ExternalModule {
pub path: ModulePath,
pub rust_namespace: String,
pub rust_language_types: LanguageTypes,
}
impl ExternalModule {
pub fn new(path: ModulePath, rust_namespace: &str) -> Self {
ExternalModule {
path,
rust_namespace: rust_namespace.to_owned(),
rust_language_types: LanguageTypes {
fallback: None,
definitions: Map::new(),
},
}
}
pub fn set_fallback_language_types<F: 'static + Fn(&str) -> Set<String>>(
mut self,
f: F,
) -> Self {
self.rust_language_types.fallback = Some(Box::new(f));
self
}
pub fn set_definition_language_types<F: 'static + Fn(&str) -> Set<String>>(
mut self,
d: &str,
f: F,
) -> Self {
if self
.rust_language_types
.definitions
.insert(d.to_owned(), Box::new(f))
.is_some()
{
panic!(
"Duplicate language types definition installed: {:?} {:?}",
&self.path, d
);
}
self
}
}
/// Used to collect output from the compiler.
pub enum CodeModuleCollector<'a> {
/// Default file-based code emitter.
Files {
/// Where output Rust code files will be placed.
output_dir: PathBuf,
},
Custom {
/// Used to collect the various produced source files.
/// Useful for when compiling in e.g. proc_macro context.
collect_output: &'a mut dyn FnMut(Option<&ModulePath>, &str) -> io::Result<()>,
},
}
/// Used to configure and collect output from the compiler.
pub struct CodeCollector<'a> {
pub emit_mod_declarations: bool,
pub collect_module: CodeModuleCollector<'a>,
}
/// Main entry point to the compiler.
#[derive(Debug)]
pub struct CompilerConfig {
/// All known Schema modules, indexed by [ModulePath] and annotated with a [Purpose].
pub bundle: Map<ModulePath, (Schema, Purpose)>,
/// Fully-qualified Rust module prefix to use for each generated module.
pub fully_qualified_module_prefix: String,
/// Rust module path to the [preserves_schema::support][crate::support] module.
pub support_crate: String,
/// External modules for cross-referencing.
pub external_modules: Map<ModulePath, ExternalModule>,
/// Plugins active in this compiler instance.
pub plugins: Vec<Box<dyn Plugin>>,
/// If true, a directive is emitted in each module instructing
/// [rustfmt](https://github.com/rust-lang/rustfmt) to ignore it.
pub rustfmt_skip: bool,
}
/// Loads a [Schema] or [Bundle] from path `i` into `bundle` for the given `purpose`.
///
/// If `i` holds a [Schema], then the file stem of `i` is used as the module name when placing
/// the schema in `bundle`.
pub fn load_schema_or_bundle_with_purpose(
bundle: &mut Map<ModulePath, (Schema, Purpose)>,
i: &PathBuf,
purpose: Purpose,
) -> io::Result<()> {
let mut inserted = Map::<ModulePath, Schema>::new();
load_schema_or_bundle(&mut inserted, i)?;
for (k, v) in inserted.into_iter() {
bundle.insert(k, (v, purpose));
}
Ok(())
}
/// Loads a [Schema] or [Bundle] from raw binary encoded value `input` into `bundle` for the
/// given `purpose`.
///
/// If `input` corresponds to a [Schema], then `prefix` is used as its module name; otherwise,
/// it's a [Bundle], and `prefix` is ignored.
pub fn load_schema_or_bundle_bin_with_purpose(
bundle: &mut Map<ModulePath, (Schema, Purpose)>,
prefix: &str,
input: &[u8],
purpose: Purpose,
) -> io::Result<()> {
let mut inserted = Map::<ModulePath, Schema>::new();
load_schema_or_bundle_bin(&mut inserted, prefix, input)?;
for (k, v) in inserted.into_iter() {
bundle.insert(k, (v, purpose));
}
Ok(())
}
fn bundle_prefix(i: &PathBuf) -> io::Result<&str> {
i.file_stem()
.ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("Bad schema file stem: {:?}", i),
)
})?
.to_str()
.ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("Invalid UTF-8 in schema file name: {:?}", i),
)
})
}
/// Loads a [Schema] or [Bundle] from path `i` into `bundle`.
///
/// If `i` holds a [Schema], then the file stem of `i` is used as the module name when placing
/// the schema in `bundle`.
///
/// Returns true if it was a schema, false if it was a bundle.
pub fn load_schema_or_bundle(bundle: &mut Map<ModulePath, Schema>, i: &PathBuf) -> io::Result<bool> {
let mut f = File::open(&i)?;
let mut bs = vec![];
f.read_to_end(&mut bs)?;
load_schema_or_bundle_bin(bundle, bundle_prefix(i)?, &bs[..])
}
/// Loads a [Schema] or [Bundle] from raw binary encoded value `input` into `bundle`.
///
/// If `input` corresponds to a [Schema], then `prefix` is used as its module name; otherwise,
/// it's a [Bundle], and `prefix` is ignored.
///
/// Returns true if it was a schema, false if it was a bundle.
pub fn load_schema_or_bundle_bin(
bundle: &mut Map<ModulePath, Schema>,
prefix: &str,
input: &[u8],
) -> io::Result<bool> {
let mut src = BytesBinarySource::new(input);
let mut reader = src.packed_iovalues();
let blob = reader.demand_next(false)?;
let language = Language::default();
if let Ok(s) = language.parse(&blob) {
bundle.insert(vec![prefix.to_owned()], s);
Ok(true)
} else if let Ok(Bundle { modules }) = language.parse(&blob) {
for (ModulePath(k), v) in modules.0 {
bundle.insert(k, v);
}
Ok(false)
} else {
Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("Invalid schema binary blob {:?}", prefix),
))
}
}
impl CompilerConfig {
/// Construct a [CompilerConfig] configured to use `fully_qualified_module_prefix` as the
/// Rust module prefix for generated code.
pub fn new(fully_qualified_module_prefix: String) -> Self {
CompilerConfig {
bundle: Map::new(),
fully_qualified_module_prefix,
support_crate: "preserves_schema".to_owned(),
external_modules: Map::new(),
plugins: vec![
Box::new(types::TypePlugin),
Box::new(readers::ReaderPlugin),
Box::new(parsers::ParserPlugin),
Box::new(unparsers::UnparserPlugin),
],
rustfmt_skip: false,
}
}
pub fn add_external_module(&mut self, m: ExternalModule) {
let path = m.path.clone();
if self.external_modules.insert(path.clone(), m).is_some() {
panic!("Duplicate external module installed: {:?}", path)
}
}
pub fn load_schemas_and_bundles(
&mut self,
inputs: &Vec<PathBuf>,
xrefs: &Vec<PathBuf>,
) -> io::Result<()> {
for i in inputs {
load_schema_or_bundle_with_purpose(&mut self.bundle, i, Purpose::Codegen)?;
}
for i in xrefs {
load_schema_or_bundle_with_purpose(&mut self.bundle, i, Purpose::Xref)?;
}
Ok(())
}
pub fn load_xref_bin(&mut self, prefix: &str, bundle_or_schema: &[u8]) -> io::Result<()> {
load_schema_or_bundle_bin_with_purpose(
&mut self.bundle,
prefix,
bundle_or_schema,
Purpose::Xref,
)
}
fn build_type_cache(&self) -> Map<Ref, types::TDefinition> {
self.bundle
.iter()
.flat_map(|(modpath, s)| {
let modpath = ModulePath(modpath.clone());
s.0.definitions.0.iter().map(move |(name, def)| {
let ty = types::definition_type(&modpath, s.1, name, def);
(ty.self_ref.clone(), ty)
})
})
.collect()
}
fn generate_definition(
&self,
b: &mut BundleContext,
k: &ModulePath,
v: &Schema,
n: &str,
d: &Definition,
mode: ModuleContextMode,
generated: &mut Map<ModuleContextMode, Vec<Item>>,
) {
b.generate_module(k, v, mode, generated, |m| {
for plugin in self.plugins.iter() {
plugin.generate_definition(m, n, d);
}
});
}
}
/// Expands a vector of [mod@glob]s to a vector of actual paths.
pub fn expand_inputs(globs: &Vec<String>) -> io::Result<Vec<PathBuf>> {
let mut result = Vec::new();
for g in globs.iter() {
for p in
glob(g).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, format!("{}", e)))?
{
result.push(p.map_err(glob::GlobError::into_error)?)
}
}
Ok(result)
}
impl<'a> CodeCollector<'a> {
/// Construct a [CodeCollector] that collects output Rust modules directly into the file
/// system tree rooted at `output_dir`.
pub fn files(output_dir: PathBuf) -> Self {
CodeCollector {
emit_mod_declarations: true,
collect_module: CodeModuleCollector::Files { output_dir },
}
}
#[doc(hidden)]
pub fn collect_output(&mut self, module: Option<&ModulePath>, contents: &str) -> io::Result<()> {
match &mut self.collect_module {
CodeModuleCollector::Files { output_dir } => {
let mut output_path = output_dir.clone();
if let Some(k) = module {
output_path.extend(k);
let module_name = output_path
.file_stem()
.unwrap()
.to_str()
.unwrap()
.to_owned();
let module_name = names::render_modname(&module_name);
output_path.set_file_name(format!("{}.rs", module_name));
} else {
output_path.push("mod.rs");
}
DirBuilder::new().recursive(true).create(output_path.parent().unwrap())?;
if output_path.exists() {
if let Ok(mut f) = File::open(&output_path) {
let mut existing_contents = String::new();
f.read_to_string(&mut existing_contents)?;
if existing_contents == contents {
return Ok(());
}
}
}
let mut f = File::create(output_path)?;
f.write_all(contents.as_bytes())
}
CodeModuleCollector::Custom { collect_output } => {
collect_output(module, contents)
}
}
}
}
impl Ref {
pub fn qualify(&self, default_module_path: &schema::ModulePath) -> Ref {
if self.module.0.is_empty() {
Ref {
module: default_module_path.clone(),
name: self.name.clone(),
}
} else {
self.clone()
}
}
}
impl Schema {
pub fn has_embedded_type(&self) -> bool {
self.embedded_type != EmbeddedTypeName::False
}
}
/// Main entry point: runs the compilation process.
pub fn compile<'a>(config: &CompilerConfig, emitter: &mut CodeCollector<'a>) -> io::Result<()> {
let mut b = BundleContext::new(config);
for (k, (v, module_purpose)) in config.bundle.iter() {
if *module_purpose != Purpose::Codegen {
continue;
}
//---------------------------------------------------------------------------
let mut generated = Map::new();
b.generate_module(k, v, ModuleContextMode::TargetModule, &mut generated, |m| {
for plugin in config.plugins.iter() {
plugin.generate_module(m);
}
});
for (n, d) in &v.definitions.0 {
use ModuleContextMode::*;
config.generate_definition(&mut b, k, v, n, d, TargetToplevel, &mut generated);
config.generate_definition(&mut b, k, v, n, d, TargetGeneric, &mut generated);
}
//---------------------------------------------------------------------------
let mut lines: Vec<String> = Vec::new();
lines.push(Formatter::to_string(vertical(
false,
seq!["#![allow(unused_parens)]", "#![allow(unused_imports)]"],
)));
if config.rustfmt_skip {
lines.push("#![cfg_attr(rustfmt, rustfmt_skip)]".to_owned());
}
lines.push(Formatter::to_string(vertical(
false,
seq![
"",
"use std::convert::TryFrom;",
format!("use {}::support as _support;", &config.support_crate),
"use _support::Deserialize;",
"use _support::Parse;",
"use _support::Unparse;",
"use _support::preserves;",
"use preserves::value::Domain;",
"use preserves::value::NestedValue;",
""
],
)));
let mut emit_items = |items: Vec<Item>| {
if !items.is_empty() {
lines.push(Formatter::to_string(vertical(true, seq(items))));
lines.push("".to_owned());
}
};
emit_items(generated.remove(&ModuleContextMode::TargetModule).unwrap());
emit_items(
generated
.remove(&ModuleContextMode::TargetToplevel)
.unwrap(),
);
emit_items(generated.remove(&ModuleContextMode::TargetGeneric).unwrap());
{
let contents = lines.join("\n");
emitter.collect_output(Some(k), &contents)?;
}
}
{
let mut lines = Vec::new();
if config.rustfmt_skip {
lines.push("#![cfg_attr(rustfmt, rustfmt_skip)]".to_owned());
lines.push("".to_owned());
}
if emitter.emit_mod_declarations {
for (modpath, (_, module_purpose)) in config.bundle.iter() {
if *module_purpose != Purpose::Codegen {
continue;
}
lines.push(format!(
"pub mod {};",
names::render_modname(modpath.last().unwrap())
));
}
lines.push("".to_owned());
}
lines.push(format!(
"use {}::support as _support;",
&config.support_crate
));
lines.push("use _support::preserves;".to_owned());
lines.push("".to_owned());
lines.push("#[allow(non_snake_case)]".to_owned());
lines.push(Formatter::to_string(item(seq![
"pub struct ",
b.language_struct_name(),
anglebrackets!["N: preserves::value::NestedValue"],
" ",
vertical(
false,
braces(
b.literals
.iter()
.map(|(value, name)| item(format!("pub {}: N /* {:?} */", name, value)))
.collect()
)
)
])));
lines.push("".to_owned());
lines.push(Formatter::to_string(item(seq![
"impl",
anglebrackets!["N: preserves::value::NestedValue"],
" Default for ",
b.language_struct_name(),
"<N> ",
codeblock![seq![
"fn default() -> Self ",
codeblock![seq![
b.language_struct_name(),
" ",
vertical(
false,
braces(
b.literals
.iter()
.map(|(value, name)| {
let bs = preserves::value::PackedWriter::encode_iovalue(&value)
.unwrap();
item(format!(
"{}: /* {:?} */ _support::decode_lit(&{:?}).unwrap()",
name, value, bs
))
})
.collect()
)
)
]]
]]
])));
lines.push("".to_owned());
{
let mut b = Bundle {
modules: Modules(Map::new()),
};
for (modpath, (schema, purpose)) in config.bundle.iter() {
if *purpose == Purpose::Codegen {
b.modules
.0
.insert(ModulePath(modpath.clone()), schema.clone());
}
}
let b_value = Language::default().unparse(&b);
let b_bin = preserves::value::PackedWriter::encode_iovalue(&b_value).unwrap();
let mut hex_encoded_bundle = String::new();
let mut count = 0;
for b in b_bin {
if count % 16 == 0 {
hex_encoded_bundle.push_str("\\\n ");
}
count += 1;
hex_encoded_bundle.push_str(&format!("\\x{:02x}", b));
}
lines.push(Formatter::to_string(item(seq![
"pub fn _bundle() -> &'static [u8] ",
codeblock![seq!["b\"", hex_encoded_bundle, "\""]]
])));
}
lines.push("".to_owned());
let contents = lines.join("\n");
emitter.collect_output(None, &contents)?;
}
Ok(())
}

View File

@ -1,13 +0,0 @@
use convert_case::{Case, Casing};
pub fn render_constructor(n: &str) -> String {
n.to_case(Case::UpperCamel)
}
pub fn render_fieldname(n: &str) -> String {
n.to_case(Case::Snake)
}
pub fn render_modname(n: &str) -> String {
n.to_case(Case::Snake)
}

View File

@ -1,467 +0,0 @@
use crate::gen::schema::*;
use crate::syntax::block::constructors::*;
use crate::syntax::block::Item;
use crate::*;
use super::context::FunctionContext;
use super::context::ModuleContext;
use super::context::ModuleContextMode;
use super::context::RefRenderStyle;
use super::names;
use super::types::*;
#[derive(Debug)]
pub struct ParserPlugin;
impl compiler::Plugin for ParserPlugin {
fn generate_definition(
&self,
module_ctxt: &mut ModuleContext,
definition_name: &str,
definition: &Definition,
) {
if let ModuleContextMode::TargetGeneric = module_ctxt.mode {
gen_definition_parser(module_ctxt, definition_name, definition)
}
}
}
pub fn gen_definition_parser(m: &mut ModuleContext, n: &str, d: &Definition) {
let ty = definition_type(&m.module_path, Purpose::Codegen, n, d);
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);
for NamedAlternative {
variant_label: name,
pattern: pat,
} in ps
{
let fname = seq![
"parse_",
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);
let dest = dest.as_ref().map(String::as_str);
construct(&ctxt, ctorname, false, &pattern_type(pat), dest, &mut body);
item(seq![
"fn ",
fname.clone(),
ctxt.m.parse_unparse_generic_decls(&ty),
"(_ctxt: _L, value: &",
ctxt.m.any_type(),
") -> ",
"std::result::Result<",
names::render_constructor(n),
ty.generic_arg(ctxt.m),
", _support::ParseError> ",
codeblock(body)
])
});
body.push(item(seq![
"if let Ok(r) = ",
fname,
"(_ctxt, value) { return Ok(r); }"
]));
}
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_parser(&mut ctxt, e, "value", None, &mut body);
}
construct(
&ctxt,
item(names::render_constructor(n)),
true,
&record_type(&ps),
None,
&mut body,
);
}
Definition::Pattern(p) => {
let dest = pattern_parser(&mut ctxt, p, "value", None, &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",
ctxt.m.parse_unparse_generic_decls(&ty),
" _support::Parse",
anglebrackets!["_L", ctxt.m.any_type()],
" for ",
names::render_constructor(n),
ty.generic_arg(ctxt.m),
" ",
codeblock![seq![
"fn parse(_ctxt: _L, value: &",
ctxt.m.any_type(),
")",
" -> std::result::Result<Self, _support::ParseError> ",
codeblock(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(_) | TField::Any | TField::Embedded => format!("{}.clone()", expr),
}
}
fn simple_pattern_parser(
ctxt: &mut FunctionContext,
p: &SimplePattern,
src: &str,
sequence_base: Option<usize>,
body: &mut Vec<Item>,
) -> String {
let dest = ctxt.gentempname();
match p {
SimplePattern::Any => {
ctxt.define_atom(body, &dest, item(src.to_owned()));
dest
}
SimplePattern::Atom { atom_kind: k } => {
let converter = match &**k {
AtomKind::Boolean => "to_boolean",
AtomKind::Double => "to_double",
AtomKind::SignedInteger => "to_signedinteger",
AtomKind::String => "to_string",
AtomKind::ByteString => "to_bytestring",
AtomKind::Symbol => "to_symbol",
};
ctxt.define_atom(
body,
&dest,
item(seq![src.to_owned(), ".value().", converter, "()?"]),
);
dest
}
SimplePattern::Embedded { .. } => {
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 ",
ctxt.err_code(),
"; }"
]));
ctxt.define_atom(body, &dest, item("()"));
dest
}
SimplePattern::Seqof { pattern } => {
let (src, n) = sequenceify(ctxt, src, sequence_base, body);
let tmp = ctxt.gentempname();
let mut inner = Vec::new();
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),
");"
]));
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(), ".."]],
" ",
codeblock(inner)
]));
dest
}
SimplePattern::Setof { pattern } => {
let tmp = ctxt.gentempname();
let mut inner = Vec::new();
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),
");"
]));
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()?",
" ",
codeblock(inner)
]));
dest
}
SimplePattern::Dictof { key, value } => {
let tmp_key = ctxt.gentempname();
let tmp_value = ctxt.gentempname();
let mut inner = Vec::new();
let key_dest = simple_pattern_parser(ctxt, key, &tmp_key, None, &mut inner);
let value_dest = simple_pattern_parser(ctxt, value, &tmp_value, None, &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![
"for (",
tmp_key.to_owned(),
", ",
tmp_value.to_owned(),
")",
" in ",
src.to_owned(),
".value().to_dictionary()?",
" ",
codeblock(inner)
]));
dest
}
SimplePattern::Ref(r) => {
let tf = name![ctxt.m.render_ref(&**r, RefRenderStyle::Bare), "parse"];
ctxt.define_atom(
body,
&dest,
item(seq![tf, parens!["_ctxt", src.to_owned()], "?"]),
);
dest
}
}
}
fn sequenceify(
ctxt: &mut FunctionContext,
src: &str,
sequence_base: Option<usize>,
body: &mut Vec<Item>,
) -> (String, usize) {
match sequence_base {
Some(n) => (src.to_owned(), n),
None => {
let tmp = ctxt.gentempname();
ctxt.define_atom(
body,
&tmp,
item(seq![src.to_owned(), ".value().to_sequence()?"]),
);
(tmp, 0)
}
}
}
fn fixed_sequence_parser(
ctxt: &mut FunctionContext,
base: usize,
ps: &[NamedPattern],
src: &str,
body: &mut Vec<Item>,
) {
let mut i = base;
let required_count = ps.len();
if required_count > 0 {
body.push(item(seq![
"if ",
src.to_owned(),
".len()",
if base > 0 {
seq![" - ", base.to_string()]
} else {
seq![]
},
" < ",
required_count.to_string(),
" { return ",
ctxt.err_code(),
"; }"
]));
}
for p in ps {
named_pattern_parser(ctxt, p, &format!("(&{}[{}])", src, i), None, body);
i += 1;
}
}
fn named_pattern_parser(
ctxt: &mut FunctionContext,
p: &NamedPattern,
src: &str,
sequence_base: Option<usize>,
body: &mut Vec<Item>,
) {
match p {
NamedPattern::Anonymous(p) => {
pattern_parser(ctxt, p, src, sequence_base, body);
}
NamedPattern::Named(b) => {
let Binding { name, pattern } = &**b;
let dest = simple_pattern_parser(ctxt, pattern, src, sequence_base, body);
let capture_ty = field_type(pattern);
ctxt.capture(names::render_fieldname(name), capture_ty, dest);
}
}
}
fn pattern_parser(
ctxt: &mut FunctionContext,
p: &Pattern,
src: &str,
sequence_base: Option<usize>,
body: &mut Vec<Item>,
) -> Option<String> {
match p {
Pattern::SimplePattern(s) => Some(simple_pattern_parser(ctxt, s, src, sequence_base, body)),
Pattern::CompoundPattern(c) => {
match &**c {
CompoundPattern::Rec { label, fields } => {
let rtmp = ctxt.gentempname();
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,
);
}
CompoundPattern::Tuple { patterns } => {
let (src, n) = sequenceify(ctxt, src, sequence_base, body);
fixed_sequence_parser(ctxt, n, patterns, &src, body);
}
CompoundPattern::TuplePrefix { fixed, variable } => {
let (src, n) = sequenceify(ctxt, src, sequence_base, body);
fixed_sequence_parser(ctxt, n, fixed, &src, body);
named_pattern_parser(
ctxt,
&promote(variable),
&src,
Some(n + fixed.len()),
body,
);
}
CompoundPattern::Dict { entries } => {
let dtmp = ctxt.gentempname();
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();
let init_expr = item(seq![
dtmp.to_owned(),
".get",
parens![ctxt.m.define_literal(key_lit)],
".ok_or_else(|| ",
ctxt.conformance_err_code(),
")?"
]);
ctxt.define_atom(body, &vtmp, init_expr);
named_pattern_parser(ctxt, &promote(value_pat), &vtmp, None, body);
}
}
}
None
}
}
}

View File

@ -1,652 +0,0 @@
use crate::gen::schema::*;
use crate::syntax::block::constructors::*;
use crate::syntax::block::escape_bytes;
use crate::syntax::block::escape_string;
use crate::syntax::block::Item;
use crate::*;
use preserves::value::AtomClass;
use preserves::value::CompoundClass;
use preserves::value::IOValue;
use preserves::value::NestedValue;
use preserves::value::ValueClass;
use super::context::FunctionContext;
use super::context::ModuleContext;
use super::context::ModuleContextMode;
use super::context::RefRenderStyle;
use super::names;
use super::types::*;
#[derive(Debug)]
pub struct ReaderPlugin;
impl compiler::Plugin for ReaderPlugin {
fn generate_definition(
&self,
module_ctxt: &mut ModuleContext,
definition_name: &str,
definition: &Definition,
) {
if let ModuleContextMode::TargetGeneric = module_ctxt.mode {
gen_definition_reader(module_ctxt, definition_name, definition)
}
}
}
#[derive(Clone)]
struct BoundaryTracker {
tracker_name: String,
item_expr: &'static str,
}
impl BoundaryTracker {
fn unwrap(
ctxt: &mut FunctionContext,
body: &mut Vec<Item>,
open_expr: &'static str,
e: Option<&BoundaryTracker>,
) -> Self {
match e {
None => Self::new(ctxt, body, open_expr, "_support::B::Item::SequenceValue"),
Some(b) => b.clone(),
}
}
fn new(
ctxt: &mut FunctionContext,
body: &mut Vec<Item>,
open_expr: &'static str,
item_expr: &'static str,
) -> Self {
let tracker_name = ctxt.gentempname();
body.push(item(open_expr));
body.push(item(seq![
"let mut ",
tracker_name.clone(),
" = _support::B::Type::default();"
]));
BoundaryTracker {
tracker_name,
item_expr,
}
}
fn emit_boundary(&self, body: &mut Vec<Item>) {
body.push(item(seq![
self.tracker_name.clone(),
".shift(Some(",
self.item_expr,
"));"
]));
body.push(item(seq!["r.boundary(&", self.tracker_name.clone(), ")?;"]));
}
fn emit_loop(&self, body: &mut Vec<Item>, inner: Vec<Item>) {
body.push(item(seq![
"while !r.close_compound",
parens![
seq!["&mut ", self.tracker_name.clone()],
seq!["&", self.item_expr]
],
"? ",
codeblock(inner)
]))
}
}
pub fn gen_definition_reader(m: &mut ModuleContext, n: &str, d: &Definition) {
let ty = definition_type(&m.module_path, Purpose::Codegen, n, d);
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![
"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, None, &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",
seq![ctxt.m.any_type(), ": preserves::value::NestedValue"],
seq!["R: _support::Reader<'de, ", ctxt.m.any_type(), ">"]
],
"(r: &mut R) -> ",
"std::result::Result<",
names::render_constructor(n),
ty.generic_arg(ctxt.m),
", _support::ParseError> ",
codeblock(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];
let mut need_restore = false;
ps.extend(pattern_n);
ctxt.define_atom(&mut body, "_mark", item("r.mark()?"));
for e in &ps {
if need_restore {
body.push(item("r.restore(&_mark)?;"));
} else {
need_restore = true;
}
named_pattern_reader(&mut ctxt, e, None, &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, None, &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![seq![ctxt.m.any_type(), ": preserves::value::NestedValue"]],
" _support::Deserialize",
anglebrackets![ctxt.m.any_type()],
" for ",
names::render_constructor(n),
ty.generic_arg(ctxt.m),
" ",
codeblock![seq![
"fn deserialize",
anglebrackets![
"'de",
seq!["R: _support::Reader<'de, ", ctxt.m.any_type(), ">"]
],
"(r: &mut R) -> ",
"std::result::Result<Self, _support::ParseError> ",
codeblock(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(_) | TField::Any | TField::Embedded => 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<(IOValue, LiteralContinuation)>;
type LiteralSeqCases = Vec<(Vec<IOValue>, 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 => ",
codeblock(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(true)? ", codeblock(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::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())),
},
" => ",
codeblock(inner)]));
}
subcases.push(item(seq!["_ => return ", ctxt.err_code(), "?,"]));
item(seq!["preserves::value::Token::Atom(v) => match v.value() ", codeblock(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) => ",
codeblock(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) => ",
codeblock(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(true)? ", codeblock(cases)]));
}
fn simple_pattern_reader(
ctxt: &mut FunctionContext,
p: &SimplePattern,
boundary_tracker: Option<&BoundaryTracker>,
body: &mut Vec<Item>,
) -> String {
let dest = ctxt.gentempname();
match p {
SimplePattern::Any => {
ctxt.define_atom(body, &dest, item("r.demand_next(true)?"));
dest
}
SimplePattern::Atom { atom_kind: k } => {
let reader = match &**k {
AtomKind::Boolean => "r.next_boolean()?",
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 { .. } => {
ctxt.define_atom(
body,
&dest,
item("r.demand_next(true)?.value().to_embedded()?.clone()"),
);
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 } => {
let compound_dest = ctxt.gentempname();
ctxt.with_definite_mode(|ctxt| {
let boundary_tracker =
BoundaryTracker::unwrap(ctxt, body, "r.open_sequence()?;", boundary_tracker);
let mut inner = Vec::new();
boundary_tracker.emit_boundary(&mut inner);
let item_dest = simple_pattern_reader(ctxt, pattern, None, &mut inner);
inner.push(item(seq![
compound_dest.to_owned(),
".push(",
store_wrap(true, &field_type(pattern), &item_dest),
");"
]));
ctxt.declare_compound(body, &compound_dest, item("std::vec::Vec::new()"));
boundary_tracker.emit_loop(body, inner);
});
ctxt.define_atom(body, &dest, item(compound_dest));
dest
}
SimplePattern::Setof { pattern } => {
let compound_dest = ctxt.gentempname();
ctxt.with_definite_mode(|ctxt| {
let boundary_tracker = BoundaryTracker::new(
ctxt,
body,
"r.open_set()?;",
"_support::B::Item::SetValue",
);
let mut inner = Vec::new();
boundary_tracker.emit_boundary(&mut inner);
let item_dest = simple_pattern_reader(ctxt, pattern, None, &mut inner);
inner.push(item(seq![
compound_dest.to_owned(),
".insert(",
store_wrap(true, &field_type(pattern), &item_dest),
");"
]));
ctxt.declare_compound(body, &compound_dest, item("preserves::value::Set::new()"));
boundary_tracker.emit_loop(body, inner);
});
ctxt.define_atom(body, &dest, item(compound_dest));
dest
}
SimplePattern::Dictof { key, value } => {
let compound_dest = ctxt.gentempname();
ctxt.with_definite_mode(|ctxt| {
let mut boundary_tracker = BoundaryTracker::new(
ctxt,
body,
"r.open_dictionary()?;",
"_support::B::Item::DictionaryKey",
);
let mut inner = Vec::new();
boundary_tracker.emit_boundary(&mut inner);
let key_dest = simple_pattern_reader(ctxt, key, None, &mut inner);
boundary_tracker.item_expr = "_support::B::Item::DictionaryValue";
boundary_tracker.emit_boundary(&mut inner);
let value_dest = simple_pattern_reader(ctxt, value, None, &mut inner);
inner.push(item(seq![
compound_dest.to_owned(),
".insert(",
store_wrap(true, &field_type(key), &key_dest),
", ",
store_wrap(true, &field_type(value), &value_dest),
");"
]));
ctxt.declare_compound(body, &compound_dest, item("preserves::value::Map::new()"));
boundary_tracker.item_expr = "_support::B::Item::DictionaryKey";
boundary_tracker.emit_loop(body, inner);
});
ctxt.define_atom(body, &dest, item(compound_dest));
dest
}
SimplePattern::Ref(r) => {
let tf = name![ctxt.m.render_ref(&**r, RefRenderStyle::Bare), "deserialize"];
ctxt.define_atom(body, &dest, item(seq![tf, "(r)?"]));
dest
}
}
}
fn named_pattern_reader(
ctxt: &mut FunctionContext,
p: &NamedPattern,
boundary_tracker: Option<&BoundaryTracker>,
body: &mut Vec<Item>,
) {
match p {
NamedPattern::Anonymous(p) => {
pattern_reader(ctxt, p, boundary_tracker, body);
}
NamedPattern::Named(b) => {
let Binding { name, pattern } = &**b;
let dest = simple_pattern_reader(ctxt, pattern, boundary_tracker, body);
let capture_ty = field_type(pattern);
ctxt.capture(names::render_fieldname(name), capture_ty, dest);
}
}
}
fn pattern_reader(
ctxt: &mut FunctionContext,
p: &Pattern,
boundary_tracker: Option<&BoundaryTracker>,
body: &mut Vec<Item>,
) -> Option<String> {
match p {
Pattern::SimplePattern(s) => Some(simple_pattern_reader(ctxt, s, boundary_tracker, body)),
Pattern::CompoundPattern(c) => {
match &**c {
CompoundPattern::Rec { label, fields } => {
let mut boundary_tracker = BoundaryTracker::new(
ctxt,
body,
"r.open_record(None)?;",
"_support::B::Item::RecordLabel",
);
boundary_tracker.emit_boundary(body);
boundary_tracker.item_expr = "_support::B::Item::RecordField";
named_pattern_reader(ctxt, &**label, None, body);
named_pattern_reader(ctxt, &**fields, Some(&boundary_tracker), body);
}
CompoundPattern::Tuple { patterns } => {
let boundary_tracker = BoundaryTracker::unwrap(
ctxt,
body,
"r.open_sequence()?;",
boundary_tracker,
);
for p in patterns {
boundary_tracker.emit_boundary(body);
named_pattern_reader(ctxt, p, None, body);
}
body.push(item(seq![
"r.ensure_complete",
parens![
boundary_tracker.tracker_name.clone(),
seq!["&", boundary_tracker.item_expr]
],
"?;"
]));
}
CompoundPattern::TuplePrefix { fixed, variable } => {
let boundary_tracker = BoundaryTracker::unwrap(
ctxt,
body,
"r.open_sequence()?;",
boundary_tracker,
);
for p in fixed {
boundary_tracker.emit_boundary(body);
named_pattern_reader(ctxt, p, None, body);
}
named_pattern_reader(ctxt, &promote(variable), Some(&boundary_tracker), body);
}
CompoundPattern::Dict { entries } => {
let boundary_tracker = BoundaryTracker::new(
ctxt,
body,
"r.open_dictionary()?;",
"_support::B::Item::DictionaryKey",
);
let mut inner = Vec::new();
boundary_tracker.emit_boundary(&mut inner);
let mut val_boundary_tracker = boundary_tracker.clone();
val_boundary_tracker.item_expr = "_support::B::Item::DictionaryValue";
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 val_boundary_tracker = val_boundary_tracker.clone();
let f: LiteralContinuation = Box::new(
move |ctxt: &mut FunctionContext, innerinner: &mut Vec<Item>| {
val_boundary_tracker.emit_boundary(innerinner);
named_pattern_reader(ctxt, &promote(&value_pat), None, innerinner);
innerinner.push(item("continue;"));
});
(key_lit.clone(), f)
}).collect());
}));
boundary_tracker.emit_loop(body, inner);
}
}
None
}
}
}

View File

@ -1,461 +0,0 @@
use crate::gen::schema::*;
use crate::syntax::block::constructors::*;
use crate::syntax::block::{Emittable, Item};
use crate::*;
use preserves::value::Set;
use super::context::BundleContext;
use super::context::ModuleContext;
use super::context::ModuleContextMode;
use super::context::RefRenderStyle;
use super::names;
#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
pub enum Purpose {
Codegen,
Xref,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct TDefinition {
pub purpose: Purpose,
pub self_ref: Ref,
pub body: TDefinitionBody,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum TDefinitionBody {
Union(Vec<(String, TSimple)>),
Simple(TSimple),
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum TSimple {
Field(TField),
Record(TRecord),
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum TField {
Unit,
Any,
Embedded,
Array(Box<TField>),
Set(Box<TField>),
Map(Box<TField>, Box<TField>),
Ref(Ref),
Base(String),
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct TRecord(pub Vec<(String, TField)>);
#[derive(Debug)]
pub struct TypePlugin;
impl compiler::Plugin for TypePlugin {
fn generate_module(&self, m: &mut ModuleContext) {
if let EmbeddedTypeName::Ref(r) = &m.schema.embedded_type {
m.define_type(item(vertical(
false,
seq![
seq![
"pub type _Dom = ",
m.render_ref(&*r, RefRenderStyle::Bare),
";"
],
seq!["pub type _Ptr = std::sync::Arc<_Dom>;"],
seq!["pub type _Any = preserves::value::ArcValue<_Ptr>;"]
],
)));
}
}
fn generate_definition(&self, m: &mut ModuleContext, n: &str, d: &Definition) {
if let ModuleContextMode::TargetGeneric = m.mode {
let ty = definition_type(&m.module_path, Purpose::Codegen, n, d);
m.define_type(item(ty.render(m, n)));
m.define_type(item(seq![
"impl",
ty.generic_decl(m),
" preserves::value::Domain for ",
names::render_constructor(n),
ty.generic_arg(m),
" {}"
]));
}
}
}
pub fn definition_type(
module: &ModulePath,
purpose: Purpose,
n: &str,
d: &Definition,
) -> TDefinition {
TDefinition {
purpose,
self_ref: Ref {
module: module.clone(),
name: n.to_owned(),
},
body: match d {
Definition::Or {
pattern_0,
pattern_1,
pattern_n,
} => TDefinitionBody::Union(or_definition_type(pattern_0, pattern_1, pattern_n)),
Definition::And {
pattern_0,
pattern_1,
pattern_n,
} => TDefinitionBody::Simple(and_definition_type(pattern_0, pattern_1, pattern_n)),
Definition::Pattern(p) => TDefinitionBody::Simple(pattern_type(p)),
},
}
}
pub fn or_definition_type(
p0: &NamedAlternative,
p1: &NamedAlternative,
pn: &Vec<NamedAlternative>,
) -> Vec<(String, TSimple)> {
let mut entries = Vec::new();
entries.push((p0.variant_label.to_owned(), pattern_type(&p0.pattern)));
entries.push((p1.variant_label.to_owned(), pattern_type(&p1.pattern)));
for e in pn {
entries.push((e.variant_label.to_owned(), pattern_type(&e.pattern)));
}
entries
}
pub fn and_definition_type(
p0: &NamedPattern,
p1: &NamedPattern,
pn: &Vec<NamedPattern>,
) -> TSimple {
let mut arms = vec![p0, p1];
arms.extend(pn);
record_type(&arms)
}
pub fn pattern_type(p: &Pattern) -> TSimple {
match p {
Pattern::SimplePattern(p) => TSimple::Field(field_type(p)),
Pattern::CompoundPattern(_) => {
record_type(&vec![&NamedPattern::Anonymous(Box::new(p.clone()))])
}
}
}
pub fn record_type(ps: &Vec<&NamedPattern>) -> TSimple {
let fs = gather_fields(ps, Vec::new());
if fs.is_empty() {
TSimple::Field(TField::Unit)
} else {
TSimple::Record(TRecord(fs))
}
}
pub fn gather_fields(
ps: &Vec<&NamedPattern>,
mut fs: Vec<(String, TField)>,
) -> Vec<(String, TField)> {
for p in ps.iter() {
fs = gather_field(p, fs);
}
fs
}
pub fn gather_field(p: &NamedPattern, mut fs: Vec<(String, TField)>) -> Vec<(String, TField)> {
match p {
NamedPattern::Named(b) => {
let Binding { name, pattern } = &**b;
fs.push((name.to_owned(), field_type(pattern)));
fs
}
NamedPattern::Anonymous(p) => match &**p {
Pattern::SimplePattern(_) => fs,
Pattern::CompoundPattern(c) => match &**c {
CompoundPattern::Rec { label, fields } => {
gather_field(&*fields, gather_field(&*label, fs))
}
CompoundPattern::Tuple { patterns } => {
gather_fields(&patterns.iter().collect(), fs)
}
CompoundPattern::TuplePrefix { fixed, variable } => gather_field(
&promote(&**variable),
gather_fields(&fixed.iter().collect(), fs),
),
CompoundPattern::Dict { entries } => {
for (_k, p) in &entries.0 {
fs = gather_field(&promote(&p), fs);
}
fs
}
},
},
}
}
pub fn promote(p: &NamedSimplePattern) -> NamedPattern {
match p {
NamedSimplePattern::Anonymous(p) => {
NamedPattern::Anonymous(Box::new(Pattern::SimplePattern(p.clone())))
}
NamedSimplePattern::Named(n) => NamedPattern::Named(n.clone()),
}
}
pub fn field_type(p: &SimplePattern) -> TField {
match p {
SimplePattern::Any => TField::Any,
SimplePattern::Atom { atom_kind: k } => match **k {
AtomKind::Boolean => TField::Base("bool".to_owned()),
AtomKind::Double => TField::Base("preserves::value::Double".to_owned()),
AtomKind::SignedInteger => {
TField::Base("preserves::value::signed_integer::SignedInteger".to_owned())
}
AtomKind::String => TField::Base("std::string::String".to_owned()),
AtomKind::ByteString => TField::Base("std::vec::Vec<u8>".to_owned()),
AtomKind::Symbol => TField::Base("std::string::String".to_owned()),
},
SimplePattern::Embedded { .. } => TField::Embedded,
SimplePattern::Lit { .. } => TField::Unit,
SimplePattern::Seqof { pattern: t } => TField::Array(Box::new(field_type(t))),
SimplePattern::Setof { pattern: t } => TField::Set(Box::new(field_type(t))),
SimplePattern::Dictof { key: k, value: v } => {
TField::Map(Box::new(field_type(k)), Box::new(field_type(v)))
}
SimplePattern::Ref(r) => TField::Ref((**r).clone()),
}
}
type WalkState<'a, 'b> = super::cycles::WalkState<&'a BundleContext<'b>>;
impl TField {
fn render(&self, ctxt: &ModuleContext, box_needed: bool) -> impl Emittable {
match self {
TField::Unit => seq!["()"],
TField::Any => seq![ctxt.any_type()],
TField::Embedded => seq![ctxt.any_type(), "::Embedded"],
TField::Array(t) => seq!["std::vec::Vec<", t.render(ctxt, false), ">"],
TField::Set(t) => seq!["preserves::value::Set<", t.render(ctxt, false), ">"],
TField::Map(k, v) => seq![
"preserves::value::Map",
anglebrackets![k.render(ctxt, false), v.render(ctxt, false)]
],
TField::Ref(r) => {
if box_needed {
seq![
"std::boxed::Box",
anglebrackets![ctxt.render_ref(r, RefRenderStyle::Qualified)]
]
} else {
seq![ctxt.render_ref(r, RefRenderStyle::Qualified)]
}
}
TField::Base(n) => seq![n.to_owned()],
}
}
fn language_types(&self, s: &mut WalkState, ts: &mut Set<String>) {
match self {
TField::Unit | TField::Any | TField::Embedded | TField::Base(_) => (),
TField::Array(f) => f.language_types(s, ts),
TField::Set(f) => f.language_types(s, ts),
TField::Map(k, v) => {
k.language_types(s, ts);
v.language_types(s, ts);
}
TField::Ref(r) => s.cycle_check(
r,
|ctxt, r| ctxt.type_for_name(r),
|s, t| match t {
Some(ty) if ty.purpose == Purpose::Codegen => ty._language_types(s, ts),
Some(_) | None => {
let xmts = &s
.context
.config
.external_modules
.get(&r.module.0)
.unwrap()
.rust_language_types;
if let Some(f) = xmts.definitions.get(&r.name).or(xmts.fallback.as_ref()) {
ts.extend(f(s.context.any_type()));
}
}
},
|| (),
),
}
}
fn has_embedded(&self, s: &mut WalkState) -> bool {
match self {
TField::Unit | TField::Base(_) => false,
TField::Any | TField::Embedded => true, // at least potentially true
TField::Array(f) => f.has_embedded(s),
TField::Set(f) => f.has_embedded(s),
TField::Map(k, v) => k.has_embedded(s) || v.has_embedded(s),
TField::Ref(r) =>
// v TODO: should the "false" be configurable? cf. ModuleContext::ref_has_embedded.
{
s.cycle_check(
r,
|ctxt, r| ctxt.type_for_name(r),
|s, t| t.map(|t| t._has_embedded(s)).unwrap_or(false),
|| false,
)
}
}
}
}
impl TSimple {
pub fn render(
&self,
ctxt: &ModuleContext,
ptr: Item,
is_struct: bool,
n: &str,
) -> impl Emittable {
let semi = if is_struct { seq![";"] } else { seq![] };
let ppub = if is_struct { "pub " } else { "" };
seq![
names::render_constructor(n),
ptr.to_owned(),
match self {
TSimple::Record(TRecord(fs)) => seq![
" ",
vertical(
false,
braces(
fs.iter()
.map(|(n, d)| item(seq![
ppub,
names::render_fieldname(n),
": ",
d.render(ctxt, !is_struct)
]))
.collect()
)
)
],
TSimple::Field(TField::Unit) => semi,
TSimple::Field(t) => seq![parens![seq![ppub, t.render(ctxt, !is_struct)]], semi],
}
]
}
fn language_types(&self, s: &mut WalkState, ts: &mut Set<String>) {
match self {
TSimple::Field(f) => f.language_types(s, ts),
TSimple::Record(TRecord(fs)) => fs.iter().for_each(|(_k, v)| v.language_types(s, ts)),
}
}
fn has_embedded(&self, s: &mut WalkState) -> bool {
match self {
TSimple::Field(f) => f.has_embedded(s),
TSimple::Record(TRecord(fs)) => fs.iter().any(|(_k, v)| v.has_embedded(s)),
}
}
}
impl TDefinition {
pub fn generic_decl(&self, ctxt: &ModuleContext) -> Item {
if self.has_embedded(ctxt.bundle) {
item(anglebrackets![seq![
ctxt.any_type(),
": preserves::value::NestedValue"
]])
} else {
item("")
}
}
pub fn generic_decl_with_defaults(&self, ctxt: &ModuleContext) -> Item {
if self.has_embedded(ctxt.bundle) {
item(anglebrackets![seq![
ctxt.any_type(),
": preserves::value::NestedValue = ",
match ctxt.schema.embedded_type {
EmbeddedTypeName::False => "preserves::value::IOValue",
EmbeddedTypeName::Ref(_) => "_Any",
}
]])
} else {
item("")
}
}
pub fn generic_arg(&self, ctxt: &ModuleContext) -> Item {
if self.has_embedded(ctxt.bundle) {
item(anglebrackets![ctxt.any_type()])
} else {
item("")
}
}
pub fn render(&self, ctxt: &ModuleContext, n: &str) -> impl Emittable {
vertical(
false,
seq![
"#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Hash)]",
match &self.body {
TDefinitionBody::Union(items) => seq![
"pub enum ",
names::render_constructor(n),
self.generic_decl_with_defaults(ctxt),
" ",
vertical(
false,
braces(
items
.iter()
.map(|(n, d)| item(d.render(ctxt, item(""), false, n)))
.collect()
)
)
],
TDefinitionBody::Simple(s) => seq![
"pub struct ",
s.render(ctxt, self.generic_decl_with_defaults(ctxt), true, n)
],
}
],
)
}
fn walk_state<'a, 'b>(&self, ctxt: &'a BundleContext<'b>) -> WalkState<'a, 'b> {
WalkState::new(ctxt, self.self_ref.module.clone())
}
pub fn language_types(&self, ctxt: &BundleContext) -> Set<String> {
let mut ts = Set::new();
self._language_types(&mut self.walk_state(ctxt), &mut ts);
ts
}
fn _language_types(&self, s: &mut WalkState, ts: &mut Set<String>) {
match &self.body {
TDefinitionBody::Union(entries) => {
entries.iter().for_each(|(_k, v)| v.language_types(s, ts))
}
TDefinitionBody::Simple(t) => t.language_types(s, ts),
}
}
pub fn has_embedded(&self, ctxt: &BundleContext) -> bool {
self._has_embedded(&mut self.walk_state(ctxt))
}
fn _has_embedded(&self, s: &mut WalkState) -> bool {
match &self.body {
TDefinitionBody::Union(entries) => entries.iter().any(|(_k, v)| v.has_embedded(s)),
TDefinitionBody::Simple(t) => t.has_embedded(s),
}
}
}

View File

@ -1,440 +0,0 @@
use crate::gen::schema::*;
use crate::syntax::block::constructors::*;
use crate::syntax::block::{escape_string, Emittable, Item};
use crate::*;
use std::cell::Cell;
use std::rc::Rc;
use super::context::{FunctionContext, ModuleContext, ModuleContextMode};
use super::names;
use super::types::*;
#[derive(Debug)]
pub struct UnparserPlugin;
impl compiler::Plugin for UnparserPlugin {
fn generate_definition(
&self,
module_ctxt: &mut ModuleContext,
definition_name: &str,
definition: &Definition,
) {
if let ModuleContextMode::TargetGeneric = module_ctxt.mode {
gen_definition_unparser(module_ctxt, definition_name, definition)
}
}
}
type ValueSource = Option<String>;
#[derive(Clone)]
struct FieldsSink {
finish: Item,
vec_expr: Item,
body: Vec<Item>,
}
#[derive(Clone)]
enum ValueSink {
Normal,
Fields(Rc<Cell<Option<FieldsSink>>>),
}
impl std::fmt::Debug for ValueSink {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
match self {
ValueSink::Normal => write!(f, "ValueSink::Normal"),
ValueSink::Fields(_) => write!(f, "ValueSink::Normal"),
}
}
}
#[derive(Debug)]
struct ValueContext {
src: ValueSource,
sink: ValueSink,
is_struct: bool,
}
fn normal_none(is_struct: bool) -> ValueContext {
ValueContext {
src: None,
sink: ValueSink::Normal,
is_struct,
}
}
fn normal_src(src: String, is_struct: bool) -> ValueContext {
ValueContext {
src: Some(src),
sink: ValueSink::Normal,
is_struct,
}
}
pub fn gen_definition_unparser(m: &mut ModuleContext, n: &str, d: &Definition) {
let ty = definition_type(&m.module_path, Purpose::Codegen, n, d);
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);
body.push(item(seq![
"match self ",
codeblock(
ps.iter()
.map(
|NamedAlternative {
variant_label: name,
pattern: pat,
}| ctxt.branch(|ctxt| {
let ctorname = item(name![
names::render_constructor(n),
names::render_constructor(name)
]);
let (patpat, vc) =
destruct(ctxt, ctorname, false, &pattern_type(pat));
item(seq![
patpat,
" => ",
pattern_unparser(ctxt, pat, &vc),
","
])
})
)
.collect()
)
]));
}
Definition::And {
pattern_0,
pattern_1,
pattern_n,
} => {
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),
);
body.push(item(seq!["let ", patpat, " = self;"]));
body.push(item(seq![
"preserves::value::merge(vec!",
brackets(
ps.iter()
.map(|p| named_pattern_unparser(&mut ctxt, p, &vc))
.collect()
),
").expect",
parens![escape_string(
&("merge of ".to_owned() + &ctxt.fully_qualified_error_context())
)]
]));
}
Definition::Pattern(p) => {
let (patpat, vc) = destruct(
&mut ctxt,
item(names::render_constructor(n)),
true,
&pattern_type(p),
);
body.push(item(seq!["let ", patpat, " = self;"]));
body.push(pattern_unparser(&mut ctxt, p, &vc));
}
}
item(seq![
"impl",
ctxt.m.parse_unparse_generic_decls(&ty),
" _support::Unparse",
anglebrackets!["_L", ctxt.m.any_type()],
" for ",
names::render_constructor(n),
ty.generic_arg(ctxt.m),
" ",
codeblock![seq![
"fn unparse(&self, _ctxt: _L) -> ",
ctxt.m.any_type(),
" ",
codeblock(body)
]]
])
});
}
fn destruct(
ctxt: &mut FunctionContext,
ctorname: Item,
is_struct: bool,
ty: &TSimple,
) -> (impl Emittable, ValueContext) {
match ty {
TSimple::Field(TField::Unit) => (seq![ctorname], normal_none(is_struct)),
TSimple::Field(_) => {
let src = ctxt.gentempname();
(
seq![ctorname, parens![src.to_owned()]],
normal_src(src, is_struct),
)
}
TSimple::Record(TRecord(fs)) => {
for (fname, fty) in fs {
let fsrc = ctxt.gentempname();
ctxt.capture(names::render_fieldname(fname), fty.clone(), fsrc);
}
(
seq![
ctorname,
" ",
braces(
ctxt.captures
.iter()
.map(|c| item(seq![c.field_name.clone(), ": ", c.source_expr.clone()]))
.collect()
)
],
normal_none(is_struct),
)
}
}
}
fn simple_pattern_unparser(
ctxt: &mut FunctionContext,
p: &SimplePattern,
vc: &ValueContext,
) -> Item {
let src = &vc.src;
match p {
SimplePattern::Any => item(seq![src.as_ref().unwrap().to_owned(), ".clone()"]),
SimplePattern::Atom { atom_kind: k } => match &**k {
AtomKind::Symbol => item(seq![
"preserves::value::Value::symbol(",
src.as_ref().unwrap().to_owned(),
").wrap()"
]),
AtomKind::ByteString => item(seq![
"preserves::value::Value::ByteString(",
src.as_ref().unwrap().to_owned(),
".clone()).wrap()"
]),
_ => item(seq![
"preserves::value::Value::from(",
src.as_ref().unwrap().to_owned(),
").wrap()"
]),
},
SimplePattern::Embedded { .. } => item(seq![
"preserves::value::Value::Embedded(",
src.as_ref().unwrap().to_owned(),
".clone()).wrap()"
]),
SimplePattern::Lit { value } => {
item(seq![parens![ctxt.m.define_literal(value)], ".clone()"])
}
SimplePattern::Seqof { pattern } => {
let mut fields_sink = sequenceify(ctxt, vc);
let tmp = ctxt.gentempname();
fields_sink.body.push(item(seq![
"for ",
tmp.to_owned(),
" in ",
src.as_ref().unwrap().to_owned(),
" ",
codeblock![seq![
fields_sink.vec_expr.clone(),
".push(",
simple_pattern_unparser(ctxt, pattern, &normal_src(tmp, true)),
");"
]]
]));
finish(fields_sink)
}
SimplePattern::Setof { pattern } => {
let tmp = ctxt.gentempname();
item(seq![
"preserves::value::Value::Set(",
src.as_ref().unwrap().to_owned(),
".iter().map(|",
tmp.to_owned(),
"| ",
simple_pattern_unparser(ctxt, pattern, &normal_src(tmp, true)),
").collect()).wrap()"
])
}
SimplePattern::Dictof { key, value } => {
let tmp_key = ctxt.gentempname();
let tmp_value = ctxt.gentempname();
item(seq![
"preserves::value::Value::Dictionary(",
src.as_ref().unwrap().to_owned(),
".iter().map(|(",
tmp_key.to_owned(),
", ",
tmp_value.to_owned(),
")| ",
parens![
simple_pattern_unparser(ctxt, key, &normal_src(tmp_key, true)),
simple_pattern_unparser(ctxt, value, &normal_src(tmp_value, true))
],
").collect()).wrap()"
])
}
SimplePattern::Ref(_r) => item(seq![
src.as_ref().unwrap().to_owned(),
if vc.is_struct { "" } else { ".as_ref()" },
".unparse(_ctxt)"
]),
}
}
fn named_pattern_unparser(ctxt: &mut FunctionContext, p: &NamedPattern, vc: &ValueContext) -> Item {
match p {
NamedPattern::Anonymous(p) => pattern_unparser(ctxt, p, vc),
NamedPattern::Named(b) => {
let Binding { name, pattern } = &**b;
let src = ctxt
.lookup_capture(&names::render_fieldname(name))
.source_expr
.to_owned();
simple_pattern_unparser(
ctxt,
pattern,
&ValueContext {
src: Some(src),
sink: vc.sink.clone(),
is_struct: vc.is_struct,
},
)
}
}
}
fn pattern_unparser(ctxt: &mut FunctionContext, p: &Pattern, vc: &ValueContext) -> Item {
match p {
Pattern::SimplePattern(s) => simple_pattern_unparser(ctxt, s, vc),
Pattern::CompoundPattern(c) => match &**c {
CompoundPattern::Rec { label, fields } => {
let rtmp = ctxt.gentempname();
let mut body = Vec::new();
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 {
finish: item(seq![rtmp.clone(), ".finish().wrap()"]),
vec_expr: item(seq![rtmp.clone(), ".fields_vec_mut()"]),
body,
})))),
is_struct: vc.is_struct,
},
)
}
CompoundPattern::Tuple { patterns } => {
let mut fields_sink = sequenceify(ctxt, vc);
fixed_sequence_parser(ctxt, patterns, &mut fields_sink, vc.is_struct);
finish(fields_sink)
}
CompoundPattern::TuplePrefix { fixed, variable } => {
let mut fields_sink = sequenceify(ctxt, vc);
fixed_sequence_parser(ctxt, fixed, &mut fields_sink, vc.is_struct);
named_pattern_unparser(
ctxt,
&promote(variable),
&ValueContext {
src: vc.src.clone(),
sink: ValueSink::Fields(Rc::new(Cell::new(Some(fields_sink)))),
is_struct: true,
},
)
}
CompoundPattern::Dict { entries } => {
let dtmp = ctxt.gentempname();
let mut body = Vec::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()"],
named_pattern_unparser(
ctxt,
&promote(value_pat),
&normal_none(vc.is_struct)
)
],
";"
]));
}
body.push(item(seq![
"preserves::value::Value::Dictionary(",
dtmp,
").wrap()"
]));
item(codeblock(body))
}
},
}
}
fn sequenceify<'a>(ctxt: &mut FunctionContext, vc: &'a ValueContext) -> FieldsSink {
match vc {
ValueContext {
sink: ValueSink::Fields(fields_sink),
..
} => (**fields_sink).take().unwrap(),
_ => {
let rtmp = ctxt.gentempname();
let mut body = Vec::new();
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: item(rtmp),
body,
}
}
}
}
fn finish(mut fields_sink: FieldsSink) -> Item {
fields_sink.body.push(fields_sink.finish);
item(codeblock(fields_sink.body))
}
fn fixed_sequence_parser(
ctxt: &mut FunctionContext,
patterns: &Vec<NamedPattern>,
fields_sink: &mut FieldsSink,
is_struct: bool,
) {
for p in patterns {
fields_sink.body.push(item(seq![
fields_sink.vec_expr.clone(),
".push",
parens![named_pattern_unparser(ctxt, p, &normal_none(is_struct))],
";"
]));
}
}

View File

@ -1,261 +0,0 @@
#![cfg_attr(rustfmt, rustfmt_skip)]
pub mod schema;
use crate::support as _support;
use _support::preserves;
#[allow(non_snake_case)]
pub struct Language<N: preserves::value::NestedValue> {
pub LIT_14_FALSE: N /* #f */,
pub LIT_27_1: N /* 1 */,
pub LIT_0_BOOLEAN: N /* Boolean */,
pub LIT_4_BYTE_STRING: N /* ByteString */,
pub LIT_1_DOUBLE: N /* Double */,
pub LIT_2_SIGNED_INTEGER: N /* SignedInteger */,
pub LIT_3_STRING: N /* String */,
pub LIT_5_SYMBOL: N /* Symbol */,
pub LIT_13_AND: N /* and */,
pub LIT_20_ANY: N /* any */,
pub LIT_21_ATOM: N /* atom */,
pub LIT_7_BUNDLE: N /* bundle */,
pub LIT_17_DEFINITIONS: N /* definitions */,
pub LIT_11_DICT: N /* dict */,
pub LIT_26_DICTOF: N /* dictof */,
pub LIT_22_EMBEDDED: N /* embedded */,
pub LIT_18_EMBEDDED_TYPE: N /* embeddedType */,
pub LIT_23_LIT: N /* lit */,
pub LIT_6_NAMED: N /* named */,
pub LIT_12_OR: N /* or */,
pub LIT_8_REC: N /* rec */,
pub LIT_15_REF: N /* ref */,
pub LIT_16_SCHEMA: N /* schema */,
pub LIT_24_SEQOF: N /* seqof */,
pub LIT_25_SETOF: N /* setof */,
pub LIT_9_TUPLE: N /* tuple */,
pub LIT_10_TUPLE_PREFIX: N /* tuplePrefix */,
pub LIT_19_VERSION: N /* version */
}
impl<N: preserves::value::NestedValue> Default for Language<N> {
fn default() -> Self {
Language {
LIT_14_FALSE: /* #f */ _support::decode_lit(&[128]).unwrap(),
LIT_27_1: /* 1 */ _support::decode_lit(&[176, 1, 1]).unwrap(),
LIT_0_BOOLEAN: /* Boolean */ _support::decode_lit(&[179, 7, 66, 111, 111, 108, 101, 97, 110]).unwrap(),
LIT_4_BYTE_STRING: /* ByteString */ _support::decode_lit(&[179, 10, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103]).unwrap(),
LIT_1_DOUBLE: /* Double */ _support::decode_lit(&[179, 6, 68, 111, 117, 98, 108, 101]).unwrap(),
LIT_2_SIGNED_INTEGER: /* SignedInteger */ _support::decode_lit(&[179, 13, 83, 105, 103, 110, 101, 100, 73, 110, 116, 101, 103, 101, 114]).unwrap(),
LIT_3_STRING: /* String */ _support::decode_lit(&[179, 6, 83, 116, 114, 105, 110, 103]).unwrap(),
LIT_5_SYMBOL: /* Symbol */ _support::decode_lit(&[179, 6, 83, 121, 109, 98, 111, 108]).unwrap(),
LIT_13_AND: /* and */ _support::decode_lit(&[179, 3, 97, 110, 100]).unwrap(),
LIT_20_ANY: /* any */ _support::decode_lit(&[179, 3, 97, 110, 121]).unwrap(),
LIT_21_ATOM: /* atom */ _support::decode_lit(&[179, 4, 97, 116, 111, 109]).unwrap(),
LIT_7_BUNDLE: /* bundle */ _support::decode_lit(&[179, 6, 98, 117, 110, 100, 108, 101]).unwrap(),
LIT_17_DEFINITIONS: /* definitions */ _support::decode_lit(&[179, 11, 100, 101, 102, 105, 110, 105, 116, 105, 111, 110, 115]).unwrap(),
LIT_11_DICT: /* dict */ _support::decode_lit(&[179, 4, 100, 105, 99, 116]).unwrap(),
LIT_26_DICTOF: /* dictof */ _support::decode_lit(&[179, 6, 100, 105, 99, 116, 111, 102]).unwrap(),
LIT_22_EMBEDDED: /* embedded */ _support::decode_lit(&[179, 8, 101, 109, 98, 101, 100, 100, 101, 100]).unwrap(),
LIT_18_EMBEDDED_TYPE: /* embeddedType */ _support::decode_lit(&[179, 12, 101, 109, 98, 101, 100, 100, 101, 100, 84, 121, 112, 101]).unwrap(),
LIT_23_LIT: /* lit */ _support::decode_lit(&[179, 3, 108, 105, 116]).unwrap(),
LIT_6_NAMED: /* named */ _support::decode_lit(&[179, 5, 110, 97, 109, 101, 100]).unwrap(),
LIT_12_OR: /* or */ _support::decode_lit(&[179, 2, 111, 114]).unwrap(),
LIT_8_REC: /* rec */ _support::decode_lit(&[179, 3, 114, 101, 99]).unwrap(),
LIT_15_REF: /* ref */ _support::decode_lit(&[179, 3, 114, 101, 102]).unwrap(),
LIT_16_SCHEMA: /* schema */ _support::decode_lit(&[179, 6, 115, 99, 104, 101, 109, 97]).unwrap(),
LIT_24_SEQOF: /* seqof */ _support::decode_lit(&[179, 5, 115, 101, 113, 111, 102]).unwrap(),
LIT_25_SETOF: /* setof */ _support::decode_lit(&[179, 5, 115, 101, 116, 111, 102]).unwrap(),
LIT_9_TUPLE: /* tuple */ _support::decode_lit(&[179, 5, 116, 117, 112, 108, 101]).unwrap(),
LIT_10_TUPLE_PREFIX: /* tuplePrefix */ _support::decode_lit(&[179, 11, 116, 117, 112, 108, 101, 80, 114, 101, 102, 105, 120]).unwrap(),
LIT_19_VERSION: /* version */ _support::decode_lit(&[179, 7, 118, 101, 114, 115, 105, 111, 110]).unwrap()
}
}
}
pub fn _bundle() -> &'static [u8] {
b"\
\xb4\xb3\x06\x62\x75\x6e\x64\x6c\x65\xb7\xb5\xb3\x06\x73\x63\x68\
\x65\x6d\x61\x84\xb4\xb3\x06\x73\x63\x68\x65\x6d\x61\xb7\xb3\x07\
\x76\x65\x72\x73\x69\x6f\x6e\xb0\x01\x01\xb3\x0b\x64\x65\x66\x69\
\x6e\x69\x74\x69\x6f\x6e\x73\xb7\xb3\x03\x52\x65\x66\xb4\xb3\x03\
\x72\x65\x63\xb4\xb3\x03\x6c\x69\x74\xb3\x03\x72\x65\x66\x84\xb4\
\xb3\x05\x74\x75\x70\x6c\x65\xb5\xb4\xb3\x05\x6e\x61\x6d\x65\x64\
\xb3\x06\x6d\x6f\x64\x75\x6c\x65\xb4\xb3\x03\x72\x65\x66\xb5\x84\
\xb3\x0a\x4d\x6f\x64\x75\x6c\x65\x50\x61\x74\x68\x84\x84\xb4\xb3\
\x05\x6e\x61\x6d\x65\x64\xb3\x04\x6e\x61\x6d\x65\xb4\xb3\x04\x61\
\x74\x6f\x6d\xb3\x06\x53\x79\x6d\x62\x6f\x6c\x84\x84\x84\x84\x84\
\xb3\x06\x42\x75\x6e\x64\x6c\x65\xb4\xb3\x03\x72\x65\x63\xb4\xb3\
\x03\x6c\x69\x74\xb3\x06\x62\x75\x6e\x64\x6c\x65\x84\xb4\xb3\x05\
\x74\x75\x70\x6c\x65\xb5\xb4\xb3\x05\x6e\x61\x6d\x65\x64\xb3\x07\
\x6d\x6f\x64\x75\x6c\x65\x73\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\
\x07\x4d\x6f\x64\x75\x6c\x65\x73\x84\x84\x84\x84\x84\xb3\x06\x53\
\x63\x68\x65\x6d\x61\xb4\xb3\x03\x72\x65\x63\xb4\xb3\x03\x6c\x69\
\x74\xb3\x06\x73\x63\x68\x65\x6d\x61\x84\xb4\xb3\x05\x74\x75\x70\
\x6c\x65\xb5\xb4\xb3\x04\x64\x69\x63\x74\xb7\xb3\x07\x76\x65\x72\
\x73\x69\x6f\x6e\xb4\xb3\x05\x6e\x61\x6d\x65\x64\xb3\x07\x76\x65\
\x72\x73\x69\x6f\x6e\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\x07\x56\
\x65\x72\x73\x69\x6f\x6e\x84\x84\xb3\x0b\x64\x65\x66\x69\x6e\x69\
\x74\x69\x6f\x6e\x73\xb4\xb3\x05\x6e\x61\x6d\x65\x64\xb3\x0b\x64\
\x65\x66\x69\x6e\x69\x74\x69\x6f\x6e\x73\xb4\xb3\x03\x72\x65\x66\
\xb5\x84\xb3\x0b\x44\x65\x66\x69\x6e\x69\x74\x69\x6f\x6e\x73\x84\
\x84\xb3\x0c\x65\x6d\x62\x65\x64\x64\x65\x64\x54\x79\x70\x65\xb4\
\xb3\x05\x6e\x61\x6d\x65\x64\xb3\x0c\x65\x6d\x62\x65\x64\x64\x65\
\x64\x54\x79\x70\x65\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\x10\x45\
\x6d\x62\x65\x64\x64\x65\x64\x54\x79\x70\x65\x4e\x61\x6d\x65\x84\
\x84\x84\x84\x84\x84\x84\xb3\x07\x42\x69\x6e\x64\x69\x6e\x67\xb4\
\xb3\x03\x72\x65\x63\xb4\xb3\x03\x6c\x69\x74\xb3\x05\x6e\x61\x6d\
\x65\x64\x84\xb4\xb3\x05\x74\x75\x70\x6c\x65\xb5\xb4\xb3\x05\x6e\
\x61\x6d\x65\x64\xb3\x04\x6e\x61\x6d\x65\xb4\xb3\x04\x61\x74\x6f\
\x6d\xb3\x06\x53\x79\x6d\x62\x6f\x6c\x84\x84\xb4\xb3\x05\x6e\x61\
\x6d\x65\x64\xb3\x07\x70\x61\x74\x74\x65\x72\x6e\xb4\xb3\x03\x72\
\x65\x66\xb5\x84\xb3\x0d\x53\x69\x6d\x70\x6c\x65\x50\x61\x74\x74\
\x65\x72\x6e\x84\x84\x84\x84\x84\xb3\x07\x4d\x6f\x64\x75\x6c\x65\
\x73\xb4\xb3\x06\x64\x69\x63\x74\x6f\x66\xb4\xb3\x03\x72\x65\x66\
\xb5\x84\xb3\x0a\x4d\x6f\x64\x75\x6c\x65\x50\x61\x74\x68\x84\xb4\
\xb3\x03\x72\x65\x66\xb5\x84\xb3\x06\x53\x63\x68\x65\x6d\x61\x84\
\x84\xb3\x07\x50\x61\x74\x74\x65\x72\x6e\xb4\xb3\x02\x6f\x72\xb5\
\xb5\xb1\x0d\x53\x69\x6d\x70\x6c\x65\x50\x61\x74\x74\x65\x72\x6e\
\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\x0d\x53\x69\x6d\x70\x6c\x65\
\x50\x61\x74\x74\x65\x72\x6e\x84\x84\xb5\xb1\x0f\x43\x6f\x6d\x70\
\x6f\x75\x6e\x64\x50\x61\x74\x74\x65\x72\x6e\xb4\xb3\x03\x72\x65\
\x66\xb5\x84\xb3\x0f\x43\x6f\x6d\x70\x6f\x75\x6e\x64\x50\x61\x74\
\x74\x65\x72\x6e\x84\x84\x84\x84\xb3\x07\x56\x65\x72\x73\x69\x6f\
\x6e\xb4\xb3\x03\x6c\x69\x74\xb0\x01\x01\x84\xb3\x08\x41\x74\x6f\
\x6d\x4b\x69\x6e\x64\xb4\xb3\x02\x6f\x72\xb5\xb5\xb1\x07\x42\x6f\
\x6f\x6c\x65\x61\x6e\xb4\xb3\x03\x6c\x69\x74\xb3\x07\x42\x6f\x6f\
\x6c\x65\x61\x6e\x84\x84\xb5\xb1\x06\x44\x6f\x75\x62\x6c\x65\xb4\
\xb3\x03\x6c\x69\x74\xb3\x06\x44\x6f\x75\x62\x6c\x65\x84\x84\xb5\
\xb1\x0d\x53\x69\x67\x6e\x65\x64\x49\x6e\x74\x65\x67\x65\x72\xb4\
\xb3\x03\x6c\x69\x74\xb3\x0d\x53\x69\x67\x6e\x65\x64\x49\x6e\x74\
\x65\x67\x65\x72\x84\x84\xb5\xb1\x06\x53\x74\x72\x69\x6e\x67\xb4\
\xb3\x03\x6c\x69\x74\xb3\x06\x53\x74\x72\x69\x6e\x67\x84\x84\xb5\
\xb1\x0a\x42\x79\x74\x65\x53\x74\x72\x69\x6e\x67\xb4\xb3\x03\x6c\
\x69\x74\xb3\x0a\x42\x79\x74\x65\x53\x74\x72\x69\x6e\x67\x84\x84\
\xb5\xb1\x06\x53\x79\x6d\x62\x6f\x6c\xb4\xb3\x03\x6c\x69\x74\xb3\
\x06\x53\x79\x6d\x62\x6f\x6c\x84\x84\x84\x84\xb3\x0a\x44\x65\x66\
\x69\x6e\x69\x74\x69\x6f\x6e\xb4\xb3\x02\x6f\x72\xb5\xb5\xb1\x02\
\x6f\x72\xb4\xb3\x03\x72\x65\x63\xb4\xb3\x03\x6c\x69\x74\xb3\x02\
\x6f\x72\x84\xb4\xb3\x05\x74\x75\x70\x6c\x65\xb5\xb4\xb3\x0b\x74\
\x75\x70\x6c\x65\x50\x72\x65\x66\x69\x78\xb5\xb4\xb3\x05\x6e\x61\
\x6d\x65\x64\xb3\x08\x70\x61\x74\x74\x65\x72\x6e\x30\xb4\xb3\x03\
\x72\x65\x66\xb5\x84\xb3\x10\x4e\x61\x6d\x65\x64\x41\x6c\x74\x65\
\x72\x6e\x61\x74\x69\x76\x65\x84\x84\xb4\xb3\x05\x6e\x61\x6d\x65\
\x64\xb3\x08\x70\x61\x74\x74\x65\x72\x6e\x31\xb4\xb3\x03\x72\x65\
\x66\xb5\x84\xb3\x10\x4e\x61\x6d\x65\x64\x41\x6c\x74\x65\x72\x6e\
\x61\x74\x69\x76\x65\x84\x84\x84\xb4\xb3\x05\x6e\x61\x6d\x65\x64\
\xb3\x08\x70\x61\x74\x74\x65\x72\x6e\x4e\xb4\xb3\x05\x73\x65\x71\
\x6f\x66\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\x10\x4e\x61\x6d\x65\
\x64\x41\x6c\x74\x65\x72\x6e\x61\x74\x69\x76\x65\x84\x84\x84\x84\
\x84\x84\x84\x84\xb5\xb1\x03\x61\x6e\x64\xb4\xb3\x03\x72\x65\x63\
\xb4\xb3\x03\x6c\x69\x74\xb3\x03\x61\x6e\x64\x84\xb4\xb3\x05\x74\
\x75\x70\x6c\x65\xb5\xb4\xb3\x0b\x74\x75\x70\x6c\x65\x50\x72\x65\
\x66\x69\x78\xb5\xb4\xb3\x05\x6e\x61\x6d\x65\x64\xb3\x08\x70\x61\
\x74\x74\x65\x72\x6e\x30\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\x0c\
\x4e\x61\x6d\x65\x64\x50\x61\x74\x74\x65\x72\x6e\x84\x84\xb4\xb3\
\x05\x6e\x61\x6d\x65\x64\xb3\x08\x70\x61\x74\x74\x65\x72\x6e\x31\
\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\x0c\x4e\x61\x6d\x65\x64\x50\
\x61\x74\x74\x65\x72\x6e\x84\x84\x84\xb4\xb3\x05\x6e\x61\x6d\x65\
\x64\xb3\x08\x70\x61\x74\x74\x65\x72\x6e\x4e\xb4\xb3\x05\x73\x65\
\x71\x6f\x66\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\x0c\x4e\x61\x6d\
\x65\x64\x50\x61\x74\x74\x65\x72\x6e\x84\x84\x84\x84\x84\x84\x84\
\x84\xb5\xb1\x07\x50\x61\x74\x74\x65\x72\x6e\xb4\xb3\x03\x72\x65\
\x66\xb5\x84\xb3\x07\x50\x61\x74\x74\x65\x72\x6e\x84\x84\x84\x84\
\xb3\x0a\x4d\x6f\x64\x75\x6c\x65\x50\x61\x74\x68\xb4\xb3\x05\x73\
\x65\x71\x6f\x66\xb4\xb3\x04\x61\x74\x6f\x6d\xb3\x06\x53\x79\x6d\
\x62\x6f\x6c\x84\x84\xb3\x0b\x44\x65\x66\x69\x6e\x69\x74\x69\x6f\
\x6e\x73\xb4\xb3\x06\x64\x69\x63\x74\x6f\x66\xb4\xb3\x04\x61\x74\
\x6f\x6d\xb3\x06\x53\x79\x6d\x62\x6f\x6c\x84\xb4\xb3\x03\x72\x65\
\x66\xb5\x84\xb3\x0a\x44\x65\x66\x69\x6e\x69\x74\x69\x6f\x6e\x84\
\x84\xb3\x0c\x4e\x61\x6d\x65\x64\x50\x61\x74\x74\x65\x72\x6e\xb4\
\xb3\x02\x6f\x72\xb5\xb5\xb1\x05\x6e\x61\x6d\x65\x64\xb4\xb3\x03\
\x72\x65\x66\xb5\x84\xb3\x07\x42\x69\x6e\x64\x69\x6e\x67\x84\x84\
\xb5\xb1\x09\x61\x6e\x6f\x6e\x79\x6d\x6f\x75\x73\xb4\xb3\x03\x72\
\x65\x66\xb5\x84\xb3\x07\x50\x61\x74\x74\x65\x72\x6e\x84\x84\x84\
\x84\xb3\x0d\x53\x69\x6d\x70\x6c\x65\x50\x61\x74\x74\x65\x72\x6e\
\xb4\xb3\x02\x6f\x72\xb5\xb5\xb1\x03\x61\x6e\x79\xb4\xb3\x03\x6c\
\x69\x74\xb3\x03\x61\x6e\x79\x84\x84\xb5\xb1\x04\x61\x74\x6f\x6d\
\xb4\xb3\x03\x72\x65\x63\xb4\xb3\x03\x6c\x69\x74\xb3\x04\x61\x74\
\x6f\x6d\x84\xb4\xb3\x05\x74\x75\x70\x6c\x65\xb5\xb4\xb3\x05\x6e\
\x61\x6d\x65\x64\xb3\x08\x61\x74\x6f\x6d\x4b\x69\x6e\x64\xb4\xb3\
\x03\x72\x65\x66\xb5\x84\xb3\x08\x41\x74\x6f\x6d\x4b\x69\x6e\x64\
\x84\x84\x84\x84\x84\x84\xb5\xb1\x08\x65\x6d\x62\x65\x64\x64\x65\
\x64\xb4\xb3\x03\x72\x65\x63\xb4\xb3\x03\x6c\x69\x74\xb3\x08\x65\
\x6d\x62\x65\x64\x64\x65\x64\x84\xb4\xb3\x05\x74\x75\x70\x6c\x65\
\xb5\xb4\xb3\x05\x6e\x61\x6d\x65\x64\xb3\x09\x69\x6e\x74\x65\x72\
\x66\x61\x63\x65\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\x0d\x53\x69\
\x6d\x70\x6c\x65\x50\x61\x74\x74\x65\x72\x6e\x84\x84\x84\x84\x84\
\x84\xb5\xb1\x03\x6c\x69\x74\xb4\xb3\x03\x72\x65\x63\xb4\xb3\x03\
\x6c\x69\x74\xb3\x03\x6c\x69\x74\x84\xb4\xb3\x05\x74\x75\x70\x6c\
\x65\xb5\xb4\xb3\x05\x6e\x61\x6d\x65\x64\xb3\x05\x76\x61\x6c\x75\
\x65\xb3\x03\x61\x6e\x79\x84\x84\x84\x84\x84\xb5\xb1\x05\x73\x65\
\x71\x6f\x66\xb4\xb3\x03\x72\x65\x63\xb4\xb3\x03\x6c\x69\x74\xb3\
\x05\x73\x65\x71\x6f\x66\x84\xb4\xb3\x05\x74\x75\x70\x6c\x65\xb5\
\xb4\xb3\x05\x6e\x61\x6d\x65\x64\xb3\x07\x70\x61\x74\x74\x65\x72\
\x6e\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\x0d\x53\x69\x6d\x70\x6c\
\x65\x50\x61\x74\x74\x65\x72\x6e\x84\x84\x84\x84\x84\x84\xb5\xb1\
\x05\x73\x65\x74\x6f\x66\xb4\xb3\x03\x72\x65\x63\xb4\xb3\x03\x6c\
\x69\x74\xb3\x05\x73\x65\x74\x6f\x66\x84\xb4\xb3\x05\x74\x75\x70\
\x6c\x65\xb5\xb4\xb3\x05\x6e\x61\x6d\x65\x64\xb3\x07\x70\x61\x74\
\x74\x65\x72\x6e\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\x0d\x53\x69\
\x6d\x70\x6c\x65\x50\x61\x74\x74\x65\x72\x6e\x84\x84\x84\x84\x84\
\x84\xb5\xb1\x06\x64\x69\x63\x74\x6f\x66\xb4\xb3\x03\x72\x65\x63\
\xb4\xb3\x03\x6c\x69\x74\xb3\x06\x64\x69\x63\x74\x6f\x66\x84\xb4\
\xb3\x05\x74\x75\x70\x6c\x65\xb5\xb4\xb3\x05\x6e\x61\x6d\x65\x64\
\xb3\x03\x6b\x65\x79\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\x0d\x53\
\x69\x6d\x70\x6c\x65\x50\x61\x74\x74\x65\x72\x6e\x84\x84\xb4\xb3\
\x05\x6e\x61\x6d\x65\x64\xb3\x05\x76\x61\x6c\x75\x65\xb4\xb3\x03\
\x72\x65\x66\xb5\x84\xb3\x0d\x53\x69\x6d\x70\x6c\x65\x50\x61\x74\
\x74\x65\x72\x6e\x84\x84\x84\x84\x84\x84\xb5\xb1\x03\x52\x65\x66\
\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\x03\x52\x65\x66\x84\x84\x84\
\x84\xb3\x0f\x43\x6f\x6d\x70\x6f\x75\x6e\x64\x50\x61\x74\x74\x65\
\x72\x6e\xb4\xb3\x02\x6f\x72\xb5\xb5\xb1\x03\x72\x65\x63\xb4\xb3\
\x03\x72\x65\x63\xb4\xb3\x03\x6c\x69\x74\xb3\x03\x72\x65\x63\x84\
\xb4\xb3\x05\x74\x75\x70\x6c\x65\xb5\xb4\xb3\x05\x6e\x61\x6d\x65\
\x64\xb3\x05\x6c\x61\x62\x65\x6c\xb4\xb3\x03\x72\x65\x66\xb5\x84\
\xb3\x0c\x4e\x61\x6d\x65\x64\x50\x61\x74\x74\x65\x72\x6e\x84\x84\
\xb4\xb3\x05\x6e\x61\x6d\x65\x64\xb3\x06\x66\x69\x65\x6c\x64\x73\
\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\x0c\x4e\x61\x6d\x65\x64\x50\
\x61\x74\x74\x65\x72\x6e\x84\x84\x84\x84\x84\x84\xb5\xb1\x05\x74\
\x75\x70\x6c\x65\xb4\xb3\x03\x72\x65\x63\xb4\xb3\x03\x6c\x69\x74\
\xb3\x05\x74\x75\x70\x6c\x65\x84\xb4\xb3\x05\x74\x75\x70\x6c\x65\
\xb5\xb4\xb3\x05\x6e\x61\x6d\x65\x64\xb3\x08\x70\x61\x74\x74\x65\
\x72\x6e\x73\xb4\xb3\x05\x73\x65\x71\x6f\x66\xb4\xb3\x03\x72\x65\
\x66\xb5\x84\xb3\x0c\x4e\x61\x6d\x65\x64\x50\x61\x74\x74\x65\x72\
\x6e\x84\x84\x84\x84\x84\x84\x84\xb5\xb1\x0b\x74\x75\x70\x6c\x65\
\x50\x72\x65\x66\x69\x78\xb4\xb3\x03\x72\x65\x63\xb4\xb3\x03\x6c\
\x69\x74\xb3\x0b\x74\x75\x70\x6c\x65\x50\x72\x65\x66\x69\x78\x84\
\xb4\xb3\x05\x74\x75\x70\x6c\x65\xb5\xb4\xb3\x05\x6e\x61\x6d\x65\
\x64\xb3\x05\x66\x69\x78\x65\x64\xb4\xb3\x05\x73\x65\x71\x6f\x66\
\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\x0c\x4e\x61\x6d\x65\x64\x50\
\x61\x74\x74\x65\x72\x6e\x84\x84\x84\xb4\xb3\x05\x6e\x61\x6d\x65\
\x64\xb3\x08\x76\x61\x72\x69\x61\x62\x6c\x65\xb4\xb3\x03\x72\x65\
\x66\xb5\x84\xb3\x12\x4e\x61\x6d\x65\x64\x53\x69\x6d\x70\x6c\x65\
\x50\x61\x74\x74\x65\x72\x6e\x84\x84\x84\x84\x84\x84\xb5\xb1\x04\
\x64\x69\x63\x74\xb4\xb3\x03\x72\x65\x63\xb4\xb3\x03\x6c\x69\x74\
\xb3\x04\x64\x69\x63\x74\x84\xb4\xb3\x05\x74\x75\x70\x6c\x65\xb5\
\xb4\xb3\x05\x6e\x61\x6d\x65\x64\xb3\x07\x65\x6e\x74\x72\x69\x65\
\x73\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\x11\x44\x69\x63\x74\x69\
\x6f\x6e\x61\x72\x79\x45\x6e\x74\x72\x69\x65\x73\x84\x84\x84\x84\
\x84\x84\x84\x84\xb3\x10\x45\x6d\x62\x65\x64\x64\x65\x64\x54\x79\
\x70\x65\x4e\x61\x6d\x65\xb4\xb3\x02\x6f\x72\xb5\xb5\xb1\x05\x66\
\x61\x6c\x73\x65\xb4\xb3\x03\x6c\x69\x74\x80\x84\x84\xb5\xb1\x03\
\x52\x65\x66\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\x03\x52\x65\x66\
\x84\x84\x84\x84\xb3\x10\x4e\x61\x6d\x65\x64\x41\x6c\x74\x65\x72\
\x6e\x61\x74\x69\x76\x65\xb4\xb3\x05\x74\x75\x70\x6c\x65\xb5\xb4\
\xb3\x05\x6e\x61\x6d\x65\x64\xb3\x0c\x76\x61\x72\x69\x61\x6e\x74\
\x4c\x61\x62\x65\x6c\xb4\xb3\x04\x61\x74\x6f\x6d\xb3\x06\x53\x74\
\x72\x69\x6e\x67\x84\x84\xb4\xb3\x05\x6e\x61\x6d\x65\x64\xb3\x07\
\x70\x61\x74\x74\x65\x72\x6e\xb4\xb3\x03\x72\x65\x66\xb5\x84\xb3\
\x07\x50\x61\x74\x74\x65\x72\x6e\x84\x84\x84\x84\xb3\x11\x44\x69\
\x63\x74\x69\x6f\x6e\x61\x72\x79\x45\x6e\x74\x72\x69\x65\x73\xb4\
\xb3\x06\x64\x69\x63\x74\x6f\x66\xb3\x03\x61\x6e\x79\xb4\xb3\x03\
\x72\x65\x66\xb5\x84\xb3\x12\x4e\x61\x6d\x65\x64\x53\x69\x6d\x70\
\x6c\x65\x50\x61\x74\x74\x65\x72\x6e\x84\x84\xb3\x12\x4e\x61\x6d\
\x65\x64\x53\x69\x6d\x70\x6c\x65\x50\x61\x74\x74\x65\x72\x6e\xb4\
\xb3\x02\x6f\x72\xb5\xb5\xb1\x05\x6e\x61\x6d\x65\x64\xb4\xb3\x03\
\x72\x65\x66\xb5\x84\xb3\x07\x42\x69\x6e\x64\x69\x6e\x67\x84\x84\
\xb5\xb1\x09\x61\x6e\x6f\x6e\x79\x6d\x6f\x75\x73\xb4\xb3\x03\x72\
\x65\x66\xb5\x84\xb3\x0d\x53\x69\x6d\x70\x6c\x65\x50\x61\x74\x74\
\x65\x72\x6e\x84\x84\x84\x84\x84\xb3\x0c\x65\x6d\x62\x65\x64\x64\
\x65\x64\x54\x79\x70\x65\x80\x84\x84\x84\x84"
}

File diff suppressed because it is too large Load Diff

View File

@ -1,98 +0,0 @@
#![doc = concat!(
include_str!("../README.md"),
"# What is Preserves Schema?\n\n",
include_str!("../doc/what-is-preserves-schema.md"),
include_str!("../doc/example.md"),
)]
pub mod compiler;
/// Auto-generated Preserves Schema Metaschema types, parsers, and unparsers.
pub mod gen;
pub mod support;
pub mod syntax;
pub use support::Codec;
pub use support::Deserialize;
pub use support::ParseError;
#[cfg(test)]
mod tests {
#[test]
fn can_access_preserves_core() {
use preserves::value::*;
assert_eq!(format!("{:?}", UnwrappedIOValue::from(3 + 4)), "7");
}
#[test]
fn simple_rendering() {
use crate::syntax::block::*;
use crate::*;
let code = semiblock![
seq!["f", parens!["a", "b", "c"]],
seq!["f", parens!["a", "b", "c"]],
seq!["f", parens!["a", "b", "c"]],
seq!["f", parens!["a", "b", "c"]],
seq!["f", parens!["a", "b", "c"]],
seq!["f", parens!["a", "b", "c"]],
seq!["g", parens![]],
parens![]
];
println!("{}", Formatter::to_string(&code));
}
#[test]
fn metaschema_parsing() -> Result<(), std::io::Error> {
use crate::gen::schema::*;
use crate::support::Parse;
use crate::support::Unparse;
use preserves::value::{BinarySource, IOBinarySource, Reader};
let mut f = std::fs::File::open("../../../schema/schema.bin")?;
let mut src = IOBinarySource::new(&mut f);
let mut reader = src.packed_iovalues();
let schema = reader.demand_next(false)?;
let language = crate::gen::Language::default();
let parsed = Schema::parse(&language, &schema).expect("successful parse");
assert_eq!(schema, parsed.unparse(&language));
Ok(())
}
}
#[macro_export]
macro_rules! define_language {
($fname:ident () : $lang:ident < $default_value:ty > { $($field:ident : $($type:ident)::+ ,)* }) => {
pub struct $lang<N: $crate::support::preserves::value::NestedValue> {
$(pub $field: std::sync::Arc<$($type)::*<N>>),*
}
$(impl<'a, N: $crate::support::preserves::value::NestedValue> From<&'a $lang<N>> for &'a $($type)::*<N> {
fn from(v: &'a $lang<N>) -> Self {
&v.$field
}
})*
impl<N: $crate::support::preserves::value::NestedValue> $crate::support::NestedValueCodec
for $lang<N> {}
mod $fname {
use super::*;
lazy_static::lazy_static! {
pub static ref GLOBAL_LANG: std::sync::Arc<$lang<$default_value>> =
std::sync::Arc::new($lang {
$($field: std::sync::Arc::new($($type)::*::default())),*
});
}
}
impl $lang<$default_value> {
pub fn arc() -> &'static std::sync::Arc<$lang<$default_value>> {
&*$fname::GLOBAL_LANG
}
}
pub fn $fname() -> &'static $lang<$default_value> {
&*$fname::GLOBAL_LANG
}
};
}

View File

@ -1,297 +0,0 @@
//! Interpreter for instances of Preserves Schema Metaschema, for schema-directed dynamic
//! parsing and unparsing of terms.
use crate::gen::schema::*;
use preserves::value::merge::merge2;
use preserves::value::Map;
use preserves::value::NestedValue;
use preserves::value::Value;
/// Represents an environment mapping schema module names to [Schema] instances.
pub type Env<V> = Map<Vec<String>, Schema<V>>;
/// Context for a given interpretation of a [Schema].
#[derive(Debug)]
pub struct Context<'a, V: NestedValue> {
pub env: &'a Env<V>,
module: Vec<String>,
}
#[derive(Debug)]
enum DynField<V: NestedValue> {
Simple(V),
Compound(Map<V, V>),
}
impl<'a, V: NestedValue> Context<'a, V> {
/// Construct a new [Context] with the given [Env].
pub fn new(env: &'a Env<V>) -> Self {
Context {
env,
module: Vec::new(),
}
}
/// Parse `v` using the rule named `name` from the module at path `module` in `self.env`.
/// Yields `Some(...)` if the parse succeeds, and `None` otherwise.
pub fn dynamic_parse(&mut self, module: &Vec<String>, name: &str, v: &V) -> Option<V> {
let old_module =
(module.len() > 0).then(|| std::mem::replace(&mut self.module, module.clone()));
let schema = self.env.get(&self.module);
let definition = schema.and_then(|s| s.definitions.0.get(name));
let result = definition.and_then(|d| d.dynamic_parse(self, v));
if let Some(m) = old_module {
self.module = m;
}
result
}
#[doc(hidden)]
pub fn dynamic_unparse(&mut self, _module: &Vec<String>, _name: &str, _w: &V) -> Option<V> {
panic!("Not yet implemented");
}
}
impl<V: NestedValue> Definition<V> {
fn dynamic_parse(&self, ctxt: &mut Context<V>, v: &V) -> Option<V> {
match self {
Definition::Or {
pattern_0,
pattern_1,
pattern_n,
} => pattern_0
.dynamic_parse(ctxt, v)
.or_else(|| pattern_1.dynamic_parse(ctxt, v))
.or_else(|| pattern_n.iter().find_map(|p| p.dynamic_parse(ctxt, v))),
Definition::And {
pattern_0,
pattern_1,
pattern_n,
} => pattern_0
.dynamic_parse(ctxt, v)
.and_then(|w0| {
pattern_1.dynamic_parse(ctxt, v).and_then(|w1| {
pattern_n.iter().fold(merge(w0, w1), |w, p| {
w.and_then(|w| p.dynamic_parse(ctxt, v).and_then(|wn| merge(w, wn)))
})
})
})
.map(|w| DynField::Compound(w).finish()),
Definition::Pattern(p) => p.dynamic_parse(ctxt, v).map(|w| w.finish()),
}
}
}
impl<V: NestedValue> NamedAlternative<V> {
fn dynamic_parse(&self, ctxt: &mut Context<V>, v: &V) -> Option<V> {
self.pattern.dynamic_parse(ctxt, v).map(|w| {
let mut r = Value::simple_record(&self.variant_label, 1);
match w {
DynField::Simple(field) => r.fields_vec_mut().push(field),
DynField::Compound(fields) => {
if fields.len() > 0 {
r.fields_vec_mut().push(V::new(fields))
}
}
}
r.finish().wrap()
})
}
}
impl<V: NestedValue> NamedPattern<V> {
fn dynamic_parse(&self, ctxt: &mut Context<V>, v: &V) -> Option<Map<V, V>> {
match self {
NamedPattern::Named(b) => {
let binding = &**b;
binding
.pattern
.dynamic_parse(ctxt, v)
.map(|w| w.to_map(Some(&binding.name)))
}
NamedPattern::Anonymous(b) => b.dynamic_parse(ctxt, v).map(|w| w.to_map(None)),
}
}
}
impl<V: NestedValue> NamedSimplePattern<V> {
fn dynamic_parse(&self, ctxt: &mut Context<V>, v: &V) -> Option<DynField<V>> {
match self {
NamedSimplePattern::Named(b) => {
let binding = &**b;
binding
.pattern
.dynamic_parse(ctxt, v)
.map(|w| DynField::Compound(w.to_map(Some(&binding.name))))
}
NamedSimplePattern::Anonymous(b) => b.dynamic_parse(ctxt, v),
}
}
}
impl<V: NestedValue> SimplePattern<V> {
fn dynamic_parse(&self, ctxt: &mut Context<V>, v: &V) -> Option<DynField<V>> {
match self {
SimplePattern::Any => Some(DynField::Simple(v.clone())),
SimplePattern::Atom { atom_kind } => match &**atom_kind {
AtomKind::Boolean => v.value().is_boolean().then(|| DynField::Simple(v.clone())),
AtomKind::Double => v.value().is_double().then(|| DynField::Simple(v.clone())),
AtomKind::SignedInteger => v
.value()
.is_signedinteger()
.then(|| DynField::Simple(v.clone())),
AtomKind::String => v.value().is_string().then(|| DynField::Simple(v.clone())),
AtomKind::ByteString => v
.value()
.is_bytestring()
.then(|| DynField::Simple(v.clone())),
AtomKind::Symbol => v.value().is_symbol().then(|| DynField::Simple(v.clone())),
},
SimplePattern::Embedded { .. } => {
v.value().is_embedded().then(|| DynField::Simple(v.clone()))
}
SimplePattern::Lit { value } => (v == value).then(|| DynField::Compound(Map::new())),
SimplePattern::Seqof { pattern } => v
.value()
.as_sequence()
.and_then(|vs| {
vs.iter()
.map(|v| (**pattern).dynamic_parse(ctxt, v).map(|w| w.finish()))
.collect::<Option<Vec<V>>>()
})
.map(|ws| DynField::Simple(V::new(ws))),
SimplePattern::Setof { pattern } => v
.value()
.as_set()
.and_then(|vs| {
vs.iter()
.map(|v| (**pattern).dynamic_parse(ctxt, v).map(|w| w.finish()))
.collect::<Option<Vec<V>>>()
})
.map(|ws| DynField::Simple(V::new(ws))),
SimplePattern::Dictof { key, value } => v
.value()
.as_dictionary()
.and_then(|d| {
d.iter()
.map(|(k, v)| {
(**key).dynamic_parse(ctxt, k).and_then(|kw| {
(**value)
.dynamic_parse(ctxt, v)
.map(|vw| (kw.finish(), vw.finish()))
})
})
.collect::<Option<Map<V, V>>>()
})
.map(|d| DynField::Simple(V::new(d))),
SimplePattern::Ref(r) => ctxt
.dynamic_parse(&r.module.0, &r.name, v)
.map(DynField::Simple),
}
}
}
impl<V: NestedValue> CompoundPattern<V> {
fn dynamic_parse(&self, ctxt: &mut Context<V>, v: &V) -> Option<Map<V, V>> {
match self {
CompoundPattern::Rec { label, fields } => v.value().as_record(None).and_then(|r| {
(**label).dynamic_parse(ctxt, r.label()).and_then(|lw| {
(**fields)
.dynamic_parse(ctxt, &V::new(r.fields().to_vec()))
.and_then(|fsw| merge(lw, fsw))
})
}),
CompoundPattern::Tuple { patterns } => v.value().as_sequence().and_then(|vs| {
if vs.len() == patterns.len() {
patterns
.iter()
.zip(vs)
.fold(Some(Map::new()), |acc, (p, v)| {
acc.and_then(|acc| p.dynamic_parse(ctxt, v).and_then(|w| merge(acc, w)))
})
} else {
None
}
}),
CompoundPattern::TuplePrefix { fixed, variable } => {
v.value().as_sequence().and_then(|vs| {
if vs.len() >= fixed.len() {
fixed
.iter()
.zip(vs)
.fold(Some(Map::new()), |acc, (p, v)| {
acc.and_then(|acc| {
p.dynamic_parse(ctxt, v).and_then(|w| merge(acc, w))
})
})
.and_then(|fixed_ws| {
let remainder = V::new(vs[fixed.len()..].to_vec());
(**variable).dynamic_parse(ctxt, &remainder).and_then(
|variable_ws| merge(fixed_ws, variable_ws.unwrap_compound()),
)
})
} else {
None
}
})
}
CompoundPattern::Dict { entries } => v.value().as_dictionary().and_then(|d| {
(**entries).0.iter().fold(Some(Map::new()), |acc, (k, p)| {
acc.and_then(|acc| {
d.get(k).and_then(|v| {
p.dynamic_parse(ctxt, v)
.and_then(|w| merge(acc, w.unwrap_compound()))
})
})
})
}),
}
}
}
impl<V: NestedValue> Pattern<V> {
fn dynamic_parse(&self, ctxt: &mut Context<V>, v: &V) -> Option<DynField<V>> {
match self {
Pattern::SimplePattern(b) => (**b).dynamic_parse(ctxt, v),
Pattern::CompoundPattern(b) => (**b).dynamic_parse(ctxt, v).map(DynField::Compound),
}
}
}
impl<V: NestedValue> DynField<V> {
fn finish(self) -> V {
match self {
DynField::Simple(v) => v,
DynField::Compound(v) => V::new(v),
}
}
fn to_map(self, key: Option<&str>) -> Map<V, V> {
match self {
DynField::Simple(v) => {
let mut d = Map::new();
if let Some(k) = key {
d.insert(V::symbol(k), v);
}
d
}
DynField::Compound(d) => d,
}
}
fn unwrap_compound(self) -> Map<V, V> {
match self {
DynField::Simple(_) => panic!("Cannot unwrap DynField::Simple to compound fields"),
DynField::Compound(d) => d,
}
}
}
fn merge<V: NestedValue>(a: Map<V, V>, b: Map<V, V>) -> Option<Map<V, V>> {
merge2(V::new(a), V::new(b)).map(|d| {
d.value_owned()
.into_dictionary()
.expect("merge to yield Dictionary")
})
}

View File

@ -1,168 +0,0 @@
//! The runtime support library for compiled Schemas.
#[doc(hidden)]
/// Reexport lazy_static for generated code to use.
pub use lazy_static::lazy_static;
pub use preserves;
pub use preserves::value::boundary as B;
pub use preserves::value::Reader;
pub mod interpret;
use preserves::value::ArcValue;
use preserves::value::Domain;
use preserves::value::IOValue;
use preserves::value::NestedValue;
use preserves::value::NoEmbeddedDomainCodec;
use preserves::value::Value;
use std::convert::From;
use std::convert::Into;
use std::convert::TryFrom;
use std::io;
use std::sync::Arc;
use thiserror::Error;
/// Every [language][crate::define_language] implements [NestedValueCodec] as a marker trait.
pub trait NestedValueCodec {} // marker trait
impl NestedValueCodec for () {}
/// Implementors of [Parse] can produce instances of themselves from a [Value], given a
/// supporting [language][crate::define_language]. All Schema-compiler-produced types implement
/// [Parse].
pub trait Parse<L, Value: NestedValue>: Sized {
/// Decode the given `value` (using auxiliary structure from the `language` instance) to
/// produce an instance of [Self].
fn parse(language: L, value: &Value) -> Result<Self, ParseError>;
}
impl<'a, T: NestedValueCodec, Value: NestedValue> Parse<&'a T, Value> for Value {
fn parse(_language: &'a T, value: &Value) -> Result<Self, ParseError> {
Ok(value.clone())
}
}
/// Implementors of [Unparse] can convert themselves into a [Value], given a supporting
/// [language][crate::define_language]. All Schema-compiler-produced types implement [Unparse].
pub trait Unparse<L, Value: NestedValue> {
/// Encode `self` into a [Value] (using auxiliary structure from the `language` instance).
fn unparse(&self, language: L) -> Value;
}
impl<'a, T: NestedValueCodec, Value: NestedValue> Unparse<&'a T, Value> for Value {
fn unparse(&self, _language: &'a T) -> Value {
self.clone()
}
}
/// Every [language][crate::define_language] implements [Codec], which supplies convenient
/// shorthand for invoking [Parse::parse] and [Unparse::unparse].
pub trait Codec<N: NestedValue> {
/// Delegates to [`T::parse`][Parse::parse], using `self` as language and the given `value`
/// as input.
fn parse<'a, T: Parse<&'a Self, N>>(&'a self, value: &N) -> Result<T, ParseError>;
/// Delegates to [`value.unparse`][Unparse::unparse], using `self` as language.
fn unparse<'a, T: Unparse<&'a Self, N>>(&'a self, value: &T) -> N;
}
impl<L, N: NestedValue> Codec<N> for L {
fn parse<'a, T: Parse<&'a L, N>>(&'a self, value: &N) -> Result<T, ParseError> {
T::parse(self, value)
}
fn unparse<'a, T: Unparse<&'a L, N>>(&'a self, value: &T) -> N {
value.unparse(self)
}
}
/// Implementors of [Deserialize] can produce instances of themselves from a [Value]. All
/// Schema-compiler-produced types implement [Deserialize].
///
/// The difference between [Deserialize] and [Parse] is that implementors of [Deserialize] know
/// which [language][crate::define_language] to use.
pub trait Deserialize<N: NestedValue>
where
Self: Sized,
{
fn deserialize<'de, R: Reader<'de, N>>(r: &mut R) -> Result<Self, ParseError>;
}
/// Extracts a simple literal term from a byte array using
/// [PackedReader][preserves::value::packed::PackedReader]. No embedded values are permitted.
pub fn decode_lit<N: NestedValue>(bs: &[u8]) -> io::Result<N> {
preserves::value::packed::from_bytes(bs, NoEmbeddedDomainCodec)
}
/// When `D` can parse itself from an [IOValue], this function parses all embedded [IOValue]s
/// into `D`s.
pub fn decode_embedded<D: Domain>(v: &IOValue) -> Result<ArcValue<Arc<D>>, ParseError>
where
for<'a> D: TryFrom<&'a IOValue, Error = ParseError>,
{
v.copy_via(&mut |d| Ok(Value::Embedded(Arc::new(D::try_from(d)?))))
}
/// When `D` can unparse itself into an [IOValue], this function converts all embedded `D`s
/// into [IOValue]s.
pub fn encode_embedded<D: Domain>(v: &ArcValue<Arc<D>>) -> IOValue
where
for<'a> IOValue: From<&'a D>,
{
v.copy_via::<_, _, std::convert::Infallible>(&mut |d| Ok(Value::Embedded(IOValue::from(d))))
.unwrap()
}
/// Error value yielded when parsing of an [IOValue] into a Schema-compiler-produced type.
#[derive(Error, Debug)]
pub enum ParseError {
/// Signalled when the input does not match the Preserves Schema associated with the type.
#[error("Input not conformant with Schema: {0}")]
ConformanceError(&'static str),
/// Signalled when the underlying Preserves library signals an error.
#[error(transparent)]
Preserves(preserves::error::Error),
}
impl From<preserves::error::Error> for ParseError {
fn from(v: preserves::error::Error) -> Self {
match v {
preserves::error::Error::Expected(_, _) => {
ParseError::ConformanceError("preserves::error::Error::Expected")
}
_ => ParseError::Preserves(v),
}
}
}
impl From<io::Error> for ParseError {
fn from(v: io::Error) -> Self {
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, v),
ParseError::Preserves(e) => e.into(),
}
}
}
impl ParseError {
/// Constructs a [ParseError::ConformanceError].
pub fn conformance_error(context: &'static str) -> Self {
ParseError::ConformanceError(context)
}
/// True iff `self` is a [ParseError::ConformanceError].
pub fn is_conformance_error(&self) -> bool {
return if let ParseError::ConformanceError(_) = self {
true
} else {
false
};
}
}

View File

@ -1,538 +0,0 @@
//! A library for emitting pretty-formatted structured source code.
//!
//! The main entry points are [Formatter::to_string] and [Formatter::write], plus the utilities
//! in the [macros] submodule.
use std::fmt::Write;
use std::str;
/// Default width for pretty-formatting, in columns.
pub const DEFAULT_WIDTH: usize = 80;
/// All pretty-formattable items must implement this trait.
pub trait Emittable: std::fmt::Debug {
/// Serializes `self`, as pretty-printed code, on `f`.
fn write_on(&self, f: &mut Formatter);
}
/// Tailoring of behaviour for [Vertical] groupings.
#[derive(Clone, PartialEq, Eq)]
pub enum VerticalMode {
Variable,
Normal,
ExtraNewline,
}
/// Vertical formatting for [Emittable]s.
pub trait Vertical {
fn set_vertical_mode(&mut self, mode: VerticalMode);
fn write_vertically_on(&self, f: &mut Formatter);
}
/// Polymorphic [Emittable], used consistently in the API.
pub type Item = std::rc::Rc<dyn Emittable>;
/// A possibly-vertical sequence of items with item-separating and -terminating text.
#[derive(Clone)]
pub struct Sequence {
pub items: Vec<Item>,
pub vertical_mode: VerticalMode,
pub separator: &'static str,
pub terminator: &'static str,
}
/// A sequence of items, indented when formatted vertically, surrounded by opening and closing
/// text.
#[derive(Clone)]
pub struct Grouping {
pub sequence: Sequence,
pub open: &'static str,
pub close: &'static str,
}
/// State needed for pretty-formatting of [Emittable]s.
pub struct Formatter {
/// Number of available columns. Used to decide between horizontal and vertical layouts.
pub width: usize,
indent_delta: String,
current_indent: String,
/// Mutable output buffer. Accumulates emitted text during writing.
pub buffer: String,
}
impl Formatter {
/// Construct a Formatter using [DEFAULT_WIDTH] and a four-space indent.
pub fn new() -> Self {
Formatter {
width: DEFAULT_WIDTH,
indent_delta: " ".to_owned(),
current_indent: "\n".to_owned(),
buffer: String::new(),
}
}
/// Construct a Formatter just like `self` but with an empty `buffer`.
pub fn copy_empty(&self) -> Formatter {
Formatter {
width: self.width,
indent_delta: self.indent_delta.clone(),
current_indent: self.current_indent.clone(),
buffer: String::new(),
}
}
/// Yields the indent size.
pub fn indent_size(self) -> usize {
self.indent_delta.len()
}
/// Updates the indent size.
pub fn set_indent_size(&mut self, n: usize) {
self.indent_delta = str::repeat(" ", n)
}
/// Accumulates a text serialization of `e` in `buffer`.
pub fn write<E: Emittable>(&mut self, e: E) {
e.write_on(self)
}
/// Emits a newline followed by indentation into `buffer`.
pub fn newline(&mut self) {
self.buffer.push_str(&self.current_indent)
}
/// Creates a default Formatter, uses it to [write][Formatter::write] `e`, and yields the
/// contents of its `buffer`.
pub fn to_string<E: Emittable>(e: E) -> String {
let mut f = Formatter::new();
f.write(e);
f.buffer
}
/// Calls `f` in a context where the indentation has been increased by
/// [Formatter::indent_size] spaces. Restores the indentation level after `f` returns.
/// Yields the result of the call to `f`.
pub fn with_indent<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R {
let old_indent = self.current_indent.clone();
self.current_indent += &self.indent_delta;
let r = f(self);
self.current_indent = old_indent;
r
}
}
impl Default for Formatter {
fn default() -> Self {
Self::new()
}
}
impl Default for VerticalMode {
fn default() -> Self {
Self::Variable
}
}
//---------------------------------------------------------------------------
impl Emittable for &str {
fn write_on(&self, f: &mut Formatter) {
f.buffer.push_str(self)
}
}
impl Emittable for String {
fn write_on(&self, f: &mut Formatter) {
f.write(self.as_str())
}
}
impl<'a, E: Emittable> Emittable for &'a Vec<E>
where
&'a E: Emittable,
{
fn write_on(&self, f: &mut Formatter) {
for e in self.iter() {
f.write(e)
}
}
}
impl Emittable for Sequence {
fn write_on(&self, f: &mut Formatter) {
if self.vertical_mode != VerticalMode::Variable {
self.write_vertically_on(f)
} else {
let mut need_sep = false;
for e in self.items.iter() {
if need_sep {
self.separator.write_on(f)
} else {
need_sep = true
}
e.write_on(f)
}
if !self.items.is_empty() {
self.terminator.write_on(f)
}
}
}
}
impl Vertical for Sequence {
fn set_vertical_mode(&mut self, vertical_mode: VerticalMode) {
self.vertical_mode = vertical_mode;
}
fn write_vertically_on(&self, f: &mut Formatter) {
let mut i = self.items.len();
let mut first = true;
for e in self.items.iter() {
if !first {
if self.vertical_mode == VerticalMode::ExtraNewline {
f.write("\n");
}
f.newline();
}
first = false;
e.write_on(f);
let delim = if i == 1 {
self.terminator
} else {
self.separator
};
delim
.trim_end_matches(|c: char| c.is_whitespace() && c != '\n')
.write_on(f);
i = i - 1;
}
}
}
impl Emittable for Grouping {
fn write_on(&self, f: &mut Formatter) {
if self.sequence.vertical_mode != VerticalMode::Variable {
self.write_vertically_on(f)
} else {
let mut g = f.copy_empty();
self.open.write_on(&mut g);
g.write(&self.sequence);
self.close.write_on(&mut g);
let s = g.buffer;
if s.len() <= f.width {
f.write(&s)
} else {
self.write_vertically_on(f)
}
}
}
}
impl Vertical for Grouping {
fn set_vertical_mode(&mut self, vertical_mode: VerticalMode) {
self.sequence.set_vertical_mode(vertical_mode);
}
fn write_vertically_on(&self, f: &mut Formatter) {
self.open.write_on(f);
if !self.sequence.items.is_empty() {
f.with_indent(|f| {
f.newline();
self.sequence.write_vertically_on(f)
});
f.newline()
}
self.close.write_on(f);
}
}
impl<'a, E: Emittable> Emittable for &'a E {
fn write_on(&self, f: &mut Formatter) {
(*self).write_on(f)
}
}
impl Emittable for Item {
fn write_on(&self, f: &mut Formatter) {
(**self).write_on(f)
}
}
impl std::fmt::Debug for Sequence {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
f.write_str(&Formatter::to_string(self))
}
}
impl std::fmt::Debug for Grouping {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
f.write_str(&Formatter::to_string(self))
}
}
//---------------------------------------------------------------------------
/// Escapes `s` by substituting `\\` for `\`, `\"` for `"`, and `\u{...}` for characters
/// outside the range 32..126, inclusive.
///
/// This process is intended to generate literals compatible with `rustc`; see [the language
/// reference on "Character and string
/// literals"](https://doc.rust-lang.org/reference/tokens.html#character-and-string-literals).
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
}
/// Escapes `bs` into a Rust byte string literal, treating each byte as its ASCII equivalent
/// except producing `\\` for 0x5c, `\"` for 0x22, and `\x..` for bytes outside the range
/// 0x20..0x7e, inclusive.
///
/// This process is intended to generate literals compatible with `rustc`; see [the language
/// reference on "Byte string
/// literals"](https://doc.rust-lang.org/reference/tokens.html#byte-string-literals).
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
}
//---------------------------------------------------------------------------
/// Utilities for constructing many useful kinds of [Sequence] and [Grouping].
pub mod constructors {
use super::Emittable;
use super::Grouping;
use super::Item;
use super::Sequence;
use super::Vertical;
use super::VerticalMode;
/// Produces a polymorphic, reference-counted [Item] from some generic [Emittable].
pub fn item<E: 'static + Emittable>(i: E) -> Item {
std::rc::Rc::new(i)
}
/// *a*`::`*b*`::`*...*`::`*z*
pub fn name(pieces: Vec<Item>) -> Sequence {
Sequence {
items: pieces,
vertical_mode: VerticalMode::default(),
separator: "::",
terminator: "",
}
}
/// *ab...z* (directly adjacent, no separators or terminators)
pub fn seq(items: Vec<Item>) -> Sequence {
Sequence {
items: items,
vertical_mode: VerticalMode::default(),
separator: "",
terminator: "",
}
}
/// *a*`, `*b*`, `*...*`, `*z*
pub fn commas(items: Vec<Item>) -> Sequence {
Sequence {
items: items,
vertical_mode: VerticalMode::default(),
separator: ", ",
terminator: "",
}
}
/// `(`*a*`, `*b*`, `*...*`, `*z*`)`
pub fn parens(items: Vec<Item>) -> Grouping {
Grouping {
sequence: commas(items),
open: "(",
close: ")",
}
}
/// `[`*a*`, `*b*`, `*...*`, `*z*`]`
pub fn brackets(items: Vec<Item>) -> Grouping {
Grouping {
sequence: commas(items),
open: "[",
close: "]",
}
}
/// `<`*a*`, `*b*`, `*...*`, `*z*`>`
pub fn anglebrackets(items: Vec<Item>) -> Grouping {
Grouping {
sequence: commas(items),
open: "<",
close: ">",
}
}
/// `{`*a*`, `*b*`, `*...*`, `*z*`}`
pub fn braces(items: Vec<Item>) -> Grouping {
Grouping {
sequence: commas(items),
open: "{",
close: "}",
}
}
/// `{`*a*` `*b*` `*...*` `*z*`}`
pub fn block(items: Vec<Item>) -> Grouping {
Grouping {
sequence: Sequence {
items: items,
vertical_mode: VerticalMode::default(),
separator: " ",
terminator: "",
},
open: "{",
close: "}",
}
}
/// As [block], but always vertical
pub fn codeblock(items: Vec<Item>) -> Grouping {
vertical(false, block(items))
}
/// `{`*a*`; `*b*`; `*...*`; `*z*`}`
pub fn semiblock(items: Vec<Item>) -> Grouping {
Grouping {
sequence: Sequence {
items: items,
vertical_mode: VerticalMode::default(),
separator: "; ",
terminator: "",
},
open: "{",
close: "}",
}
}
/// Overrides `v` to be always vertical.
///
/// If `spaced` is true, inserts an extra newline between items.
pub fn vertical<V: Vertical>(spaced: bool, mut v: V) -> V {
v.set_vertical_mode(if spaced {
VerticalMode::ExtraNewline
} else {
VerticalMode::Normal
});
v
}
/// Adds a layer of indentation to the given [Sequence].
pub fn indented(sequence: Sequence) -> Grouping {
Grouping {
sequence,
open: "",
close: "",
}
}
}
/// Ergonomic syntax for using the constructors in submodule [constructors]; see the
/// documentation for the macros, which appears on the [page for the crate
/// itself][crate#macros].
pub mod macros {
/// `name!(`*a*`, `*b*`, `*...*`, `*z*`)` ⟶ *a*`::`*b*`::`*...*`::`*z*
///
/// See [super::constructors::name].
#[macro_export]
macro_rules! name {
($($item:expr),*) => {$crate::syntax::block::constructors::name(vec![$(std::rc::Rc::new($item)),*])}
}
/// `seq!(`*a*`, `*b*`, `*...*`, `*z*`)` ⟶ *ab...z*
///
/// See [super::constructors::seq].
#[macro_export]
macro_rules! seq {
($($item:expr),*) => {$crate::syntax::block::constructors::seq(vec![$(std::rc::Rc::new($item)),*])}
}
/// `commas!(`*a*`, `*b*`, `*...*`, `*z*`)` ⟶ *a*`, `*b*`, `*...*`, `*z*
///
/// See [super::constructors::commas].
#[macro_export]
macro_rules! commas {
($($item:expr),*) => {$crate::syntax::block::constructors::commas(vec![$(std::rc::Rc::new($item)),*])}
}
/// `parens!(`*a*`, `*b*`, `*...*`, `*z*`)` ⟶ `(`*a*`, `*b*`, `*...*`, `*z*`)`
///
/// See [super::constructors::parens].
#[macro_export]
macro_rules! parens {
($($item:expr),*) => {$crate::syntax::block::constructors::parens(vec![$(std::rc::Rc::new($item)),*])}
}
/// `brackets!(`*a*`, `*b*`, `*...*`, `*z*`)` ⟶ `[`*a*`, `*b*`, `*...*`, `*z*`]`
///
/// See [super::constructors::brackets].
#[macro_export]
macro_rules! brackets {
($($item:expr),*) => {$crate::syntax::block::constructors::brackets(vec![$(std::rc::Rc::new($item)),*])}
}
/// `anglebrackets!(`*a*`, `*b*`, `*...*`, `*z*`)` ⟶ `<`*a*`, `*b*`, `*...*`, `*z*`>`
///
/// See [super::constructors::anglebrackets].
#[macro_export]
macro_rules! anglebrackets {
($($item:expr),*) => {$crate::syntax::block::constructors::anglebrackets(vec![$(std::rc::Rc::new($item)),*])}
}
/// `braces!(`*a*`, `*b*`, `*...*`, `*z*`)` ⟶ `{`*a*`, `*b*`, `*...*`, `*z*`}`
///
/// See [super::constructors::braces].
#[macro_export]
macro_rules! braces {
($($item:expr),*) => {$crate::syntax::block::constructors::braces(vec![$(std::rc::Rc::new($item)),*])}
}
/// `block!(`*a*`, `*b*`, `*...*`, `*z*`)` ⟶ `{`*a*` `*b*` `*...*` `*z*`}`
///
/// See [super::constructors::block].
#[macro_export]
macro_rules! block {
($($item:expr),*) => {$crate::syntax::block::constructors::block(vec![$(std::rc::Rc::new($item)),*])}
}
/// As [`block`]`!`, but always vertical. See
/// [constructors::codeblock][super::constructors::codeblock].
#[macro_export]
macro_rules! codeblock {
($($item:expr),*) => {$crate::syntax::block::constructors::codeblock(vec![$(std::rc::Rc::new($item)),*])}
}
/// `semiblock!(`*a*`, `*b*`, `*...*`, `*z*`)` ⟶ `{`*a*`; `*b*`; `*...*`; `*z*`}`
///
/// See [super::constructors::semiblock].
#[macro_export]
macro_rules! semiblock {
($($item:expr),*) => {$crate::syntax::block::constructors::semiblock(vec![$(std::rc::Rc::new($item)),*])}
}
}

View File

@ -1,3 +0,0 @@
//! A library for emitting pretty-formatted structured source code.
pub mod block;

View File

@ -1,21 +0,0 @@
[package]
name = "preserves-tools"
version = "4.993.0"
authors = ["Tony Garnock-Jones <tonyg@leastfixedpoint.com>"]
edition = "2018"
description = "Command-line utilities for working with Preserves documents."
homepage = "https://preserves.dev/"
repository = "https://gitlab.com/preserves/preserves"
license = "Apache-2.0"
[dependencies]
preserves = { path = "../preserves", version = "4.993.0"}
preserves-path = { path = "../preserves-path", version = "5.993.0"}
preserves-schema = { path = "../preserves-schema", version = "5.993.0"}
bytes = "1.0"
clap = { version = "3", features = ["derive"] }
clap_complete = "3"
[package.metadata.workspaces]
independent = true

View File

@ -1,548 +0,0 @@
use bytes::Buf;
use bytes::BufMut;
use bytes::BytesMut;
use clap::{value_parser, ArgEnum, Command, IntoApp, Parser};
use clap_complete::{generate, Generator, Shell};
use preserves::value::IOBinarySource;
use preserves::value::IOValue;
use preserves::value::IOValueDomainCodec;
use preserves::value::NestedValue;
use preserves::value::PackedReader;
use preserves::value::PackedWriter;
use preserves::value::Reader;
use preserves::value::Set;
use preserves::value::TextReader;
use preserves::value::TextWriter;
use preserves::value::Value;
use preserves::value::ViaCodec;
use preserves::value::Writer;
use preserves::value::text::writer::CommaStyle;
use std::io;
use std::io::Read;
use std::iter::FromIterator;
// #[derive(ArgEnum, Clone, Debug)]
// enum Encoding {
// None,
// Base64,
// Hex,
// }
#[derive(ArgEnum, Clone, Debug)]
enum InputFormat {
AutoDetect,
Text,
Binary,
}
#[derive(ArgEnum, Clone, Debug)]
enum OutputFormat {
Text,
Binary,
Unquoted,
}
#[derive(ArgEnum, Clone, Debug)]
enum CommasFormat {
None,
Separating,
Terminating,
}
#[derive(ArgEnum, Clone, Copy, Debug)]
enum Boolish {
#[clap(alias = "no", alias = "n", alias = "off", alias = "0", alias = "false")]
Disabled,
#[clap(alias = "yes", alias = "y", alias = "on", alias = "1", alias = "true")]
Enabled,
}
impl From<Boolish> for bool {
fn from(b: Boolish) -> Self {
matches!(b, Boolish::Enabled)
}
}
impl From<CommasFormat> for CommaStyle {
fn from(commas: CommasFormat) -> Self {
match commas {
CommasFormat::None => CommaStyle::None,
CommasFormat::Separating => CommaStyle::Separating,
CommasFormat::Terminating => CommaStyle::Terminating,
}
}
}
#[derive(ArgEnum, Clone, Debug)]
enum SelectOutput {
Sequence,
Set,
}
#[derive(Clone, Debug, Parser)]
struct Convert {
// #[clap(long, arg_enum, default_value = "none")]
// input_encoding: Encoding,
// #[clap(long, arg_enum, default_value = "none")]
// output_encoding: Encoding,
#[clap(long, short, arg_enum, default_value = "auto-detect")]
input_format: InputFormat,
#[clap(long, short, arg_enum, default_value = "text")]
output_format: OutputFormat,
#[clap(long)]
escape_spaces: bool,
#[clap(long, short, arg_enum, default_value = "none")]
commas: CommasFormat,
#[clap(long)]
limit: Option<usize>,
#[clap(long, arg_enum, value_name = "on/off", default_value = "on")]
indent: Boolish,
#[clap(long = "select", default_value = "*")]
select_expr: String,
#[clap(long, arg_enum, default_value = "sequence")]
select_output: SelectOutput,
#[clap(long)]
collect: bool,
#[clap(long, arg_enum, value_name = "on/off", default_value = "on")]
read_annotations: Boolish,
#[clap(long, arg_enum, value_name = "on/off", default_value = "on")]
write_annotations: Boolish,
#[clap(long, value_name = "filename")]
bundle: Vec<std::path::PathBuf>,
// #[clap(long)]
// schema: Option<String>,
}
#[derive(ArgEnum, Clone, Debug)]
enum StringInputTerminator {
EOF,
Newline,
Nul,
}
#[derive(Clone, Debug, Parser)]
struct StringQuotation {
#[clap(long, arg_enum, default_value = "eof")]
input_terminator: StringInputTerminator,
#[clap(long)]
include_terminator: bool,
#[clap(long)]
escape_spaces: bool,
}
#[derive(Clone, Debug, Parser)]
enum QuotationOutput {
String(StringQuotation),
ByteString,
Symbol(StringQuotation),
}
#[derive(Clone, Debug, Parser)]
struct Quote {
#[clap(long, short, arg_enum, default_value = "text")]
output_format: OutputFormat,
#[clap(subcommand)]
output: QuotationOutput,
}
#[derive(Clone, Debug, Parser)]
enum Subcommand {
Completions {
#[clap(value_parser=value_parser!(Shell))]
shell: Shell,
},
Convert(Convert),
Quote(Quote),
}
#[derive(Clone, Debug, Parser)]
#[clap(name = "preserves-tool")]
#[clap(version)]
#[clap(args_conflicts_with_subcommands = true)]
/// Swiss-army knife tool for working with Preserves data.
/// See https://preserves.dev/.
/// If no subcommand is specified, the default subcommand will be `convert`.
struct CommandLine {
#[clap(subcommand)]
command: Option<Subcommand>,
#[clap(flatten, next_help_heading="OPTIONS FOR DEFAULT SUBCOMMAND convert")]
convert: Convert,
}
fn print_completions<G: Generator>(gen: G, cmd: &mut Command) {
generate(gen, cmd, cmd.get_name().to_string(), &mut io::stdout());
}
fn main() -> io::Result<()> {
let args = CommandLine::parse();
Ok(match args.command {
Some(subcommand) => match subcommand {
Subcommand::Completions { shell } => {
let mut cmd = CommandLine::into_app();
print_completions(shell, &mut cmd);
}
Subcommand::Convert(c) => convert(c)?,
Subcommand::Quote(q) => quote(q)?,
}
None => convert(args.convert)?,
})
}
struct RollingBuffer<R: io::Read> {
r: R,
discarded: usize,
pos: usize,
buf: BytesMut,
}
impl<R: io::Read> RollingBuffer<R> {
fn new(r: R) -> Self {
RollingBuffer {
r,
discarded: 0,
pos: 0,
buf: BytesMut::new(),
}
}
fn read_more(&mut self) -> io::Result<usize> {
let mut buf = [0; 8192];
let n = self.r.read(&mut buf)?;
self.buf.put(&buf[..n]);
Ok(n)
}
fn peek_buf(&mut self) -> io::Result<&[u8]> {
if self.rhs() == self.pos {
let _ = self.read_more()?;
}
return Ok(&self.buf[self.pos - self.discarded..]);
}
fn rhs(&self) -> usize {
self.buf.remaining() + self.discarded
}
fn discard(&mut self, count: usize) {
self.buf.advance(count);
self.discarded += count;
}
fn discard_to_pos(&mut self) {
self.discard(self.pos - self.discarded)
}
fn read_upto(&mut self, delimiter: u8, inclusive: bool) -> io::Result<Option<Vec<u8>>> {
let mut result = Vec::new();
let mut buf = [0; 1];
while self.read(&mut buf)? == 1 {
if buf[0] == delimiter {
if inclusive {
result.push(delimiter);
}
return Ok(Some(result));
}
result.push(buf[0]);
}
Ok(if result.is_empty() {
None
} else {
Some(result)
})
}
}
impl<R: io::Read> io::Seek for RollingBuffer<R> {
fn seek(&mut self, offset: io::SeekFrom) -> io::Result<u64> {
let new_position = match offset {
io::SeekFrom::Current(delta) => {
if delta >= 0 {
self.pos + delta as usize
} else {
self.pos - (-delta) as usize
}
}
io::SeekFrom::End(_) => Err(io::Error::new(
io::ErrorKind::Unsupported,
"Cannot seek wrt end on open-ended stream",
))?,
io::SeekFrom::Start(new_position) => new_position as usize,
};
if new_position > self.rhs() {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Attempt to seek beyond end of buffer",
))?;
}
if new_position < self.discarded {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Attempt to seek before start of buffer",
))?;
}
self.pos = new_position;
Ok(new_position as u64)
}
fn stream_position(&mut self) -> io::Result<u64> {
Ok(self.pos as u64)
}
}
impl<R: io::Read> io::Read for RollingBuffer<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let i = self.pos - self.discarded;
loop {
let n = std::cmp::min(self.buf.remaining() - i, buf.len());
if n == 0 {
if self.read_more()? == 0 {
return Ok(0);
}
continue;
}
let _ = &buf[..n].copy_from_slice(&self.buf[i..i + n]);
self.pos += n;
return Ok(n);
}
}
}
// TODO: extract this and RollingBuffer to some preserves utils module
pub struct ValueStream<R: io::Read> {
input_format: InputFormat,
read_annotations: bool,
source: IOBinarySource<RollingBuffer<R>>,
count: usize,
}
impl<R: io::Read> ValueStream<R> {
fn new(input_format: InputFormat, read_annotations: bool, r: R) -> Self {
ValueStream {
input_format,
read_annotations,
source: IOBinarySource::new(RollingBuffer::new(r)),
count: 0,
}
}
fn read(&mut self) -> io::Result<Option<IOValue>> {
let is_text = {
let peek_buf = self.source.read.peek_buf()?;
if peek_buf.is_empty() {
return Ok(None);
}
peek_buf[0] < 128
};
let maybe_value: Option<IOValue> = if is_text {
match self.input_format {
InputFormat::AutoDetect | InputFormat::Text => (),
InputFormat::Binary => {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Expected binary input, saw text input",
))
}
}
TextReader::new(&mut self.source, ViaCodec::new(IOValueDomainCodec))
.next(self.read_annotations)?
} else {
match self.input_format {
InputFormat::AutoDetect | InputFormat::Binary => (),
InputFormat::Text => {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Expected text input, saw binary input",
))
}
}
PackedReader::new(&mut self.source, IOValueDomainCodec).next(self.read_annotations)?
};
match maybe_value {
None => return Ok(None),
Some(value) => {
self.source.read.discard_to_pos();
self.count += 1;
Ok(Some(value))
}
}
}
}
impl<R: io::Read> std::iter::Iterator for ValueStream<R> {
type Item = io::Result<IOValue>;
fn next(&mut self) -> Option<Self::Item> {
self.read().transpose()
}
}
fn print_unquoted(v: &IOValue) {
match v.value() {
Value::String(s) => println!("{}", &s),
Value::Symbol(s) => println!("{}", &s),
_ => (),
}
}
fn convert(c: Convert) -> io::Result<()> {
let mut env = preserves_path::Env::new();
for f in c.bundle.iter() {
env.load_bundle(f)?;
}
let select = preserves_path::Node::from_str(&env, &c.select_expr).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("Invalid select expression: {}: {:?}", e, c.select_expr),
)
})?;
let mut vs = ValueStream::new(c.input_format, c.read_annotations.into(), io::stdin());
let write_ann: bool = c.write_annotations.into();
let mut w: Box<dyn FnMut(&IOValue) -> io::Result<()>> = match c.output_format {
OutputFormat::Text => {
let mut t = TextWriter::new(io::stdout())
.set_escape_spaces(c.escape_spaces)
.set_comma_style(c.commas.into());
if c.indent.into() {
t.indentation = 2;
}
Box::new(move |v| {
if write_ann {
t.write(&mut IOValueDomainCodec, v)?;
} else {
t.write(&mut IOValueDomainCodec, &v.strip_annotations::<IOValue>())?;
}
println!();
Ok(())
})
}
OutputFormat::Binary => {
let mut p = PackedWriter::new(io::stdout());
Box::new(move |v| {
if write_ann {
p.write(&mut IOValueDomainCodec, v)?;
} else {
p.write(&mut IOValueDomainCodec, &v.strip_annotations::<IOValue>())?;
}
Ok(())
})
}
OutputFormat::Unquoted => Box::new(|v| {
print_unquoted(v);
Ok(())
}),
};
while let Some(value) = vs.next() {
let value = value?;
let matches = select.exec(&mut env.to_context(), &value);
if c.collect {
match c.select_output {
SelectOutput::Sequence => w(&IOValue::new(matches))?,
SelectOutput::Set => w(&IOValue::new(Set::from_iter(matches)))?,
}
} else {
match c.select_output {
SelectOutput::Sequence => {
for v in matches {
w(&v)?;
}
}
SelectOutput::Set => {
for v in Set::from_iter(matches) {
w(&v)?;
}
}
}
}
if let Some(limit) = c.limit {
if vs.count >= limit {
break;
}
}
}
Ok(())
}
impl Quote {
fn escape_spaces(&self) -> bool {
match &self.output {
QuotationOutput::ByteString => false,
QuotationOutput::String(s) | QuotationOutput::Symbol(s) => s.escape_spaces,
}
}
}
fn output_one(q: &Quote, v: &IOValue) -> io::Result<()> {
match q.output_format {
OutputFormat::Binary => PackedWriter::new(io::stdout()).write(&mut IOValueDomainCodec, v),
OutputFormat::Text => {
TextWriter::new(io::stdout())
.set_escape_spaces(q.escape_spaces())
.write(&mut IOValueDomainCodec, v)?;
println!();
Ok(())
}
OutputFormat::Unquoted => {
print_unquoted(v);
Ok(())
}
}
}
fn quote(q: Quote) -> io::Result<()> {
match &q.output {
QuotationOutput::ByteString => {
let mut buf = Vec::new();
io::stdin().read_to_end(&mut buf)?;
output_one(&q, &IOValue::new(&buf[..]))
}
QuotationOutput::String(s) | QuotationOutput::Symbol(s) => match s.input_terminator {
StringInputTerminator::EOF => {
let mut buf = String::new();
io::stdin().read_to_string(&mut buf)?;
quote_chunk(&q, buf)
}
StringInputTerminator::Newline => quote_terminated_strings(b'\n', &q, s),
StringInputTerminator::Nul => quote_terminated_strings(b'\0', &q, s),
},
}
}
fn quote_chunk(q: &Quote, buf: String) -> io::Result<()> {
match q.output {
QuotationOutput::Symbol(_) => output_one(q, &IOValue::symbol(&buf)),
_ => output_one(q, &IOValue::new(buf)),
}
}
fn quote_terminated_strings(delimiter: u8, q: &Quote, s: &StringQuotation) -> io::Result<()> {
let mut r = RollingBuffer::new(io::stdin());
while let Some(chunk) = r.read_upto(delimiter, s.include_terminator)? {
quote_chunk(
q,
String::from_utf8(chunk)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Invalid UTF-8"))?,
)?
}
Ok(())
}

View File

@ -1,31 +0,0 @@
[package]
name = "preserves"
version = "4.993.0"
authors = ["Tony Garnock-Jones <tonyg@leastfixedpoint.com>"]
edition = "2018"
description = "Implementation of the Preserves serialization format via serde."
homepage = "https://preserves.dev/"
repository = "https://gitlab.com/preserves/preserves"
license = "Apache-2.0"
[badges]
gitlab = { repository = "preserves/preserves" }
[dependencies]
base64 = "0.13"
dtoa = "0.4"
num = "0.4"
lazy_static = "1.4.0"
regex = "1.5"
serde = { version = "1.0", features = ["derive"] }
serde_bytes = "0.11"
[dev-dependencies]
criterion = "0.3"
[[bench]]
name = "codec"
harness = false
[package.metadata.workspaces]
independent = true

View File

@ -1,25 +0,0 @@
TESTARGS=--lib --bins --examples --tests
# cargo install cargo-watch
watch:
cargo watch -c -x 'test $(TESTARGS) -- --nocapture'
test:
cargo test $(TESTARGS) -- --nocapture
bench: benches/testdata.bin
cargo bench --benches
.INTERMEDIATE: benches/testdata.bin
benches/testdata.bin: benches/testdata.bin.gz
gzip -dc $< > $@
clippy-watch:
cargo watch -c -x 'clippy $(TESTARGS)'
inotifytest:
inotifytest sh -c 'reset; cargo build $(TESTARGS) && RUST_BACKTRACE=1 cargo test $(TESTARGS) -- --nocapture'
debug-tests:
cargo test $(TESTARGS) --no-run
gdb --args $$(cargo test 3>&1 1>&2 2>&3 3>&- | grep Running | awk '{print $$2}') --test-threads=1

View File

@ -1,23 +0,0 @@
```shell
cargo add preserves
```
This crate ([`preserves` on crates.io](https://crates.io/crates/preserves)) implements
[Preserves](https://preserves.dev/) for Rust. It provides the core
[semantics](https://preserves.dev/preserves.html#semantics) as well as both the [human-readable
text syntax][crate::value::text] (a superset of JSON) and [machine-oriented binary
format][crate::value::packed] (including
[canonicalization](https://preserves.dev/canonical-binary.html)) for Preserves.
This crate is the foundation for others such as
- [`preserves-schema`](https://docs.rs/preserves-schema/), which implements [Preserves
Schema](https://preserves.dev/preserves-schema.html);
- [`preserves-path`](https://docs.rs/preserves-path/), which implements [Preserves
Path](https://preserves.dev/preserves-path.html); and
- [`preserves-tools`](https://crates.io/crates/preserves-tools), which provides command-line
utilities for working with Preserves, in particular
[`preserves-tool`](https://preserves.dev/doc/preserves-tool.html), a kind of Preserves
Swiss-army knife.
It also includes [Serde](https://serde.rs/) support (modules [de], [ser], [symbol], [set]).

View File

@ -1 +0,0 @@
testdata.bin

View File

@ -1,170 +0,0 @@
use criterion::{criterion_group, criterion_main, Criterion};
use preserves::de;
use preserves::ser;
use preserves::value;
use preserves::value::packed::annotated_iovalue_from_bytes;
use preserves::value::BinarySource;
use preserves::value::BytesBinarySource;
use preserves::value::IOBinarySource;
use preserves::value::IOValueDomainCodec;
use preserves::value::PackedWriter;
use preserves::value::Reader;
use preserves::value::Writer;
use std::fs::File;
use std::io;
use std::io::Read;
use std::io::Seek;
#[path = "../tests/samples/mod.rs"]
mod samples;
use samples::TestCases;
pub fn bench_decoder_bytes(c: &mut Criterion) {
let mut fh = File::open("../../../tests/samples.bin").unwrap();
let mut bs = vec![];
fh.read_to_end(&mut bs).ok();
c.bench_function("decode samples.bin via bytes", |b| {
b.iter_with_large_drop(|| annotated_iovalue_from_bytes(&bs[..]).unwrap())
});
}
pub fn bench_decoder_file(c: &mut Criterion) {
let mut fh = File::open("../../../tests/samples.bin").unwrap();
c.bench_function("decode samples.bin via file", |b| {
b.iter_with_large_drop(|| {
fh.seek(io::SeekFrom::Start(0)).ok();
IOBinarySource::new(&mut fh)
.packed_iovalues()
.demand_next(true)
.unwrap()
})
});
}
pub fn bench_decoder_buffered_file(c: &mut Criterion) {
let mut fh = io::BufReader::new(File::open("../../../tests/samples.bin").unwrap());
c.bench_function("decode samples.bin via buffered file", |b| {
b.iter_with_large_drop(|| {
fh.seek(io::SeekFrom::Start(0)).ok();
IOBinarySource::new(&mut fh)
.packed_iovalues()
.demand_next(true)
.unwrap()
})
});
}
pub fn bench_encoder(c: &mut Criterion) {
let mut fh = File::open("../../../tests/samples.bin").unwrap();
let v = IOBinarySource::new(&mut fh)
.packed_iovalues()
.demand_next(true)
.unwrap();
c.bench_function("encode samples.bin", |b| {
b.iter_with_large_drop(|| PackedWriter::encode_iovalue(&v).unwrap())
});
}
pub fn bench_de(c: &mut Criterion) {
let mut fh = File::open("../../../tests/samples.bin").unwrap();
let mut bs = vec![];
fh.read_to_end(&mut bs).ok();
c.bench_function("deserialize samples.bin", |b| {
b.iter_with_large_drop(|| de::from_bytes::<TestCases>(&bs[..]).unwrap())
});
}
pub fn bench_ser(c: &mut Criterion) {
let mut fh = File::open("../../../tests/samples.bin").unwrap();
let v: TestCases = de::from_read(&mut fh).unwrap();
c.bench_function("serialize samples.bin", |b| {
b.iter_with_large_drop(|| {
let mut bs = vec![];
ser::to_writer(&mut PackedWriter::new(&mut bs), &v).unwrap();
bs
})
});
}
pub fn bench_decoder_de(c: &mut Criterion) {
let mut fh = File::open("../../../tests/samples.bin").unwrap();
let mut bs = vec![];
fh.read_to_end(&mut bs).ok();
c.bench_function("decode-then-deserialize samples.bin", |b| {
b.iter_with_large_drop(|| {
value::de::from_value::<TestCases>(&annotated_iovalue_from_bytes(&bs[..]).unwrap())
.unwrap()
})
});
}
pub fn bench_ser_encoder(c: &mut Criterion) {
let mut fh = File::open("../../../tests/samples.bin").unwrap();
let v: TestCases = de::from_read(&mut fh).unwrap();
c.bench_function("serialize-then-encode samples.bin", |b| {
b.iter_with_large_drop(|| PackedWriter::encode_iovalue(&value::ser::to_value(&v)).unwrap())
});
}
pub fn large_testdata_decoder_with_ann(c: &mut Criterion) {
c.bench_function("decode testdata.bin with annotations", |b| {
let mut fh = File::open("benches/testdata.bin").unwrap();
let mut bs = vec![];
fh.read_to_end(&mut bs).ok();
b.iter(|| {
let mut src = BytesBinarySource::new(&bs[..]);
let mut r = src.packed_iovalues();
while let Some(_) = r.next(true).unwrap() {}
})
});
}
pub fn large_testdata_decoder_without_ann(c: &mut Criterion) {
c.bench_function("decode testdata.bin without annotations", |b| {
let mut fh = File::open("benches/testdata.bin").unwrap();
let mut bs = vec![];
fh.read_to_end(&mut bs).ok();
b.iter(|| {
let mut src = BytesBinarySource::new(&bs[..]);
let mut r = src.packed_iovalues();
while let Some(_) = r.next(false).unwrap() {}
})
});
}
pub fn large_testdata_encoder(c: &mut Criterion) {
c.bench_function("encode testdata.bin", |b| {
let mut fh = io::BufReader::new(File::open("benches/testdata.bin").unwrap());
let mut vs = vec![];
let mut src = IOBinarySource::new(&mut fh);
let mut r = src.packed_iovalues();
while let Some(v) = r.next(true).unwrap() {
vs.push(v);
}
b.iter_with_large_drop(|| {
let mut bs = vec![];
let mut w = PackedWriter::new(&mut bs);
let mut enc = IOValueDomainCodec;
for v in &vs {
w.write(&mut enc, v).unwrap();
}
bs
})
});
}
criterion_group!(
codec,
bench_decoder_bytes,
bench_decoder_file,
bench_decoder_buffered_file,
bench_encoder
);
criterion_group!(serde, bench_de, bench_ser);
criterion_group!(codec_then_serde, bench_decoder_de, bench_ser_encoder);
criterion_group! {
name = large_testdata;
config = Criterion::default().sample_size(10);
targets = large_testdata_decoder_with_ann, large_testdata_decoder_without_ann, large_testdata_encoder
}
criterion_main!(codec, serde, codec_then_serde, large_testdata);

View File

@ -1,31 +0,0 @@
For a value `V`, we write `«V»` for the binary encoding of `V`.
```text
«#f» = [0x80]
«#t» = [0x81]
«@W V» = [0x85] ++ «W» ++ «V»
«#!V» = [0x86] ++ «V»
«V» if V ∈ Double = [0x87, 0x08] ++ binary64(V)
«V» if V ∈ SignedInteger = [0xB0] ++ varint(|intbytes(V)|) ++ intbytes(V)
«V» if V ∈ String = [0xB1] ++ varint(|utf8(V)|) ++ utf8(V)
«V» if V ∈ ByteString = [0xB2] ++ varint(|V|) ++ V
«V» if V ∈ Symbol = [0xB3] ++ varint(|utf8(V)|) ++ utf8(V)
«<L F_1...F_m>» = [0xB4] ++ «L» ++ «F_1» ++...++ «F_m» ++ [0x84]
«[X_1...X_m]» = [0xB5] ++ «X_1» ++...++ «X_m» ++ [0x84]
«#{E_1...E_m}» = [0xB6] ++ «E_1» ++...++ «E_m» ++ [0x84]
«{K_1:V_1...K_m:V_m}» = [0xB7] ++ «K_1» ++ «V_1» ++...++ «K_m» ++ «V_m» ++ [0x84]
varint(n) = [n] if n < 128
[(n & 127) | 128] ++ varint(n >> 7) if n ≥ 128
intbytes(n) = the empty sequence if n = 0, otherwise signedBigEndian(n)
signedBigEndian(n) = [n & 255] if -128 ≤ n ≤ 127
signedBigEndian(n >> 8) ++ [n & 255] otherwise
```
The function `binary64(D)` yields the big-endian 8-byte IEEE 754 binary representation of `D`.

View File

@ -1,48 +0,0 @@
```text
Document := Value ws
Value := ws (Record | Collection | Embedded | Annotated | Atom)
Collection := Sequence | Dictionary | Set
Record := `<` Value+ ws `>`
Sequence := `[` (commas Value)* commas `]`
Set := `#{` (commas Value)* commas `}`
Dictionary := `{` (commas Value ws `:` Value)* commas `}`
commas := (ws `,`)* ws
Embedded := `#!` Value
Annotated := Annotation Value
Annotation := `@` Value | `#` ((space | tab) linecomment) (cr | lf)
Atom := Boolean | ByteString | String | QuotedSymbol | Symbol | Number
Boolean := `#t` | `#f`
ByteString := `#"` binchar* `"`
| `#x"` (ws hex hex)* ws `"`
| `#[` (ws base64char)* ws `]`
String := `"` («any unicode scalar except `\` or `"`» | escaped | `\"`)* `"`
QuotedSymbol := `|` («any unicode scalar except `\` or `|`» | escaped | `\|`)* `|`
Symbol := (`A`..`Z` | `a`..`z` | `0`..`9` | sympunct | symuchar)+
Number := Double | SignedInteger
Double := flt | `#xd"` (ws hex hex)8 ws `"`
SignedInteger := int
escaped := `\\` | `\/` | `\b` | `\f` | `\n` | `\r` | `\t` | `\u` hex hex hex hex
binescaped := `\\` | `\/` | `\b` | `\f` | `\n` | `\r` | `\t` | `\x` hex hex
binchar := «any scalar ≥32 and ≤126, except `\` or `"`» | binescaped | `\"`
base64char := `A`..`Z` | `a`..`z` | `0`..`9` | `+` | `/` | `-` | `_` | `=`
sympunct := `~` | `!` | `$` | `%` | `^` | `&` | `*` | `?`
| `_` | `=` | `+` | `-` | `/` | `.`
symuchar := «any scalar value ≥128 whose Unicode category is
Lu, Ll, Lt, Lm, Lo, Mn, Mc, Me, Nd, Nl, No, Pc,
Pd, Po, Sc, Sm, Sk, So, or Co»
flt := int ( frac exp | frac | exp )
int := (`-`|`+`) (`0`..`9`)+
frac := `.` (`0`..`9`)+
exp := (`e`|`E`) (`-`|`+`) (`0`..`9`)+
hex := `A`..`F` | `a`..`f` | `0`..`9`
ws := (space | tab | cr | lf)*
delimiter := ws | `<` | `>` | `[` | `]` | `{` | `}`
| `#` | `:` | `"` | `|` | `@` | `;` | `,`
linecomment := «any unicode scalar except cr or lf»*
```

View File

@ -1,17 +0,0 @@
```text
Value = Atom
| Compound
| Embedded
Atom = Boolean
| Double
| SignedInteger
| String
| ByteString
| Symbol
Compound = Record
| Sequence
| Set
| Dictionary
```

View File

@ -1,12 +0,0 @@
*Preserves* is a data model, with associated serialization formats.
It supports *records* with user-defined *labels*, embedded
*references*, and the usual suite of atomic and compound data types,
including *binary* data as a distinct type from text strings. Its
*annotations* allow separation of data from metadata such as comments,
trace information, and provenance information.
Preserves departs from many other data languages in defining how to
*compare* two values. Comparison is based on the data model, not on
syntax or on data structures of any particular implementation
language.

View File

@ -1,10 +0,0 @@
BINARY_FILES=known-data.bin unknown-data.bin
all: $(BINARY_FILES)
%.bin: %.txt Makefile
racket ../../../racket/preserves/preserves/tool.rkt --atob --no-annotations < $< > $@.tmp || (rm -f $@.tmp; false)
mv $@.tmp $@
clean:
rm -f $(BINARY_FILES)

View File

@ -1,57 +0,0 @@
use preserves::{
de,
value::{self, BinarySource, IOBinarySource, Reader},
};
use serde::{Deserialize, Serialize};
use std::fs::File;
use std::io;
#[derive(Debug, Serialize, Deserialize, PartialEq)]
enum Fruit {
Apple(Colour),
Pear(Variety),
Banana(Weight, Colour, u8),
// Peach,
#[serde(other)]
Unknown,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename = "kilograms")]
struct Weight(f32);
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Colour {
name: String,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
enum Variety {
Conference,
Bosc,
European,
Anjou,
}
fn try_file(kind: &str, path: &str) -> io::Result<()> {
let fruits_value = IOBinarySource::new(&mut File::open(path)?)
.packed_iovalues()
.demand_next(true)?;
println!("{:#?}", fruits_value);
let fruits1: Vec<Fruit> = value::de::from_value(&fruits_value)?;
println!("(via generic decoding) {}: {:?}", kind, fruits1);
let fruits2: Vec<Fruit> = de::from_read(&mut File::open(path)?)?;
println!("(direct from binary) {}: {:?}\n", kind, fruits2);
assert_eq!(fruits1, fruits2);
Ok(())
}
fn main() -> io::Result<()> {
try_file("KNOWN", "examples/known-data.bin")?;
try_file("UNKNOWN", "examples/unknown-data.bin")?;
Ok(())
}

View File

@ -1,2 +0,0 @@
µ´³Apple´³Colour±red„„´³Apple´³Colour±green„„´³Banana´³ kilogramsƒ?¾¸Që…¸„´³Colour±brownish„•„´³Pear´³
Conference„„„

View File

@ -1,7 +0,0 @@
@<EmacsMode "-*- preserves -*-">
[
<Apple <Colour "red">>
<Apple <Colour "green">>
<Banana <kilograms 0.12> <Colour "brownish"> 5>
<Pear <Conference>>
]

View File

@ -1,2 +0,0 @@
µ´³Apple´³Colour±red„„´³Peach„´³Apple´³Colour±green„„´³Banana´³ kilogramsƒ?¾¸Që…¸„´³Colour±brownish„•·³ripeness´³Squishy„„„´³Pear´³
Conference„„„

View File

@ -1,8 +0,0 @@
@<EmacsMode "-*- preserves -*-">
[
<Apple <Colour "red">>
<Peach>
<Apple <Colour "green">>
<Banana <kilograms 0.12> <Colour "brownish"> 5 {ripeness: <Squishy>}>
<Pear <Conference>>
]

View File

@ -1,479 +0,0 @@
//! Support for Serde deserialization of Preserves terms described by Rust data types.
use serde::de::{DeserializeSeed, EnumAccess, MapAccess, SeqAccess, VariantAccess, Visitor};
use serde::Deserialize;
use std::borrow::Cow;
use std::io;
use std::marker::PhantomData;
use super::value::boundary as B;
use super::value::reader::{BytesBinarySource, IOBinarySource, Reader};
use super::value::{IOValue, IOValueDomainCodec, PackedReader, TextReader, ViaCodec};
pub use super::error::Error;
/// A [std::result::Result] type including [Error], the Preserves Serde deserialization error
/// type, as its error.
pub type Result<T> = std::result::Result<T, Error>;
/// Serde deserializer for Preserves-encoded Rust data. Use [Deserializer::from_reader] to
/// construct instances, or [from_bytes]/[from_text]/[from_read]/[from_reader] etc to
/// deserialize single terms directly.
pub struct Deserializer<'de, 'r, R: Reader<'de, IOValue>> {
/// The underlying Preserves [reader][crate::value::reader::Reader].
pub read: &'r mut R,
phantom: PhantomData<&'de ()>,
}
/// Deserialize a `T` from `bytes`, which must contain a Preserves [machine-oriented binary
/// syntax][crate::value::packed] term corresponding to the Serde serialization of a `T`.
pub fn from_bytes<'de, T>(bytes: &'de [u8]) -> Result<T>
where
T: Deserialize<'de>,
{
from_reader(&mut PackedReader::new(
&mut BytesBinarySource::new(bytes),
IOValueDomainCodec,
))
}
/// Deserialize a `T` from `text`, which must contain a Preserves [text
/// syntax][crate::value::text] term corresponding to the Serde serialization of a `T`.
pub fn from_text<'de, T>(text: &'de str) -> Result<T>
where
T: Deserialize<'de>,
{
from_reader(&mut TextReader::new(
&mut BytesBinarySource::new(text.as_bytes()),
ViaCodec::new(IOValueDomainCodec),
))
}
/// Deserialize a `T` from `read`, which must yield a Preserves [machine-oriented binary
/// syntax][crate::value::packed] term corresponding to the Serde serialization of a `T`.
pub fn from_read<'de, 'r, IOR: io::Read + io::Seek, T>(read: &'r mut IOR) -> Result<T>
where
T: Deserialize<'de>,
{
from_reader(&mut PackedReader::new(
&mut IOBinarySource::new(read),
IOValueDomainCodec,
))
}
/// Deserialize a `T` from `read`, which must yield a Preserves term corresponding to the Serde
/// serialization of a `T`.
pub fn from_reader<'r, 'de, R: Reader<'de, IOValue>, T>(read: &'r mut R) -> Result<T>
where
T: Deserialize<'de>,
{
let mut de = Deserializer::from_reader(read);
let t = T::deserialize(&mut de)?;
Ok(t)
}
impl<'r, 'de, R: Reader<'de, IOValue>> Deserializer<'de, 'r, R> {
/// Construct a Deserializer from `read`, a Preserves [reader][crate::value::Reader].
pub fn from_reader(read: &'r mut R) -> Self {
Deserializer {
read,
phantom: PhantomData,
}
}
}
impl<'r, 'de, 'a, R: Reader<'de, IOValue>> serde::de::Deserializer<'de>
for &'a mut Deserializer<'de, 'r, R>
{
type Error = Error;
fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
// Won't support this here -- use value::de::Deserializer for this
Err(Error::CannotDeserializeAny)
}
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_bool(self.read.next_boolean()?)
}
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_i8(self.read.next_i8()?)
}
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_i16(self.read.next_i16()?)
}
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_i32(self.read.next_i32()?)
}
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_i64(self.read.next_i64()?)
}
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_u8(self.read.next_u8()?)
}
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_u16(self.read.next_u16()?)
}
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_u32(self.read.next_u32()?)
}
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_u64(self.read.next_u64()?)
}
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_f32(self.read.next_f64()? as f32)
}
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_f64(self.read.next_f64()?)
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_char(self.read.next_char()?)
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.read.next_str()? {
Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
Cow::Owned(s) => visitor.visit_str(&s),
}
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.read.next_bytestring()? {
Cow::Borrowed(bs) => visitor.visit_borrowed_bytes(bs),
Cow::Owned(bs) => visitor.visit_bytes(&bs),
}
}
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_byte_buf(self.read.next_bytestring()?.into_owned())
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
if let Some(mut b) = self.read.open_option()? {
self.read
.ensure_more_expected(&mut b, &B::Item::RecordField)?;
let result = visitor.visit_some(&mut *self)?;
self.read.ensure_complete(b, &B::Item::RecordField)?;
Ok(result)
} else {
Ok(visitor.visit_none::<Error>()?)
}
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let b = self.read.open_simple_record("tuple", Some(0))?;
let result = visitor.visit_unit::<Error>()?;
self.read.ensure_complete(b, &B::Item::RecordField)?;
Ok(result)
}
fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let b = self.read.open_simple_record(name, Some(0))?;
let result = visitor.visit_unit::<Error>()?;
self.read.ensure_complete(b, &B::Item::RecordField)?;
Ok(result)
}
fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match super::value::magic::transmit_input_value(name, || {
Ok(self.read.demand_next(true)?)
})? {
Some(v) => visitor.visit_u64(v),
None => {
let mut b = self.read.open_simple_record(name, Some(1))?;
self.read
.ensure_more_expected(&mut b, &B::Item::RecordField)?;
let result = visitor.visit_newtype_struct(&mut *self)?;
self.read.ensure_complete(b, &B::Item::RecordField)?;
Ok(result)
}
}
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
// Hack around serde's model: Deserialize *sets* as sequences,
// too, and reconstruct them as Rust Sets on the visitor side.
let i = self.read.open_sequence_or_set()?;
visitor.visit_seq(Seq::new(self, B::Type::default(), i))
}
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let b = self.read.open_simple_record("tuple", Some(len))?;
let mut seq = Seq::new(self, b, B::Item::RecordField);
let result = visitor.visit_seq(&mut seq)?;
seq.skip_remainder()?;
Ok(result)
}
fn deserialize_tuple_struct<V>(
self,
name: &'static str,
len: usize,
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
let b = self.read.open_simple_record(name, Some(len))?;
let mut seq = Seq::new(self, b, B::Item::RecordField);
let result = visitor.visit_seq(&mut seq)?;
seq.skip_remainder()?;
Ok(result)
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.read.open_dictionary()?;
let mut seq = Seq::new(self, B::Type::default(), B::Item::DictionaryKey);
let result = visitor.visit_map(&mut seq)?;
Ok(result)
}
fn deserialize_struct<V>(
self,
name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
let b = self.read.open_simple_record(name, Some(fields.len()))?;
let mut seq = Seq::new(self, b, B::Item::RecordField);
let result = visitor.visit_seq(&mut seq)?;
seq.skip_remainder()?;
Ok(result)
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_enum(self)
}
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.read.next_symbol()? {
Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
Cow::Owned(s) => visitor.visit_str(&s),
}
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_none()
}
}
#[doc(hidden)]
pub struct Seq<'de, 'r, 'a, R: Reader<'de, IOValue>> {
b: B::Type,
i: B::Item,
de: &'a mut Deserializer<'de, 'r, R>,
}
impl<'de, 'r, 'a, R: Reader<'de, IOValue>> Seq<'de, 'r, 'a, R> {
fn new(de: &'a mut Deserializer<'de, 'r, R>, b: B::Type, i: B::Item) -> Self {
Seq { b, i, de }
}
fn skip_remainder(&mut self) -> Result<()> {
while !self.de.read.close_compound(&mut self.b, &self.i)? {
self.de.read.skip_value()?;
}
Ok(())
}
fn next_item<T>(&mut self, seed: T) -> Result<Option<T::Value>>
where
T: DeserializeSeed<'de>,
{
match self.de.read.close_compound(&mut self.b, &self.i)? {
true => Ok(None),
false => Ok(Some(seed.deserialize(&mut *self.de)?)),
}
}
}
impl<'de, 'r, 'a, R: Reader<'de, IOValue>> SeqAccess<'de> for Seq<'de, 'r, 'a, R> {
type Error = Error;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
where
T: DeserializeSeed<'de>,
{
Ok(self.next_item(seed)?)
}
}
impl<'de, 'r, 'a, R: Reader<'de, IOValue>> MapAccess<'de> for Seq<'de, 'r, 'a, R> {
type Error = Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
where
K: DeserializeSeed<'de>,
{
self.i = B::Item::DictionaryKey;
self.next_item(seed)
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
where
V: DeserializeSeed<'de>,
{
self.i = B::Item::DictionaryValue;
match self.next_item(seed)? {
Some(item) => Ok(item),
None => Err(Error::MissingItem),
}
}
}
impl<'de, 'r, 'a, R: Reader<'de, IOValue>> EnumAccess<'de> for &'a mut Deserializer<'de, 'r, R> {
type Error = Error;
type Variant = Seq<'de, 'r, 'a, R>;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
where
V: DeserializeSeed<'de>,
{
let b = self.read.open_record(None)?;
let variant = seed.deserialize(&mut *self)?;
Ok((variant, Seq::new(self, b, B::Item::RecordField)))
}
}
impl<'de, 'r, 'a, R: Reader<'de, IOValue>> VariantAccess<'de> for Seq<'de, 'r, 'a, R> {
type Error = Error;
fn unit_variant(mut self) -> Result<()> {
self.skip_remainder()
}
fn newtype_variant_seed<T>(mut self, seed: T) -> Result<T::Value>
where
T: DeserializeSeed<'de>,
{
match self.next_item(seed)? {
None => Err(Error::MissingItem),
Some(v) => {
self.skip_remainder()?;
Ok(v)
}
}
}
fn tuple_variant<V>(mut self, _len: usize, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let result = visitor.visit_seq(&mut self)?;
self.skip_remainder()?;
Ok(result)
}
fn struct_variant<V>(mut self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let result = visitor.visit_seq(&mut self)?;
self.skip_remainder()?;
Ok(result)
}
}

View File

@ -1,165 +0,0 @@
//! Serde and plain-Preserves codec errors.
use num::bigint::BigInt;
use std::convert::From;
use std::io;
/// Representation of parse, deserialization, and other conversion errors.
#[derive(Debug)]
pub enum Error {
/// Generic IO error.
Io(io::Error),
/// Generic message for the user.
Message(String),
/// Invalid unicode scalar `n` found during interpretation of a `<UnicodeScalar n>` record
/// as a Rust `char`.
InvalidUnicodeScalar(u32),
/// Preserves supports arbitrary integers; when these are converted to specific Rust
/// machine word types, sometimes they exceed the available range.
NumberOutOfRange(BigInt),
/// Serde has limited support for deserializing free-form data; this error is signalled
/// when one of the limits is hit.
CannotDeserializeAny,
/// Syntax error: missing closing delimiter (`)`, `]`, `}`, `>` in text syntax; `0x84` in binary syntax; etc.)
MissingCloseDelimiter,
/// Signalled when an expected term is not present.
MissingItem,
/// Signalled when what was received did not match expectations.
Expected(ExpectedKind, Received),
#[doc(hidden)] // TODO remove this enum variant? It isn't used
StreamingSerializationUnsupported,
}
/// Used in [Error::Expected] to indicate what was received.
#[derive(Debug)]
pub enum Received {
#[doc(hidden)] // TODO remove this enum variant? It isn't used
ReceivedSomethingElse,
/// Received a record with the given label symbol text.
ReceivedRecordWithLabel(String),
/// Received some other value, described in the `String`
ReceivedOtherValue(String),
}
/// Used in [Error::Expected] to indicate what was expected.
#[derive(Debug, PartialEq)]
pub enum ExpectedKind {
Boolean,
Float,
Double,
SignedIntegerI128,
SignedIntegerU128,
SignedInteger,
String,
ByteString,
Symbol,
/// Expected a record, either of a specific arity (length) or of no specific arity
Record(Option<usize>),
/// Expected a record with a symbol label with text `String`, perhaps of some specific arity
SimpleRecord(String, Option<usize>),
Sequence,
Set,
Dictionary,
Embedded,
SequenceOrSet, // Because of hacking up serde's data model: see open_sequence_or_set etc.
Option,
UnicodeScalar,
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Error::Io(e)
}
}
impl From<Error> for io::Error {
fn from(e: Error) -> Self {
match e {
Error::Io(ioe) => ioe,
Error::Message(str) => io::Error::new(io::ErrorKind::Other, str),
_ => io::Error::new(io::ErrorKind::Other, e.to_string()),
}
}
}
impl serde::ser::Error for Error {
fn custom<T: std::fmt::Display>(msg: T) -> Self {
Self::Message(msg.to_string())
}
}
impl serde::de::Error for Error {
fn custom<T: std::fmt::Display>(msg: T) -> Self {
Self::Message(msg.to_string())
}
}
impl std::error::Error for Error {}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
//---------------------------------------------------------------------------
/// True iff `e` is `Error::Io`
pub fn is_io_error(e: &Error) -> bool {
matches!(e, Error::Io(_))
}
/// Produce the generic "end of file" error, `Error::Io(`[io_eof]`())`
pub fn eof() -> Error {
Error::Io(io_eof())
}
/// True iff `e` is an "end of file" error; see [is_eof_io_error]
pub fn is_eof_error(e: &Error) -> bool {
if let Error::Io(ioe) = e {
is_eof_io_error(ioe)
} else {
false
}
}
/// Produce a syntax error bearing the message `s`
pub fn syntax_error(s: &str) -> Error {
Error::Io(io_syntax_error(s))
}
/// True iff `e` is a syntax error; see [is_syntax_io_error]
pub fn is_syntax_error(e: &Error) -> bool {
if let Error::Io(ioe) = e {
is_syntax_io_error(ioe)
} else {
false
}
}
//---------------------------------------------------------------------------
/// Produce an [io::Error] of [io::ErrorKind::UnexpectedEof].
pub fn io_eof() -> io::Error {
io::Error::new(io::ErrorKind::UnexpectedEof, "EOF")
}
/// True iff `e` is [io::ErrorKind::UnexpectedEof]
pub fn is_eof_io_error(e: &io::Error) -> bool {
matches!(e.kind(), io::ErrorKind::UnexpectedEof)
}
/// Produce a syntax error ([io::ErrorKind::InvalidData]) bearing the message `s`
pub fn io_syntax_error(s: &str) -> io::Error {
io::Error::new(io::ErrorKind::InvalidData, s)
}
/// True iff `e` is an [io::ErrorKind::InvalidData] (a syntax error)
pub fn is_syntax_io_error(e: &io::Error) -> bool {
matches!(e.kind(), io::ErrorKind::InvalidData)
}

View File

@ -1,188 +0,0 @@
//! Utilities for producing and flexibly parsing strings containing hexadecimal binary data.
/// Utility for parsing hex binary data from strings.
pub enum HexParser {
/// "Liberal" parsing simply ignores characters that are not (case-insensitive) hex digits.
Liberal,
/// "Whitespace allowed" parsing ignores whitespace, but fails a parse on anything other
/// than hex or whitespace.
WhitespaceAllowed,
/// "Strict" parsing accepts only (case-insensitive) hex digits; no whitespace, no other
/// characters.
Strict,
}
/// Utility for formatting binary data as hex.
pub enum HexFormatter {
/// Produces LF-separated lines with a maximum of `usize` hex digits in each line.
Lines(usize),
/// Simply packs hex digits in as tightly as possible.
Packed,
}
/// Convert a number 0..15 to a hex digit [char].
///
/// # Panics
///
/// Panics if given `v` outside the range 0..15 inclusive.
///
pub fn hexdigit(v: u8) -> char {
char::from_digit(v as u32, 16).expect("hexadecimal digit value")
}
impl HexParser {
/// Decode `s` according to the given rules for `self`; see [HexParser].
/// If the parse fails, yield `None`.
pub fn decode(&self, s: &str) -> Option<Vec<u8>> {
let mut result = Vec::new();
let mut buf: u8 = 0;
let mut buf_full = false;
for c in s.chars() {
match c.to_digit(16) {
None => match self {
HexParser::Liberal => (),
HexParser::WhitespaceAllowed => {
if !c.is_whitespace() {
return None;
}
}
HexParser::Strict => return None,
},
Some(nibble) => {
if buf_full {
result.push(buf << 4 | (nibble as u8));
buf_full = false;
} else {
buf = nibble as u8;
buf_full = true;
}
}
}
}
if buf_full {
None // odd number of hexits
} else {
Some(result)
}
}
}
impl HexFormatter {
/// Encode `bs` according to the given rules for `self; see [HexFormatter].
pub fn encode(&self, bs: &[u8]) -> String {
match self {
HexFormatter::Lines(max_line_length) => {
let mut lines = Vec::new();
let mut line = String::new();
for b in bs {
if line.len() + 2 > *max_line_length {
lines.push(std::mem::take(&mut line));
}
line.push(hexdigit(b >> 4));
line.push(hexdigit(b & 15));
}
lines.push(std::mem::take(&mut line));
lines.join("\n")
}
HexFormatter::Packed => {
let mut result = String::new();
for b in bs {
result.push(hexdigit(b >> 4));
result.push(hexdigit(b & 15));
}
result
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_decode_packed() {
let s = "01ab00ff";
assert_eq!(HexParser::Strict.decode(s), Some(vec![1, 171, 0, 255]));
assert_eq!(
HexParser::WhitespaceAllowed.decode(s),
Some(vec![1, 171, 0, 255])
);
assert_eq!(HexParser::Liberal.decode(s), Some(vec![1, 171, 0, 255]));
}
#[test]
fn test_decode_whitespace() {
let s = "01ab 00ff";
assert_eq!(HexParser::Strict.decode(s), None);
assert_eq!(
HexParser::WhitespaceAllowed.decode(s),
Some(vec![1, 171, 0, 255])
);
assert_eq!(HexParser::Liberal.decode(s), Some(vec![1, 171, 0, 255]));
}
#[test]
fn test_decode_liberal() {
let s = "01ab zz 00ff";
assert_eq!(HexParser::Strict.decode(s), None);
assert_eq!(HexParser::WhitespaceAllowed.decode(s), None);
assert_eq!(HexParser::Liberal.decode(s), Some(vec![1, 171, 0, 255]));
}
#[test]
fn test_encode_lines() {
assert_eq!(
HexFormatter::Lines(10).encode(&vec![0x5a; 11]),
"5a5a5a5a5a\n5a5a5a5a5a\n5a"
);
assert_eq!(
HexFormatter::Lines(10).encode(&vec![0x5a; 10]),
"5a5a5a5a5a\n5a5a5a5a5a"
);
assert_eq!(
HexFormatter::Lines(10).encode(&vec![0x5a; 9]),
"5a5a5a5a5a\n5a5a5a5a"
);
assert_eq!(
HexFormatter::Lines(9).encode(&vec![0x5a; 11]),
"5a5a5a5a\n5a5a5a5a\n5a5a5a"
);
assert_eq!(
HexFormatter::Lines(9).encode(&vec![0x5a; 10]),
"5a5a5a5a\n5a5a5a5a\n5a5a"
);
assert_eq!(
HexFormatter::Lines(9).encode(&vec![0x5a; 9]),
"5a5a5a5a\n5a5a5a5a\n5a"
);
assert_eq!(
HexFormatter::Lines(8).encode(&vec![0x5a; 11]),
"5a5a5a5a\n5a5a5a5a\n5a5a5a"
);
assert_eq!(
HexFormatter::Lines(8).encode(&vec![0x5a; 10]),
"5a5a5a5a\n5a5a5a5a\n5a5a"
);
assert_eq!(
HexFormatter::Lines(8).encode(&vec![0x5a; 9]),
"5a5a5a5a\n5a5a5a5a\n5a"
);
}
#[test]
fn test_encode_packed() {
assert_eq!(
HexFormatter::Packed.encode(&vec![0x5a; 11]),
"5a5a5a5a5a5a5a5a5a5a5a"
);
assert_eq!(
HexFormatter::Packed.encode(&vec![0x5a; 10]),
"5a5a5a5a5a5a5a5a5a5a"
);
assert_eq!(
HexFormatter::Packed.encode(&vec![0x5a; 9]),
"5a5a5a5a5a5a5a5a5a"
);
}
}

View File

@ -1,810 +0,0 @@
#![doc = concat!(
include_str!("../README.md"),
"# What is Preserves?\n\n",
include_str!("../doc/what-is-preserves.md"),
)]
pub mod de;
pub mod error;
pub mod hex;
pub mod ser;
pub mod set;
pub mod symbol;
pub mod value;
#[cfg(test)]
mod dom {
use super::value::*;
use std::io;
#[derive(Debug, Hash, Clone, Ord, PartialEq, Eq, PartialOrd)]
pub enum Dom {
One,
Two,
}
impl Domain for Dom {}
impl std::str::FromStr for Dom {
type Err = io::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"One" => Ok(Dom::One),
"Two" => Ok(Dom::Two),
_ => Err(io::Error::new(
io::ErrorKind::Other,
"cannot parse preserves test domain",
)),
}
}
}
fn dom_as_preserves(v: &Dom) -> io::Result<UnwrappedIOValue> {
Ok(match v {
Dom::One => Value::bytestring(vec![255, 255, 255, 255]),
Dom::Two => Value::symbol(&format!("Dom::{:?}", v)),
})
}
#[test]
fn test_one() {
let v: PlainValue<_> = Value::from(vec![
Value::from(1).wrap(),
Value::Embedded(Dom::One).wrap(),
Value::from(2).wrap(),
])
.wrap();
assert_eq!(
PackedWriter::encode_iovalue(&v.copy_via(&mut dom_as_preserves).unwrap()).unwrap(),
[0xb5, 0xb0, 0x01, 0x01, 0xb2, 0x04, 255, 255, 255, 255, 0xb0, 0x01, 0x02, 0x84]
);
}
#[test]
fn test_two() {
let v: PlainValue<_> = Value::from(vec![
Value::from(1).wrap(),
Value::Embedded(Dom::Two).wrap(),
Value::from(2).wrap(),
])
.wrap();
assert_eq!(
PackedWriter::encode_iovalue(&v.copy_via(&mut dom_as_preserves).unwrap()).unwrap(),
[0xb5, 0xb0, 0x01, 0x01, 0xb3, 0x08, 68, 111, 109, 58, 58, 84, 119, 111, 0xb0, 0x01, 0x02, 0x84]
);
}
}
#[cfg(test)]
mod ieee754_section_5_10_total_order_tests {
use super::dom::Dom;
use std::cmp::Ordering::{Equal, Greater, Less};
use crate::value::{PlainValue, Value};
fn d(val: f64) -> Value<PlainValue<Dom>> {
Value::from(val)
}
// TODO: Test cases with a few different signalling and non-signalling NaNs
#[test]
fn case64_a_1() {
assert_eq!(d(1.0).cmp(&d(2.0)), Less)
}
#[test]
fn case64_a_2() {
assert_eq!(d(-1.0).cmp(&d(1.0)), Less)
}
#[test]
fn case64_a_3() {
assert_eq!(d(0.0).cmp(&d(1.0)), Less)
}
#[test]
fn case64_a_4() {
assert_eq!(d(-1.0).cmp(&d(0.0)), Less)
}
#[test]
fn case64_a_5() {
assert_eq!(d(-1e32).cmp(&d(-1e31)), Less)
}
#[test]
fn case64_a_6() {
assert_eq!(d(-1e32).cmp(&d(1e33)), Less)
}
#[test]
fn case64_a_7() {
assert_eq!(d(std::f64::NEG_INFINITY).cmp(&d(std::f64::INFINITY)), Less)
}
#[test]
fn case64_a_8() {
assert_eq!(d(std::f64::NEG_INFINITY).cmp(&d(0.0)), Less)
}
#[test]
fn case64_a_9() {
assert_eq!(d(std::f64::NEG_INFINITY).cmp(&d(1.0)), Less)
}
#[test]
fn case64_a_10() {
assert_eq!(d(std::f64::NEG_INFINITY).cmp(&d(1e33)), Less)
}
#[test]
fn case64_a_11() {
assert_eq!(d(0.0).cmp(&d(std::f64::INFINITY)), Less)
}
#[test]
fn case64_a_12() {
assert_eq!(d(1.0).cmp(&d(std::f64::INFINITY)), Less)
}
#[test]
fn case64_a_13() {
assert_eq!(d(1e33).cmp(&d(std::f64::INFINITY)), Less)
}
#[test]
fn case64_b_1() {
assert_eq!(d(2.0).cmp(&d(1.0)), Greater)
}
#[test]
fn case64_b_2() {
assert_eq!(d(1.0).cmp(&d(-1.0)), Greater)
}
#[test]
fn case64_b_3() {
assert_eq!(d(1.0).cmp(&d(0.0)), Greater)
}
#[test]
fn case64_b_4() {
assert_eq!(d(0.0).cmp(&d(-1.0)), Greater)
}
#[test]
fn case64_b_5() {
assert_eq!(d(-1e31).cmp(&d(-1e32)), Greater)
}
#[test]
fn case64_b_6() {
assert_eq!(d(1e33).cmp(&d(-1e32)), Greater)
}
#[test]
fn case64_b_7() {
assert_eq!(
d(std::f64::INFINITY).cmp(&d(std::f64::NEG_INFINITY)),
Greater
)
}
#[test]
fn case64_b_8() {
assert_eq!(d(std::f64::INFINITY).cmp(&d(0.0)), Greater)
}
#[test]
fn case64_b_9() {
assert_eq!(d(std::f64::INFINITY).cmp(&d(1.0)), Greater)
}
#[test]
fn case64_b_10() {
assert_eq!(d(std::f64::INFINITY).cmp(&d(1e33)), Greater)
}
#[test]
fn case64_b_11() {
assert_eq!(d(0.0).cmp(&d(std::f64::NEG_INFINITY)), Greater)
}
#[test]
fn case64_b_12() {
assert_eq!(d(1.0).cmp(&d(std::f64::NEG_INFINITY)), Greater)
}
#[test]
fn case64_b_13() {
assert_eq!(d(1e33).cmp(&d(std::f64::NEG_INFINITY)), Greater)
}
#[test]
fn case64_c1() {
assert_eq!(d(-0.0).cmp(&d(0.0)), Less)
}
#[test]
fn case64_c2() {
assert_eq!(d(0.0).cmp(&d(-0.0)), Greater)
}
#[test]
fn case64_c3_1() {
assert_eq!(d(-0.0).cmp(&d(-0.0)), Equal)
}
#[test]
fn case64_c3_2() {
assert_eq!(d(0.0).cmp(&d(0.0)), Equal)
}
#[test]
fn case64_c3_3() {
assert_eq!(d(1.0).cmp(&d(1.0)), Equal)
}
#[test]
fn case64_c3_4() {
assert_eq!(d(-1.0).cmp(&d(-1.0)), Equal)
}
#[test]
fn case64_c3_5() {
assert_eq!(d(-1e32).cmp(&d(-1e32)), Equal)
}
#[test]
fn case64_c3_6() {
assert_eq!(d(1e33).cmp(&d(1e33)), Equal)
}
}
#[cfg(test)]
mod value_tests {
use super::dom::Dom;
use crate::value::{repr::Record, signed_integer::SignedInteger, PlainValue, Value};
type VV = Value<PlainValue<Dom>>;
#[test]
fn boolean_mut() {
let mut b = VV::Boolean(true);
assert!(b.is_boolean());
*(b.as_boolean_mut().unwrap()) = false;
assert_eq!(b, VV::Boolean(false));
}
#[test]
fn double_mut() {
let mut f = VV::from(1.0);
assert!(f.is_f64());
*(f.as_f64_mut().unwrap()) = 123.45;
assert_eq!(f, VV::from(123.45));
assert_eq!(
(f.as_f64().unwrap() - 123.45).abs() < std::f64::EPSILON,
true
);
}
#[test]
fn signedinteger_mut() {
let mut i = VV::from(123);
assert!(i.is_signedinteger());
*(i.as_signedinteger_mut().unwrap()) = SignedInteger::from(234i128);
assert_eq!(i, VV::from(234));
assert_eq!(i.as_i().unwrap(), 234);
}
#[test]
fn string_mut() {
let mut s = VV::from("hello, world!");
assert!(s.is_string());
s.as_string_mut().unwrap().replace_range(7..12, "there");
assert_eq!(s, VV::from("hello, there!"));
}
#[test]
fn bytes_mut() {
let mut b = VV::from(&b"hello, world!"[..]);
assert!(b.is_bytestring());
b.as_bytestring_mut()
.unwrap()
.splice(7..12, Vec::from(&b"there"[..]));
assert_eq!(b, VV::from(&b"hello, there!"[..]));
}
#[test]
fn symbol_mut() {
let mut s = VV::symbol("abcd");
assert!(s.is_symbol());
s.as_symbol_mut().unwrap().replace_range(..2, "AB");
assert_eq!(s, VV::symbol("ABcd"));
}
#[test]
fn record_mut() {
let says = VV::symbol("says").wrap();
let mut r = VV::Record(Record(vec![
says.clone(),
VV::from("Tony").wrap(),
VV::from("Hello!").wrap(),
]));
assert_eq!(r.as_record_mut(Some(0)), None);
assert_eq!(r.as_record_mut(Some(1)), None);
assert!(r.as_record_mut(Some(2)).is_some());
assert_eq!(r.as_record_mut(Some(3)), None);
r.as_record_mut(None).unwrap().fields_mut()[0] = VV::from("Alice").wrap();
assert_eq!(
r,
VV::Record(Record(vec![
says,
VV::from("Alice").wrap(),
VV::from("Hello!").wrap()
]))
);
}
#[test]
fn sequence_mut() {
let mut s = VV::Sequence(vec![
VV::from(1).wrap(),
VV::from(2).wrap(),
VV::from(3).wrap(),
]);
let r = VV::Sequence(vec![
VV::from(1).wrap(),
VV::from(99).wrap(),
VV::from(3).wrap(),
]);
s.as_sequence_mut().unwrap()[1] = VV::from(99).wrap();
assert_eq!(r, s);
}
}
#[cfg(test)]
mod decoder_tests {
use crate::de::from_bytes;
use crate::error::{is_eof_io_error, Error, ExpectedKind};
use crate::value::{BinarySource, BytesBinarySource, ConfiguredReader, NestedValue, Value};
fn expect_number_out_of_range<T: core::fmt::Debug>(r: Result<T, Error>) {
match r {
Ok(v) => panic!("Expected NumberOutOfRange, but got a parse of {:?}", v),
Err(Error::NumberOutOfRange(_)) => (),
Err(e) => panic!("Expected NumberOutOfRange, but got an error of {:?}", e),
}
}
fn expect_expected<T: core::fmt::Debug>(k: ExpectedKind, r: Result<T, Error>) {
match r {
Ok(v) => panic!("Expected Expected({:?}), but got a parse of {:?}", k, v),
Err(Error::Expected(k1, _)) if k1 == k => (),
Err(e) => panic!("Expected Expected({:?}), but got an error of {:?}", k, e),
}
}
#[test]
fn skip_annotations_noskip() {
let buf = &b"\x85\xB0\x01\x02\xB0\x01\x01"[..];
let mut src = BytesBinarySource::new(&buf);
let mut d = ConfiguredReader::new(src.packed_iovalues());
let v = d.demand_next().unwrap();
assert_eq!(v.annotations().slice().len(), 1);
assert_eq!(v.annotations().slice()[0], Value::from(2).wrap());
assert_eq!(v.value(), &Value::from(1));
}
#[test]
fn skip_annotations_skip() {
let buf = &b"\x85\xB0\x01\x02\xB0\x01\x01"[..];
let mut src = BytesBinarySource::new(&buf);
let mut d = ConfiguredReader::new(src.packed_iovalues());
d.set_read_annotations(false);
let v = d.demand_next().unwrap();
assert_eq!(v.annotations().slice().len(), 0);
assert_eq!(v.value(), &Value::from(1));
}
#[test]
fn multiple_values_buf_advanced() {
let buf = &b"\xb4\xb3\x04Ping\x84\xb4\xb3\x04Pong\x84"[..];
assert_eq!(buf.len(), 16);
let mut src = BytesBinarySource::new(&buf);
let mut d = ConfiguredReader::new(src.packed_iovalues());
assert_eq!(d.reader.source.index, 0);
assert_eq!(
d.demand_next().unwrap().value(),
&Value::simple_record0("Ping")
);
assert_eq!(d.reader.source.index, 8);
assert_eq!(
d.demand_next().unwrap().value(),
&Value::simple_record0("Pong")
);
assert_eq!(d.reader.source.index, 16);
assert!(d.next().is_none());
assert!(if let Err(e) = d.demand_next() {
is_eof_io_error(&e)
} else {
false
});
}
#[test]
fn direct_i8_format_a_positive() {
assert_eq!(from_bytes::<i8>(b"\xB0\x01\x01").unwrap(), 1)
}
#[test]
fn direct_i8_format_a_zero() {
assert_eq!(from_bytes::<i8>(b"\xB0\x00").unwrap(), 0)
}
#[test]
fn direct_i8_format_a_negative() {
assert_eq!(from_bytes::<i8>(b"\xB0\x01\xff").unwrap(), -1)
}
#[test]
fn direct_i8_format_b() {
assert_eq!(from_bytes::<i8>(b"\xb0\x01\xfe").unwrap(), -2)
}
#[test]
fn direct_i8_format_b_too_long() {
assert_eq!(from_bytes::<i8>(b"\xb0\x03\xff\xff\xfe").unwrap(), -2)
}
#[test]
fn direct_i8_format_b_much_too_long() {
assert_eq!(
from_bytes::<i8>(b"\xb0\x0a\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe").unwrap(),
-2
)
}
#[test]
fn direct_u8_format_a_positive() {
assert_eq!(from_bytes::<u8>(b"\xB0\x01\x01").unwrap(), 1)
}
#[test]
fn direct_u8_format_a_zero() {
assert_eq!(from_bytes::<u8>(b"\xB0\x00").unwrap(), 0)
}
#[test]
fn direct_u8_format_b() {
assert_eq!(from_bytes::<u8>(b"\xb0\x011").unwrap(), 49)
}
#[test]
fn direct_u8_format_b_too_long() {
assert_eq!(from_bytes::<u8>(b"\xb0\x04\0\0\01").unwrap(), 49)
}
#[test]
fn direct_u8_format_b_much_too_long() {
assert_eq!(from_bytes::<u8>(b"\xb0\x0a\0\0\0\0\0\0\0\0\01").unwrap(), 49)
}
#[test]
fn direct_i16_format_a() {
assert_eq!(from_bytes::<i16>(b"\xB0\x01\xfe").unwrap(), -2)
}
#[test]
fn direct_i16_format_b() {
assert_eq!(from_bytes::<i16>(b"\xb0\x02\xfe\xff").unwrap(), -257)
}
#[test]
fn direct_u8_wrong_format() {
expect_expected(
ExpectedKind::SignedInteger,
from_bytes::<u8>(b"\xb1\x05bogus"),
)
}
#[test]
fn direct_u8_format_b_too_large() {
expect_number_out_of_range(from_bytes::<u8>(b"\xb0\x04\0\011"))
}
#[test]
fn direct_i8_format_b_too_large() {
expect_number_out_of_range(from_bytes::<i8>(b"\xb0\x02\xfe\xff"))
}
#[test]
fn direct_i16_format_b_too_large() {
expect_number_out_of_range(from_bytes::<i16>(b"\xb0\x03\xfe\xff\xff"));
}
#[test]
fn direct_i32_format_b_ok() {
assert_eq!(from_bytes::<i32>(b"\xb0\x03\xfe\xff\xff").unwrap(), -65537);
}
#[test]
fn direct_i32_format_b_ok_2() {
assert_eq!(
from_bytes::<i32>(b"\xb0\x04\xfe\xff\xff\xff").unwrap(),
-16777217
);
}
#[test]
fn direct_i64_format_b() {
assert_eq!(from_bytes::<i64>(b"\xb0\x01\xff").unwrap(), -1);
assert_eq!(from_bytes::<i64>(b"\xb0\x03\xff\xff\xff").unwrap(), -1);
assert_eq!(
from_bytes::<i64>(b"\xb0\x0a\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff").unwrap(),
-1
);
assert_eq!(from_bytes::<i64>(b"\xb0\x01\xfe").unwrap(), -2);
assert_eq!(from_bytes::<i64>(b"\xb0\x03\xff\xfe\xff").unwrap(), -257);
assert_eq!(from_bytes::<i64>(b"\xb0\x03\xfe\xff\xff").unwrap(), -65537);
assert_eq!(
from_bytes::<i64>(b"\xb0\x0a\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff").unwrap(),
-16777217
);
assert_eq!(
from_bytes::<i64>(b"\xb0\x0a\xff\xff\xfe\xff\xff\xff\xff\xff\xff\xff").unwrap(),
-72057594037927937
);
expect_number_out_of_range(from_bytes::<i64>(
b"\xb0\x0a\xff\xff\x0e\xff\xff\xff\xff\xff\xff\xff",
));
expect_number_out_of_range(from_bytes::<i64>(
b"\xb0\x09\xff\x0e\xff\xff\xff\xff\xff\xff\xff",
));
expect_number_out_of_range(from_bytes::<i64>(
b"\xb0\x09\x80\x0e\xff\xff\xff\xff\xff\xff\xff",
));
expect_number_out_of_range(from_bytes::<i64>(
b"\xb0\x0a\xff\x00\x0e\xff\xff\xff\xff\xff\xff\xff",
));
assert_eq!(
from_bytes::<i64>(b"\xb0\x08\xfe\xff\xff\xff\xff\xff\xff\xff").unwrap(),
-72057594037927937
);
assert_eq!(
from_bytes::<i64>(b"\xb0\x08\x0e\xff\xff\xff\xff\xff\xff\xff").unwrap(),
1080863910568919039
);
assert_eq!(
from_bytes::<i64>(b"\xb0\x08\x80\0\0\0\0\0\0\0").unwrap(),
-9223372036854775808
);
assert_eq!(from_bytes::<i64>(b"\xb0\x08\0\0\0\0\0\0\0\0").unwrap(), 0);
assert_eq!(from_bytes::<i64>(b"\xB0\x00").unwrap(), 0);
assert_eq!(
from_bytes::<i64>(b"\xb0\x08\x7f\xff\xff\xff\xff\xff\xff\xff").unwrap(),
9223372036854775807
);
}
#[test]
fn direct_u64_format_b() {
expect_number_out_of_range(from_bytes::<u64>(b"\xb0\x01\xff"));
assert_eq!(from_bytes::<u64>(b"\xb0\x02\0\xff").unwrap(), 255);
expect_number_out_of_range(from_bytes::<u64>(b"\xb0\x03\xff\xff\xff"));
assert_eq!(from_bytes::<u64>(b"\xb0\x04\0\xff\xff\xff").unwrap(), 0xffffff);
expect_number_out_of_range(from_bytes::<u64>(
b"\xb0\x0a\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
));
assert_eq!(from_bytes::<u64>(b"\xb0\x01\x02").unwrap(), 2);
assert_eq!(from_bytes::<u64>(b"\xb0\x03\x00\x01\x00").unwrap(), 256);
assert_eq!(from_bytes::<u64>(b"\xb0\x03\x01\x00\x00").unwrap(), 65536);
assert_eq!(
from_bytes::<u64>(b"\xb0\x0a\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00").unwrap(),
16777216
);
assert_eq!(
from_bytes::<u64>(b"\xb0\x0a\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00").unwrap(),
72057594037927936
);
assert_eq!(
from_bytes::<u64>(b"\xb0\x0a\x00\x00\xf2\x00\x00\x00\x00\x00\x00\x00").unwrap(),
0xf200000000000000
);
assert_eq!(
from_bytes::<u64>(b"\xb0\x0a\x00\x00\x72\x00\x00\x00\x00\x00\x00\x00").unwrap(),
0x7200000000000000
);
expect_number_out_of_range(from_bytes::<u64>(
b"\xb0\x0a\x00\xf2\x00\x00\x00\x00\x00\x00\x00\x00",
));
assert_eq!(
from_bytes::<u64>(b"\xb0\x09\x00\xf2\x00\x00\x00\x00\x00\x00\x00").unwrap(),
0xf200000000000000
);
expect_number_out_of_range(from_bytes::<u64>(
b"\xb0\x09\x7f\xf2\x00\x00\x00\x00\x00\x00\x00",
));
expect_number_out_of_range(from_bytes::<u64>(
b"\xb0\x0a\x00\xff\xf2\x00\x00\x00\x00\x00\x00\x00",
));
assert_eq!(
from_bytes::<u64>(b"\xb0\x08\x01\x00\x00\x00\x00\x00\x00\x00").unwrap(),
72057594037927936
);
assert_eq!(
from_bytes::<u64>(b"\xb0\x08\x0e\xff\xff\xff\xff\xff\xff\xff").unwrap(),
1080863910568919039
);
expect_number_out_of_range(from_bytes::<u64>(b"\xb0\x08\x80\0\0\0\0\0\0\0"));
assert_eq!(
from_bytes::<u64>(b"\xb0\x09\0\x80\0\0\0\0\0\0\0").unwrap(),
9223372036854775808
);
assert_eq!(from_bytes::<u64>(b"\xb0\x08\0\0\0\0\0\0\0\0").unwrap(), 0);
assert_eq!(from_bytes::<u64>(b"\xB0\x00").unwrap(), 0);
assert_eq!(
from_bytes::<u64>(b"\xb0\x08\x7f\xff\xff\xff\xff\xff\xff\xff").unwrap(),
9223372036854775807
);
}
}
#[cfg(test)]
mod formatting_tests {
use super::dom::Dom;
use super::value::ArcValue;
use super::value::IOValue;
use super::value::Value;
#[test]
fn format_debug_and_parse() {
let v = "[1, {z: 2, a: #!\"One\"}, 3]"
.parse::<Value<ArcValue<Dom>>>()
.unwrap();
assert_eq!(format!("{:?}", &v), "[1, {a: #!\"One\", z: 2}, 3]");
}
#[test]
fn format_pretty_debug_and_parse() {
let v = "[1, {z: 2, a: #!\"One\"}, 3]"
.parse::<Value<ArcValue<Dom>>>()
.unwrap();
assert_eq!(
format!("{:#?}", &v),
concat!(
"[\n",
" 1,\n",
" {\n",
" a: #!\"One\",\n",
" z: 2\n",
" },\n",
" 3\n",
"]"
)
);
}
#[test]
fn iovalue_parse() {
let v = "[1 @{a:b c:d} @\"foo\" #![2 3] 4]"
.parse::<IOValue>()
.unwrap();
assert_eq!(
format!("{:#?}", &v),
concat!(
"[\n",
" 1,\n",
" @{\n",
" a: b,\n",
" c: d\n",
" } @\"foo\" #![\n",
" 2,\n",
" 3\n",
" ],\n",
" 4\n",
"]"
)
);
}
}
#[cfg(test)]
mod serde_tests {
use crate::de::from_bytes as deserialize_from_bytes;
use crate::symbol::Symbol;
use crate::value::de::from_value as deserialize_from_value;
use crate::value::packed::PackedWriter;
use crate::value::to_value;
use crate::value::{IOValue, Map, Set, Value};
#[test]
fn simple_to_value() {
use serde::Serialize;
#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
struct Colour {
red: u8,
green: u8,
blue: u8,
}
#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
struct SimpleValue<'a>(
String,
#[serde(with = "crate::symbol")] String,
Symbol,
#[serde(with = "crate::symbol")] String,
Symbol,
&'a str,
#[serde(with = "serde_bytes")] &'a [u8],
#[serde(with = "serde_bytes")] Vec<u8>,
Vec<bool>,
#[serde(with = "crate::set")] Set<String>,
i16,
IOValue,
Map<String, Colour>,
f32,
f64,
);
let mut str_set = Set::new();
str_set.insert("one".to_owned());
str_set.insert("two".to_owned());
str_set.insert("three".to_owned());
let mut colours = Map::new();
colours.insert(
"red".to_owned(),
Colour {
red: 255,
green: 0,
blue: 0,
},
);
colours.insert(
"green".to_owned(),
Colour {
red: 0,
green: 255,
blue: 0,
},
);
colours.insert(
"blue".to_owned(),
Colour {
red: 0,
green: 0,
blue: 255,
},
);
let v = SimpleValue(
"hello".to_string(),
"sym1".to_string(),
Symbol("sym2".to_string()),
"sym3".to_string(),
Symbol("sym4".to_string()),
"world",
&b"slice"[..],
b"vec".to_vec(),
vec![false, true, false, true],
str_set,
12345,
Value::from("hi").wrap(),
colours,
12.345f32,
12.3456789,
);
println!("== v: {:#?}", v);
let w: IOValue = to_value(&v);
println!("== w: {:#?}", w);
let x = deserialize_from_value(&w).unwrap();
println!("== x: {:#?}", &x);
assert_eq!(v, x);
let expected_bytes = vec![
0xb4, // Struct
0xb3, 0x0b, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75,
0x65, // SimpleValue
0xb1, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, // "hello"
0xb3, 0x04, 0x73, 0x79, 0x6d, 0x31, // sym1
0xb3, 0x04, 0x73, 0x79, 0x6d, 0x32, // sym2
0xb3, 0x04, 0x73, 0x79, 0x6d, 0x33, // sym3
0xb3, 0x04, 0x73, 0x79, 0x6d, 0x34, // sym4
0xb1, 0x05, 0x77, 0x6f, 0x72, 0x6c, 0x64, // "world"
0xb2, 0x05, 0x73, 0x6c, 0x69, 0x63, 0x65, // #"slice"
0xb2, 0x03, 0x76, 0x65, 0x63, // #"vec"
0xb5, // Sequence
0x80, // false
0x81, // true
0x80, // false
0x81, // true
0x84, 0xb6, // Set
0xb1, 0x03, 0x6f, 0x6e, 0x65, 0xb1, 0x03, 0x74, 0x77, 0x6f, 0xb1, 0x05, 0x74, 0x68,
0x72, 0x65, 0x65, 0x84, 0xb0, 0x02, 0x30, 0x39, // 12345
0xb1, 0x02, 0x68, 0x69, // "hi"
0xb7, // Dictionary
0xb1, 0x03, 0x72, 0x65, 0x64, // "red"
0xb4, 0xb3, 0x06, 0x43, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0xb0, 0x02, 0x00, 0xff, 0xb0, 0x00, 0xb0, 0x00,
0x84, 0xb1, 0x04, 0x62, 0x6c, 0x75, 0x65, // "blue"
0xb4, 0xb3, 0x06, 0x43, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0xb0, 0x00, 0xb0, 0x00, 0xb0, 0x02, 0x00, 0xff,
0x84, 0xb1, 0x05, 0x67, 0x72, 0x65, 0x65, 0x6e, // "green"
0xb4, 0xb3, 0x06, 0x43, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0xb0, 0x00, 0xb0, 0x02, 0x00, 0xff, 0xb0, 0x00,
0x84, 0x84,
0x87, 0x08, 0x40, 0x28, 0xb0, 0xa3, 0xe0, 0x00, 0x00, 0x00, // 12.345f32
0x87, 0x08, 0x40, 0x28, 0xb0, 0xfc, 0xd3, 0x24, 0xd5, 0xa2, // 12.3456789
0x84,
];
let y = deserialize_from_bytes(&expected_bytes).unwrap();
println!("== y: {:#?}", &y);
assert_eq!(v, y);
let v_bytes_1 = PackedWriter::encode_iovalue(&w).unwrap();
println!("== w bytes = {:?}", v_bytes_1);
assert_eq!(expected_bytes, v_bytes_1);
let mut v_bytes_2 = Vec::new();
v.serialize(&mut crate::ser::Serializer::new(&mut PackedWriter::new(
&mut v_bytes_2,
)))
.unwrap();
println!("== v bytes = {:?}", v_bytes_2);
assert_eq!(v_bytes_1, v_bytes_2);
}
}

View File

@ -1,458 +0,0 @@
//! Support for Serde serialization of Rust data types into Preserves terms.
use super::value::boundary as B;
use super::value::writer::{CompoundWriter, Writer};
use super::value::IOValueDomainCodec;
use serde::Serialize;
pub use super::error::Error;
type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
/// Serde serializer for Preserves-encoding Rust data. Construct via [Serializer::new], and use
/// with [serde::Serialize::serialize] methods.
pub struct Serializer<'w, W: Writer> {
/// The underlying Preserves [writer][crate::value::writer::Writer].
pub write: &'w mut W,
}
impl<'w, W: Writer> Serializer<'w, W> {
/// Construct a new [Serializer] targetting the given
/// [writer][crate::value::writer::Writer].
pub fn new(write: &'w mut W) -> Self {
Serializer { write }
}
}
enum SequenceVariant<W: Writer> {
Sequence(W::SeqWriter),
Record(W::RecWriter),
}
#[doc(hidden)]
pub struct SerializeCompound<'a, 'w, W: Writer> {
b: B::Type,
i: B::Item,
ser: &'a mut Serializer<'w, W>,
c: SequenceVariant<W>,
}
#[doc(hidden)]
pub struct SerializeDictionary<'a, 'w, W: Writer> {
b: B::Type,
ser: &'a mut Serializer<'w, W>,
d: W::DictWriter,
}
impl<'a, 'w, W: Writer> serde::Serializer for &'a mut Serializer<'w, W> {
type Ok = ();
type Error = Error;
type SerializeSeq = SerializeCompound<'a, 'w, W>;
type SerializeTuple = SerializeCompound<'a, 'w, W>;
type SerializeTupleStruct = SerializeCompound<'a, 'w, W>;
type SerializeTupleVariant = SerializeCompound<'a, 'w, W>;
type SerializeMap = SerializeDictionary<'a, 'w, W>;
type SerializeStruct = SerializeCompound<'a, 'w, W>;
type SerializeStructVariant = SerializeCompound<'a, 'w, W>;
fn serialize_bool(self, v: bool) -> Result<Self::Ok> {
Ok(self.write.write_bool(v)?)
}
fn serialize_i8(self, v: i8) -> Result<Self::Ok> {
Ok(self.write.write_i8(v)?)
}
fn serialize_i16(self, v: i16) -> Result<Self::Ok> {
Ok(self.write.write_i16(v)?)
}
fn serialize_i32(self, v: i32) -> Result<Self::Ok> {
Ok(self.write.write_i32(v)?)
}
fn serialize_i64(self, v: i64) -> Result<Self::Ok> {
Ok(self.write.write_i64(v)?)
}
fn serialize_u8(self, v: u8) -> Result<Self::Ok> {
Ok(self.write.write_u8(v)?)
}
fn serialize_u16(self, v: u16) -> Result<Self::Ok> {
Ok(self.write.write_u16(v)?)
}
fn serialize_u32(self, v: u32) -> Result<Self::Ok> {
Ok(self.write.write_u32(v)?)
}
fn serialize_u64(self, v: u64) -> Result<Self::Ok> {
Ok(self.write.write_u64(v)?)
}
fn serialize_f32(self, v: f32) -> Result<Self::Ok> {
Ok(self.write.write_f64(v as f64)?)
}
fn serialize_f64(self, v: f64) -> Result<Self::Ok> {
Ok(self.write.write_f64(v)?)
}
fn serialize_char(self, v: char) -> Result<Self::Ok> {
let mut c = self.write.start_record(Some(1))?;
c.boundary(&B::start(B::Item::RecordLabel))?;
c.write_symbol("UnicodeScalar")?;
c.boundary(&B::mid(B::Item::RecordLabel, B::Item::RecordField))?;
c.write_u32(v as u32)?;
c.boundary(&B::end(B::Item::RecordField))?;
Ok(self.write.end_record(c)?)
}
fn serialize_str(self, v: &str) -> Result<Self::Ok> {
Ok(self.write.write_string(v)?)
}
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok> {
Ok(self.write.write_bytes(v)?)
}
fn serialize_none(self) -> Result<Self::Ok> {
let mut c = self.write.start_record(Some(0))?;
c.boundary(&B::start(B::Item::RecordLabel))?;
c.write_symbol("None")?;
c.boundary(&B::end(B::Item::RecordLabel))?;
Ok(self.write.end_record(c)?)
}
fn serialize_some<T: ?Sized>(self, v: &T) -> Result<Self::Ok>
where
T: Serialize,
{
let mut c = self.write.start_record(Some(1))?;
c.boundary(&B::start(B::Item::RecordLabel))?;
c.write_symbol("Some")?;
c.boundary(&B::mid(B::Item::RecordLabel, B::Item::RecordField))?;
to_writer(&mut c, v)?;
c.boundary(&B::end(B::Item::RecordField))?;
Ok(self.write.end_record(c)?)
}
fn serialize_unit(self) -> Result<Self::Ok> {
let mut c = self.write.start_record(Some(0))?;
c.boundary(&B::start(B::Item::RecordLabel))?;
c.write_symbol("tuple")?;
c.boundary(&B::end(B::Item::RecordLabel))?;
Ok(self.write.end_record(c)?)
}
fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok> {
let mut c = self.write.start_record(Some(0))?;
c.boundary(&B::start(B::Item::RecordLabel))?;
c.write_symbol(name)?;
c.boundary(&B::end(B::Item::RecordLabel))?;
Ok(self.write.end_record(c)?)
}
fn serialize_unit_variant(
self,
_name: &'static str,
_variant: u32,
variant_name: &'static str,
) -> Result<Self::Ok> {
let mut c = self.write.start_record(Some(0))?;
c.boundary(&B::start(B::Item::RecordLabel))?;
c.write_symbol(variant_name)?;
c.boundary(&B::end(B::Item::RecordLabel))?;
Ok(self.write.end_record(c)?)
}
fn serialize_newtype_struct<T: ?Sized>(self, name: &'static str, value: &T) -> Result<Self::Ok>
where
T: Serialize,
{
match super::value::magic::receive_output_value(name, value) {
Some(v) => Ok(self.write.write(&mut IOValueDomainCodec, &v)?),
None => {
// TODO: This is apparently discouraged, and we should apparently just serialize `value`?
let mut c = self.write.start_record(Some(1))?;
c.boundary(&B::start(B::Item::RecordLabel))?;
c.write_symbol(name)?;
c.boundary(&B::mid(B::Item::RecordLabel, B::Item::RecordField))?;
to_writer(&mut c, value)?;
c.boundary(&B::end(B::Item::RecordField))?;
Ok(self.write.end_record(c)?)
}
}
}
fn serialize_newtype_variant<T: ?Sized>(
self,
_name: &'static str,
_variant: u32,
variant_name: &'static str,
value: &T,
) -> Result<Self::Ok>
where
T: Serialize,
{
let mut c = self.write.start_record(Some(1))?;
c.boundary(&B::start(B::Item::RecordLabel))?;
c.write_symbol(variant_name)?;
c.boundary(&B::mid(B::Item::RecordLabel, B::Item::RecordField))?;
to_writer(&mut c, value)?;
c.boundary(&B::end(B::Item::RecordField))?;
Ok(self.write.end_record(c)?)
}
fn serialize_seq(self, count: Option<usize>) -> Result<Self::SerializeSeq> {
let c = self.write.start_sequence(count)?;
Ok(SerializeCompound::seq(self, c))
}
fn serialize_tuple(self, count: usize) -> Result<Self::SerializeTuple> {
let mut c = self.write.start_record(Some(count))?;
c.boundary(&B::start(B::Item::RecordLabel))?;
c.write_symbol("tuple")?;
Ok(SerializeCompound::rec(self, c))
}
fn serialize_tuple_struct(
self,
name: &'static str,
count: usize,
) -> Result<Self::SerializeTupleStruct> {
let mut c = self.write.start_record(Some(count))?;
c.boundary(&B::start(B::Item::RecordLabel))?;
c.write_symbol(name)?;
Ok(SerializeCompound::rec(self, c))
}
fn serialize_tuple_variant(
self,
_name: &'static str,
_variant: u32,
variant_name: &'static str,
count: usize,
) -> Result<Self::SerializeTupleVariant> {
let mut c = self.write.start_record(Some(count))?;
c.boundary(&B::start(B::Item::RecordLabel))?;
c.write_symbol(variant_name)?;
Ok(SerializeCompound::rec(self, c))
}
fn serialize_map(self, count: Option<usize>) -> Result<Self::SerializeMap> {
let d = self.write.start_dictionary(count)?;
Ok(SerializeDictionary {
b: B::Type::default(),
ser: self,
d,
})
}
fn serialize_struct(self, name: &'static str, count: usize) -> Result<Self::SerializeStruct> {
let mut c = self.write.start_record(Some(count))?;
c.boundary(&B::start(B::Item::RecordLabel))?;
c.write_symbol(name)?;
Ok(SerializeCompound::rec(self, c))
}
fn serialize_struct_variant(
self,
_name: &'static str,
_variant: u32,
variant_name: &'static str,
count: usize,
) -> Result<Self::SerializeStructVariant> {
let mut c = self.write.start_record(Some(count))?;
c.boundary(&B::start(B::Item::RecordLabel))?;
c.write_symbol(variant_name)?;
Ok(SerializeCompound::rec(self, c))
}
}
impl<'a, 'w, W: Writer> serde::ser::SerializeMap for SerializeDictionary<'a, 'w, W> {
type Ok = ();
type Error = Error;
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<()>
where
T: Serialize,
{
self.b.opening = Some(B::Item::DictionaryKey);
self.d.boundary(&self.b)?;
to_writer(&mut self.d, key)?;
self.b.shift(None);
Ok(())
}
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<()>
where
T: Serialize,
{
self.b.opening = Some(B::Item::DictionaryValue);
self.d.boundary(&self.b)?;
to_writer(&mut self.d, value)?;
self.b.shift(None);
Ok(())
}
fn end(mut self) -> Result<Self::Ok> {
self.d.boundary(&self.b)?;
Ok(self.ser.write.end_dictionary(self.d)?)
}
}
impl<'a, 'w, W: Writer> SerializeCompound<'a, 'w, W> {
fn seq(ser: &'a mut Serializer<'w, W>, c: W::SeqWriter) -> Self {
SerializeCompound {
b: B::Type::default(),
i: B::Item::SequenceValue,
ser,
c: SequenceVariant::Sequence(c),
}
}
fn rec(ser: &'a mut Serializer<'w, W>, c: W::RecWriter) -> Self {
SerializeCompound {
b: B::end(B::Item::RecordLabel),
i: B::Item::RecordField,
ser,
c: SequenceVariant::Record(c),
}
}
fn extend<T: ?Sized>(&mut self, value: &T) -> Result<()>
where
T: Serialize,
{
self.b.opening = Some(self.i.clone());
match &mut self.c {
SequenceVariant::Sequence(w) => {
w.boundary(&self.b)?;
to_writer(w, value)?;
}
SequenceVariant::Record(w) => {
w.boundary(&self.b)?;
to_writer(w, value)?;
}
}
self.b.shift(None);
Ok(())
}
fn complete(self) -> Result<()> {
match self.c {
SequenceVariant::Sequence(mut w) => {
w.boundary(&self.b)?;
Ok(self.ser.write.end_sequence(w)?)
}
SequenceVariant::Record(mut w) => {
w.boundary(&self.b)?;
Ok(self.ser.write.end_record(w)?)
}
}
}
}
impl<'a, 'w, W: Writer> serde::ser::SerializeStruct for SerializeCompound<'a, 'w, W> {
type Ok = ();
type Error = Error;
fn serialize_field<T: ?Sized>(&mut self, _name: &'static str, value: &T) -> Result<()>
where
T: Serialize,
{
self.extend(value)
}
fn end(self) -> Result<Self::Ok> {
self.complete()
}
}
impl<'a, 'w, W: Writer> serde::ser::SerializeStructVariant for SerializeCompound<'a, 'w, W> {
type Ok = ();
type Error = Error;
fn serialize_field<T: ?Sized>(&mut self, _name: &'static str, value: &T) -> Result<()>
where
T: Serialize,
{
self.extend(value)
}
fn end(self) -> Result<Self::Ok> {
self.complete()
}
}
impl<'a, 'w, W: Writer> serde::ser::SerializeTuple for SerializeCompound<'a, 'w, W> {
type Ok = ();
type Error = Error;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<()>
where
T: Serialize,
{
self.extend(value)
}
fn end(self) -> Result<Self::Ok> {
self.complete()
}
}
impl<'a, 'w, W: Writer> serde::ser::SerializeTupleStruct for SerializeCompound<'a, 'w, W> {
type Ok = ();
type Error = Error;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<()>
where
T: Serialize,
{
self.extend(value)
}
fn end(self) -> Result<Self::Ok> {
self.complete()
}
}
impl<'a, 'w, W: Writer> serde::ser::SerializeTupleVariant for SerializeCompound<'a, 'w, W> {
type Ok = ();
type Error = Error;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<()>
where
T: Serialize,
{
self.extend(value)
}
fn end(self) -> Result<Self::Ok> {
self.complete()
}
}
impl<'a, 'w, W: Writer> serde::ser::SerializeSeq for SerializeCompound<'a, 'w, W> {
type Ok = ();
type Error = Error;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<()>
where
T: Serialize,
{
self.extend(value)
}
fn end(self) -> Result<Self::Ok> {
self.complete()
}
}
/// Convenience function for directly serializing a Serde-serializable `T` to the given
/// `write`, a Preserves [writer][crate::value::writer::Writer].
pub fn to_writer<W: Writer, T: Serialize + ?Sized>(write: &mut W, value: &T) -> Result<()> {
Ok(value.serialize(&mut Serializer::new(write))?)
}

View File

@ -1,42 +0,0 @@
//! Serde support for serializing Rust collections as Preserves sets.
//!
//! Serde doesn't include sets in its data model, so we do some somewhat awful tricks to force
//! things to come out the way we want them.
//!
//! # Example
//!
//! Annotate collection-valued fields that you want to (en|de)code as Preserves `Set`s with
//! `#[serde(with = "preserves::set")]`:
//!
//! ```rust
//! #[derive(serde::Serialize, serde::Deserialize)]
//! struct Example {
//! #[serde(with = "preserves::set")]
//! items: preserves::value::Set<String>,
//! }
//! ```
use crate::value::{self, to_value, IOValue, UnwrappedIOValue};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::iter::IntoIterator;
#[doc(hidden)]
pub fn serialize<S, T, Item>(s: T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: IntoIterator<Item = Item>,
Item: Serialize,
{
let s = s.into_iter().map(to_value).collect::<value::Set<IOValue>>();
UnwrappedIOValue::from(s).wrap().serialize(serializer)
}
#[doc(hidden)]
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
// Relies on the way we hack around serde's data model in de.rs and value/de.rs.
T::deserialize(deserializer)
}

View File

@ -1,65 +0,0 @@
//! Serde support for serializing Rust data as Preserves symbols.
//!
//! Serde doesn't include symbols in its data model, so we do some somewhat awful tricks to
//! force things to come out the way we want them.
//!
//! # Example
//!
//! Either use [Symbol] directly in your data types, or annotate [String]-valued fields that
//! you want to (en|de)code as Preserves `Symbol`s with `#[serde(with = "preserves::symbol")]`:
//!
//! ```rust
//! #[derive(serde::Serialize, serde::Deserialize)]
//! struct Example {
//! sym1: preserves::symbol::Symbol,
//! #[serde(with = "preserves::symbol")]
//! sym2: String,
//! }
//! ```
use crate::value::{IOValue, NestedValue};
/// Wrapper for a string to coerce its Preserves-serialization to `Symbol`.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Symbol(pub String);
impl serde::Serialize for Symbol {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
IOValue::symbol(&self.0).serialize(serializer)
}
}
impl<'de> serde::Deserialize<'de> for Symbol {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let v = IOValue::deserialize(deserializer)?;
let s = v
.value()
.as_symbol()
.ok_or_else(|| serde::de::Error::custom("Expected symbol"))?;
Ok(Symbol(s.clone()))
}
}
#[doc(hidden)]
pub fn serialize<S>(s: &str, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::Serialize;
Symbol(s.to_string()).serialize(serializer)
}
#[doc(hidden)]
pub fn deserialize<'de, D>(deserializer: D) -> Result<String, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::Deserialize;
Symbol::deserialize(deserializer).map(|v| v.0)
}

View File

@ -1,48 +0,0 @@
#![doc(hidden)]
#[derive(Default, Clone, Debug)]
pub struct Type {
pub closing: Option<Item>,
pub opening: Option<Item>,
}
#[derive(Clone, Debug)]
pub enum Item {
Annotation,
AnnotatedValue,
DictionaryKey,
DictionaryValue,
RecordField,
RecordLabel,
SequenceValue,
SetValue,
}
impl Type {
#[inline]
pub fn shift(&mut self, i: Option<Item>) {
let tmp = std::mem::replace(&mut self.opening, i);
self.closing = tmp;
}
}
pub fn start(i: Item) -> Type {
Type {
closing: None,
opening: Some(i),
}
}
pub fn mid(c: Item, o: Item) -> Type {
Type {
closing: Some(c),
opening: Some(o),
}
}
pub fn end(i: Item) -> Type {
Type {
closing: Some(i),
opening: None,
}
}

View File

@ -1,465 +0,0 @@
//! Support Serde deserialization of Rust data types from Preserves *values* (not syntax).
use crate::error::{Error, ExpectedKind, Received};
use crate::value::repr::Double;
use crate::value::{IOValue, Map, NestedValue, UnwrappedIOValue, Value};
use serde::de::{DeserializeSeed, EnumAccess, MapAccess, SeqAccess, VariantAccess, Visitor};
use serde::Deserialize;
use std::iter::Iterator;
pub type Result<T> = std::result::Result<T, Error>;
/// Serde deserializer for constructing Rust data from an in-memory Preserves value. Use
/// [Deserializer::from_value] to construct instances, or [from_value] to deserialize single
/// values directly.
pub struct Deserializer<'de> {
input: &'de IOValue,
}
/// Deserialize a `T` from `v`, a Preserves [IOValue].
pub fn from_value<'a, T>(v: &'a IOValue) -> Result<T>
where
T: Deserialize<'a>,
{
let mut de = Deserializer::from_value(v);
let t = T::deserialize(&mut de)?;
Ok(t)
}
impl<'de> Deserializer<'de> {
/// Construct a Deserializer from `v`, an [IOValue].
pub fn from_value(v: &'de IOValue) -> Self {
Deserializer { input: v }
}
fn check<'a, T, F>(&'a mut self, f: F, k: ExpectedKind) -> Result<T>
where
F: FnOnce(&'de UnwrappedIOValue) -> Option<T>,
{
f(self.input.value()).ok_or_else(|| {
Error::Expected(k, Received::ReceivedOtherValue(format!("{:?}", self.input)))
})
}
}
impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut Deserializer<'de> {
type Error = Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let v = self.input.value();
match v {
Value::Boolean(b) => visitor.visit_bool(*b),
Value::Double(Double(d)) => visitor.visit_f64(*d),
Value::String(ref s) => visitor.visit_str(&s),
Value::ByteString(_) => self.deserialize_bytes(visitor),
Value::Record(_) => {
if v.is_simple_record("tuple", Some(0)) {
self.deserialize_unit(visitor)
} else if v.is_simple_record("UnicodeScalar", Some(1)) {
self.deserialize_char(visitor)
} else if v.is_simple_record("None", Some(0)) || v.is_simple_record("Some", Some(1))
{
self.deserialize_option(visitor)
} else if v.is_simple_record("tuple", None) {
visitor.visit_seq(VecSeq::new(
self,
v.as_simple_record("tuple", None).unwrap().iter(),
))
} else {
Err(Error::CannotDeserializeAny)
}
}
Value::Sequence(ref v) => visitor.visit_seq(VecSeq::new(self, v.iter())),
Value::Dictionary(ref d) => visitor.visit_map(DictMap::new(self, d)),
_ => match v.as_i64() {
Some(i) => visitor.visit_i64(i),
None => match v.as_u64() {
Some(u) => visitor.visit_u64(u),
None => match v.as_signedinteger() {
Some(n) => Err(Error::NumberOutOfRange(n.into())),
None => Err(Error::CannotDeserializeAny),
},
},
},
}
}
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_bool(self.input.value().to_boolean()?)
}
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_i8(self.input.value().to_i8()?)
}
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_i16(self.input.value().to_i16()?)
}
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_i32(self.input.value().to_i32()?)
}
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_i64(self.input.value().to_i64()?)
}
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_u8(self.input.value().to_u8()?)
}
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_u16(self.input.value().to_u16()?)
}
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_u32(self.input.value().to_u32()?)
}
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_u64(self.input.value().to_u64()?)
}
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_f32(self.input.value().to_f64()? as f32)
}
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_f64(self.input.value().to_f64()?)
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_char(self.input.value().to_char()?)
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let s: &'de str = &self.input.value().to_string()?;
visitor.visit_borrowed_str(s)
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let bs: &'de [u8] = &self.input.value().to_bytestring()?;
visitor.visit_borrowed_bytes(bs)
}
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_byte_buf(self.input.value().to_bytestring()?.clone())
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.input.value().to_option()? {
None => visitor.visit_none(),
Some(v) => {
self.input = v;
visitor.visit_some(self)
}
}
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let _fs = self.input.value().to_simple_record("tuple", Some(0))?;
visitor.visit_unit()
}
fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let _fs = self.input.value().to_simple_record(name, Some(0))?;
visitor.visit_unit()
}
fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match super::magic::transmit_input_value(name, || Ok(self.input.clone()))? {
Some(v) => visitor.visit_u64(v),
None => {
let fs = self.input.value().to_simple_record(name, Some(1))?;
self.input = &fs[0];
visitor.visit_newtype_struct(self)
}
}
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.input.value().as_sequence() {
Some(vs) => visitor.visit_seq(VecSeq::new(self, vs.iter())),
None => {
// Hack around serde's model: Deserialize *sets* as
// sequences, too, and reconstruct them as Rust Sets
// on the visitor side.
visitor.visit_seq(VecSeq::new(self, self.input.value().to_set()?.iter()))
}
}
}
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let fs = self.input.value().to_simple_record("tuple", Some(len))?;
visitor.visit_seq(VecSeq::new(self, fs.iter()))
}
fn deserialize_tuple_struct<V>(
self,
name: &'static str,
len: usize,
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
let fs = self.input.value().to_simple_record(name, Some(len))?;
visitor.visit_seq(VecSeq::new(self, fs.iter()))
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let d = self.input.value().to_dictionary()?;
visitor.visit_map(DictMap::new(self, d))
}
fn deserialize_struct<V>(
self,
name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
let fs = self
.input
.value()
.to_simple_record(name, Some(fields.len()))?;
visitor.visit_seq(VecSeq::new(self, fs.iter()))
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_enum(self)
}
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_str(&self.input.value().to_symbol()?)
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_none()
}
}
#[doc(hidden)]
pub struct VecSeq<'a, 'de: 'a, I: Iterator<Item = &'de IOValue>> {
iter: I,
de: &'a mut Deserializer<'de>,
}
impl<'de, 'a, I: Iterator<Item = &'de IOValue>> VecSeq<'a, 'de, I> {
fn new(de: &'a mut Deserializer<'de>, iter: I) -> Self {
VecSeq { iter, de }
}
}
impl<'de, 'a, I: Iterator<Item = &'de IOValue>> SeqAccess<'de> for VecSeq<'a, 'de, I> {
type Error = Error;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
where
T: DeserializeSeed<'de>,
{
match self.iter.next() {
None => Ok(None),
Some(v) => {
self.de.input = v;
Ok(Some(seed.deserialize(&mut *self.de)?))
}
}
}
}
#[doc(hidden)]
pub struct DictMap<'a, 'de: 'a> {
pending: Option<&'de IOValue>,
iter: Box<dyn Iterator<Item = (&'de IOValue, &'de IOValue)> + 'a>,
de: &'a mut Deserializer<'de>,
}
impl<'de, 'a> DictMap<'a, 'de> {
fn new(de: &'a mut Deserializer<'de>, d: &'de Map<IOValue, IOValue>) -> Self {
DictMap {
pending: None,
iter: Box::new(d.iter()),
de,
}
}
}
impl<'de, 'a> MapAccess<'de> for DictMap<'a, 'de> {
type Error = Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
where
K: DeserializeSeed<'de>,
{
match self.iter.next() {
None => Ok(None),
Some((k, v)) => {
self.pending = Some(v);
self.de.input = k;
Ok(Some(seed.deserialize(&mut *self.de)?))
}
}
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
where
V: DeserializeSeed<'de>,
{
let v = self.pending.unwrap();
self.pending = None;
self.de.input = v;
Ok(seed.deserialize(&mut *self.de)?)
}
}
impl<'a, 'de> EnumAccess<'de> for &'a mut Deserializer<'de> {
type Error = Error;
type Variant = Self;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
where
V: DeserializeSeed<'de>,
{
let r = self.check(|v| v.as_record(None), ExpectedKind::Record(None))?;
let v = self.input;
self.input = r.label();
let variant = seed.deserialize(&mut *self)?;
self.input = v;
Ok((variant, self))
}
}
impl<'a, 'de> VariantAccess<'de> for &'a mut Deserializer<'de> {
type Error = Error;
fn unit_variant(self) -> Result<()> {
Ok(())
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
where
T: DeserializeSeed<'de>,
{
let r = self.check(|v| v.as_record(Some(1)), ExpectedKind::Record(Some(1)))?;
self.input = &r.fields()[0];
seed.deserialize(&mut *self)
}
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_seq(VecSeq::new(
self,
self.input.value().as_record(None).unwrap().fields().iter(),
))
}
fn struct_variant<V>(self, fields: &'static [&'static str], visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_seq(VecSeq::new(
self,
self.input
.value()
.as_record(Some(fields.len()))
.unwrap()
.fields()
.iter(),
))
}
}

View File

@ -1,148 +0,0 @@
//! Traits for working with Preserves [embedded
//! values](https://preserves.dev/preserves.html#embeddeds).
use std::io;
use super::packed;
use super::BinarySource;
use super::BytesBinarySource;
use super::Embeddable;
use super::IOValue;
use super::NestedValue;
use super::Reader;
use super::Writer;
/// Implementations parse [IOValue]s to their own particular [Embeddable] values of type `D`.
pub trait DomainParse<D: Embeddable> {
fn parse_embedded(&mut self, v: &IOValue) -> io::Result<D>;
}
/// Implementations read and parse from `src` to produce [Embeddable] values of type `D`.
pub trait DomainDecode<D: Embeddable> {
fn decode_embedded<'de, 'src, S: BinarySource<'de>>(
&mut self,
src: &'src mut S,
read_annotations: bool,
) -> io::Result<D>;
}
/// Implementations unparse and write `D`s to `w`, a [writer][crate::value::writer::Writer].
pub trait DomainEncode<D: Embeddable> {
fn encode_embedded<W: Writer>(&mut self, w: &mut W, d: &D) -> io::Result<()>;
}
impl<'a, D: Embeddable, T: DomainParse<D>> DomainParse<D> for &'a mut T {
fn parse_embedded(&mut self, v: &IOValue) -> io::Result<D> {
(**self).parse_embedded(v)
}
}
impl<'a, D: Embeddable, T: DomainDecode<D>> DomainDecode<D> for &'a mut T {
fn decode_embedded<'de, 'src, S: BinarySource<'de>>(
&mut self,
src: &'src mut S,
read_annotations: bool,
) -> io::Result<D> {
(**self).decode_embedded(src, read_annotations)
}
}
/// Convenience codec: use this as embedded codec for encoding (only) when embedded values
/// should be serialized as Preserves `String`s holding their Rust [std::fmt::Debug]
/// representation.
pub struct DebugDomainEncode;
impl<D: Embeddable> DomainEncode<D> for DebugDomainEncode {
fn encode_embedded<W: Writer>(&mut self, w: &mut W, d: &D) -> io::Result<()> {
d.debug_encode(w)
}
}
/// Convenience codec: use this as embedded codec for decoding (only) when embedded values are
/// expected to conform to the syntax implicit in their [std::str::FromStr] implementation.
pub struct FromStrDomainParse;
impl<Err: Into<io::Error>, D: Embeddable + std::str::FromStr<Err = Err>> DomainParse<D>
for FromStrDomainParse
{
fn parse_embedded(&mut self, v: &IOValue) -> io::Result<D> {
Ok(D::from_str(v.value().to_string()?).map_err(|e| e.into())?)
}
}
/// Use this as embedded codec when embedded data are already [IOValue]s that can be directly
/// serialized and deserialized without further transformation.
pub struct IOValueDomainCodec;
impl DomainDecode<IOValue> for IOValueDomainCodec {
fn decode_embedded<'de, 'src, S: BinarySource<'de>>(
&mut self,
src: &'src mut S,
read_annotations: bool,
) -> io::Result<IOValue> {
packed::PackedReader::new(src, IOValueDomainCodec).demand_next(read_annotations)
}
}
impl DomainEncode<IOValue> for IOValueDomainCodec {
fn encode_embedded<W: Writer>(&mut self, w: &mut W, d: &IOValue) -> io::Result<()> {
w.write(self, d)
}
}
/// Use this as embedded codec to forbid use of embedded values; an [io::Error] is signalled.
pub struct NoEmbeddedDomainCodec;
impl<D: Embeddable> DomainDecode<D> for NoEmbeddedDomainCodec {
fn decode_embedded<'de, 'src, S: BinarySource<'de>>(
&mut self,
_src: &'src mut S,
_read_annotations: bool,
) -> io::Result<D> {
Err(io::Error::new(
io::ErrorKind::Unsupported,
"Embedded values not supported here",
))
}
}
impl<D: Embeddable> DomainEncode<D> for NoEmbeddedDomainCodec {
fn encode_embedded<W: Writer>(&mut self, _w: &mut W, _d: &D) -> io::Result<()> {
Err(io::Error::new(
io::ErrorKind::Unsupported,
"Embedded values not supported here",
))
}
}
/// If some `C` implements [DomainDecode] but not [DomainParse], or vice versa, use `ViaCodec`
/// to promote the one to the other. Construct instances with [ViaCodec::new].
pub struct ViaCodec<C>(C);
impl<C> ViaCodec<C> {
/// Constructs a `ViaCodec` wrapper around an underlying codec of type `C`.
pub fn new(c: C) -> Self {
ViaCodec(c)
}
}
impl<D: Embeddable, C: DomainDecode<D>> DomainParse<D> for ViaCodec<C> {
fn parse_embedded(&mut self, v: &IOValue) -> io::Result<D> {
let bs = packed::PackedWriter::encode_iovalue(v)?;
self.0
.decode_embedded(&mut BytesBinarySource::new(&bs), true)
}
}
impl<D: Embeddable, C: DomainParse<D>> DomainDecode<D> for ViaCodec<C> {
fn decode_embedded<'de, 'src, S: BinarySource<'de>>(
&mut self,
src: &'src mut S,
read_annotations: bool,
) -> io::Result<D> {
let v = src
.packed(IOValueDomainCodec)
.demand_next(read_annotations)?;
self.0.parse_embedded(&v)
}
}

View File

@ -1,64 +0,0 @@
#![doc(hidden)]
//! A horrifying hack to Serde-serialize [IOValue] instances to Preserves *as themselves*.
//!
//! Frankly I think this portion of the codebase might not survive for long. I can't think of a
//! better way of achieving this, but the drawbacks of having this functionality are *severe*.
//!
//! See <https://gitlab.com/preserves/preserves/-/issues/42>.
use super::repr::IOValue;
pub static MAGIC: &str = "$____Preserves_Serde_Magic";
struct IOValueVisitor;
impl<'de> serde::de::Visitor<'de> for IOValueVisitor {
type Value = IOValue;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "a magic encoding of an embedded Preserves Value")
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let b = unsafe { Box::from_raw(v as *mut IOValue) };
Ok(*b)
}
}
#[inline(always)]
pub fn output_value<S: serde::Serializer>(serializer: S, v: IOValue) -> Result<S::Ok, S::Error> {
serializer.serialize_newtype_struct(MAGIC, &(Box::into_raw(Box::new(v)) as u64))
}
#[inline(always)]
pub fn input_value<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<IOValue, D::Error> {
deserializer.deserialize_newtype_struct(MAGIC, IOValueVisitor)
}
//---------------------------------------------------------------------------
#[inline]
pub fn receive_output_value<T: ?Sized>(name: &'static str, magic_value: &T) -> Option<IOValue> {
if name == MAGIC {
let b =
unsafe { Box::from_raw(*((magic_value as *const T) as *const u64) as *mut IOValue) };
let v: IOValue = *b;
Some(v)
} else {
None
}
}
#[inline]
pub fn transmit_input_value<F>(name: &'static str, f: F) -> Result<Option<u64>, crate::error::Error>
where
F: FnOnce() -> Result<IOValue, crate::error::Error>,
{
if name == MAGIC {
let b: Box<IOValue> = Box::new(f()?);
Ok(Some(Box::into_raw(b) as u64))
} else {
Ok(None)
}
}

View File

@ -1,74 +0,0 @@
//! Implements the Preserves
//! [merge](https://preserves.dev/preserves.html#appendix-merging-values) of values.
use super::Map;
use super::NestedValue;
use super::Record;
use super::Value;
/// Merge two sequences of values according to [the
/// specification](https://preserves.dev/preserves.html#appendix-merging-values).
pub fn merge_seqs<N: NestedValue>(mut a: Vec<N>, mut b: Vec<N>) -> Option<Vec<N>> {
if a.len() > b.len() {
std::mem::swap(&mut a, &mut b);
}
let mut r = vec![];
let mut bi = b.into_iter();
for av in a.into_iter() {
r.push(merge2(av, bi.next().unwrap())?);
}
r.extend(bi);
Some(r)
}
/// Merge two values according to [the
/// specification](https://preserves.dev/preserves.html#appendix-merging-values).
pub fn merge2<N: NestedValue>(v: N, w: N) -> Option<N> {
let (mut v_anns, v_val) = v.pieces();
let (w_anns, w_val) = w.pieces();
v_anns.modify(|anns| anns.extend(w_anns.to_vec().into_iter()));
if v_val == w_val {
Some(N::wrap(v_anns, v_val))
} else {
let maybe_merged = match v_val {
Value::Record(rv) => Some(Value::Record(Record(merge_seqs(
rv.0,
w_val.into_record()?.0,
)?))),
Value::Sequence(vs) => Some(Value::Sequence(merge_seqs(vs, w_val.into_sequence()?)?)),
Value::Set(_vs) => None, // unsure how to merge sets
Value::Dictionary(vs) => {
let mut ws = w_val.into_dictionary()?;
let mut rs = Map::new();
for (k, vv) in vs.into_iter() {
match ws.remove(&k) {
Some(wv) => {
rs.insert(k, merge2(vv, wv)?);
}
None => {
rs.insert(k, vv);
}
}
}
rs.extend(ws.into_iter());
Some(Value::Dictionary(rs))
}
_ => None,
};
maybe_merged.map(|vw| N::wrap(v_anns, vw))
}
}
/// Merge several values into a single value according to [the
/// specification](https://preserves.dev/preserves.html#appendix-merging-values).
pub fn merge<N: NestedValue, I: IntoIterator<Item = N>>(vs: I) -> Option<N> {
let mut vs = vs.into_iter();
let mut v = vs.next().expect("at least one value in merge()");
for w in vs {
match merge2(v, w) {
Some(merged) => v = merged,
None => return None,
}
}
Some(v)
}

View File

@ -1,116 +0,0 @@
//! # Representing, reading, and writing Preserves `Value`s as Rust data
//!
//! ```
//! use preserves::value::{IOValue, text, packed};
//! let v: IOValue = text::iovalue_from_str("<hi>")?;
//! let w: IOValue = packed::iovalue_from_bytes(b"\xb4\xb3\x02hi\x84")?;
//! assert_eq!(v, w);
//! assert_eq!(text::TextWriter::encode_iovalue(&v)?, "<hi>");
//! assert_eq!(packed::PackedWriter::encode_iovalue(&v)?, b"\xb4\xb3\x02hi\x84");
//! # Ok::<(), std::io::Error>(())
//! ```
//!
//! Preserves `Value`s are categorized in the following way. The core representation type,
//! [crate::value::repr::Value], reflects this structure. However, most of the time you will
//! work with [IOValue] or some other implementation of trait [NestedValue], which augments an
//! underlying [Value] with [*annotations*][crate::value::repr::Annotations] (e.g. comments) and fixes a strategy
//! for memory management.
//!
#![doc = include_str!("../../doc/value-grammar.md")]
//!
//! ## Memory management
//!
//! Each implementation of [NestedValue] chooses a different point in the space of possible
//! approaches to memory management for `Value`s.
//!
//! ##### `IOValue`
//!
//! The most commonly-used and versatile implementation, [IOValue], uses [std::sync::Arc] for
//! internal links in compound `Value`s. Unlike many of the other implementations of
//! [NestedValue], [IOValue] doesn't offer flexibility in the Rust data type to be used for
//! Preserves [embedded values](https://preserves.dev/preserves.html#embeddeds): instead,
//! embedded values in an [IOValue] are themselves [IOValue]s.
//!
//! ##### `ArcValue<D>`, `RcValue<D>`, and `PlainValue<D>`
//!
//! For control over the Rust type to use for embedded values, choose [ArcValue], [RcValue], or
//! [PlainValue]. Use [ArcValue] when you wish to transfer values among threads. [RcValue] is
//! more niche; it may be useful for complex terms that do not need to cross thread boundaries.
//! [PlainValue] is even more niche: it does not use a reference-counted pointer type, meaning
//! it does not offer any kind of aliasing or sharing among subterms at all.
//!
//! # Parsing, pretty-printing, encoding and decoding `Value`s
//!
//! Modules [reader] and [writer] supply generic [Reader] and [Writer] traits for parsing and
//! unparsing Preserves data. Implementations of [Reader] and [Writer] connect Preserves data
//! to specific transfer syntaxes:
//!
//! - module [packed] supplies tools for working with the machine-oriented binary syntax
//! - module [text] supplies tools for working with human-readable text syntax
pub mod boundary;
pub mod de;
pub mod domain;
pub mod magic;
pub mod merge;
pub mod packed;
pub mod reader;
pub mod repr;
pub mod ser;
pub mod signed_integer;
pub mod suspendable;
pub mod text;
pub mod writer;
pub use de::from_value;
pub use de::Deserializer;
pub use domain::DebugDomainEncode;
pub use domain::DomainDecode;
pub use domain::DomainEncode;
pub use domain::DomainParse;
pub use domain::FromStrDomainParse;
pub use domain::IOValueDomainCodec;
pub use domain::NoEmbeddedDomainCodec;
pub use domain::ViaCodec;
pub use merge::merge;
pub use packed::PackedReader;
pub use packed::PackedWriter;
pub use reader::BinarySource;
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::DummyValue;
pub use repr::Embeddable;
pub use repr::IOValue;
pub use repr::Map;
pub use repr::NestedValue;
pub use repr::PlainValue;
pub use repr::RcValue;
pub use repr::Record;
pub use repr::Set;
pub use repr::UnwrappedIOValue;
pub use repr::Value;
pub use repr::ValueClass;
pub use ser::to_value;
pub use ser::Serializer;
pub use text::TextReader;
pub use text::ToplevelWhitespaceMode;
pub use text::TextWriter;
pub use writer::Writer;
#[doc(hidden)]
pub fn invert_map<A, B>(m: &Map<A, B>) -> Map<B, A>
where
A: Clone,
B: Clone + Ord,
{
m.iter().map(|(a, b)| (b.clone(), a.clone())).collect()
}

View File

@ -1,86 +0,0 @@
//! Definitions of the tags used in the binary encoding.
use std::convert::{From, TryFrom};
use std::io;
/// Rust representation of tags used in the binary encoding.
#[derive(Debug, PartialEq, Eq)]
pub enum Tag {
False,
True,
End,
Annotation,
Embedded,
Ieee754,
SignedInteger,
String,
ByteString,
Symbol,
Record,
Sequence,
Set,
Dictionary,
}
/// Error value representing failure to decode a byte into a [Tag].
#[derive(Debug, PartialEq, Eq)]
pub struct InvalidTag(pub u8);
impl From<InvalidTag> for io::Error {
fn from(v: InvalidTag) -> Self {
io::Error::new(
io::ErrorKind::InvalidData,
format!("Invalid Preserves tag {}", v.0),
)
}
}
impl From<InvalidTag> for crate::error::Error {
fn from(v: InvalidTag) -> Self {
crate::error::Error::Io(v.into())
}
}
impl TryFrom<u8> for Tag {
type Error = InvalidTag;
fn try_from(v: u8) -> Result<Self, Self::Error> {
match v {
0x80 => Ok(Self::False),
0x81 => Ok(Self::True),
0x84 => Ok(Self::End),
0x85 => Ok(Self::Annotation),
0x86 => Ok(Self::Embedded),
0x87 => Ok(Self::Ieee754),
0xb0 => Ok(Self::SignedInteger),
0xb1 => Ok(Self::String),
0xb2 => Ok(Self::ByteString),
0xb3 => Ok(Self::Symbol),
0xb4 => Ok(Self::Record),
0xb5 => Ok(Self::Sequence),
0xb6 => Ok(Self::Set),
0xb7 => Ok(Self::Dictionary),
_ => Err(InvalidTag(v)),
}
}
}
impl From<Tag> for u8 {
fn from(v: Tag) -> Self {
match v {
Tag::False => 0x80,
Tag::True => 0x81,
Tag::End => 0x84,
Tag::Annotation => 0x85,
Tag::Embedded => 0x86,
Tag::Ieee754 => 0x87,
Tag::SignedInteger => 0xb0,
Tag::String => 0xb1,
Tag::ByteString => 0xb2,
Tag::Symbol => 0xb3,
Tag::Record => 0xb4,
Tag::Sequence => 0xb5,
Tag::Set => 0xb6,
Tag::Dictionary => 0xb7,
}
}
}

View File

@ -1,54 +0,0 @@
//! Implements the Preserves [machine-oriented binary
//! syntax](https://preserves.dev/preserves-binary.html).
//!
//! The main entry points for reading are functions [iovalue_from_bytes],
//! [annotated_iovalue_from_bytes], [from_bytes], and [annotated_from_bytes].
//!
//! The main entry points for writing are [PackedWriter::encode_iovalue] and
//! [PackedWriter::encode].
//!
//! # Summary of Binary Syntax
#![doc = include_str!("../../../doc/cheatsheet-binary-plaintext.md")]
pub mod constants;
pub mod reader;
pub mod writer;
pub use reader::PackedReader;
pub use writer::PackedWriter;
use std::io;
use super::{BinarySource, DomainDecode, IOValue, IOValueDomainCodec, NestedValue, Reader};
/// Reads a value from the given byte vector `bs` using the binary encoding, discarding
/// annotations.
pub fn from_bytes<N: NestedValue, Dec: DomainDecode<N::Embedded>>(
bs: &[u8],
decode_embedded: Dec,
) -> io::Result<N> {
super::BytesBinarySource::new(bs)
.packed(decode_embedded)
.demand_next(false)
}
/// Reads an [IOValue] from the given byte vector `bs` using the binary encoding, discarding
/// annotations.
pub fn iovalue_from_bytes(bs: &[u8]) -> io::Result<IOValue> {
from_bytes(bs, IOValueDomainCodec)
}
/// As [from_bytes], but includes annotations.
pub fn annotated_from_bytes<N: NestedValue, Dec: DomainDecode<N::Embedded>>(
bs: &[u8],
decode_embedded: Dec,
) -> io::Result<N> {
super::BytesBinarySource::new(bs)
.packed(decode_embedded)
.demand_next(true)
}
/// As [iovalue_from_bytes], but includes annotations.
pub fn annotated_iovalue_from_bytes(bs: &[u8]) -> io::Result<IOValue> {
annotated_from_bytes(bs, IOValueDomainCodec)
}

View File

@ -1,616 +0,0 @@
//! Implementation of [Reader] for the binary encoding.
use crate::error::{self, io_syntax_error, is_eof_io_error, ExpectedKind, Received};
use num::bigint::BigInt;
use num::traits::cast::{FromPrimitive, ToPrimitive};
use std::borrow::Cow;
use std::convert::TryFrom;
use std::convert::TryInto;
use std::io;
use std::marker::PhantomData;
use super::super::{
boundary as B,
reader::{BinarySource, Reader, ReaderResult, Token},
repr::Annotations,
signed_integer::SignedInteger,
CompoundClass, DomainDecode, Map, NestedValue, Record, Set, Value,
};
use super::constants::Tag;
/// The binary encoding Preserves reader.
pub struct PackedReader<
'de,
'src,
N: NestedValue,
Dec: DomainDecode<N::Embedded>,
S: BinarySource<'de>,
> {
/// Underlying source of bytes.
pub source: &'src mut S,
/// Decoder for producing Rust values embedded in the binary data.
pub decode_embedded: Dec,
phantom: PhantomData<&'de N>,
}
impl<'de, 'src, N: NestedValue, Dec: DomainDecode<N::Embedded>, S: BinarySource<'de>>
BinarySource<'de> for PackedReader<'de, 'src, N, Dec, S>
{
type Mark = S::Mark;
#[inline(always)]
fn mark(&mut self) -> io::Result<Self::Mark> {
self.source.mark()
}
#[inline(always)]
fn restore(&mut self, mark: &Self::Mark) -> io::Result<()> {
self.source.restore(mark)
}
#[inline(always)]
fn skip(&mut self) -> io::Result<()> {
self.source.skip()
}
#[inline(always)]
fn peek(&mut self) -> io::Result<u8> {
self.source.peek()
}
#[inline(always)]
fn readbytes(&mut self, count: usize) -> io::Result<Cow<'de, [u8]>> {
self.source.readbytes(count)
}
#[inline(always)]
fn readbytes_into(&mut self, bs: &mut [u8]) -> io::Result<()> {
self.source.readbytes_into(bs)
}
}
fn out_of_range<I: Into<BigInt>>(i: I) -> error::Error {
error::Error::NumberOutOfRange(i.into())
}
impl<'de, 'src, N: NestedValue, Dec: DomainDecode<N::Embedded>, S: BinarySource<'de>>
PackedReader<'de, 'src, N, Dec, S>
{
/// Construct a new reader from a byte source and embedded-value decoder.
#[inline(always)]
pub fn new(source: &'src mut S, decode_embedded: Dec) -> Self {
PackedReader {
source,
decode_embedded,
phantom: PhantomData,
}
}
#[inline(always)]
fn read(&mut self) -> io::Result<u8> {
let v = self.peek()?;
self.skip()?;
Ok(v)
}
fn expected(&mut self, k: ExpectedKind) -> error::Error {
match self.demand_next(true) {
Ok(v) => error::Error::Expected(k, Received::ReceivedOtherValue(format!("{:?}", v))),
Err(e) => e.into(),
}
}
#[inline(always)]
fn varint(&mut self) -> io::Result<usize> {
let mut shift = 0;
let mut acc: usize = 0;
loop {
let v = self.read()?;
acc |= ((v & 0x7f) as usize) << shift;
shift += 7;
if v & 0x80 == 0 {
return Ok(acc);
}
}
}
#[inline(always)]
fn peekend(&mut self) -> io::Result<bool> {
if self.peek()? == Tag::End.into() {
self.skip()?;
Ok(true)
} else {
Ok(false)
}
}
#[inline(always)]
fn try_next_nonannotation<T, F>(&mut self, f: F) -> ReaderResult<T>
where
F: FnOnce(&mut Self, Tag) -> ReaderResult<T>,
{
let m = self.source.mark()?;
loop {
match Tag::try_from(self.peek()?)? {
Tag::Annotation => {
self.skip()?;
self.skip_value()?;
}
tag => match f(self, tag) {
Ok(v) => return Ok(v),
Err(e) => {
self.source.restore(&m)?;
return Err(e);
}
}
}
}
}
fn next_atomic(&mut self, expected_tag: Tag, k: ExpectedKind) -> ReaderResult<Cow<'de, [u8]>> {
self.try_next_nonannotation(|r, actual_tag| {
if actual_tag == expected_tag {
r.skip()?;
let count = r.varint()?;
Ok(r.readbytes(count)?)
} else {
Err(r.expected(k))
}
})
}
fn next_compound(&mut self, expected_tag: Tag, k: ExpectedKind) -> ReaderResult<()> {
self.try_next_nonannotation(|r, actual_tag| {
if actual_tag == expected_tag {
r.skip()?;
Ok(())
} else {
Err(r.expected(k))
}
})
}
#[inline(always)]
fn read_signed_integer(&mut self, count: usize) -> io::Result<SignedInteger> {
if count == 0 {
return Ok(SignedInteger::from(0_i128));
}
if count > 16 {
let bs = self.readbytes(count)?;
if (bs[0] & 0x80) == 0 {
// Positive or zero.
let mut i = 0;
while i < count && bs[i] == 0 {
i += 1;
}
if count - i <= 16 {
Ok(SignedInteger::from(u128::from_be_bytes(
bs[bs.len() - 16..].try_into().unwrap(),
)))
} else {
Ok(SignedInteger::from(Cow::Owned(BigInt::from_bytes_be(
num::bigint::Sign::Plus,
&bs[i..],
))))
}
} else {
// Negative.
let mut i = 0;
while i < count && bs[i] == 0xff {
i += 1;
}
if count - i <= 16 {
Ok(SignedInteger::from(i128::from_be_bytes(
bs[bs.len() - 16..].try_into().unwrap(),
)))
} else {
Ok(SignedInteger::from(Cow::Owned(
BigInt::from_signed_bytes_be(&bs),
)))
}
}
} else {
let first_byte = self.read()?;
let prefix_byte = if (first_byte & 0x80) == 0 { 0x00 } else { 0xff };
let mut bs = [prefix_byte; 16];
bs[16 - count] = first_byte;
self.readbytes_into(&mut bs[16 - (count - 1)..])?;
Ok(SignedInteger::from(i128::from_be_bytes(bs)))
}
}
#[inline(always)]
fn next_unsigned<T: FromPrimitive, F>(&mut self, f: F) -> ReaderResult<T>
where
F: FnOnce(u128) -> Option<T>,
{
self.try_next_nonannotation(|r, tag| {
match tag {
Tag::SignedInteger => {
r.skip()?;
let count = r.varint()?;
let n = &r.read_signed_integer(count)?;
let i = n.try_into().map_err(|_| out_of_range(n))?;
f(i).ok_or_else(|| out_of_range(i))
}
_ => Err(r.expected(ExpectedKind::SignedInteger)),
}
})
}
#[inline(always)]
fn next_signed<T: FromPrimitive, F>(&mut self, f: F) -> ReaderResult<T>
where
F: FnOnce(i128) -> Option<T>,
{
self.try_next_nonannotation(|r, tag| {
match tag {
Tag::SignedInteger => {
r.skip()?;
let count = r.varint()?;
let n = &r.read_signed_integer(count)?;
let i = n.try_into().map_err(|_| out_of_range(n))?;
f(i).ok_or_else(|| out_of_range(i))
}
_ => Err(r.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(())
}
fn next_upto_end(&mut self, read_annotations: bool) -> io::Result<Option<N>> {
match self.peekend()? {
true => Ok(None),
false => Ok(Some(self.demand_next(read_annotations)?)),
}
}
}
impl<'de, 'src, N: NestedValue, Dec: DomainDecode<N::Embedded>, S: BinarySource<'de>> Reader<'de, N>
for PackedReader<'de, 'src, N, Dec, S>
{
fn next(&mut self, read_annotations: bool) -> io::Result<Option<N>> {
match self.peek() {
Err(e) if is_eof_io_error(&e) => return Ok(None),
Err(e) => return Err(e),
Ok(_) => (),
}
Ok(Some(match Tag::try_from(self.read()?)? {
Tag::False => N::new(false),
Tag::True => N::new(true),
Tag::Annotation => {
if 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_annotations()?;
self.demand_next(read_annotations)?
}
}
Tag::Embedded => Value::Embedded(
self.decode_embedded
.decode_embedded(self.source, read_annotations)?,
).wrap(),
Tag::Ieee754 => match self.varint()? {
8 => {
let mut bs = [0; 8];
self.readbytes_into(&mut bs)?;
Value::from(f64::from_bits(u64::from_be_bytes(bs))).wrap()
}
_ => return Err(io_syntax_error("Invalid IEEE754 size"))
}
Tag::SignedInteger => {
let count = self.varint()?;
let n = self.read_signed_integer(count)?;
Value::SignedInteger(n).wrap()
}
Tag::String => {
let count = self.varint()?;
Value::String(decodestr(self.readbytes(count)?)?.into_owned()).wrap()
}
Tag::ByteString => {
let count = self.varint()?;
Value::ByteString(self.readbytes(count)?.into_owned()).wrap()
}
Tag::Symbol => {
let count = self.varint()?;
Value::Symbol(decodestr(self.readbytes(count)?)?.into_owned()).wrap()
}
Tag::Record => {
let mut vs = Vec::new();
while let Some(v) = self.next_upto_end(read_annotations)? {
vs.push(v);
}
if vs.is_empty() {
return Err(io_syntax_error("Too few elements in encoded record"));
}
Value::Record(Record(vs)).wrap()
}
Tag::Sequence => {
let mut vs = Vec::new();
while let Some(v) = self.next_upto_end(read_annotations)? {
vs.push(v);
}
Value::Sequence(vs).wrap()
}
Tag::Set => {
let mut s = Set::new();
while let Some(v) = self.next_upto_end(read_annotations)? {
s.insert(v);
}
Value::Set(s).wrap()
}
Tag::Dictionary => {
let mut d = Map::new();
while let Some(k) = self.next_upto_end(read_annotations)? {
match self.next_upto_end(read_annotations)? {
Some(v) => {
d.insert(k, v);
}
None => return Err(io_syntax_error("Missing dictionary value")),
}
}
Value::Dictionary(d).wrap()
}
tag @ Tag::End => {
return Err(io_syntax_error(&format!("Invalid tag: {:?}", tag)));
}
}))
}
#[inline(always)]
fn open_record(&mut self, arity: Option<usize>) -> ReaderResult<B::Type> {
self.next_compound(Tag::Record, ExpectedKind::Record(arity))?;
let mut b = B::Type::default();
self.ensure_more_expected(&mut b, &B::Item::RecordLabel)?;
Ok(b)
}
#[inline(always)]
fn open_sequence_or_set(&mut self) -> ReaderResult<B::Item> {
self.try_next_nonannotation(|r, tag| {
match tag {
Tag::Sequence => {
r.skip()?;
Ok(B::Item::SequenceValue)
}
Tag::Set => {
r.skip()?;
Ok(B::Item::SetValue)
}
_ => Err(r.expected(ExpectedKind::SequenceOrSet)),
}
})
}
#[inline(always)]
fn open_sequence(&mut self) -> ReaderResult<()> {
self.next_compound(Tag::Sequence, ExpectedKind::Sequence)
}
#[inline(always)]
fn open_set(&mut self) -> ReaderResult<()> {
self.next_compound(Tag::Set, ExpectedKind::Set)
}
#[inline(always)]
fn open_dictionary(&mut self) -> ReaderResult<()> {
self.next_compound(Tag::Dictionary, ExpectedKind::Dictionary)
}
#[inline(always)]
fn boundary(&mut self, _b: &B::Type) -> ReaderResult<()> {
Ok(())
}
#[inline(always)]
fn close_compound(&mut self, _b: &mut B::Type, _i: &B::Item) -> ReaderResult<bool> {
Ok(self.peekend()?)
}
#[inline(always)]
fn open_embedded(&mut self) -> ReaderResult<()> {
self.next_compound(Tag::Embedded, ExpectedKind::Embedded)
}
#[inline(always)]
fn close_embedded(&mut self) -> ReaderResult<()> {
Ok(())
}
type Mark = S::Mark;
#[inline(always)]
fn mark(&mut self) -> io::Result<Self::Mark> {
self.source.mark()
}
#[inline(always)]
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<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::Ieee754
| 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_value()?;
continue;
}
});
}
}
fn next_annotations_and_token(&mut self) -> io::Result<(Vec<N>, Token<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)?)),
}
}
#[inline(always)]
fn next_boolean(&mut self) -> ReaderResult<bool> {
self.try_next_nonannotation(|r, tag| {
match tag {
Tag::False => {
r.skip()?;
Ok(false)
},
Tag::True => {
r.skip()?;
Ok(true)
},
_ => Err(r.expected(ExpectedKind::Boolean)),
}
})
}
fn next_signedinteger(&mut self) -> ReaderResult<SignedInteger> {
self.try_next_nonannotation(|r, tag| {
match tag {
Tag::SignedInteger => {
r.skip()?;
let count = r.varint()?;
Ok(r.read_signed_integer(count)?)
}
_ => Err(r.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())
}
fn next_i64(&mut self) -> ReaderResult<i64> {
self.next_signed(|n| n.to_i64())
}
fn next_i128(&mut self) -> ReaderResult<i128> {
self.next_signed(|n| n.to_i128())
}
fn next_u8(&mut self) -> ReaderResult<u8> {
self.next_unsigned(|n| n.to_u8())
}
fn next_u16(&mut self) -> ReaderResult<u16> {
self.next_unsigned(|n| n.to_u16())
}
fn next_u32(&mut self) -> ReaderResult<u32> {
self.next_unsigned(|n| n.to_u32())
}
fn next_u64(&mut self) -> ReaderResult<u64> {
self.next_unsigned(|n| n.to_u64())
}
fn next_u128(&mut self) -> ReaderResult<u128> {
self.next_unsigned(|n| n.to_u128())
}
fn next_f64(&mut self) -> ReaderResult<f64> {
self.try_next_nonannotation(|r, tag| {
if tag == Tag::Ieee754 {
r.skip()?;
match r.varint()? {
8 => {
let mut bs = [0; 8];
r.readbytes_into(&mut bs)?;
Ok(f64::from_bits(u64::from_be_bytes(bs)))
}
_ => Err(io_syntax_error("Invalid IEEE754 size"))?,
}
} else {
Err(r.expected(ExpectedKind::Double))
}
})
}
fn next_str(&mut self) -> ReaderResult<Cow<'de, str>> {
Ok(decodestr(
self.next_atomic(Tag::String, ExpectedKind::Symbol)?,
)?)
}
fn next_bytestring(&mut self) -> ReaderResult<Cow<'de, [u8]>> {
self.next_atomic(Tag::ByteString, ExpectedKind::Symbol)
}
fn next_symbol(&mut self) -> ReaderResult<Cow<'de, str>> {
Ok(decodestr(
self.next_atomic(Tag::Symbol, ExpectedKind::Symbol)?,
)?)
}
}
#[inline(always)]
fn decodestr(cow: Cow<'_, [u8]>) -> io::Result<Cow<'_, str>> {
match cow {
Cow::Borrowed(bs) => Ok(Cow::Borrowed(
std::str::from_utf8(bs).map_err(|_| io_syntax_error("Invalid UTF-8"))?,
)),
Cow::Owned(bs) => Ok(Cow::Owned(
String::from_utf8(bs).map_err(|_| io_syntax_error("Invalid UTF-8"))?,
)),
}
}

View File

@ -1,583 +0,0 @@
//! Implementation of [Writer] for the binary encoding.
use super::super::boundary as B;
use super::super::suspendable::Suspendable;
use super::super::DomainEncode;
use super::super::IOValue;
use super::super::IOValueDomainCodec;
use super::super::NestedValue;
use super::constants::Tag;
use num::bigint::BigInt;
use num::cast::ToPrimitive;
use std::convert::TryInto;
use std::io;
use std::ops::DerefMut;
use super::super::writer::{varint, CompoundWriter, Writer};
/// The binary encoding Preserves writer.
pub struct PackedWriter<W: io::Write>(Suspendable<W>);
impl PackedWriter<&mut Vec<u8>> {
/// Encodes `v` to a byte vector.
#[inline(always)]
pub fn encode<N: NestedValue, Enc: DomainEncode<N::Embedded>>(
enc: &mut Enc,
v: &N,
) -> io::Result<Vec<u8>> {
let mut buf: Vec<u8> = Vec::new();
PackedWriter::new(&mut buf).write(enc, v)?;
Ok(buf)
}
/// Encodes `v` to a byte vector.
#[inline(always)]
pub fn encode_iovalue(v: &IOValue) -> io::Result<Vec<u8>> {
Self::encode(&mut IOValueDomainCodec, v)
}
}
impl<W: io::Write> PackedWriter<W> {
/// Construct a writer from the given byte sink `write`.
#[inline(always)]
pub fn new(write: W) -> Self {
PackedWriter(Suspendable::new(write))
}
/// Retrieve a mutable reference to the underlying byte sink.
#[inline(always)]
pub fn w(&mut self) -> &mut W {
self.0.deref_mut()
}
#[doc(hidden)]
#[inline(always)]
pub fn write_byte(&mut self, b: u8) -> io::Result<()> {
self.w().write_all(&[b])
}
#[doc(hidden)]
#[inline(always)]
pub fn write_integer(&mut self, bs: &[u8]) -> io::Result<()> {
self.write_atom(Tag::SignedInteger, bs)
}
#[doc(hidden)]
#[inline(always)]
pub fn write_atom(&mut self, tag: Tag, bs: &[u8]) -> io::Result<()> {
self.write_byte(tag.into())?;
varint(&mut self.w(), bs.len().try_into().unwrap())?;
self.w().write_all(bs)
}
#[doc(hidden)]
#[inline(always)]
pub fn suspend(&mut self) -> Self {
PackedWriter(self.0.suspend())
}
#[doc(hidden)]
#[inline(always)]
pub fn resume(&mut self, other: Self) {
self.0.resume(other.0)
}
}
#[doc(hidden)]
pub struct BinaryOrderWriter(Vec<Vec<u8>>);
impl BinaryOrderWriter {
#[inline(always)]
fn new() -> Self {
BinaryOrderWriter(vec![vec![]])
}
#[inline(always)]
fn pop(&mut self) -> PackedWriter<Vec<u8>> {
PackedWriter::new(self.0.pop().unwrap())
}
#[inline(always)]
fn push(&mut self, w: PackedWriter<Vec<u8>>) {
self.0.push(w.0.take())
}
#[inline(always)]
fn items(&self) -> &Vec<Vec<u8>> {
&self.0
}
#[inline(always)]
fn items_mut(&mut self) -> &mut Vec<Vec<u8>> {
&mut self.0
}
#[inline(always)]
fn buffer(&mut self) -> &mut Vec<u8> {
self.0.last_mut().unwrap()
}
#[inline(always)]
fn finish<W: WriteWriter>(mut self, w: &mut W) -> io::Result<()> {
if !self.buffer().is_empty() {
panic!("Missing final boundary()");
}
self.items_mut().pop();
self.items_mut().sort();
for bs in self.items() {
w.write_raw_bytes(&bs)?;
}
w.write_tag(Tag::End)?;
Ok(())
}
}
#[doc(hidden)]
pub trait WriteWriter: Writer {
fn write_raw_bytes(&mut self, v: &[u8]) -> io::Result<()>;
#[inline(always)]
fn write_tag(&mut self, tag: Tag) -> io::Result<()> {
self.write_raw_bytes(&[tag.into()])
}
}
impl<W: io::Write> WriteWriter for PackedWriter<W> {
#[inline(always)]
fn write_raw_bytes(&mut self, v: &[u8]) -> io::Result<()> {
self.w().write_all(v)
}
}
impl WriteWriter for BinaryOrderWriter {
#[inline(always)]
fn write_raw_bytes(&mut self, v: &[u8]) -> io::Result<()> {
use io::Write;
self.buffer().write_all(v)
}
}
impl<W: io::Write> CompoundWriter for PackedWriter<W> {
#[inline(always)]
fn boundary(&mut self, b: &B::Type) -> io::Result<()> {
if let Some(B::Item::Annotation) = b.opening {
self.write_tag(Tag::Annotation)?;
}
Ok(())
}
}
impl CompoundWriter for BinaryOrderWriter {
#[inline(always)]
fn boundary(&mut self, b: &B::Type) -> io::Result<()> {
match b.closing {
Some(B::Item::DictionaryValue)
| Some(B::Item::RecordField)
| Some(B::Item::SequenceValue)
| Some(B::Item::SetValue) => self.items_mut().push(vec![]),
_ => (),
}
Ok(())
}
}
macro_rules! binary_order_writer_method {
(mut $n:ident ($($argname:ident : $argty:ty),*) -> $retty:ty) =>
(#[inline(always)] fn $n (&mut self, $($argname : $argty),*) -> $retty {
(&mut PackedWriter::new(self.buffer())).$n($($argname),*)
});
}
impl Writer for BinaryOrderWriter {
type AnnWriter = PackedWriter<Vec<u8>>;
type RecWriter = PackedWriter<Vec<u8>>;
type SeqWriter = PackedWriter<Vec<u8>>;
type SetWriter = BinaryOrderWriter;
type DictWriter = BinaryOrderWriter;
type EmbeddedWriter = PackedWriter<Vec<u8>>;
#[inline(always)]
fn start_annotations(&mut self) -> io::Result<Self::AnnWriter> {
Ok(self.pop())
}
#[inline(always)]
fn end_annotations(&mut self, ann: Self::AnnWriter) -> io::Result<()> {
self.push(ann);
Ok(())
}
binary_order_writer_method!(mut write_bool(v: bool) -> io::Result<()>);
binary_order_writer_method!(mut write_f64(v: f64) -> io::Result<()>);
binary_order_writer_method!(mut write_i8(v: i8) -> io::Result<()>);
binary_order_writer_method!(mut write_u8(v: u8) -> io::Result<()>);
binary_order_writer_method!(mut write_i16(v: i16) -> io::Result<()>);
binary_order_writer_method!(mut write_u16(v: u16) -> io::Result<()>);
binary_order_writer_method!(mut write_i32(v: i32) -> io::Result<()>);
binary_order_writer_method!(mut write_u32(v: u32) -> io::Result<()>);
binary_order_writer_method!(mut write_i64(v: i64) -> io::Result<()>);
binary_order_writer_method!(mut write_u64(v: u64) -> io::Result<()>);
binary_order_writer_method!(mut write_i128(v: i128) -> io::Result<()>);
binary_order_writer_method!(mut write_u128(v: u128) -> io::Result<()>);
binary_order_writer_method!(mut write_int(v: &BigInt) -> io::Result<()>);
binary_order_writer_method!(mut write_string(v: &str) -> io::Result<()>);
binary_order_writer_method!(mut write_bytes(v: &[u8]) -> io::Result<()>);
binary_order_writer_method!(mut write_symbol(v: &str) -> io::Result<()>);
#[inline(always)]
fn start_record(&mut self, _field_count: Option<usize>) -> io::Result<Self::RecWriter> {
self.write_tag(Tag::Record)?;
Ok(self.pop())
}
#[inline(always)]
fn end_record(&mut self, rec: Self::RecWriter) -> io::Result<()> {
self.push(rec);
self.write_tag(Tag::End)
}
#[inline(always)]
fn start_sequence(&mut self, _item_count: Option<usize>) -> io::Result<Self::SeqWriter> {
self.write_tag(Tag::Sequence)?;
Ok(self.pop())
}
#[inline(always)]
fn end_sequence(&mut self, seq: Self::SeqWriter) -> io::Result<()> {
self.push(seq);
self.write_tag(Tag::End)
}
#[inline(always)]
fn start_set(&mut self, _item_count: Option<usize>) -> io::Result<Self::SetWriter> {
self.write_tag(Tag::Set)?;
Ok(BinaryOrderWriter::new())
}
#[inline(always)]
fn end_set(&mut self, set: Self::SetWriter) -> io::Result<()> {
set.finish(self)
}
#[inline(always)]
fn start_dictionary(&mut self, _entry_count: Option<usize>) -> io::Result<Self::DictWriter> {
self.write_tag(Tag::Dictionary)?;
Ok(BinaryOrderWriter::new())
}
#[inline(always)]
fn end_dictionary(&mut self, dict: Self::DictWriter) -> io::Result<()> {
dict.finish(self)
}
#[inline(always)]
fn start_embedded(&mut self) -> io::Result<Self::EmbeddedWriter> {
self.write_tag(Tag::Embedded)?;
Ok(self.pop())
}
#[inline(always)]
fn end_embedded(&mut self, ptr: Self::EmbeddedWriter) -> io::Result<()> {
self.push(ptr);
Ok(())
}
#[inline(always)]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
macro_rules! fits_in_bytes {
($v:ident, $limit:literal) => {{
let bits = $limit * 8 - 1;
$v >= -(1 << bits) && $v < (1 << bits)
}};
}
impl<W: io::Write> Writer for PackedWriter<W> {
type AnnWriter = Self;
type RecWriter = Self;
type SeqWriter = Self;
type SetWriter = BinaryOrderWriter;
type DictWriter = BinaryOrderWriter;
type EmbeddedWriter = Self;
#[inline(always)]
fn start_annotations(&mut self) -> io::Result<Self::AnnWriter> {
Ok(self.suspend())
}
#[inline(always)]
fn end_annotations(&mut self, ann: Self::AnnWriter) -> io::Result<()> {
self.resume(ann);
Ok(())
}
#[inline(always)]
fn write_bool(&mut self, v: bool) -> io::Result<()> {
self.write_tag(if v { Tag::True } else { Tag::False })
}
#[inline(always)]
fn write_f64(&mut self, v: f64) -> io::Result<()> {
self.write_tag(Tag::Ieee754)?;
self.write_byte(8)?;
self.write_raw_bytes(&u64::to_be_bytes(f64::to_bits(v)))
}
#[inline(always)]
fn write_i8(&mut self, v: i8) -> io::Result<()> {
if v == 0 {
return self.write_integer(&[]);
}
self.write_integer(&[v as u8])
}
#[inline(always)]
fn write_u8(&mut self, v: u8) -> io::Result<()> {
if let Ok(w) = v.try_into() {
return self.write_i8(w);
}
self.write_integer(&[0, v])
}
#[inline(always)]
fn write_i16(&mut self, v: i16) -> io::Result<()> {
if let Ok(w) = v.try_into() {
return self.write_i8(w);
}
self.write_integer(&[(v >> 8) as u8, (v & 255) as u8])
}
#[inline(always)]
fn write_u16(&mut self, v: u16) -> io::Result<()> {
if let Ok(w) = v.try_into() {
return self.write_i16(w);
}
self.write_integer(&[0, (v >> 8) as u8, (v & 255) as u8])
}
#[inline(always)]
fn write_i32(&mut self, v: i32) -> io::Result<()> {
if let Ok(w) = v.try_into() {
return self.write_i16(w);
}
if fits_in_bytes!(v, 3) {
return self.write_integer(&[(v >> 16) as u8, (v >> 8) as u8, (v & 255) as u8]);
}
self.write_integer(&[
(v >> 24) as u8,
(v >> 16) as u8,
(v >> 8) as u8,
(v & 255) as u8,
])
}
#[inline(always)]
fn write_u32(&mut self, v: u32) -> io::Result<()> {
if let Ok(w) = v.try_into() {
return self.write_i32(w);
}
self.write_integer(&[
0,
(v >> 24) as u8,
(v >> 16) as u8,
(v >> 8) as u8,
(v & 255) as u8,
])
}
#[inline(always)]
fn write_i64(&mut self, v: i64) -> io::Result<()> {
if let Ok(w) = v.try_into() {
return self.write_i32(w);
}
if fits_in_bytes!(v, 5) {
return self.write_integer(&[
(v >> 32) as u8,
(v >> 24) as u8,
(v >> 16) as u8,
(v >> 8) as u8,
(v & 255) as u8,
]);
}
if fits_in_bytes!(v, 6) {
return self.write_integer(&[
(v >> 40) as u8,
(v >> 32) as u8,
(v >> 24) as u8,
(v >> 16) as u8,
(v >> 8) as u8,
(v & 255) as u8,
]);
}
if fits_in_bytes!(v, 7) {
return self.write_integer(&[
(v >> 48) as u8,
(v >> 40) as u8,
(v >> 32) as u8,
(v >> 24) as u8,
(v >> 16) as u8,
(v >> 8) as u8,
(v & 255) as u8,
]);
}
self.write_integer(&[
(v >> 56) as u8,
(v >> 48) as u8,
(v >> 40) as u8,
(v >> 32) as u8,
(v >> 24) as u8,
(v >> 16) as u8,
(v >> 8) as u8,
(v & 255) as u8,
])
}
#[inline(always)]
fn write_u64(&mut self, v: u64) -> io::Result<()> {
if let Ok(w) = v.try_into() {
return self.write_i64(w);
}
self.write_integer(&[
0,
(v >> 56) as u8,
(v >> 48) as u8,
(v >> 40) as u8,
(v >> 32) as u8,
(v >> 24) as u8,
(v >> 16) as u8,
(v >> 8) as u8,
(v & 255) as u8,
])
}
#[inline(always)]
fn write_i128(&mut self, v: i128) -> io::Result<()> {
if let Ok(w) = v.try_into() {
return self.write_i64(w);
}
let bs: [u8; 16] = v.to_be_bytes();
if fits_in_bytes!(v, 9) {
return self.write_integer(&bs[7..]);
}
if fits_in_bytes!(v, 10) {
return self.write_integer(&bs[6..]);
}
if fits_in_bytes!(v, 11) {
return self.write_integer(&bs[5..]);
}
if fits_in_bytes!(v, 12) {
return self.write_integer(&bs[4..]);
}
if fits_in_bytes!(v, 13) {
return self.write_integer(&bs[3..]);
}
if fits_in_bytes!(v, 14) {
return self.write_integer(&bs[2..]);
}
if fits_in_bytes!(v, 15) {
return self.write_integer(&bs[1..]);
}
self.write_integer(&bs)
}
#[inline(always)]
fn write_u128(&mut self, v: u128) -> io::Result<()> {
if let Ok(w) = v.try_into() {
return self.write_i128(w);
}
let bs: [u8; 16] = v.to_be_bytes();
self.write_tag(Tag::SignedInteger)?;
varint(&mut self.w(), 17)?;
self.write_byte(0)?;
self.write_raw_bytes(&bs)
}
#[inline(always)]
fn write_int(&mut self, v: &BigInt) -> io::Result<()> {
match v.to_i8() {
Some(n) => self.write_i8(n),
None => match v.to_i128() {
Some(n) => self.write_i128(n),
None => self.write_integer(&v.to_signed_bytes_be()),
},
}
}
#[inline(always)]
fn write_string(&mut self, v: &str) -> io::Result<()> {
self.write_atom(Tag::String, v.as_bytes())
}
#[inline(always)]
fn write_bytes(&mut self, v: &[u8]) -> io::Result<()> {
self.write_atom(Tag::ByteString, v)
}
#[inline(always)]
fn write_symbol(&mut self, v: &str) -> io::Result<()> {
self.write_atom(Tag::Symbol, v.as_bytes())
}
#[inline(always)]
fn start_record(&mut self, _field_count: Option<usize>) -> io::Result<Self::RecWriter> {
self.write_tag(Tag::Record)?;
Ok(self.suspend())
}
#[inline(always)]
fn end_record(&mut self, rec: Self::RecWriter) -> io::Result<()> {
self.resume(rec);
self.write_tag(Tag::End)
}
#[inline(always)]
fn start_sequence(&mut self, _item_count: Option<usize>) -> io::Result<Self::SeqWriter> {
self.write_tag(Tag::Sequence)?;
Ok(self.suspend())
}
#[inline(always)]
fn end_sequence(&mut self, seq: Self::SeqWriter) -> io::Result<()> {
self.resume(seq);
self.write_tag(Tag::End)
}
#[inline(always)]
fn start_set(&mut self, _item_count: Option<usize>) -> io::Result<Self::SetWriter> {
self.write_tag(Tag::Set)?;
Ok(BinaryOrderWriter::new())
}
#[inline(always)]
fn end_set(&mut self, set: Self::SetWriter) -> io::Result<()> {
set.finish(self)
}
#[inline(always)]
fn start_dictionary(&mut self, _entry_count: Option<usize>) -> io::Result<Self::DictWriter> {
self.write_tag(Tag::Dictionary)?;
Ok(BinaryOrderWriter::new())
}
#[inline(always)]
fn end_dictionary(&mut self, dict: Self::DictWriter) -> io::Result<()> {
dict.finish(self)
}
#[inline(always)]
fn start_embedded(&mut self) -> io::Result<Self::EmbeddedWriter> {
self.write_tag(Tag::Embedded)?;
Ok(self.suspend())
}
#[inline(always)]
fn end_embedded(&mut self, ann: Self::EmbeddedWriter) -> io::Result<()> {
self.resume(ann);
Ok(())
}
#[inline(always)]
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
}

View File

@ -1,567 +0,0 @@
//! Generic [Reader] trait for parsing Preserves [Value][crate::value::repr::Value]s,
//! implemented by code that provides each specific transfer syntax.
use crate::error::{self, io_eof, ExpectedKind, Received};
use std::borrow::Cow;
use std::io;
use std::marker::PhantomData;
use super::boundary as B;
use super::signed_integer::SignedInteger;
use super::CompoundClass;
use super::DomainDecode;
use super::DomainParse;
use super::Double;
use super::IOValue;
use super::IOValueDomainCodec;
use super::NestedValue;
use super::ViaCodec;
pub type ReaderResult<T> = std::result::Result<T, error::Error>;
/// Tokens produced when performing
/// [SAX](https://en.wikipedia.org/wiki/Simple_API_for_XML)-style reading of terms.
pub enum Token<N: NestedValue> {
/// An embedded value was seen and completely decoded.
Embedded(N::Embedded),
/// An atomic value was seen and completely decoded.
Atom(N),
/// A compound value has been opened; its contents follow, and it will be terminated by
/// [Token::End].
Compound(CompoundClass),
/// Closes a previously-opened compound value.
End,
}
/// Generic parser for Preserves.
pub trait Reader<'de, N: NestedValue> {
/// Retrieve the next parseable value or an indication of end-of-input.
///
/// Yields `Ok(Some(...))` if a complete value is available, `Ok(None)` if the end of
/// stream has been reached, or `Err(...)` for parse or IO errors, including
/// incomplete/partial input. See also [Reader::demand_next].
fn next(&mut self, read_annotations: bool) -> io::Result<Option<N>>;
// Hiding these from the documentation for the moment because I don't want to have to
// document the whole Boundary thing.
#[doc(hidden)]
fn open_record(&mut self, arity: Option<usize>) -> ReaderResult<B::Type>;
#[doc(hidden)]
fn open_sequence_or_set(&mut self) -> ReaderResult<B::Item>;
#[doc(hidden)]
fn open_sequence(&mut self) -> ReaderResult<()>;
#[doc(hidden)]
fn open_set(&mut self) -> ReaderResult<()>;
#[doc(hidden)]
fn open_dictionary(&mut self) -> ReaderResult<()>;
#[doc(hidden)]
fn boundary(&mut self, b: &B::Type) -> ReaderResult<()>;
#[doc(hidden)]
// close_compound implies a b.shift(...) and a self.boundary(b).
fn close_compound(&mut self, b: &mut B::Type, i: &B::Item) -> ReaderResult<bool>;
#[doc(hidden)]
fn open_embedded(&mut self) -> ReaderResult<()>;
#[doc(hidden)]
fn close_embedded(&mut self) -> ReaderResult<()>;
/// Allows structured backtracking to an earlier stage in a parse. Useful for layering
/// parser combinators atop a Reader.
type Mark;
/// Retrieve a marker for the current position in the input.
fn mark(&mut self) -> io::Result<Self::Mark>;
/// Seek the input to a previously-saved position.
fn restore(&mut self, mark: &Self::Mark) -> io::Result<()>;
/// Get the next [SAX](https://en.wikipedia.org/wiki/Simple_API_for_XML)-style event,
/// discarding annotations.
///
/// The `read_embedded_annotations` controls whether annotations are also skipped on
/// *embedded* values or not.
fn next_token(&mut self, read_embedded_annotations: bool) -> io::Result<Token<N>>;
/// Get the next [SAX](https://en.wikipedia.org/wiki/Simple_API_for_XML)-style event, plus
/// a vector containing any annotations that preceded it.
fn next_annotations_and_token(&mut self) -> io::Result<(Vec<N>, Token<N>)>;
//---------------------------------------------------------------------------
/// Skips the next available complete value. Yields an error if no such value exists.
fn skip_value(&mut self) -> io::Result<()> {
// TODO efficient skipping in specific impls of this trait
let _ = self.demand_next(false)?;
Ok(())
}
/// Retrieve the next parseable value, treating end-of-input as an error.
///
/// Yields `Ok(...)` if a complete value is available or `Err(...)` for parse or IO errors,
/// including incomplete/partial input or end of stream. See also [Reader::next].
fn demand_next(&mut self, read_annotations: bool) -> io::Result<N> {
self.next(read_annotations)?.ok_or_else(io_eof)
}
/// Yields the next value, if it is a `Boolean`, or an error otherwise.
fn next_boolean(&mut self) -> ReaderResult<bool> {
self.demand_next(false)?.value().to_boolean()
}
/// Yields the next value, if it is a `Double`, or an error otherwise.
fn next_double(&mut self) -> ReaderResult<Double> {
Ok(self.demand_next(false)?.value().to_double()?.to_owned())
}
/// Yields the next value, if it is a `SignedInteger`, or an error otherwise.
fn next_signedinteger(&mut self) -> ReaderResult<SignedInteger> {
Ok(self
.demand_next(false)?
.value()
.to_signedinteger()?
.to_owned())
}
/// Yields the next value, if it is a `SignedInteger` that fits in [i8], or an error
/// otherwise.
fn next_i8(&mut self) -> ReaderResult<i8> {
self.demand_next(false)?.value().to_i8()
}
/// Yields the next value, if it is a `SignedInteger` that fits in [u8], or an error
/// otherwise.
fn next_u8(&mut self) -> ReaderResult<u8> {
self.demand_next(false)?.value().to_u8()
}
/// Yields the next value, if it is a `SignedInteger` that fits in [i16], or an error
/// otherwise.
fn next_i16(&mut self) -> ReaderResult<i16> {
self.demand_next(false)?.value().to_i16()
}
/// Yields the next value, if it is a `SignedInteger` that fits in [u16], or an error
/// otherwise.
fn next_u16(&mut self) -> ReaderResult<u16> {
self.demand_next(false)?.value().to_u16()
}
/// Yields the next value, if it is a `SignedInteger` that fits in [i32], or an error
/// otherwise.
fn next_i32(&mut self) -> ReaderResult<i32> {
self.demand_next(false)?.value().to_i32()
}
/// Yields the next value, if it is a `SignedInteger` that fits in [u32], or an error
/// otherwise.
fn next_u32(&mut self) -> ReaderResult<u32> {
self.demand_next(false)?.value().to_u32()
}
/// Yields the next value, if it is a `SignedInteger` that fits in [i64], or an error
/// otherwise.
fn next_i64(&mut self) -> ReaderResult<i64> {
self.demand_next(false)?.value().to_i64()
}
/// Yields the next value, if it is a `SignedInteger` that fits in [u64], or an error
/// otherwise.
fn next_u64(&mut self) -> ReaderResult<u64> {
self.demand_next(false)?.value().to_u64()
}
/// Yields the next value, if it is a `SignedInteger` that fits in [i128], or an error
/// otherwise.
fn next_i128(&mut self) -> ReaderResult<i128> {
self.demand_next(false)?.value().to_i128()
}
/// Yields the next value, if it is a `SignedInteger` that fits in [u128], or an error
/// otherwise.
fn next_u128(&mut self) -> ReaderResult<u128> {
self.demand_next(false)?.value().to_u128()
}
/// Yields the next value as an [f64], if it is a `Double`, or an error otherwise.
fn next_f64(&mut self) -> ReaderResult<f64> {
self.demand_next(false)?.value().to_f64()
}
/// Yields the next value as a [char], if it is parseable by
/// [Value::to_char][crate::value::Value::to_char], or an error otherwise.
fn next_char(&mut self) -> ReaderResult<char> {
self.demand_next(false)?.value().to_char()
}
/// Yields the next value, if it is a `String`, or an error otherwise.
fn next_str(&mut self) -> ReaderResult<Cow<'de, str>> {
Ok(Cow::Owned(
self.demand_next(false)?.value().to_string()?.to_owned(),
))
}
/// Yields the next value, if it is a `ByteString`, or an error otherwise.
fn next_bytestring(&mut self) -> ReaderResult<Cow<'de, [u8]>> {
Ok(Cow::Owned(
self.demand_next(false)?.value().to_bytestring()?.to_owned(),
))
}
/// Yields the next value, if it is a `Symbol`, or an error otherwise.
fn next_symbol(&mut self) -> ReaderResult<Cow<'de, str>> {
Ok(Cow::Owned(
self.demand_next(false)?.value().to_symbol()?.to_owned(),
))
}
#[doc(hidden)]
fn open_option(&mut self) -> ReaderResult<Option<B::Type>> {
let b = self.open_record(None)?;
let label: &str = &self.next_symbol()?;
match label {
"None" => {
self.ensure_complete(b, &B::Item::RecordField)?;
Ok(None)
}
"Some" => Ok(Some(b)),
_ => Err(error::Error::Expected(
ExpectedKind::Option,
Received::ReceivedRecordWithLabel(label.to_owned()),
)),
}
}
#[doc(hidden)]
fn open_simple_record(&mut self, name: &str, arity: Option<usize>) -> ReaderResult<B::Type> {
let b = self.open_record(arity)?;
let label: &str = &self.next_symbol()?;
if label == name {
Ok(b)
} else {
Err(error::Error::Expected(
ExpectedKind::SimpleRecord(name.to_owned(), arity),
Received::ReceivedRecordWithLabel(label.to_owned()),
))
}
}
/// Constructs a [ConfiguredReader] set with the given value for `read_annotations`.
fn configured(self, read_annotations: bool) -> ConfiguredReader<'de, N, Self>
where
Self: std::marker::Sized,
{
ConfiguredReader {
reader: self,
read_annotations,
phantom: PhantomData,
}
}
#[doc(hidden)]
fn ensure_more_expected(&mut self, b: &mut B::Type, i: &B::Item) -> ReaderResult<()> {
if !self.close_compound(b, i)? {
Ok(())
} else {
Err(error::Error::MissingItem)
}
}
#[doc(hidden)]
fn ensure_complete(&mut self, mut b: B::Type, i: &B::Item) -> ReaderResult<()> {
if !self.close_compound(&mut b, i)? {
Err(error::Error::MissingCloseDelimiter)
} else {
Ok(())
}
}
}
impl<'r, 'de, N: NestedValue, R: Reader<'de, N>> Reader<'de, N> for &'r mut R {
fn next(&mut self, read_annotations: bool) -> io::Result<Option<N>> {
(*self).next(read_annotations)
}
fn open_record(&mut self, arity: Option<usize>) -> ReaderResult<B::Type> {
(*self).open_record(arity)
}
fn open_sequence_or_set(&mut self) -> ReaderResult<B::Item> {
(*self).open_sequence_or_set()
}
fn open_sequence(&mut self) -> ReaderResult<()> {
(*self).open_sequence()
}
fn open_set(&mut self) -> ReaderResult<()> {
(*self).open_set()
}
fn open_dictionary(&mut self) -> ReaderResult<()> {
(*self).open_dictionary()
}
fn boundary(&mut self, b: &B::Type) -> ReaderResult<()> {
(*self).boundary(b)
}
fn close_compound(&mut self, b: &mut B::Type, i: &B::Item) -> ReaderResult<bool> {
(*self).close_compound(b, i)
}
fn open_embedded(&mut self) -> ReaderResult<()> {
(*self).open_embedded()
}
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<N>> {
(*self).next_token(read_embedded_annotations)
}
fn next_annotations_and_token(&mut self) -> io::Result<(Vec<N>, Token<N>)> {
(*self).next_annotations_and_token()
}
}
/// Generic seekable stream of input bytes.
pub trait BinarySource<'de>: Sized {
/// Allows structured backtracking to an earlier position in an input.
type Mark;
/// Retrieve a marker for the current position in the input.
fn mark(&mut self) -> io::Result<Self::Mark>;
/// Seek the input to a previously-saved position.
fn restore(&mut self, mark: &Self::Mark) -> io::Result<()>;
/// Skip the next byte.
fn skip(&mut self) -> io::Result<()>;
/// Returns the next byte without advancing over it.
fn peek(&mut self) -> io::Result<u8>;
/// Returns and consumes the next `count` bytes, which must all be available. Always yields
/// exactly `count` bytes or an error.
fn readbytes(&mut self, count: usize) -> io::Result<Cow<'de, [u8]>>;
/// As [BinarySource::readbytes], but uses `bs` as destination for the read bytes as well
/// as taking the size of `bs` as the count of bytes to read.
fn readbytes_into(&mut self, bs: &mut [u8]) -> io::Result<()>;
/// Constructs a [PackedReader][super::PackedReader] that will read from `self`.
fn packed<N: NestedValue, Dec: DomainDecode<N::Embedded>>(
&mut self,
decode_embedded: Dec,
) -> super::PackedReader<'de, '_, N, Dec, Self> {
super::PackedReader::new(self, decode_embedded)
}
/// Constructs a [PackedReader][super::PackedReader] that will read [IOValue]s from `self`.
fn packed_iovalues(
&mut self,
) -> super::PackedReader<'de, '_, IOValue, IOValueDomainCodec, Self> {
self.packed(IOValueDomainCodec)
}
/// Constructs a [TextReader][super::TextReader] that will read from `self`.
fn text<N: NestedValue, Dec: DomainParse<N::Embedded>>(
&mut self,
decode_embedded: Dec,
) -> super::TextReader<'de, '_, N, Dec, Self> {
super::TextReader::new(self, decode_embedded)
}
/// Constructs a [TextReader][super::TextReader] that will read [IOValue]s from `self`.
fn text_iovalues(
&mut self,
) -> super::TextReader<'de, '_, IOValue, ViaCodec<IOValueDomainCodec>, Self> {
self.text::<IOValue, _>(ViaCodec::new(IOValueDomainCodec))
}
}
/// Implementation of [BinarySource] backed by an [`io::Read`]` + `[`io::Seek`] implementation.
pub struct IOBinarySource<R: io::Read + io::Seek> {
/// The underlying byte source.
pub read: R,
#[doc(hidden)]
/// One-place buffer for peeked bytes.
pub buf: Option<u8>,
}
impl<R: io::Read + io::Seek> IOBinarySource<R> {
/// Constructs an [IOBinarySource] from the given [`io::Read`]` + `[`io::Seek`]
/// implementation.
#[inline(always)]
pub fn new(read: R) -> Self {
IOBinarySource { read, buf: None }
}
}
impl<'de, R: io::Read + io::Seek> BinarySource<'de> for IOBinarySource<R> {
type Mark = u64;
#[inline(always)]
fn mark(&mut self) -> io::Result<Self::Mark> {
Ok(self.read.stream_position()? - (if self.buf.is_some() { 1 } else { 0 }))
}
#[inline(always)]
fn restore(&mut self, mark: &Self::Mark) -> io::Result<()> {
self.read.seek(io::SeekFrom::Start(*mark))?;
self.buf = None;
Ok(())
}
#[inline(always)]
fn skip(&mut self) -> io::Result<()> {
if self.buf.is_none() {
unreachable!();
}
self.buf = None;
Ok(())
}
#[inline(always)]
fn peek(&mut self) -> io::Result<u8> {
match self.buf {
Some(b) => Ok(b),
None => {
let b = &mut [0];
match self.read.read(b)? {
0 => Err(io_eof()),
1 => {
self.buf = Some(b[0]);
Ok(b[0])
}
_ => unreachable!(),
}
}
}
}
#[inline(always)]
fn readbytes(&mut self, count: usize) -> io::Result<Cow<'de, [u8]>> {
if self.buf.is_some() {
unreachable!();
}
let mut bs = vec![0; count];
self.read.read_exact(&mut bs)?;
Ok(Cow::Owned(bs))
}
#[inline(always)]
fn readbytes_into(&mut self, bs: &mut [u8]) -> io::Result<()> {
if self.buf.is_some() {
unreachable!();
}
self.read.read_exact(bs)
}
}
/// Implementation of [BinarySource] backed by a slice of [u8].
pub struct BytesBinarySource<'de> {
/// The underlying byte source.
pub bytes: &'de [u8],
#[doc(hidden)]
/// Current position within `bytes`.
pub index: usize,
}
impl<'de> BytesBinarySource<'de> {
/// Constructs a [BytesBinarySource] from the given `u8` slice.
#[inline(always)]
pub fn new(bytes: &'de [u8]) -> Self {
BytesBinarySource { bytes, index: 0 }
}
}
impl<'de> BinarySource<'de> for BytesBinarySource<'de> {
type Mark = usize;
#[inline(always)]
fn mark(&mut self) -> io::Result<Self::Mark> {
Ok(self.index)
}
#[inline(always)]
fn restore(&mut self, mark: &Self::Mark) -> io::Result<()> {
self.index = *mark;
Ok(())
}
#[inline(always)]
fn skip(&mut self) -> io::Result<()> {
if self.index >= self.bytes.len() {
unreachable!();
}
self.index += 1;
Ok(())
}
#[inline(always)]
fn peek(&mut self) -> io::Result<u8> {
if self.index >= self.bytes.len() {
Err(io_eof())
} else {
Ok(self.bytes[self.index])
}
}
#[inline(always)]
fn readbytes(&mut self, count: usize) -> io::Result<Cow<'de, [u8]>> {
if self.index + count > self.bytes.len() {
Err(io_eof())
} else {
let bs = &self.bytes[self.index..self.index + count];
self.index += count;
Ok(Cow::Borrowed(bs))
}
}
#[inline(always)]
fn readbytes_into(&mut self, bs: &mut [u8]) -> io::Result<()> {
let count = bs.len();
if self.index + count > self.bytes.len() {
Err(io_eof())
} else {
bs.copy_from_slice(&self.bytes[self.index..self.index + count]);
self.index += count;
Ok(())
}
}
}
/// A combination of a [Reader] with presets governing its operation.
pub struct ConfiguredReader<'de, N: NestedValue, R: Reader<'de, N>> {
/// The underlying [Reader].
pub reader: R,
/// Configuration as to whether to include or discard annotations while reading.
pub read_annotations: bool,
phantom: PhantomData<&'de N>,
}
impl<'de, N: NestedValue, R: Reader<'de, N>> ConfiguredReader<'de, N, R> {
/// Constructs a [ConfiguredReader] based on the given `reader`.
pub fn new(reader: R) -> Self {
reader.configured(true)
}
/// Updates the `read_annotations` field of `self`.
pub fn set_read_annotations(&mut self, read_annotations: bool) {
self.read_annotations = read_annotations
}
/// Retrieve the next parseable value, treating end-of-input as an error.
///
/// Delegates directly to [Reader::demand_next].
pub fn demand_next(&mut self) -> io::Result<N> {
self.reader.demand_next(self.read_annotations)
}
}
impl<'de, N: NestedValue, R: Reader<'de, N>> std::iter::Iterator for ConfiguredReader<'de, N, R> {
type Item = io::Result<N>;
fn next(&mut self) -> Option<Self::Item> {
match self.reader.next(self.read_annotations) {
Err(e) => Some(Err(e)),
Ok(None) => None,
Ok(Some(v)) => Some(Ok(v)),
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,377 +0,0 @@
//! Support for Serde serialization of Rust data types into Preserves *values* (not syntax).
use crate::value::{repr::Record, IOValue, Map, Value};
use serde::Serialize;
/// Empty/placeholder type for representing serialization errors: serialization to values
/// cannot fail.
#[derive(Debug)]
pub enum Error {}
impl serde::ser::Error for Error {
fn custom<T>(_: T) -> Self
where
T: std::fmt::Display,
{
unreachable!()
}
}
impl std::error::Error for Error {}
impl std::fmt::Display for Error {
fn fmt(&self, _fmt: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
unreachable!()
}
}
type Result<T> = std::result::Result<T, Error>;
/// Serde serializer for converting Rust data to in-memory Preserves values, which can then be
/// serialized using text or binary syntax, analyzed further, etc.
pub struct Serializer;
#[doc(hidden)]
pub struct SerializeDictionary {
next_key: Option<IOValue>,
items: Map<IOValue, IOValue>,
}
#[doc(hidden)]
pub struct SerializeRecord {
r: Record<IOValue>,
}
#[doc(hidden)]
pub struct SerializeSequence {
vec: Vec<IOValue>,
}
impl serde::Serializer for Serializer {
type Ok = IOValue;
type Error = Error;
type SerializeSeq = SerializeSequence;
type SerializeTuple = SerializeRecord;
type SerializeTupleStruct = SerializeRecord;
type SerializeTupleVariant = SerializeRecord;
type SerializeMap = SerializeDictionary;
type SerializeStruct = SerializeRecord;
type SerializeStructVariant = SerializeRecord;
fn serialize_bool(self, v: bool) -> Result<Self::Ok> {
Ok(Value::from(v).wrap())
}
fn serialize_i8(self, v: i8) -> Result<Self::Ok> {
Ok(Value::from(v).wrap())
}
fn serialize_i16(self, v: i16) -> Result<Self::Ok> {
Ok(Value::from(v).wrap())
}
fn serialize_i32(self, v: i32) -> Result<Self::Ok> {
Ok(Value::from(v).wrap())
}
fn serialize_i64(self, v: i64) -> Result<Self::Ok> {
Ok(Value::from(v).wrap())
}
fn serialize_u8(self, v: u8) -> Result<Self::Ok> {
Ok(Value::from(v).wrap())
}
fn serialize_u16(self, v: u16) -> Result<Self::Ok> {
Ok(Value::from(v).wrap())
}
fn serialize_u32(self, v: u32) -> Result<Self::Ok> {
Ok(Value::from(v).wrap())
}
fn serialize_u64(self, v: u64) -> Result<Self::Ok> {
Ok(Value::from(v).wrap())
}
fn serialize_f32(self, v: f32) -> Result<Self::Ok> {
Ok(Value::from(v as f64).wrap())
}
fn serialize_f64(self, v: f64) -> Result<Self::Ok> {
Ok(Value::from(v).wrap())
}
fn serialize_char(self, v: char) -> Result<Self::Ok> {
Ok(Value::simple_record1("UnicodeScalar", Value::from(v as u32).wrap()).wrap())
}
fn serialize_str(self, v: &str) -> Result<Self::Ok> {
Ok(Value::from(v).wrap())
}
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok> {
Ok(Value::from(v).wrap())
}
fn serialize_none(self) -> Result<Self::Ok> {
Ok(Value::simple_record0("None").wrap())
}
fn serialize_some<T: ?Sized>(self, v: &T) -> Result<Self::Ok>
where
T: Serialize,
{
Ok(Value::simple_record1("Some", to_value(v)).wrap())
}
fn serialize_unit(self) -> Result<Self::Ok> {
Ok(Value::simple_record0("tuple").wrap())
}
fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok> {
Ok(Value::simple_record0(name).wrap())
}
fn serialize_unit_variant(
self,
_name: &'static str,
_variant: u32,
variant_name: &'static str,
) -> Result<Self::Ok> {
Ok(Value::simple_record0(variant_name).wrap())
}
fn serialize_newtype_struct<T: ?Sized>(self, name: &'static str, value: &T) -> Result<Self::Ok>
where
T: Serialize,
{
match super::magic::receive_output_value(name, value) {
Some(v) => Ok(v),
None => {
// TODO: This is apparently discouraged, and we should apparently just serialize `value`?
Ok(Value::simple_record1(name, to_value(value)).wrap())
}
}
}
fn serialize_newtype_variant<T: ?Sized>(
self,
_name: &'static str,
_variant: u32,
variant_name: &'static str,
value: &T,
) -> Result<Self::Ok>
where
T: Serialize,
{
Ok(Value::simple_record1(variant_name, to_value(value)).wrap())
}
fn serialize_seq(self, count: Option<usize>) -> Result<Self::SerializeSeq> {
let vec = match count {
Some(n) => Vec::with_capacity(n),
None => Vec::new(),
};
Ok(SerializeSequence { vec })
}
fn serialize_tuple(self, count: usize) -> Result<Self::SerializeTuple> {
Ok(SerializeRecord {
r: Value::simple_record("tuple", count),
})
}
fn serialize_tuple_struct(
self,
name: &'static str,
count: usize,
) -> Result<Self::SerializeTupleStruct> {
Ok(SerializeRecord {
r: Value::simple_record(name, count),
})
}
fn serialize_tuple_variant(
self,
_name: &'static str,
_variant: u32,
variant_name: &'static str,
count: usize,
) -> Result<Self::SerializeTupleVariant> {
Ok(SerializeRecord {
r: Value::simple_record(variant_name, count),
})
}
fn serialize_map(self, _count: Option<usize>) -> Result<Self::SerializeMap> {
Ok(SerializeDictionary {
next_key: None,
items: Map::new(),
})
}
fn serialize_struct(self, name: &'static str, count: usize) -> Result<Self::SerializeStruct> {
Ok(SerializeRecord {
r: Value::simple_record(name, count),
})
}
fn serialize_struct_variant(
self,
_name: &'static str,
_variant: u32,
variant_name: &'static str,
count: usize,
) -> Result<Self::SerializeStructVariant> {
Ok(SerializeRecord {
r: Value::simple_record(variant_name, count),
})
}
}
impl serde::ser::SerializeMap for SerializeDictionary {
type Ok = IOValue;
type Error = Error;
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<()>
where
T: Serialize,
{
self.next_key = Some(to_value(key));
Ok(())
}
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<()>
where
T: Serialize,
{
let key = self.next_key.take().unwrap();
self.items.insert(key, to_value(value));
Ok(())
}
fn end(self) -> Result<Self::Ok> {
Ok(Value::from(self.items).wrap())
}
}
impl SerializeRecord {
fn push<T: ?Sized>(&mut self, value: &T)
where
T: Serialize,
{
self.r.fields_vec_mut().push(to_value(value))
}
fn finish(self) -> IOValue {
self.r.finish().wrap()
}
}
impl serde::ser::SerializeStruct for SerializeRecord {
type Ok = IOValue;
type Error = Error;
fn serialize_field<T: ?Sized>(&mut self, _name: &'static str, value: &T) -> Result<()>
where
T: Serialize,
{
self.push(value);
Ok(())
}
fn end(self) -> Result<Self::Ok> {
Ok(self.finish())
}
}
impl serde::ser::SerializeStructVariant for SerializeRecord {
type Ok = IOValue;
type Error = Error;
fn serialize_field<T: ?Sized>(&mut self, _name: &'static str, value: &T) -> Result<()>
where
T: Serialize,
{
self.push(value);
Ok(())
}
fn end(self) -> Result<Self::Ok> {
Ok(self.finish())
}
}
impl serde::ser::SerializeTuple for SerializeRecord {
type Ok = IOValue;
type Error = Error;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<()>
where
T: Serialize,
{
self.push(value);
Ok(())
}
fn end(self) -> Result<Self::Ok> {
Ok(self.finish())
}
}
impl serde::ser::SerializeTupleStruct for SerializeRecord {
type Ok = IOValue;
type Error = Error;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<()>
where
T: Serialize,
{
self.push(value);
Ok(())
}
fn end(self) -> Result<Self::Ok> {
Ok(self.finish())
}
}
impl serde::ser::SerializeTupleVariant for SerializeRecord {
type Ok = IOValue;
type Error = Error;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<()>
where
T: Serialize,
{
self.push(value);
Ok(())
}
fn end(self) -> Result<Self::Ok> {
Ok(self.finish())
}
}
impl serde::ser::SerializeSeq for SerializeSequence {
type Ok = IOValue;
type Error = Error;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<()>
where
T: Serialize,
{
self.vec.push(to_value(value));
Ok(())
}
fn end(self) -> Result<Self::Ok> {
Ok(Value::from(self.vec).wrap())
}
}
/// Convenience function for directly converting a Serde-serializable `T` to an [IOValue].
pub fn to_value<T>(value: T) -> IOValue
where
T: Serialize,
{
value.serialize(Serializer).unwrap()
}

View File

@ -1,265 +0,0 @@
//! Representation of Preserves `SignedInteger`s as [i128]/[u128] (if they fit) or [BigInt] (if
//! they don't).
use num::bigint::BigInt;
use num::traits::cast::ToPrimitive;
use num::traits::sign::Signed;
use std::borrow::Cow;
use std::cmp::{Ord, Ordering, PartialOrd};
use std::convert::TryFrom;
use std::convert::TryInto;
use std::fmt;
/// Internal representation of Preserves `SignedInteger`s.
///
/// Invariant: if I128 can be used, it will be; otherwise, if U128 can be used, it will be;
/// otherwise, Big will be used.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum SignedIntegerRepr {
I128(i128),
U128(u128),
Big(Box<BigInt>),
}
/// Main representation of Preserves `SignedInteger`s.
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct SignedInteger(SignedIntegerRepr);
impl fmt::Debug for SignedInteger {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}n", self)
}
}
impl fmt::Display for SignedInteger {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self.repr() {
SignedIntegerRepr::I128(i) => i.fmt(f),
SignedIntegerRepr::U128(u) => u.fmt(f),
SignedIntegerRepr::Big(n) => n.fmt(f),
}
}
}
impl Ord for SignedInteger {
fn cmp(&self, other: &Self) -> Ordering {
match self.repr() {
SignedIntegerRepr::I128(i1) => match other.repr() {
SignedIntegerRepr::I128(i2) => i1.cmp(i2),
SignedIntegerRepr::U128(_) => {
if *i1 < 0 {
Ordering::Less
} else {
Ordering::Greater
}
}
SignedIntegerRepr::Big(n) => {
if n.is_negative() {
Ordering::Less
} else {
Ordering::Greater
}
}
},
SignedIntegerRepr::U128(u1) => match other.repr() {
SignedIntegerRepr::I128(_) => Ordering::Greater,
SignedIntegerRepr::U128(u2) => u1.cmp(u2),
SignedIntegerRepr::Big(n) => {
if n.is_positive() {
Ordering::Less
} else {
Ordering::Greater
}
}
},
SignedIntegerRepr::Big(n1) => match other.repr() {
SignedIntegerRepr::I128(_) | SignedIntegerRepr::U128(_) => {
if n1.is_negative() {
Ordering::Less
} else {
Ordering::Greater
}
}
SignedIntegerRepr::Big(n2) => n1.cmp(n2),
},
}
}
}
impl PartialOrd for SignedInteger {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl SignedInteger {
/// Extract the internal representation.
pub fn repr(&self) -> &SignedIntegerRepr {
&self.0
}
/// Does this `SignedInteger` fit in an [i128]? (See also [the TryFrom instance for
/// i128](#impl-TryFrom<%26SignedInteger>-for-i128).)
pub fn is_i(&self) -> bool {
matches!(self.0, SignedIntegerRepr::I128(_))
}
/// Does this `SignedInteger` fit in a [u128], but not an [i128]? (See also [the TryFrom
/// instance for u128](#impl-TryFrom<%26SignedInteger>-for-u128).)
pub fn is_u(&self) -> bool {
matches!(self.0, SignedIntegerRepr::U128(_))
}
/// Does this `SignedInteger` fit neither in a [u128] nor an [i128]? (See also [the TryFrom
/// instance for BigInt](#impl-From<%26'a+SignedInteger>-for-BigInt).)
pub fn is_big(&self) -> bool {
matches!(self.0, SignedIntegerRepr::Big(_))
}
}
//--
macro_rules! map_integral_type_to_signed_integer {
($iN:ident, $uN:ident) => {
impl From<$iN> for SignedInteger {
fn from(v: $iN) -> Self {
SignedInteger(SignedIntegerRepr::I128(v.into()))
}
}
impl From<$uN> for SignedInteger {
fn from(v: $uN) -> Self {
SignedInteger(SignedIntegerRepr::I128(v.into()))
}
}
impl TryFrom<&SignedInteger> for $iN {
type Error = ();
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
i128::try_from(v)?.try_into().map_err(|_| ())
}
}
impl TryFrom<&SignedInteger> for $uN {
type Error = ();
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
u128::try_from(v)?.try_into().map_err(|_| ())
}
}
};
}
map_integral_type_to_signed_integer!(i8, u8);
map_integral_type_to_signed_integer!(i16, u16);
map_integral_type_to_signed_integer!(i32, u32);
map_integral_type_to_signed_integer!(i64, u64);
//--
impl From<i128> for SignedInteger {
fn from(v: i128) -> Self {
SignedInteger(SignedIntegerRepr::I128(v))
}
}
impl From<u128> for SignedInteger {
fn from(v: u128) -> Self {
if let Ok(w) = v.try_into() {
SignedInteger(SignedIntegerRepr::I128(w))
} else {
SignedInteger(SignedIntegerRepr::U128(v))
}
}
}
impl TryFrom<&SignedInteger> for i128 {
type Error = ();
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
match v.repr() {
SignedIntegerRepr::I128(i) => Ok(*i),
SignedIntegerRepr::U128(_) => Err(()),
SignedIntegerRepr::Big(_) => Err(()),
}
}
}
impl TryFrom<&SignedInteger> for u128 {
type Error = ();
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
match v.repr() {
SignedIntegerRepr::I128(i) => i.to_u128().ok_or(()),
SignedIntegerRepr::U128(u) => Ok(*u),
SignedIntegerRepr::Big(_) => Err(()),
}
}
}
//--
impl From<BigInt> for SignedInteger {
fn from(v: BigInt) -> Self {
Self::from(Cow::Owned(v))
}
}
impl<'a> From<&'a SignedInteger> for BigInt {
fn from(v: &'a SignedInteger) -> Self {
match v.repr() {
SignedIntegerRepr::I128(i) => BigInt::from(*i),
SignedIntegerRepr::U128(u) => BigInt::from(*u),
SignedIntegerRepr::Big(n) => *n.clone(),
}
}
}
//--
impl<'a> From<Cow<'a, BigInt>> for SignedInteger {
fn from(v: Cow<'a, BigInt>) -> Self {
if let Some(w) = v.to_i128() {
SignedInteger(SignedIntegerRepr::I128(w))
} else if let Some(w) = v.to_u128() {
SignedInteger(SignedIntegerRepr::U128(w))
} else {
SignedInteger(SignedIntegerRepr::Big(Box::new(v.into_owned())))
}
}
}
impl<'a> From<&'a SignedInteger> for Cow<'a, BigInt> {
fn from(v: &'a SignedInteger) -> Self {
match v.repr() {
SignedIntegerRepr::I128(i) => Cow::Owned(BigInt::from(*i)),
SignedIntegerRepr::U128(u) => Cow::Owned(BigInt::from(*u)),
SignedIntegerRepr::Big(n) => Cow::Borrowed(n),
}
}
}
//--
impl From<isize> for SignedInteger {
fn from(v: isize) -> Self {
SignedInteger(SignedIntegerRepr::I128(v as i128))
}
}
impl From<usize> for SignedInteger {
fn from(v: usize) -> Self {
SignedInteger(SignedIntegerRepr::U128(v as u128))
}
}
impl TryFrom<&SignedInteger> for isize {
type Error = ();
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
i128::try_from(v)?.try_into().map_err(|_| ())
}
}
impl TryFrom<&SignedInteger> for usize {
type Error = ();
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
u128::try_from(v)?.try_into().map_err(|_| ())
}
}

View File

@ -1,62 +0,0 @@
#![doc(hidden)]
use std::ops::{Deref, DerefMut};
pub enum Suspendable<T> {
Active(T),
Suspended,
}
impl<T> Suspendable<T> {
pub fn new(t: T) -> Self {
Suspendable::Active(t)
}
#[inline(always)]
pub fn suspend(&mut self) -> Self {
match self {
Suspendable::Active(_) => std::mem::replace(self, Suspendable::Suspended),
Suspendable::Suspended => panic!("Attempt to suspend suspended Suspendable"),
}
}
#[inline(always)]
pub fn resume(&mut self, other: Self) {
match self {
Suspendable::Suspended => match other {
Suspendable::Active(_) => *self = other,
Suspendable::Suspended => panic!("Attempt to resume from suspended Suspendable"),
},
Suspendable::Active(_) => panic!("Attempt to resume non-suspended Suspendable"),
}
}
#[inline(always)]
pub fn take(self) -> T {
match self {
Suspendable::Active(t) => t,
Suspendable::Suspended => panic!("Attempt to take from suspended Suspendable"),
}
}
}
impl<T> Deref for Suspendable<T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
match self {
Suspendable::Suspended => panic!("Suspended Suspendable at deref"),
Suspendable::Active(t) => t,
}
}
}
impl<T> DerefMut for Suspendable<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
Suspendable::Suspended => panic!("Empty Suspendable at deref_mut"),
Suspendable::Active(t) => t,
}
}
}

View File

@ -1,50 +0,0 @@
//! Implements the Preserves [human-oriented text
//! syntax](https://preserves.dev/preserves-text.html).
//!
//! The main entry points for reading are functions [iovalue_from_str],
//! [annotated_iovalue_from_str], [from_str], and [annotated_from_str].
//!
//! The main entry points for writing are [TextWriter::encode_iovalue] and
//! [TextWriter::encode].
//!
//! # Summary of Text Syntax
#![doc = include_str!("../../../doc/cheatsheet-text-plaintext.md")]
pub mod reader;
pub mod writer;
pub use reader::TextReader;
pub use reader::ToplevelWhitespaceMode;
pub use writer::TextWriter;
use crate::value::reader::BytesBinarySource;
use std::io;
use super::{DomainParse, IOValue, IOValueDomainCodec, NestedValue, Reader, ViaCodec};
/// Reads a value from the given string using the text syntax, discarding annotations.
pub fn from_str<N: NestedValue, Dec: DomainParse<N::Embedded>>(
s: &str,
decode_embedded: Dec,
) -> io::Result<N> {
TextReader::new(&mut BytesBinarySource::new(s.as_bytes()), decode_embedded).demand_next(false)
}
/// Reads an [IOValue] from the given string using the text syntax, discarding annotations.
pub fn iovalue_from_str(s: &str) -> io::Result<IOValue> {
from_str(s, ViaCodec::new(IOValueDomainCodec))
}
/// As [from_str], but includes annotations.
pub fn annotated_from_str<N: NestedValue, Dec: DomainParse<N::Embedded>>(
s: &str,
decode_embedded: Dec,
) -> io::Result<N> {
TextReader::new(&mut BytesBinarySource::new(s.as_bytes()), decode_embedded).demand_next(true)
}
/// As [iovalue_from_str], but includes annotations.
pub fn annotated_iovalue_from_str(s: &str) -> io::Result<IOValue> {
annotated_from_str(s, ViaCodec::new(IOValueDomainCodec))
}

View File

@ -1,715 +0,0 @@
//! Implementation of [Reader] for the text syntax.
use crate::error::io_syntax_error;
use crate::error::is_eof_io_error;
use crate::error::syntax_error;
use crate::error::Error;
use crate::error::ExpectedKind;
use crate::error::Received;
use crate::hex;
use crate::value::boundary as B;
use crate::value::reader::BinarySource;
use crate::value::reader::ReaderResult;
use crate::value::repr::Annotations;
use crate::value::CompoundClass;
use crate::value::DomainParse;
use crate::value::IOValue;
use crate::value::IOValueDomainCodec;
use crate::value::Map;
use crate::value::NestedValue;
use crate::value::Reader;
use crate::value::Record;
use crate::value::Set;
use crate::value::Token;
use crate::value::Value;
use crate::value::ViaCodec;
use lazy_static::lazy_static;
use num::bigint::BigInt;
use std::convert::TryInto;
use std::io;
use std::marker::PhantomData;
/// The text syntax Preserves reader.
pub struct TextReader<'de, 'src, N: NestedValue, Dec: DomainParse<N::Embedded>, S: BinarySource<'de>> {
/// Underlying source of (utf8) bytes.
pub source: &'src mut S,
/// Decoder for producing Rust values embedded in the text.
pub dec: Dec,
/// Treatment of whitespace before a toplevel term.
pub toplevel_whitespace_mode: ToplevelWhitespaceMode,
phantom: PhantomData<&'de N>,
}
/// [TextReader] chooses `Document` mode to treat whitespace preceding end-of-file as a "no
/// more values" non-error situation, or `Value` mode to treat it as an "expected more input"
/// situation.
///
/// The Preserves syntax for `Value` treats any input at all, even whitespace, as an indicator
/// that a term is to follow. However, when using a TextReader to parse a *series* of `Value`s
/// in a `Document`, whitespace followed by EOF is to be treated as the permitted optional
/// whitespace at the end of a `Document.
pub enum ToplevelWhitespaceMode {
Document,
Value,
}
fn decode_utf8(bs: Vec<u8>) -> io::Result<String> {
Ok(String::from_utf8(bs).map_err(|_| io_syntax_error("Invalid UTF-8"))?)
}
fn append_codepoint(bs: &mut Vec<u8>, n: u32) -> io::Result<()> {
let c = char::from_u32(n).ok_or_else(|| io_syntax_error("Bad code point"))?;
let mut buf = [0; 4];
let _ = c.encode_utf8(&mut buf);
bs.extend(&buf[0..c.len_utf8()]);
Ok(())
}
impl<'de, 'src, N: NestedValue, Dec: DomainParse<N::Embedded>, S: BinarySource<'de>>
TextReader<'de, 'src, N, Dec, S>
{
/// Construct a new reader from a byte (utf8) source and embedded-value decoder.
pub fn new(source: &'src mut S, dec: Dec) -> Self {
TextReader {
source,
dec,
toplevel_whitespace_mode: ToplevelWhitespaceMode::Document,
phantom: PhantomData,
}
}
pub fn toplevel_whitespace_mode(mut self, new_mode: ToplevelWhitespaceMode) -> Self {
self.toplevel_whitespace_mode = new_mode;
self
}
fn peek(&mut self) -> io::Result<u8> {
self.source.peek()
}
fn skip(&mut self) -> io::Result<()> {
self.source.skip()
}
fn next_byte(&mut self) -> io::Result<u8> {
let b = self.source.peek()?;
self.source.skip()?;
Ok(b)
}
fn skip_whitespace(&mut self) {
self.skip_whitespace_and_maybe_commas(false)
}
fn skip_whitespace_and_maybe_commas(&mut self, skip_commas: bool) {
// Deliberately swallows errors.
while let Ok(c) = self.peek() {
match c {
b' ' | b'\t' | b'\r' | b'\n' => {
let _ = self.skip();
()
}
b',' if skip_commas => {
let _ = self.skip();
()
}
_ => break,
}
}
}
// TODO: This is a duplicate of fn expected in PackedReader.
fn expected(&mut self, k: ExpectedKind) -> Error {
match Reader::<N>::demand_next(self, true) {
Ok(v) => Error::Expected(k, Received::ReceivedOtherValue(format!("{:?}", v))),
Err(e) => e.into(),
}
}
fn gather_annotations(&mut self, vs: &mut Vec<N>) -> ReaderResult<()> {
loop {
self.skip_whitespace();
match self.peek()? {
b'#' => {
let m = self.source.mark()?;
self.skip()?;
match self.next_byte()? {
b' ' | b'\t' => vs.push(N::new(self.comment_line()?)),
b'\n' | b'\r' => vs.push(N::new("")),
_ => {
self.source.restore(&m)?;
return Ok(());
}
}
}
b'@' => {
self.skip()?;
vs.push(self.demand_next(true)?)
}
_ => return Ok(()),
}
}
}
fn prepend_annotations_to_next(&mut self, mut annotations: Vec<N>) -> ReaderResult<N> {
let (existing_annotations, v) = Reader::<N>::demand_next(self, true)?.pieces();
annotations.extend_from_slice(existing_annotations.slice());
Ok(N::wrap(Annotations::new(Some(annotations)), v))
}
fn skip_annotations(&mut self) -> ReaderResult<()> {
loop {
self.skip_whitespace();
match self.peek()? {
b'#' => {
let m = self.source.mark()?;
self.skip()?;
match self.next_byte()? {
b' ' | b'\t' => { self.comment_line()?; () }
b'\n' | b'\r' => (),
_ => {
self.source.restore(&m)?;
return Ok(());
}
}
}
b'@' => {
self.skip()?;
self.skip_value()?;
}
_ => return Ok(()),
}
}
}
/// Retrieve the next [IOValue] in the input stream.
pub fn next_iovalue(&mut self, read_annotations: bool) -> io::Result<IOValue> {
let mut r = TextReader::new(self.source, ViaCodec::new(IOValueDomainCodec));
let v = r.demand_next(read_annotations)?;
Ok(v)
}
fn comment_line(&mut self) -> io::Result<String> {
let mut bs = Vec::new();
loop {
let b = self.peek()?;
self.skip()?;
match b {
b'\r' | b'\n' => return Ok(decode_utf8(bs)?),
_ => bs.push(b),
}
}
}
fn read_hex_float(&mut self) -> io::Result<N> {
if self.next_byte()? != b'"' {
return Err(io_syntax_error(
"Missing open-double-quote in hex-encoded floating-point number",
));
}
let bs = self.read_hex_binary()?;
if bs.len() != 8 {
return Err(io_syntax_error(
"Incorrect number of bytes in hex-encoded floating-point number",
));
}
Ok(Value::from(f64::from_bits(u64::from_be_bytes(bs.try_into().unwrap()))).wrap())
}
fn read_stringlike<X, H, R>(
&mut self,
mut seed: R,
xform_item: X,
terminator: u8,
hexescape: u8,
hexescaper: H,
) -> io::Result<R>
where
X: Fn(&mut R, u8) -> io::Result<()>,
H: Fn(&mut R, &mut Self) -> io::Result<()>,
{
loop {
match self.next_byte()? {
c if c == terminator => return Ok(seed),
b'\\' => match self.next_byte()? {
c if c == hexescape => hexescaper(&mut seed, self)?,
c if c == terminator || c == b'\\' || c == b'/' => xform_item(&mut seed, c)?,
b'b' => xform_item(&mut seed, b'\x08')?,
b'f' => xform_item(&mut seed, b'\x0c')?,
b'n' => xform_item(&mut seed, b'\x0a')?,
b'r' => xform_item(&mut seed, b'\x0d')?,
b't' => xform_item(&mut seed, b'\x09')?,
_ => return Err(io_syntax_error("Invalid escape code")),
},
c => xform_item(&mut seed, c)?,
}
}
}
fn hexnum(&mut self, count: usize) -> io::Result<u32> {
let mut v: u32 = 0;
for _ in 0..count {
let c = self.next_byte()?;
match (c as char).to_digit(16) {
Some(d) => v = v << 4 | d,
None => return Err(io_syntax_error("Bad hex escape")),
}
}
Ok(v)
}
fn read_string(&mut self, delimiter: u8) -> io::Result<String> {
decode_utf8(self.read_stringlike(
Vec::new(),
|bs, c| Ok(bs.push(c)),
delimiter,
b'u',
|bs, r| {
let n1 = r.hexnum(4)?;
if (0xd800..=0xdbff).contains(&n1) {
let mut ok = true;
ok = ok && r.next_byte()? == b'\\';
ok = ok && r.next_byte()? == b'u';
if !ok {
Err(io_syntax_error("Missing second half of surrogate pair"))
} else {
let n2 = r.hexnum(4)?;
if (0xdc00..=0xdfff).contains(&n2) {
let n = ((n1 - 0xd800) << 10) + (n2 - 0xdc00) + 0x10000;
append_codepoint(bs, n)
} else {
Err(io_syntax_error("Bad second half of surrogate pair"))
}
}
} else {
append_codepoint(bs, n1)
}
},
)?)
}
fn read_literal_binary(&mut self) -> io::Result<N> {
Ok(N::new(
&self.read_stringlike(
Vec::new(),
|bs, b| Ok(bs.push(b)),
b'"',
b'x',
|bs, r| Ok(bs.push(r.hexnum(2)? as u8)),
)?[..],
))
}
fn read_hex_binary(&mut self) -> io::Result<Vec<u8>> {
let mut s = String::new();
loop {
self.skip_whitespace();
let c1 = self.next_byte()? as char;
if c1 == '"' {
return Ok(hex::HexParser::Strict.decode(&s).unwrap());
}
let c2 = self.next_byte()? as char;
if !(c1.is_digit(16) && c2.is_digit(16)) {
return Err(io_syntax_error("Invalid hex binary"));
}
s.push(c1);
s.push(c2);
}
}
fn read_base64_binary(&mut self) -> io::Result<N> {
let mut bs = Vec::new();
loop {
self.skip_whitespace();
let mut c = self.next_byte()?;
if c == b']' {
let bs = base64::decode_config(&decode_utf8(bs)?, base64::STANDARD_NO_PAD)
.map_err(|_| io_syntax_error("Invalid base64 character"))?;
return Ok(N::new(&bs[..]));
}
if c == b'-' {
c = b'+';
}
if c == b'_' {
c = b'/';
}
if c == b'=' {
continue;
}
bs.push(c);
}
}
fn upto(&mut self, delimiter: u8, read_annotations: bool, skip_commas: bool) -> io::Result<Vec<N>> {
let mut vs = Vec::new();
loop {
self.skip_whitespace_and_maybe_commas(skip_commas);
if self.peek()? == delimiter {
self.skip()?;
return Ok(vs);
}
vs.push(Reader::<N>::demand_next(self, read_annotations)?);
}
}
fn read_set(&mut self, read_annotations: bool) -> io::Result<N> {
let items = self.upto(b'}', read_annotations, true)?;
let mut s = Set::<N>::new();
for i in items {
if s.contains(&i) {
return Err(io_syntax_error("Duplicate set element"));
}
s.insert(i);
}
Ok(N::new(s))
}
fn read_dictionary(&mut self, read_annotations: bool) -> io::Result<N> {
let mut d = Map::new();
loop {
self.skip_whitespace_and_maybe_commas(true);
if self.peek()? == b'}' {
self.skip()?;
return Ok(N::new(d));
}
let k = Reader::<N>::demand_next(self, read_annotations)?;
self.skip_whitespace();
if self.next_byte()? != b':' {
return Err(io_syntax_error("Missing expected key/value separator"));
}
if d.contains_key(&k) {
return Err(io_syntax_error("Duplicate key"));
}
let v = Reader::<N>::demand_next(self, read_annotations)?;
d.insert(k, v);
}
}
fn require_delimiter(&mut self, msg: &'static str) -> io::Result<()> {
if self.delimiter_follows()? {
Ok(())
} else {
Err(io_syntax_error(msg))
}
}
fn delimiter_follows(&mut self) -> io::Result<bool> {
let c = match self.peek() {
Err(e) if is_eof_io_error(&e) => return Ok(true),
Err(e) => return Err(e)?,
Ok(c) if (c as char).is_whitespace() => return Ok(true),
Ok(c) => c,
};
Ok(match c {
b'(' | b')' | b'{' | b'}' | b'[' | b']' | b'<' | b'>' | b'"' | b';' | b','
| b'@' | b'#' | b':' | b'|' | b' ' => true,
_ => false,
})
}
fn read_raw_symbol_or_number(&mut self, mut bs: Vec<u8>) -> io::Result<N> {
lazy_static! {
static ref NUMBER_RE: regex::Regex =
regex::Regex::new(r"^([-+]?\d+)((\.\d+([eE][-+]?\d+)?)|([eE][-+]?\d+))?$")
.unwrap();
}
while !self.delimiter_follows()? {
bs.push(self.next_byte()?);
}
let s = decode_utf8(bs)?;
match NUMBER_RE.captures(&s) {
None => Ok(N::symbol(&s)),
Some(m) => match m.get(2) {
None => Ok(N::new(s.parse::<BigInt>().map_err(|_| {
io_syntax_error(&format!("Invalid signed-integer number: {:?}", s))})?)),
Some(_) => Ok(N::new(s.parse::<f64>().map_err(|_| {
io_syntax_error(&format!("Invalid double-precision number: {:?}", s))})?)),
},
}
}
}
impl<'de, 'src, N: NestedValue, Dec: DomainParse<N::Embedded>, S: BinarySource<'de>> Reader<'de, N>
for TextReader<'de, 'src, N, Dec, S>
{
fn next(&mut self, read_annotations: bool) -> io::Result<Option<N>> {
'restart: loop {
match self.toplevel_whitespace_mode {
ToplevelWhitespaceMode::Document => self.skip_whitespace(),
ToplevelWhitespaceMode::Value => (),
}
match self.peek() {
Err(e) if is_eof_io_error(&e) => return Ok(None),
_ => (),
}
match self.toplevel_whitespace_mode {
ToplevelWhitespaceMode::Document => (),
ToplevelWhitespaceMode::Value => self.skip_whitespace(),
}
return Ok(Some(match self.peek()? {
b'"' => {
self.skip()?;
N::new(self.read_string(b'"')?)
}
b'|' => {
self.skip()?;
N::symbol(&self.read_string(b'|')?)
}
b';' => {
return Err(io_syntax_error(
"Semicolon is reserved syntax"
));
}
b'@' => {
if read_annotations {
let mut annotations = Vec::new();
self.gather_annotations(&mut annotations)?;
self.prepend_annotations_to_next(annotations)?
} else {
self.skip_annotations()?;
self.demand_next(read_annotations)?
}
}
b':' => {
return Err(io_syntax_error(
"Unexpected key/value separator between items",
));
}
b'#' => {
self.skip()?;
match self.next_byte()? {
b' ' | b'\t' => {
if read_annotations {
let mut annotations = vec![N::new(self.comment_line()?)];
self.gather_annotations(&mut annotations)?;
self.prepend_annotations_to_next(annotations)?
} else {
self.comment_line()?;
continue 'restart;
}
}
b'\n' | b'\r' => {
if read_annotations {
let mut annotations = vec![N::new("")];
self.gather_annotations(&mut annotations)?;
self.prepend_annotations_to_next(annotations)?
} else {
continue 'restart;
}
}
b'f' => { self.require_delimiter("Delimiter must follow #f")?; N::new(false) }
b't' => { self.require_delimiter("Delimiter must follow #t")?; N::new(true) }
b'{' => self.read_set(read_annotations)?,
b'"' => self.read_literal_binary()?,
b'x' => match self.next_byte()? {
b'"' => N::new(&self.read_hex_binary()?[..]),
b'd' => self.read_hex_float()?,
_ => return Err(io_syntax_error("Invalid #x syntax")),
},
b'[' => self.read_base64_binary()?,
b'!' => {
let v = self.next_iovalue(read_annotations)?;
Value::Embedded(self.dec.parse_embedded(&v)?).wrap()
}
other => {
return Err(io_syntax_error(&format!("Invalid # syntax: {:?}", other)))
}
}
}
b'<' => {
self.skip()?;
let vs = self.upto(b'>', read_annotations, false)?;
if vs.is_empty() {
return Err(io_syntax_error("Missing record label"));
}
Value::Record(Record(vs)).wrap()
}
b'[' => {
self.skip()?;
N::new(self.upto(b']', read_annotations, true)?)
}
b'{' => {
self.skip()?;
self.read_dictionary(read_annotations)?
}
b'>' => return Err(io_syntax_error("Unexpected >")),
b']' => return Err(io_syntax_error("Unexpected ]")),
b'}' => return Err(io_syntax_error("Unexpected }")),
b',' => return Err(io_syntax_error("Unexpected ,")),
other => {
self.skip()?;
self.read_raw_symbol_or_number(vec![other])?
}
}))
}
}
fn open_record(&mut self, arity: Option<usize>) -> ReaderResult<B::Type> {
self.skip_annotations()?;
if self.peek()? != b'<' {
return Err(self.expected(ExpectedKind::Record(arity)));
}
self.skip()?;
let mut b = B::Type::default();
Reader::<N>::ensure_more_expected(self, &mut b, &B::Item::RecordLabel)?;
Ok(b)
}
fn open_sequence_or_set(&mut self) -> ReaderResult<B::Item> {
self.skip_annotations()?;
let mark = Reader::<N>::mark(self)?;
match self.next_byte()? {
b'#' => match self.next_byte()? {
b'{' => return Ok(B::Item::SetValue),
_ => (),
},
b'[' => return Ok(B::Item::SequenceValue),
_ => (),
}
Reader::<N>::restore(self, &mark)?;
Err(self.expected(ExpectedKind::SequenceOrSet))
}
fn open_sequence(&mut self) -> ReaderResult<()> {
self.skip_annotations()?;
if self.peek()? != b'[' {
return Err(self.expected(ExpectedKind::Sequence));
}
self.skip()?;
Ok(())
}
fn open_set(&mut self) -> ReaderResult<()> {
self.skip_annotations()?;
let mark = Reader::<N>::mark(self)?;
match self.next_byte()? {
b'#' => match self.next_byte()? {
b'{' => return Ok(()),
_ => (),
},
_ => (),
}
Reader::<N>::restore(self, &mark)?;
Err(self.expected(ExpectedKind::Set))
}
fn open_dictionary(&mut self) -> ReaderResult<()> {
self.skip_annotations()?;
if self.peek()? != b'{' {
return Err(self.expected(ExpectedKind::Dictionary));
}
self.skip()?;
Ok(())
}
#[inline]
fn boundary(&mut self, b: &B::Type) -> ReaderResult<()> {
match b {
B::Type {
closing: Some(B::Item::DictionaryKey),
opening: Some(B::Item::DictionaryValue),
} => {
self.skip_whitespace();
if self.next_byte()? != b':' {
return Err(syntax_error("Missing expected key/value separator"));
}
}
B::Type { closing: Some(B::Item::DictionaryValue), opening: None } |
B::Type { closing: None, opening: Some(B::Item::DictionaryKey) } |
B::Type { closing: Some(B::Item::SetValue), opening: _ } |
B::Type { closing: _, opening: Some(B::Item::SetValue) } |
B::Type { closing: Some(B::Item::SequenceValue), opening: _ } |
B::Type { closing: _, opening: Some(B::Item::SequenceValue) } |
B::Type {
closing: Some(B::Item::DictionaryValue),
opening: Some(B::Item::DictionaryKey),
} => {
self.skip_whitespace_and_maybe_commas(true);
}
_ => (),
}
Ok(())
}
fn close_compound(&mut self, b: &mut B::Type, i: &B::Item) -> ReaderResult<bool> {
self.skip_whitespace();
match self.peek()? {
b'>' | b']' | b'}' => {
self.skip()?;
Ok(true)
}
_ => {
b.shift(Some(i.clone()));
Reader::<N>::boundary(self, b)?;
Ok(false)
}
}
}
fn open_embedded(&mut self) -> ReaderResult<()> {
self.skip_annotations()?;
let mark = Reader::<N>::mark(self)?;
match self.next_byte()? {
b'#' => match self.next_byte()? {
b'!' => return Ok(()),
_ => (),
},
_ => (),
}
Reader::<N>::restore(self, &mark)?;
Err(self.expected(ExpectedKind::Embedded))
}
fn close_embedded(&mut self) -> ReaderResult<()> {
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<N>> {
self.skip_annotations()?;
let mark = Reader::<N>::mark(self)?;
Ok(match self.next_byte()? {
b'<' => Token::Compound(CompoundClass::Record),
b'[' => Token::Compound(CompoundClass::Sequence),
b'{' => Token::Compound(CompoundClass::Dictionary),
b'>' => Token::End,
b']' => Token::End,
b'}' => Token::End,
b'#' => match self.next_byte()? {
b'!' => {
let v = self.next_iovalue(read_embedded_annotations)?;
Token::Embedded(self.dec.parse_embedded(&v)?)
}
b'{' => Token::Compound(CompoundClass::Set),
_ => {
Reader::<N>::restore(self, &mark)?;
Token::Atom(self.demand_next(false)?)
}
},
_ => {
Reader::<N>::restore(self, &mark)?;
Token::Atom(self.demand_next(false)?)
}
})
}
fn next_annotations_and_token(&mut self) -> io::Result<(Vec<N>, Token<N>)> {
let mut annotations = Vec::new();
self.gather_annotations(&mut annotations)?;
Ok((annotations, self.next_token(true)?))
}
}

View File

@ -1,379 +0,0 @@
//! Implementation of [Writer] for the text syntax.
use crate::hex::HexFormatter;
use crate::value::suspendable::Suspendable;
use crate::value::writer::CompoundWriter;
use crate::value::DomainEncode;
use crate::value::IOValue;
use crate::value::IOValueDomainCodec;
use crate::value::NestedValue;
use crate::value::Writer;
use lazy_static::lazy_static;
use num::bigint::BigInt;
use std::io;
use super::super::boundary as B;
/// Specifies a comma style for printing using [TextWriter].
#[derive(Clone, Copy, Debug)]
pub enum CommaStyle {
/// No commas will be printed. (Preserves text syntax treats commas as whitespace (!).)
None,
/// Commas will be used to separate subterms.
Separating,
/// Commas will be used to terminate subterms.
Terminating,
}
/// The (optionally pretty-printing) text syntax Preserves writer.
pub struct TextWriter<W: io::Write> {
w: Suspendable<W>,
/// Selects a comma style to use when printing.
pub comma_style: CommaStyle,
/// Specifies indentation to use when pretty-printing; 0 disables pretty-printing.
pub indentation: usize,
/// An aid to use of printed terms in shell scripts: set `true` to escape spaces embedded
/// in strings and symbols.
pub escape_spaces: bool,
indent: String,
}
impl std::default::Default for CommaStyle {
fn default() -> Self {
CommaStyle::Separating
}
}
impl TextWriter<&mut Vec<u8>> {
/// Writes `v` to `f` using text syntax. Selects indentation mode based on
/// [`f.alternate()`][std::fmt::Formatter::alternate].
pub fn fmt_value<N: NestedValue, Enc: DomainEncode<N::Embedded>>(
f: &mut std::fmt::Formatter<'_>,
enc: &mut Enc,
v: &crate::value::Value<N>,
) -> io::Result<()> {
let mut buf: Vec<u8> = Vec::new();
let mut w = TextWriter::new(&mut buf);
if f.alternate() {
w.indentation = 4
}
w.write_value(enc, v)?;
f.write_str(std::str::from_utf8(&buf).expect("valid UTF-8 from TextWriter"))
.map_err(|_| io::Error::new(io::ErrorKind::Other, "could not append to Formatter"))
}
/// Encode `v` to a [String].
pub fn encode<N: NestedValue, Enc: DomainEncode<N::Embedded>>(
enc: &mut Enc,
v: &N,
) -> io::Result<String> {
let mut buf: Vec<u8> = Vec::new();
TextWriter::new(&mut buf).write(enc, v)?;
Ok(String::from_utf8(buf).expect("valid UTF-8 from TextWriter"))
}
/// Encode `v` to a [String].
pub fn encode_iovalue(v: &IOValue) -> io::Result<String> {
Self::encode(&mut IOValueDomainCodec, v)
}
}
impl<W: io::Write> TextWriter<W> {
/// Construct a writer from the given byte sink `w`.
pub fn new(w: W) -> Self {
TextWriter {
w: Suspendable::new(w),
comma_style: CommaStyle::default(),
indentation: 0,
escape_spaces: false,
indent: "\n".to_owned(),
}
}
/// Update selected comma-printing style.
pub fn set_comma_style(mut self, v: CommaStyle) -> Self {
self.comma_style = v;
self
}
/// Update selected space-escaping style.
pub fn set_escape_spaces(mut self, v: bool) -> Self {
self.escape_spaces = v;
self
}
#[doc(hidden)]
pub fn suspend(&mut self) -> Self {
TextWriter {
w: self.w.suspend(),
indent: self.indent.clone(),
..*self
}
}
#[doc(hidden)]
pub fn resume(&mut self, other: Self) {
self.w.resume(other.w)
}
#[doc(hidden)]
pub fn write_stringlike_char_fallback<F>(&mut self, c: char, f: F) -> io::Result<()>
where
F: FnOnce(&mut W, char) -> io::Result<()>,
{
match c {
'\\' => write!(self.w, "\\\\"),
'\x08' => write!(self.w, "\\b"),
'\x0c' => write!(self.w, "\\f"),
'\x0a' => write!(self.w, "\\n"),
'\x0d' => write!(self.w, "\\r"),
'\x09' => write!(self.w, "\\t"),
_ => f(&mut self.w, c),
}
}
#[doc(hidden)]
pub fn write_stringlike_char(&mut self, c: char) -> io::Result<()> {
self.write_stringlike_char_fallback(c, |w, c| write!(w, "{}", c))
}
#[doc(hidden)]
pub fn add_indent(&mut self) {
for _ in 0..self.indentation {
self.indent.push(' ')
}
}
#[doc(hidden)]
pub fn del_indent(&mut self) {
if self.indentation > 0 {
self.indent.truncate(self.indent.len() - self.indentation)
}
}
#[doc(hidden)]
pub fn indent(&mut self) -> io::Result<()> {
if self.indentation > 0 {
write!(self.w, "{}", &self.indent)
} else {
Ok(())
}
}
#[doc(hidden)]
pub fn indent_sp(&mut self) -> io::Result<()> {
if self.indentation > 0 {
write!(self.w, "{}", &self.indent)
} else {
write!(self.w, " ")
}
}
/// Borrow the underlying byte sink.
pub fn borrow_write(&mut self) -> &mut W {
&mut self.w
}
}
impl<W: io::Write> CompoundWriter for TextWriter<W> {
#[inline]
fn boundary(&mut self, b: &B::Type) -> io::Result<()> {
match (b.closing.as_ref(), b.opening.as_ref()) {
(None, Some(B::Item::RecordLabel))
| (Some(B::Item::RecordLabel), None)
| (Some(B::Item::RecordField), None) => return Ok(()),
(_, Some(B::Item::RecordField)) => return write!(self.w, " "),
(Some(B::Item::DictionaryKey), Some(B::Item::DictionaryValue)) => {
return write!(self.w, ": ")
}
(None, Some(B::Item::Annotation)) => return write!(self.w, "@"),
(Some(_), Some(B::Item::Annotation)) => return write!(self.w, " @"),
(Some(B::Item::Annotation), Some(B::Item::AnnotatedValue)) => {
return write!(self.w, " ")
}
(Some(B::Item::AnnotatedValue), None) => return Ok(()),
_ => (),
}
match (b.closing.as_ref(), b.opening.as_ref()) {
(None, None) => (),
(None, Some(_)) => {
self.add_indent();
self.indent()?
}
(Some(_), Some(_)) => {
match self.comma_style {
CommaStyle::Separating | CommaStyle::Terminating => write!(self.w, ",")?,
CommaStyle::None => (),
}
self.indent_sp()?
}
(Some(_), None) => {
match self.comma_style {
CommaStyle::Terminating => write!(self.w, ",")?,
CommaStyle::Separating | CommaStyle::None => (),
}
self.del_indent();
self.indent()?
}
}
Ok(())
}
}
macro_rules! simple_writer_method {
($n:ident, $argty:ty) => {
fn $n(&mut self, v: $argty) -> io::Result<()> {
write!(self.w, "{}", v)
}
};
}
impl<W: io::Write> Writer for TextWriter<W> {
type AnnWriter = Self;
type RecWriter = Self;
type SeqWriter = Self;
type SetWriter = Self;
type DictWriter = Self;
type EmbeddedWriter = Self;
fn start_annotations(&mut self) -> io::Result<Self::AnnWriter> {
Ok(self.suspend())
}
fn end_annotations(&mut self, ann: Self::AnnWriter) -> io::Result<()> {
self.resume(ann);
Ok(())
}
fn write_bool(&mut self, v: bool) -> io::Result<()> {
write!(self.w, "{}", if v { "#t" } else { "#f" })
}
fn write_f64(&mut self, v: f64) -> io::Result<()> {
if v.is_nan() || v.is_infinite() {
write!(
self.w,
"#xd\"{}\"",
HexFormatter::Packed.encode(&u64::to_be_bytes(f64::to_bits(v)))
)
} else {
dtoa::write(&mut *self.w, v)?;
Ok(())
}
}
simple_writer_method!(write_i8, i8);
simple_writer_method!(write_u8, u8);
simple_writer_method!(write_i16, i16);
simple_writer_method!(write_u16, u16);
simple_writer_method!(write_i32, i32);
simple_writer_method!(write_u32, u32);
simple_writer_method!(write_i64, i64);
simple_writer_method!(write_u64, u64);
simple_writer_method!(write_i128, i128);
simple_writer_method!(write_u128, u128);
simple_writer_method!(write_int, &BigInt);
fn write_string(&mut self, v: &str) -> io::Result<()> {
write!(self.w, "\"")?;
for c in v.chars() {
match c {
'"' => write!(self.w, "\\\"")?,
' ' if self.escape_spaces => write!(self.w, "\\u0020")?,
_ => self.write_stringlike_char(c)?,
}
}
write!(self.w, "\"")
}
fn write_bytes(&mut self, v: &[u8]) -> io::Result<()> {
write!(
self.w,
"#[{}]",
base64::encode_config(v, base64::URL_SAFE_NO_PAD)
)
}
fn write_symbol(&mut self, v: &str) -> io::Result<()> {
lazy_static! {
// FIXME: This regular expression is conservatively correct, but Anglo-chauvinistic.
static ref RE: regex::Regex =
regex::Regex::new("^[-a-zA-Z0-9~!$%^&*?_=+/.]+$").unwrap();
}
if RE.is_match(v) {
write!(self.w, "{}", v)
} else {
write!(self.w, "|")?;
for c in v.chars() {
match c {
'|' => write!(self.w, "\\|")?,
' ' if self.escape_spaces => write!(self.w, "\\u0020")?,
_ => self.write_stringlike_char(c)?,
}
}
write!(self.w, "|")
}
}
fn start_record(&mut self, _field_count: Option<usize>) -> io::Result<Self::RecWriter> {
write!(self.w, "<")?;
Ok(self.suspend())
}
fn end_record(&mut self, rec: Self::RecWriter) -> io::Result<()> {
self.resume(rec);
write!(self.w, ">")
}
fn start_sequence(&mut self, _item_count: Option<usize>) -> io::Result<Self::SeqWriter> {
write!(self.w, "[")?;
Ok(self.suspend())
}
fn end_sequence(&mut self, seq: Self::SeqWriter) -> io::Result<()> {
self.resume(seq);
write!(self.w, "]")
}
fn start_set(&mut self, _item_count: Option<usize>) -> io::Result<Self::SetWriter> {
write!(self.w, "#{{")?;
Ok(self.suspend())
}
fn end_set(&mut self, set: Self::SetWriter) -> io::Result<()> {
self.resume(set);
write!(self.w, "}}")
}
fn start_dictionary(&mut self, _entry_count: Option<usize>) -> io::Result<Self::DictWriter> {
write!(self.w, "{{")?;
Ok(self.suspend())
}
fn end_dictionary(&mut self, dict: Self::DictWriter) -> io::Result<()> {
self.resume(dict);
write!(self.w, "}}")
}
fn start_embedded(&mut self) -> io::Result<Self::EmbeddedWriter> {
write!(self.w, "#!")?;
Ok(self.suspend())
}
fn end_embedded(&mut self, ptr: Self::EmbeddedWriter) -> io::Result<()> {
self.resume(ptr);
Ok(())
}
fn flush(&mut self) -> io::Result<()> {
self.w.flush()
}
}

View File

@ -1,232 +0,0 @@
//! Generic [Writer] trait for unparsing Preserves [Value]s, implemented by code that provides
//! each specific transfer syntax.
use super::boundary as B;
use super::repr::{Double, NestedValue, Value};
use super::signed_integer::SignedIntegerRepr;
use super::DomainEncode;
use num::bigint::BigInt;
use std::io;
#[doc(hidden)]
/// Utility trait for tracking unparser state during production of compound `Value`s.
pub trait CompoundWriter: Writer {
fn boundary(&mut self, b: &B::Type) -> io::Result<()>;
}
/// Generic unparser for Preserves.
pub trait Writer: Sized {
// Hiding these from the documentation for the moment because I don't want to have to
// document the whole Boundary thing.
#[doc(hidden)]
type AnnWriter: CompoundWriter;
#[doc(hidden)]
type RecWriter: CompoundWriter;
#[doc(hidden)]
type SeqWriter: CompoundWriter;
#[doc(hidden)]
type SetWriter: CompoundWriter;
#[doc(hidden)]
type DictWriter: CompoundWriter;
#[doc(hidden)]
type EmbeddedWriter: Writer;
#[doc(hidden)]
fn start_annotations(&mut self) -> io::Result<Self::AnnWriter>;
#[doc(hidden)]
fn end_annotations(&mut self, ann: Self::AnnWriter) -> io::Result<()>;
#[doc(hidden)]
fn write_bool(&mut self, v: bool) -> io::Result<()>;
#[doc(hidden)]
fn write_f64(&mut self, v: f64) -> io::Result<()>;
#[doc(hidden)]
fn write_i8(&mut self, v: i8) -> io::Result<()>;
#[doc(hidden)]
fn write_u8(&mut self, v: u8) -> io::Result<()>;
#[doc(hidden)]
fn write_i16(&mut self, v: i16) -> io::Result<()>;
#[doc(hidden)]
fn write_u16(&mut self, v: u16) -> io::Result<()>;
#[doc(hidden)]
fn write_i32(&mut self, v: i32) -> io::Result<()>;
#[doc(hidden)]
fn write_u32(&mut self, v: u32) -> io::Result<()>;
#[doc(hidden)]
fn write_i64(&mut self, v: i64) -> io::Result<()>;
#[doc(hidden)]
fn write_u64(&mut self, v: u64) -> io::Result<()>;
#[doc(hidden)]
fn write_i128(&mut self, v: i128) -> io::Result<()>;
#[doc(hidden)]
fn write_u128(&mut self, v: u128) -> io::Result<()>;
#[doc(hidden)]
fn write_int(&mut self, v: &BigInt) -> io::Result<()>;
#[doc(hidden)]
fn write_string(&mut self, v: &str) -> io::Result<()>;
#[doc(hidden)]
fn write_bytes(&mut self, v: &[u8]) -> io::Result<()>;
#[doc(hidden)]
fn write_symbol(&mut self, v: &str) -> io::Result<()>;
#[doc(hidden)]
fn start_record(&mut self, field_count: Option<usize>) -> io::Result<Self::RecWriter>;
#[doc(hidden)]
fn end_record(&mut self, rec: Self::RecWriter) -> io::Result<()>;
#[doc(hidden)]
fn start_sequence(&mut self, item_count: Option<usize>) -> io::Result<Self::SeqWriter>;
#[doc(hidden)]
fn end_sequence(&mut self, seq: Self::SeqWriter) -> io::Result<()>;
#[doc(hidden)]
fn start_set(&mut self, item_count: Option<usize>) -> io::Result<Self::SetWriter>;
#[doc(hidden)]
fn end_set(&mut self, set: Self::SetWriter) -> io::Result<()>;
#[doc(hidden)]
fn start_dictionary(&mut self, entry_count: Option<usize>) -> io::Result<Self::DictWriter>;
#[doc(hidden)]
fn end_dictionary(&mut self, dict: Self::DictWriter) -> io::Result<()>;
#[doc(hidden)]
fn start_embedded(&mut self) -> io::Result<Self::EmbeddedWriter>;
#[doc(hidden)]
fn end_embedded(&mut self, ptr: Self::EmbeddedWriter) -> io::Result<()>;
/// Flushes any buffered output.
fn flush(&mut self) -> io::Result<()>;
//---------------------------------------------------------------------------
/// Writes [NestedValue] `v` to the output of this [Writer].
fn write<N: NestedValue, Enc: DomainEncode<N::Embedded>>(
&mut self,
enc: &mut Enc,
v: &N,
) -> io::Result<()> {
match v.annotations().maybe_slice() {
None => {
self.write_value(enc, v.value())?;
}
Some(anns) => {
let mut a = self.start_annotations()?;
let mut b = B::Type::default();
for ann in anns {
b.shift(Some(B::Item::Annotation));
a.boundary(&b)?;
a.write(enc, ann)?;
}
b.shift(Some(B::Item::AnnotatedValue));
a.boundary(&b)?;
a.write_value(enc, v.value())?;
b.shift(None);
a.boundary(&b)?;
self.end_annotations(a)?;
}
}
Ok(())
}
/// Writes [Value] `v` to the output of this [Writer].
fn write_value<N: NestedValue, Enc: DomainEncode<N::Embedded>>(
&mut self,
enc: &mut Enc,
v: &Value<N>,
) -> io::Result<()> {
match v {
Value::Boolean(b) => self.write_bool(*b),
Value::Double(Double(d)) => self.write_f64(*d),
Value::SignedInteger(n) => match n.repr() {
SignedIntegerRepr::I128(i) => self.write_i128(*i),
SignedIntegerRepr::U128(u) => self.write_u128(*u),
SignedIntegerRepr::Big(n) => self.write_int(n),
},
Value::String(s) => self.write_string(s),
Value::ByteString(bs) => self.write_bytes(bs),
Value::Symbol(s) => self.write_symbol(s),
Value::Record(r) => {
let mut c = self.start_record(Some(r.arity()))?;
let mut b = B::start(B::Item::RecordLabel);
c.boundary(&b)?;
c.write(enc, r.label())?;
for f in r.fields() {
b.shift(Some(B::Item::RecordField));
c.boundary(&b)?;
c.write(enc, f)?;
}
b.shift(None);
c.boundary(&b)?;
self.end_record(c)
}
Value::Sequence(vs) => {
let mut c = self.start_sequence(Some(vs.len()))?;
let mut b = B::Type::default();
for v in vs {
b.shift(Some(B::Item::SequenceValue));
c.boundary(&b)?;
c.write(enc, v)?;
}
b.shift(None);
c.boundary(&b)?;
self.end_sequence(c)
}
Value::Set(vs) => {
let mut c = self.start_set(Some(vs.len()))?;
let mut b = B::Type::default();
for v in vs {
b.shift(Some(B::Item::SetValue));
c.boundary(&b)?;
c.write(enc, v)?;
}
b.shift(None);
c.boundary(&b)?;
self.end_set(c)
}
Value::Dictionary(vs) => {
let mut c = self.start_dictionary(Some(vs.len()))?;
let mut b = B::Type::default();
for (k, v) in vs {
b.shift(Some(B::Item::DictionaryKey));
c.boundary(&b)?;
c.write(enc, k)?;
b.shift(Some(B::Item::DictionaryValue));
c.boundary(&b)?;
c.write(enc, v)?;
}
b.shift(None);
c.boundary(&b)?;
self.end_dictionary(c)
}
Value::Embedded(d) => {
let mut c = self.start_embedded()?;
enc.encode_embedded(&mut c, d)?;
self.end_embedded(c)
}
}
}
}
/// Writes a [varint](https://protobuf.dev/programming-guides/encoding/#varints) to `w`.
/// Returns the number of bytes written.
///
/// ```text
/// varint(n) = [n] if n < 128
/// [(n & 127) | 128] ++ varint(n >> 7) if n ≥ 128
/// ```
pub fn varint<W: io::Write>(w: &mut W, mut v: u64) -> io::Result<usize> {
let mut byte_count = 0;
loop {
byte_count += 1;
if v < 128 {
w.write_all(&[v as u8])?;
return Ok(byte_count);
} else {
w.write_all(&[((v & 0x7f) + 128) as u8])?;
v >>= 7;
}
}
}

View File

@ -1,19 +0,0 @@
use preserves::symbol::Symbol;
use preserves::value::{IOValue, Map};
#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct TestCases {
pub tests: Map<Symbol, TestCase>,
}
#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum TestCase {
Test(#[serde(with = "serde_bytes")] Vec<u8>, IOValue),
NondeterministicTest(#[serde(with = "serde_bytes")] Vec<u8>, IOValue),
ParseError(String),
ParseShort(String),
ParseEOF(String),
DecodeError(#[serde(with = "serde_bytes")] Vec<u8>),
DecodeShort(#[serde(with = "serde_bytes")] Vec<u8>),
DecodeEOF(#[serde(with = "serde_bytes")] Vec<u8>),
}

View File

@ -1,214 +0,0 @@
use preserves::error::{is_eof_io_error, is_syntax_io_error};
use preserves::symbol::Symbol;
use preserves::value::de::from_value as deserialize_from_value;
use preserves::value::BinarySource;
use preserves::value::BytesBinarySource;
use preserves::value::IOBinarySource;
use preserves::value::IOValue;
use preserves::value::PackedWriter;
use preserves::value::Reader;
use preserves::value::ToplevelWhitespaceMode;
use std::io;
use std::iter::Iterator;
mod samples;
use samples::*;
fn decode_all(bytes: &'_ [u8]) -> io::Result<Vec<IOValue>> {
BytesBinarySource::new(bytes)
.packed_iovalues()
.configured(true)
.collect()
}
fn parse_all(text: &str) -> io::Result<Vec<IOValue>> {
BytesBinarySource::new(text.as_bytes())
.text_iovalues()
.configured(true)
.collect()
}
#[test]
fn compare_text_with_packed() -> io::Result<()> {
use io::prelude::*;
let from_text = {
let mut fh = std::fs::File::open("../../../tests/samples.pr").unwrap();
let mut contents = String::new();
fh.read_to_string(&mut contents)?;
BytesBinarySource::new(contents.as_bytes())
.text_iovalues()
.demand_next(true)?
};
let from_packed = {
let mut fh = std::fs::File::open("../../../tests/samples.bin").unwrap();
IOBinarySource::new(&mut fh)
.packed_iovalues()
.demand_next(true)?
};
assert_eq!(from_text, from_packed);
Ok(())
}
#[test]
fn compare_deserialize_text_with_packed() -> io::Result<()> {
use io::prelude::*;
let from_text = {
let mut fh = std::fs::File::open("../../../tests/samples.pr").unwrap();
let mut contents = String::new();
fh.read_to_string(&mut contents)?;
let tests: TestCases = preserves::de::from_text(&contents)?;
tests
};
let from_packed = {
let mut fh = std::fs::File::open("../../../tests/samples.bin").unwrap();
let tests: TestCases = preserves::de::from_read(&mut fh)?;
tests
};
assert_eq!(from_text, from_packed);
Ok(())
}
#[test]
fn read_write_read_text() -> io::Result<()> {
use io::prelude::*;
let from_text = {
let mut fh = std::fs::File::open("../../../tests/samples.pr").unwrap();
let mut contents = String::new();
fh.read_to_string(&mut contents)?;
preserves::value::text::annotated_iovalue_from_str(&contents)?
};
let roundtripped = {
let mut bs = Vec::new();
let mut w = preserves::value::TextWriter::new(&mut bs);
preserves::ser::to_writer(&mut w, &from_text)?;
let s = String::from_utf8(bs).unwrap();
preserves::value::text::annotated_iovalue_from_str(&s)?
};
let roundtripped_indented = {
let mut bs = Vec::new();
let mut w = preserves::value::TextWriter::new(&mut bs);
w.indentation = 4;
preserves::ser::to_writer(&mut w, &from_text)?;
let s = String::from_utf8(bs).unwrap();
preserves::value::text::annotated_iovalue_from_str(&s)?
};
assert_eq!(from_text, roundtripped);
assert_eq!(from_text, roundtripped_indented);
Ok(())
}
#[test]
fn deserialize_serialize_deserialize_text() -> io::Result<()> {
use io::prelude::*;
let from_text = {
let mut fh = std::fs::File::open("../../../tests/samples.pr").unwrap();
let mut contents = String::new();
fh.read_to_string(&mut contents)?;
let tests: TestCases = preserves::de::from_text(&contents)?;
tests
};
let roundtripped = {
let mut bs = Vec::new();
let mut w = preserves::value::TextWriter::new(&mut bs);
preserves::ser::to_writer(&mut w, &from_text)?;
let s = String::from_utf8(bs).unwrap();
preserves::de::from_text(&s)?
};
assert_eq!(from_text, roundtripped);
Ok(())
}
#[test]
fn run() -> io::Result<()> {
let mut fh = std::fs::File::open("../../../tests/samples.bin").unwrap();
let mut src = IOBinarySource::new(&mut fh);
let mut d = src.packed_iovalues().configured(true);
let tests: TestCases = deserialize_from_value(&d.next().unwrap().unwrap()).unwrap();
for (Symbol(name), case) in tests.tests {
println!("{:?} ==> {:?}", name, case);
match case {
TestCase::Test(bin, val) => {
assert_eq!(
&decode_all(&PackedWriter::encode_iovalue(&val)?[..])?,
&[val.clone()]
);
assert_eq!(&decode_all(&bin[..])?, &[val.clone()]);
assert_eq!(&PackedWriter::encode_iovalue(&val)?, &bin);
}
TestCase::NondeterministicTest(bin, val) => {
assert_eq!(&PackedWriter::encode_iovalue(&val)?, &bin);
assert_eq!(
&decode_all(&PackedWriter::encode_iovalue(&val)?[..])?,
&[val.clone()]
);
assert_eq!(&decode_all(&bin[..])?, &[val.clone()]);
}
TestCase::ParseError(text) => {
match parse_all(&text) {
Ok(_) => panic!("Unexpected success"),
Err(e) => {
if is_syntax_io_error(&e) {
// all is OK
} else {
panic!("Unexpected error {:?}", e)
}
}
}
}
TestCase::ParseShort(text) => {
assert!(if let Err(e) = BytesBinarySource::new(text.as_bytes())
.text_iovalues()
.toplevel_whitespace_mode(ToplevelWhitespaceMode::Value)
.configured(true)
.next()
.unwrap()
{
is_eof_io_error(&e)
} else {
false
})
}
TestCase::ParseEOF(text) => {
assert!(BytesBinarySource::new(text.as_bytes())
.text_iovalues()
.toplevel_whitespace_mode(ToplevelWhitespaceMode::Value)
.configured(true)
.next()
.is_none());
}
TestCase::DecodeError(bin) => {
match decode_all(&bin[..]) {
Ok(_) => panic!("Unexpected success"),
Err(e) => {
if is_syntax_io_error(&e) {
// all is OK
} else {
panic!("Unexpected error {:?}", e)
}
}
}
}
TestCase::DecodeShort(bin) => {
assert!(if let Err(e) = BytesBinarySource::new(&bin)
.packed_iovalues()
.configured(true)
.next()
.unwrap()
{
is_eof_io_error(&e)
} else {
false
})
}
TestCase::DecodeEOF(bin) => {
assert!(BytesBinarySource::new(&bin)
.packed_iovalues()
.configured(true)
.next()
.is_none());
}
}
}
Ok(())
}

View File

@ -1,5 +0,0 @@
consolidate-commits=true
consolidate-pushes=true
tag-prefix="rust-{{crate_name}}"
tag-name="{{prefix}}@{{version}}"
dev-version-ext="dev.0"

View File

@ -31,7 +31,7 @@ object-oriented languages like Java, [Python][python-impl] and
[nim-impl]: https://git.syndicate-lang.org/ehmry/preserves-nim [nim-impl]: https://git.syndicate-lang.org/ehmry/preserves-nim
[python-impl]: https://gitlab.com/preserves/preserves/-/blob/main/implementations/python/preserves/schema.py [python-impl]: https://gitlab.com/preserves/preserves/-/blob/main/implementations/python/preserves/schema.py
[racket-impl]: https://gitlab.com/preserves/preserves/-/tree/main/implementations/racket/preserves/preserves-schema [racket-impl]: https://gitlab.com/preserves/preserves/-/tree/main/implementations/racket/preserves/preserves-schema
[rust-impl]: https://gitlab.com/preserves/preserves/-/tree/main/implementations/rust/preserves-schema [rust-impl]: https://gitlab.com/preserves/preserves-rs/-/tree/main/preserves-schema
[smalltalk-impl]: https://squeaksource.com/Preserves.html [smalltalk-impl]: https://squeaksource.com/Preserves.html
[ts-impl]: https://gitlab.com/preserves/preserves/-/tree/main/implementations/javascript/packages/schema [ts-impl]: https://gitlab.com/preserves/preserves/-/tree/main/implementations/javascript/packages/schema