Remove MemEncoder
.
It's only used in tests. Which is bad, because it means that `FileEncoder` is used in the compiler but isn't used in tests! `tests/opaque.rs` now tests encoding/decoding round-trips via file. Because this is slower than memory, this commit also adjusts the `u16`/`i16` tests so they are more like the `u32`/`i32` tests, i.e. they don't test every possible value.
This commit is contained in:
parent
8d359e4385
commit
ebee3f8515
@ -4059,6 +4059,7 @@ dependencies = [
|
||||
"indexmap",
|
||||
"rustc_macros",
|
||||
"smallvec",
|
||||
"tempfile",
|
||||
"thin-vec",
|
||||
]
|
||||
|
||||
|
@ -10,3 +10,4 @@ thin-vec = "0.2.12"
|
||||
|
||||
[dev-dependencies]
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
tempfile = "3.2"
|
||||
|
@ -12,118 +12,14 @@
|
||||
// Encoder
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
pub struct MemEncoder {
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl MemEncoder {
|
||||
pub fn new() -> MemEncoder {
|
||||
MemEncoder { data: vec![] }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn position(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
|
||||
pub fn finish(self) -> Vec<u8> {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! write_leb128 {
|
||||
($enc:expr, $value:expr, $int_ty:ty, $fun:ident) => {{
|
||||
const MAX_ENCODED_LEN: usize = $crate::leb128::max_leb128_len::<$int_ty>();
|
||||
let old_len = $enc.data.len();
|
||||
|
||||
if MAX_ENCODED_LEN > $enc.data.capacity() - old_len {
|
||||
$enc.data.reserve(MAX_ENCODED_LEN);
|
||||
}
|
||||
|
||||
// SAFETY: The above check and `reserve` ensures that there is enough
|
||||
// room to write the encoded value to the vector's internal buffer.
|
||||
unsafe {
|
||||
let buf = &mut *($enc.data.as_mut_ptr().add(old_len)
|
||||
as *mut [MaybeUninit<u8>; MAX_ENCODED_LEN]);
|
||||
let encoded = leb128::$fun(buf, $value);
|
||||
$enc.data.set_len(old_len + encoded.len());
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
impl Encoder for MemEncoder {
|
||||
#[inline]
|
||||
fn emit_usize(&mut self, v: usize) {
|
||||
write_leb128!(self, v, usize, write_usize_leb128)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn emit_u128(&mut self, v: u128) {
|
||||
write_leb128!(self, v, u128, write_u128_leb128);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn emit_u64(&mut self, v: u64) {
|
||||
write_leb128!(self, v, u64, write_u64_leb128);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn emit_u32(&mut self, v: u32) {
|
||||
write_leb128!(self, v, u32, write_u32_leb128);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn emit_u16(&mut self, v: u16) {
|
||||
self.data.extend_from_slice(&v.to_le_bytes());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn emit_u8(&mut self, v: u8) {
|
||||
self.data.push(v);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn emit_isize(&mut self, v: isize) {
|
||||
write_leb128!(self, v, isize, write_isize_leb128)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn emit_i128(&mut self, v: i128) {
|
||||
write_leb128!(self, v, i128, write_i128_leb128)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn emit_i64(&mut self, v: i64) {
|
||||
write_leb128!(self, v, i64, write_i64_leb128)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn emit_i32(&mut self, v: i32) {
|
||||
write_leb128!(self, v, i32, write_i32_leb128)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn emit_i16(&mut self, v: i16) {
|
||||
self.data.extend_from_slice(&v.to_le_bytes());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn emit_raw_bytes(&mut self, s: &[u8]) {
|
||||
self.data.extend_from_slice(s);
|
||||
}
|
||||
}
|
||||
|
||||
pub type FileEncodeResult = Result<usize, io::Error>;
|
||||
|
||||
/// `FileEncoder` encodes data to file via fixed-size buffer.
|
||||
///
|
||||
/// When encoding large amounts of data to a file, using `FileEncoder` may be
|
||||
/// preferred over using `MemEncoder` to encode to a `Vec`, and then writing the
|
||||
/// `Vec` to file, as the latter uses as much memory as there is encoded data,
|
||||
/// while the former uses the fixed amount of memory allocated to the buffer.
|
||||
/// `FileEncoder` also has the advantage of not needing to reallocate as data
|
||||
/// is appended to it, but the disadvantage of requiring more error handling,
|
||||
/// which has some runtime overhead.
|
||||
/// There used to be a `MemEncoder` type that encoded all the data into a
|
||||
/// `Vec`. `FileEncoder` is better because its memory use is determined by the
|
||||
/// size of the buffer, rather than the full length of the encoded data, and
|
||||
/// because it doesn't need to reallocate memory along the way.
|
||||
pub struct FileEncoder {
|
||||
/// The input buffer. For adequate performance, we need more control over
|
||||
/// buffering than `BufWriter` offers. If `BufWriter` ever offers a raw
|
||||
@ -645,13 +541,6 @@ fn peek_byte(&self) -> u8 {
|
||||
|
||||
// Specialize encoding byte slices. This specialization also applies to encoding `Vec<u8>`s, etc.,
|
||||
// since the default implementations call `encode` on their slices internally.
|
||||
impl Encodable<MemEncoder> for [u8] {
|
||||
fn encode(&self, e: &mut MemEncoder) {
|
||||
Encoder::emit_usize(e, self.len());
|
||||
e.emit_raw_bytes(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable<FileEncoder> for [u8] {
|
||||
fn encode(&self, e: &mut FileEncoder) {
|
||||
Encoder::emit_usize(e, self.len());
|
||||
@ -675,16 +564,6 @@ impl IntEncodedWithFixedSize {
|
||||
pub const ENCODED_SIZE: usize = 8;
|
||||
}
|
||||
|
||||
impl Encodable<MemEncoder> for IntEncodedWithFixedSize {
|
||||
#[inline]
|
||||
fn encode(&self, e: &mut MemEncoder) {
|
||||
let _start_pos = e.position();
|
||||
e.emit_raw_bytes(&self.0.to_le_bytes());
|
||||
let _end_pos = e.position();
|
||||
debug_assert_eq!((_end_pos - _start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable<FileEncoder> for IntEncodedWithFixedSize {
|
||||
#[inline]
|
||||
fn encode(&self, e: &mut FileEncoder) {
|
||||
|
@ -1,9 +1,10 @@
|
||||
#![allow(rustc::internal)]
|
||||
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
use rustc_serialize::opaque::{MemDecoder, MemEncoder};
|
||||
use rustc_serialize::opaque::{MemDecoder, FileEncoder};
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
use std::fmt::Debug;
|
||||
use std::fs;
|
||||
|
||||
#[derive(PartialEq, Clone, Debug, Encodable, Decodable)]
|
||||
struct Struct {
|
||||
@ -27,18 +28,21 @@ struct Struct {
|
||||
}
|
||||
|
||||
fn check_round_trip<
|
||||
T: Encodable<MemEncoder> + for<'a> Decodable<MemDecoder<'a>> + PartialEq + Debug,
|
||||
T: Encodable<FileEncoder> + for<'a> Decodable<MemDecoder<'a>> + PartialEq + Debug,
|
||||
>(
|
||||
values: Vec<T>,
|
||||
) {
|
||||
let mut encoder = MemEncoder::new();
|
||||
let tmpfile = tempfile::NamedTempFile::new().unwrap();
|
||||
let tmpfile = tmpfile.path();
|
||||
|
||||
let mut encoder = FileEncoder::new(&tmpfile).unwrap();
|
||||
for value in &values {
|
||||
Encodable::encode(value, &mut encoder);
|
||||
}
|
||||
encoder.finish().unwrap();
|
||||
|
||||
let data = encoder.finish();
|
||||
let data = fs::read(&tmpfile).unwrap();
|
||||
let mut decoder = MemDecoder::new(&data[..], 0);
|
||||
|
||||
for value in values {
|
||||
let decoded = Decodable::decode(&mut decoder);
|
||||
assert_eq!(value, decoded);
|
||||
@ -61,7 +65,7 @@ fn test_u8() {
|
||||
|
||||
#[test]
|
||||
fn test_u16() {
|
||||
for i in u16::MIN..u16::MAX {
|
||||
for i in [u16::MIN, 111, 3333, 55555, u16::MAX] {
|
||||
check_round_trip(vec![1, 2, 3, i, i, i]);
|
||||
}
|
||||
}
|
||||
@ -92,7 +96,7 @@ fn test_i8() {
|
||||
|
||||
#[test]
|
||||
fn test_i16() {
|
||||
for i in i16::MIN..i16::MAX {
|
||||
for i in [i16::MIN, -100, 0, 101, i16::MAX] {
|
||||
check_round_trip(vec![-1, 2, -3, i, i, i, 2]);
|
||||
}
|
||||
}
|
||||
@ -289,4 +293,3 @@ struct B {
|
||||
let obj = B { foo: Cell::new(true), bar: RefCell::new(A { baz: 2 }) };
|
||||
check_round_trip(vec![obj]);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user