Make opaque::Encoder append-only and make it infallible

This commit is contained in:
John Kåre Alsaker 2018-06-04 22:14:02 +02:00
parent 971f7d34d4
commit 14d3c6e8f4
12 changed files with 80 additions and 118 deletions

View File

@ -52,7 +52,8 @@ impl Fingerprint {
pub fn encode_opaque(&self, encoder: &mut Encoder) -> EncodeResult {
let bytes: [u8; 16] = unsafe { mem::transmute([self.0.to_le(), self.1.to_le()]) };
encoder.emit_raw_bytes(&bytes)
encoder.emit_raw_bytes(&bytes);
Ok(())
}
pub fn decode_opaque<'a>(decoder: &mut Decoder<'a>) -> Result<Fingerprint, String> {
@ -92,7 +93,7 @@ impl serialize::UseSpecializedEncodable for Fingerprint { }
impl serialize::UseSpecializedDecodable for Fingerprint { }
impl<'a> serialize::SpecializedEncoder<Fingerprint> for serialize::opaque::Encoder<'a> {
impl serialize::SpecializedEncoder<Fingerprint> for serialize::opaque::Encoder {
fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> {
f.encode_opaque(self)
}

View File

@ -54,7 +54,7 @@ pub trait TyEncoder: Encoder {
fn position(&self) -> usize;
}
impl<'buf> TyEncoder for opaque::Encoder<'buf> {
impl TyEncoder for opaque::Encoder {
#[inline]
fn position(&self) -> usize {
self.position()

View File

@ -979,7 +979,7 @@ impl<'enc, 'a, 'tcx, E> SpecializedEncoder<NodeId> for CacheEncoder<'enc, 'a, 't
}
impl<'enc, 'a, 'tcx> SpecializedEncoder<Fingerprint>
for CacheEncoder<'enc, 'a, 'tcx, opaque::Encoder<'enc>>
for CacheEncoder<'enc, 'a, 'tcx, opaque::Encoder>
{
fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> {
f.encode_opaque(&mut self.encoder)
@ -1057,7 +1057,7 @@ impl IntEncodedWithFixedSize {
impl UseSpecializedEncodable for IntEncodedWithFixedSize {}
impl UseSpecializedDecodable for IntEncodedWithFixedSize {}
impl<'enc> SpecializedEncoder<IntEncodedWithFixedSize> for opaque::Encoder<'enc> {
impl SpecializedEncoder<IntEncodedWithFixedSize> for opaque::Encoder {
fn specialized_encode(&mut self, x: &IntEncodedWithFixedSize) -> Result<(), Self::Error> {
let start_pos = self.position();
for i in 0 .. IntEncodedWithFixedSize::ENCODED_SIZE {

View File

@ -230,8 +230,7 @@ impl WasmEncoder {
}
fn u32(&mut self, val: u32) {
let at = self.data.len();
leb128::write_u32_leb128(&mut self.data, at, val);
leb128::write_u32_leb128(&mut self.data, val);
}
fn byte(&mut self, val: u8) {

View File

@ -25,6 +25,7 @@ use std::fs;
use std::env;
use rustc::session::config::nightly_options;
use rustc_serialize::opaque::Encoder;
/// The first few bytes of files generated by incremental compilation
const FILE_MAGIC: &'static [u8] = b"RSIC";
@ -37,17 +38,15 @@ const HEADER_FORMAT_VERSION: u16 = 0;
/// the git commit hash.
const RUSTC_VERSION: Option<&'static str> = option_env!("CFG_VERSION");
pub fn write_file_header<W: io::Write>(stream: &mut W) -> io::Result<()> {
stream.write_all(FILE_MAGIC)?;
stream.write_all(&[(HEADER_FORMAT_VERSION >> 0) as u8,
(HEADER_FORMAT_VERSION >> 8) as u8])?;
pub fn write_file_header(stream: &mut Encoder) {
stream.emit_raw_bytes(FILE_MAGIC);
stream.emit_raw_bytes(&[(HEADER_FORMAT_VERSION >> 0) as u8,
(HEADER_FORMAT_VERSION >> 8) as u8]);
let rustc_version = rustc_version();
assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize);
stream.write_all(&[rustc_version.len() as u8])?;
stream.write_all(rustc_version.as_bytes())?;
Ok(())
stream.emit_raw_bytes(&[rustc_version.len() as u8]);
stream.emit_raw_bytes(rustc_version.as_bytes());
}
/// Reads the contents of a file with a file header as defined in this module.

View File

@ -16,7 +16,6 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::join;
use rustc_serialize::Encodable as RustcEncodable;
use rustc_serialize::opaque::Encoder;
use std::io::{self, Cursor};
use std::fs;
use std::path::PathBuf;
@ -98,7 +97,7 @@ pub fn save_work_product_index(sess: &Session,
}
fn save_in<F>(sess: &Session, path_buf: PathBuf, encode: F)
where F: FnOnce(&mut Encoder) -> io::Result<()>
where F: FnOnce(&mut Encoder)
{
debug!("save: storing data in {}", path_buf.display());
@ -121,20 +120,12 @@ fn save_in<F>(sess: &Session, path_buf: PathBuf, encode: F)
}
// generate the data in a memory buffer
let mut wr = Cursor::new(Vec::new());
file_format::write_file_header(&mut wr).unwrap();
match encode(&mut Encoder::new(&mut wr)) {
Ok(()) => {}
Err(err) => {
sess.err(&format!("could not encode dep-graph to `{}`: {}",
path_buf.display(),
err));
return;
}
}
let mut encoder = Encoder::new(Vec::new());
file_format::write_file_header(&mut encoder);
encode(&mut encoder);
// write the data out
let data = wr.into_inner();
let data = encoder.into_inner();
match fs::write(&path_buf, data) {
Ok(_) => {
debug!("save: data written to disk successfully");
@ -149,10 +140,9 @@ fn save_in<F>(sess: &Session, path_buf: PathBuf, encode: F)
}
fn encode_dep_graph(tcx: TyCtxt,
encoder: &mut Encoder)
-> io::Result<()> {
encoder: &mut Encoder) {
// First encode the commandline arguments hash
tcx.sess.opts.dep_tracking_hash().encode(encoder)?;
tcx.sess.opts.dep_tracking_hash().encode(encoder).unwrap();
// Encode the graph data.
let serialized_graph = time(tcx.sess, "getting serialized graph", || {
@ -234,14 +224,12 @@ fn encode_dep_graph(tcx: TyCtxt,
}
time(tcx.sess, "encoding serialized graph", || {
serialized_graph.encode(encoder)
})?;
Ok(())
serialized_graph.encode(encoder).unwrap();
});
}
fn encode_work_product_index(work_products: &FxHashMap<WorkProductId, WorkProduct>,
encoder: &mut Encoder) -> io::Result<()> {
encoder: &mut Encoder) {
let serialized_products: Vec<_> = work_products
.iter()
.map(|(id, work_product)| {
@ -252,13 +240,12 @@ fn encode_work_product_index(work_products: &FxHashMap<WorkProductId, WorkProduc
})
.collect();
serialized_products.encode(encoder)
serialized_products.encode(encoder).unwrap();
}
fn encode_query_cache(tcx: TyCtxt,
encoder: &mut Encoder)
-> io::Result<()> {
encoder: &mut Encoder) {
time(tcx.sess, "serialize query result cache", || {
tcx.serialize_query_result_cache(encoder)
tcx.serialize_query_result_cache(encoder).unwrap();
})
}

View File

@ -35,8 +35,6 @@ use rustc_data_structures::stable_hasher::StableHasher;
use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque};
use std::hash::Hash;
use std::io::prelude::*;
use std::io::Cursor;
use std::path::Path;
use rustc_data_structures::sync::Lrc;
use std::u32;
@ -52,7 +50,7 @@ use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
use rustc::hir::intravisit;
pub struct EncodeContext<'a, 'tcx: 'a> {
opaque: opaque::Encoder<'a>,
opaque: opaque::Encoder,
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
link_meta: &'a LinkMeta,
@ -76,7 +74,7 @@ macro_rules! encoder_methods {
}
impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> {
type Error = <opaque::Encoder<'a> as Encoder>::Error;
type Error = <opaque::Encoder as Encoder>::Error;
fn emit_nil(&mut self) -> Result<(), Self::Error> {
Ok(())
@ -480,7 +478,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
// Index the items
i = self.position();
let index = items.write_index(&mut self.opaque.cursor);
let index = items.write_index(&mut self.opaque);
let index_bytes = self.position() - i;
let attrs = tcx.hir.krate_attrs();
@ -537,7 +535,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
if self.tcx.sess.meta_stats() {
let mut zero_bytes = 0;
for e in self.opaque.cursor.get_ref() {
for e in self.opaque.data.iter() {
if *e == 0 {
zero_bytes += 1;
}
@ -1797,15 +1795,15 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
link_meta: &LinkMeta)
-> EncodedMetadata
{
let mut cursor = Cursor::new(vec![]);
cursor.write_all(METADATA_HEADER).unwrap();
let mut encoder = opaque::Encoder::new(vec![]);
encoder.emit_raw_bytes(METADATA_HEADER);
// Will be filled with the root position after encoding everything.
cursor.write_all(&[0, 0, 0, 0]).unwrap();
encoder.emit_raw_bytes(&[0, 0, 0, 0]);
let root = {
let (root, mut result) = {
let mut ecx = EncodeContext {
opaque: opaque::Encoder::new(&mut cursor),
opaque: encoder,
tcx,
link_meta,
lazy_state: LazyState::NoNode,
@ -1821,9 +1819,9 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// Encode all the entries and extra information in the crate,
// culminating in the `CrateRoot` which points to all of it.
ecx.encode_crate_root()
let root = ecx.encode_crate_root();
(root, ecx.opaque.into_inner())
};
let mut result = cursor.into_inner();
// Encode the root position.
let header = METADATA_HEADER.len();

View File

@ -11,7 +11,7 @@
use schema::*;
use rustc::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace};
use std::io::{Cursor, Write};
use rustc_serialize::opaque::Encoder;
use std::slice;
use std::u32;
@ -54,15 +54,15 @@ impl Index {
self.positions[space_index][array_index] = position.to_le();
}
pub fn write_index(&self, buf: &mut Cursor<Vec<u8>>) -> LazySeq<Index> {
pub fn write_index(&self, buf: &mut Encoder) -> LazySeq<Index> {
let pos = buf.position();
// First we write the length of the lower range ...
buf.write_all(words_to_bytes(&[(self.positions[0].len() as u32).to_le()])).unwrap();
buf.emit_raw_bytes(words_to_bytes(&[(self.positions[0].len() as u32).to_le()]));
// ... then the values in the lower range ...
buf.write_all(words_to_bytes(&self.positions[0][..])).unwrap();
buf.emit_raw_bytes(words_to_bytes(&self.positions[0][..]));
// ... then the values in the higher range.
buf.write_all(words_to_bytes(&self.positions[1][..])).unwrap();
buf.emit_raw_bytes(words_to_bytes(&self.positions[1][..]));
LazySeq::with_position_and_length(pos as usize,
self.positions[0].len() + self.positions[1].len() + 1)
}

View File

@ -9,12 +9,8 @@
// except according to those terms.
#[inline]
pub fn write_to_vec(vec: &mut Vec<u8>, position: usize, byte: u8) {
if position == vec.len() {
pub fn write_to_vec(vec: &mut Vec<u8>, byte: u8) {
vec.push(byte);
} else {
vec[position] = byte;
}
}
#[cfg(target_pointer_width = "32")]
@ -33,8 +29,7 @@ macro_rules! leb128_size {
macro_rules! impl_write_unsigned_leb128 {
($fn_name:ident, $int_ty:ident) => (
#[inline]
pub fn $fn_name(out: &mut Vec<u8>, start_position: usize, mut value: $int_ty) -> usize {
let mut position = start_position;
pub fn $fn_name(out: &mut Vec<u8>, mut value: $int_ty) {
for _ in 0 .. leb128_size!($int_ty) {
let mut byte = (value & 0x7F) as u8;
value >>= 7;
@ -42,15 +37,12 @@ macro_rules! impl_write_unsigned_leb128 {
byte |= 0x80;
}
write_to_vec(out, position, byte);
position += 1;
write_to_vec(out, byte);
if value == 0 {
break;
}
}
position - start_position
}
)
}
@ -105,11 +97,9 @@ impl_read_unsigned_leb128!(read_usize_leb128, usize);
/// The callback `write` is called once for each position
/// that is to be written to with the byte to be encoded
/// at that position.
pub fn write_signed_leb128_to<W>(mut value: i128, mut write: W) -> usize
where W: FnMut(usize, u8)
pub fn write_signed_leb128_to<W>(mut value: i128, mut write: W)
where W: FnMut(u8)
{
let mut position = 0;
loop {
let mut byte = (value as u8) & 0x7f;
value >>= 7;
@ -120,18 +110,16 @@ pub fn write_signed_leb128_to<W>(mut value: i128, mut write: W) -> usize
byte |= 0x80; // Mark this byte to show that more bytes will follow.
}
write(position, byte);
position += 1;
write(byte);
if !more {
break;
}
}
position
}
pub fn write_signed_leb128(out: &mut Vec<u8>, start_position: usize, value: i128) -> usize {
write_signed_leb128_to(value, |i, v| write_to_vec(out, start_position+i, v))
pub fn write_signed_leb128(out: &mut Vec<u8>, value: i128) {
write_signed_leb128_to(value, |v| write_to_vec(out, v))
}
#[inline]
@ -167,9 +155,7 @@ macro_rules! impl_test_unsigned_leb128 {
let mut stream = Vec::new();
for x in 0..62 {
let pos = stream.len();
let bytes_written = $write_fn_name(&mut stream, pos, (3u64 << x) as $int_ty);
assert_eq!(stream.len(), pos + bytes_written);
$write_fn_name(&mut stream, (3u64 << x) as $int_ty);
}
let mut position = 0;
@ -195,9 +181,7 @@ fn test_signed_leb128() {
let values: Vec<_> = (-500..500).map(|i| i * 0x12345789ABCDEF).collect();
let mut stream = Vec::new();
for &x in &values {
let pos = stream.len();
let bytes_written = write_signed_leb128(&mut stream, pos, x);
assert_eq!(stream.len(), pos + bytes_written);
write_signed_leb128(&mut stream, x);
}
let mut pos = 0;
for &x in &values {

View File

@ -23,6 +23,7 @@ Core encoding and decoding interfaces.
#![feature(box_syntax)]
#![feature(core_intrinsics)]
#![feature(specialization)]
#![feature(never_type)]
#![cfg_attr(test, feature(test))]
pub use self::serialize::{Decoder, Encoder, Decodable, Encodable};

View File

@ -10,50 +10,48 @@
use leb128::{self, read_signed_leb128, write_signed_leb128};
use std::borrow::Cow;
use std::io::{self, Write};
use serialize;
// -----------------------------------------------------------------------------
// Encoder
// -----------------------------------------------------------------------------
pub type EncodeResult = io::Result<()>;
pub type EncodeResult = Result<(), !>;
pub struct Encoder<'a> {
pub cursor: &'a mut io::Cursor<Vec<u8>>,
pub struct Encoder {
pub data: Vec<u8>,
}
impl<'a> Encoder<'a> {
pub fn new(cursor: &'a mut io::Cursor<Vec<u8>>) -> Encoder<'a> {
Encoder { cursor: cursor }
impl Encoder {
pub fn new(data: Vec<u8>) -> Encoder {
Encoder { data }
}
pub fn emit_raw_bytes(&mut self, s: &[u8]) -> EncodeResult {
self.cursor.write_all(s)
}
pub fn into_inner(self) -> Vec<u8> {
self.data
}
pub fn emit_raw_bytes(&mut self, s: &[u8]) {
self.data.extend_from_slice(s);
}
}
macro_rules! write_uleb128 {
($enc:expr, $value:expr, $fun:ident) => {{
let pos = $enc.cursor.position() as usize;
let bytes_written = leb128::$fun($enc.cursor.get_mut(), pos, $value);
$enc.cursor.set_position((pos + bytes_written) as u64);
leb128::$fun(&mut $enc.data, $value);
Ok(())
}}
}
macro_rules! write_sleb128 {
($enc:expr, $value:expr) => {{
let pos = $enc.cursor.position() as usize;
let bytes_written = write_signed_leb128($enc.cursor.get_mut(), pos, $value as i128);
$enc.cursor.set_position((pos + bytes_written) as u64);
write_signed_leb128(&mut $enc.data, $value as i128);
Ok(())
}}
}
impl<'a> serialize::Encoder for Encoder<'a> {
type Error = io::Error;
impl serialize::Encoder for Encoder {
type Error = !;
#[inline]
fn emit_nil(&mut self) -> EncodeResult {
@ -87,9 +85,7 @@ impl<'a> serialize::Encoder for Encoder<'a> {
#[inline]
fn emit_u8(&mut self, v: u8) -> EncodeResult {
let pos = self.cursor.position() as usize;
leb128::write_to_vec(self.cursor.get_mut(), pos, v);
self.cursor.set_position((pos + 1) as u64);
self.data.push(v);
Ok(())
}
@ -153,15 +149,15 @@ impl<'a> serialize::Encoder for Encoder<'a> {
#[inline]
fn emit_str(&mut self, v: &str) -> EncodeResult {
self.emit_usize(v.len())?;
let _ = self.cursor.write_all(v.as_bytes());
self.emit_raw_bytes(v.as_bytes());
Ok(())
}
}
impl<'a> Encoder<'a> {
impl Encoder {
#[inline]
pub fn position(&self) -> usize {
self.cursor.position() as usize
self.data.len()
}
}
@ -339,7 +335,6 @@ impl<'a> serialize::Decoder for Decoder<'a> {
#[cfg(test)]
mod tests {
use serialize::{Encodable, Decodable};
use std::io::Cursor;
use std::fmt::Debug;
use super::{Encoder, Decoder};
@ -368,14 +363,13 @@ mod tests {
fn check_round_trip<T: Encodable + Decodable + PartialEq + Debug>(values: Vec<T>) {
let mut cursor = Cursor::new(Vec::new());
let mut encoder = Encoder::new(Vec::new());
for value in &values {
let mut encoder = Encoder::new(&mut cursor);
Encodable::encode(&value, &mut encoder).unwrap();
}
let data = cursor.into_inner();
let data = encoder.into_inner();
let mut decoder = Decoder::new(&data[..], 0);
for value in values {

View File

@ -41,17 +41,16 @@ enum WireProtocol {
fn encode_json<T: Encodable>(val: &T, wr: &mut Cursor<Vec<u8>>) {
write!(wr, "{}", json::as_json(val));
}
fn encode_opaque<T: Encodable>(val: &T, wr: &mut Cursor<Vec<u8>>) {
fn encode_opaque<T: Encodable>(val: &T, wr: Vec<u8>) {
let mut encoder = opaque::Encoder::new(wr);
val.encode(&mut encoder);
}
pub fn main() {
let target = Foo{baz: false,};
let mut wr = Cursor::new(Vec::new());
let proto = WireProtocol::JSON;
match proto {
WireProtocol::JSON => encode_json(&target, &mut wr),
WireProtocol::Opaque => encode_opaque(&target, &mut wr)
WireProtocol::JSON => encode_json(&target, &mut Cursor::new(Vec::new())),
WireProtocol::Opaque => encode_opaque(&target, Vec::new())
}
}