diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index 4aa4ff72eb29..9b40c9a7ed88 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -807,6 +807,15 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { crate::implement_ty_decoder!(CacheDecoder<'a, 'tcx>); +// This ensures that the `Decodable::decode` specialization for `Vec` is used +// when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt +// into specializations this way, given how `CacheDecoder` and the decoding traits currently work. +impl<'a, 'tcx> Decodable> for Vec { + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result { + Decodable::decode(&mut d.opaque) + } +} + impl<'a, 'tcx> Decodable> for SyntaxContext { fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result { let syntax_contexts = decoder.syntax_contexts; diff --git a/compiler/rustc_serialize/src/collection_impls.rs b/compiler/rustc_serialize/src/collection_impls.rs index 57082da29f2e..ae6d27e037b2 100644 --- a/compiler/rustc_serialize/src/collection_impls.rs +++ b/compiler/rustc_serialize/src/collection_impls.rs @@ -295,13 +295,8 @@ impl> Encodable for Rc<[T]> { impl> Decodable for Rc<[T]> { fn decode(d: &mut D) -> Result, D::Error> { - d.read_seq(|d, len| { - let mut vec = Vec::with_capacity(len); - for index in 0..len { - vec.push(d.read_seq_elt(index, |d| Decodable::decode(d))?); - } - Ok(vec.into()) - }) + let vec: Vec = Decodable::decode(d)?; + Ok(vec.into()) } } @@ -314,12 +309,7 @@ impl> Encodable for Arc<[T]> { impl> Decodable for Arc<[T]> { fn decode(d: &mut D) -> Result, D::Error> { - d.read_seq(|d, len| { - let mut vec = Vec::with_capacity(len); - for index in 0..len { - vec.push(d.read_seq_elt(index, |d| Decodable::decode(d))?); - } - Ok(vec.into()) - }) + let vec: Vec = Decodable::decode(d)?; + Ok(vec.into()) } } diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index 0e7974afff37..f58ed14d9971 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -15,6 +15,7 @@ Core encoding and decoding interfaces. #![feature(associated_type_bounds)] #![cfg_attr(bootstrap, feature(min_const_generics))] #![feature(min_specialization)] +#![feature(vec_spare_capacity)] #![cfg_attr(test, feature(test))] #![allow(rustc::internal)] diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 5ef1c7241deb..673742df7f0d 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -327,10 +327,13 @@ impl<'a> serialize::Decoder for Decoder<'a> { } } -// Specialize encoding byte slices. The default implementation for slices encodes and emits each -// element individually. This isn't necessary for `u8` slices encoded with an `opaque::Encoder`, -// because each `u8` is emitted as-is. Therefore, we can use a more efficient implementation. This -// specialization applies to encoding `Vec`s, etc., since they call `encode` on their slices. +// Specializations for contiguous byte sequences follow. The default implementations for slices +// encode and decode each element individually. This isn't necessary for `u8` slices when using +// opaque encoders and decoders, because each `u8` is unchanged by encoding and decoding. +// Therefore, we can use more efficient implementations that process the entire sequence at once. + +// Specialize encoding byte slices. This specialization also applies to encoding `Vec`s, etc., +// since the default implementations call `encode` on their slices internally. impl serialize::Encodable for [u8] { fn encode(&self, e: &mut Encoder) -> EncodeResult { serialize::Encoder::emit_usize(e, self.len())?; @@ -338,3 +341,21 @@ impl serialize::Encodable for [u8] { Ok(()) } } + +// Specialize decoding `Vec`. This specialization also applies to decoding `Box<[u8]>`s, etc., +// since the default implementations call `decode` to produce a `Vec` internally. +impl<'a> serialize::Decodable> for Vec { + fn decode(d: &mut Decoder<'a>) -> Result { + let len = serialize::Decoder::read_usize(d)?; + + let mut v = Vec::with_capacity(len); + let buf = &mut v.spare_capacity_mut()[..len]; + d.read_raw_bytes(buf)?; + + unsafe { + v.set_len(len); + } + + Ok(v) + } +} diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index ee8ab0e9e405..47aad5b88c62 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -545,7 +545,7 @@ impl> Encodable for Vec { } impl> Decodable for Vec { - fn decode(d: &mut D) -> Result, D::Error> { + default fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut v = Vec::with_capacity(len); for i in 0..len { @@ -591,13 +591,8 @@ where [T]: ToOwned>, { fn decode(d: &mut D) -> Result, D::Error> { - d.read_seq(|d, len| { - let mut v = Vec::with_capacity(len); - for i in 0..len { - v.push(d.read_seq_elt(i, |d| Decodable::decode(d))?); - } - Ok(Cow::Owned(v)) - }) + let v: Vec = Decodable::decode(d)?; + Ok(Cow::Owned(v)) } }