From 14d3c6e8f46735ad64e8dfb907824dd3ea77dbcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 4 Jun 2018 22:14:02 +0200 Subject: [PATCH] Make opaque::Encoder append-only and make it infallible --- src/librustc/ich/fingerprint.rs | 5 +- src/librustc/ty/codec.rs | 2 +- src/librustc/ty/query/on_disk_cache.rs | 4 +- src/librustc_codegen_llvm/back/wasm.rs | 3 +- .../persist/file_format.rs | 15 +++--- src/librustc_incremental/persist/save.rs | 39 +++++---------- src/librustc_metadata/encoder.rs | 24 ++++----- src/librustc_metadata/index.rs | 10 ++-- src/libserialize/leb128.rs | 38 ++++---------- src/libserialize/lib.rs | 1 + src/libserialize/opaque.rs | 50 ++++++++----------- src/test/run-pass-fulldeps/issue-11881.rs | 7 ++- 12 files changed, 80 insertions(+), 118 deletions(-) diff --git a/src/librustc/ich/fingerprint.rs b/src/librustc/ich/fingerprint.rs index f56f4e12e7a..2a3b1ce6a36 100644 --- a/src/librustc/ich/fingerprint.rs +++ b/src/librustc/ich/fingerprint.rs @@ -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 { @@ -92,7 +93,7 @@ impl serialize::UseSpecializedEncodable for Fingerprint { } impl serialize::UseSpecializedDecodable for Fingerprint { } -impl<'a> serialize::SpecializedEncoder for serialize::opaque::Encoder<'a> { +impl serialize::SpecializedEncoder for serialize::opaque::Encoder { fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> { f.encode_opaque(self) } diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index d911f32ed3f..967a3324cfb 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -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() diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 3285380c823..c42323e3d4a 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -979,7 +979,7 @@ impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 't } impl<'enc, 'a, 'tcx> SpecializedEncoder -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 for opaque::Encoder<'enc> { +impl SpecializedEncoder 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 { diff --git a/src/librustc_codegen_llvm/back/wasm.rs b/src/librustc_codegen_llvm/back/wasm.rs index d6d386c9fbe..c553eca08e6 100644 --- a/src/librustc_codegen_llvm/back/wasm.rs +++ b/src/librustc_codegen_llvm/back/wasm.rs @@ -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) { diff --git a/src/librustc_incremental/persist/file_format.rs b/src/librustc_incremental/persist/file_format.rs index d45994adeb6..98f7873fda0 100644 --- a/src/librustc_incremental/persist/file_format.rs +++ b/src/librustc_incremental/persist/file_format.rs @@ -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(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. diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index dcef0c662c3..06b0ea946d7 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -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(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(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(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, - 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 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(); }) } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index ce270006a9d..46c4a3a1abe 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -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 = as Encoder>::Error; + type Error = ::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(); diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs index 157b8385a69..0b4f7e579ac 100644 --- a/src/librustc_metadata/index.rs +++ b/src/librustc_metadata/index.rs @@ -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>) -> LazySeq { + pub fn write_index(&self, buf: &mut Encoder) -> LazySeq { 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) } diff --git a/src/libserialize/leb128.rs b/src/libserialize/leb128.rs index 1786e296082..ae7f25c7fed 100644 --- a/src/libserialize/leb128.rs +++ b/src/libserialize/leb128.rs @@ -9,12 +9,8 @@ // except according to those terms. #[inline] -pub fn write_to_vec(vec: &mut Vec, position: usize, byte: u8) { - if position == vec.len() { - vec.push(byte); - } else { - vec[position] = byte; - } +pub fn write_to_vec(vec: &mut Vec, byte: u8) { + vec.push(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, start_position: usize, mut value: $int_ty) -> usize { - let mut position = start_position; + pub fn $fn_name(out: &mut Vec, 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(mut value: i128, mut write: W) -> usize - where W: FnMut(usize, u8) +pub fn write_signed_leb128_to(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(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, 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, 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 { diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 22d27b6697a..a5f4b32b329 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -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}; diff --git a/src/libserialize/opaque.rs b/src/libserialize/opaque.rs index 077efadd60a..a77d1d9b88b 100644 --- a/src/libserialize/opaque.rs +++ b/src/libserialize/opaque.rs @@ -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>, +pub struct Encoder { + pub data: Vec, } -impl<'a> Encoder<'a> { - pub fn new(cursor: &'a mut io::Cursor>) -> Encoder<'a> { - Encoder { cursor: cursor } +impl Encoder { + pub fn new(data: Vec) -> Encoder { + Encoder { data } } - pub fn emit_raw_bytes(&mut self, s: &[u8]) -> EncodeResult { - self.cursor.write_all(s) + pub fn into_inner(self) -> Vec { + 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(values: Vec) { - 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 { diff --git a/src/test/run-pass-fulldeps/issue-11881.rs b/src/test/run-pass-fulldeps/issue-11881.rs index 914e3dd4932..4f419e70074 100644 --- a/src/test/run-pass-fulldeps/issue-11881.rs +++ b/src/test/run-pass-fulldeps/issue-11881.rs @@ -41,17 +41,16 @@ enum WireProtocol { fn encode_json(val: &T, wr: &mut Cursor>) { write!(wr, "{}", json::as_json(val)); } -fn encode_opaque(val: &T, wr: &mut Cursor>) { +fn encode_opaque(val: &T, wr: Vec) { 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()) } }