summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_serialize/src/serialize.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_serialize/src/serialize.rs')
-rw-r--r--compiler/rustc_serialize/src/serialize.rs79
1 files changed, 65 insertions, 14 deletions
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index 527abc237..06166cabc 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -1,9 +1,5 @@
//! Support code for encoding and decoding types.
-/*
-Core encoding and decoding interfaces.
-*/
-
use std::alloc::Allocator;
use std::borrow::Cow;
use std::cell::{Cell, RefCell};
@@ -12,6 +8,13 @@ use std::path;
use std::rc::Rc;
use std::sync::Arc;
+/// A byte that [cannot occur in UTF8 sequences][utf8]. Used to mark the end of a string.
+/// This way we can skip validation and still be relatively sure that deserialization
+/// did not desynchronize.
+///
+/// [utf8]: https://en.wikipedia.org/w/index.php?title=UTF-8&oldid=1058865525#Codepage_layout
+const STR_SENTINEL: u8 = 0xC1;
+
/// A note about error handling.
///
/// Encoders may be fallible, but in practice failure is rare and there are so
@@ -28,22 +31,41 @@ use std::sync::Arc;
/// really makes sense to store floating-point values at all.
/// (If you need it, revert <https://github.com/rust-lang/rust/pull/109984>.)
pub trait Encoder {
- // Primitive types:
fn emit_usize(&mut self, v: usize);
fn emit_u128(&mut self, v: u128);
fn emit_u64(&mut self, v: u64);
fn emit_u32(&mut self, v: u32);
fn emit_u16(&mut self, v: u16);
fn emit_u8(&mut self, v: u8);
+
fn emit_isize(&mut self, v: isize);
fn emit_i128(&mut self, v: i128);
fn emit_i64(&mut self, v: i64);
fn emit_i32(&mut self, v: i32);
fn emit_i16(&mut self, v: i16);
- fn emit_i8(&mut self, v: i8);
- fn emit_bool(&mut self, v: bool);
- fn emit_char(&mut self, v: char);
- fn emit_str(&mut self, v: &str);
+
+ #[inline]
+ fn emit_i8(&mut self, v: i8) {
+ self.emit_u8(v as u8);
+ }
+
+ #[inline]
+ fn emit_bool(&mut self, v: bool) {
+ self.emit_u8(if v { 1 } else { 0 });
+ }
+
+ #[inline]
+ fn emit_char(&mut self, v: char) {
+ self.emit_u32(v as u32);
+ }
+
+ #[inline]
+ fn emit_str(&mut self, v: &str) {
+ self.emit_usize(v.len());
+ self.emit_raw_bytes(v.as_bytes());
+ self.emit_u8(STR_SENTINEL);
+ }
+
fn emit_raw_bytes(&mut self, s: &[u8]);
fn emit_enum_variant<F>(&mut self, v_id: usize, f: F)
@@ -67,23 +89,52 @@ pub trait Encoder {
/// really makes sense to store floating-point values at all.
/// (If you need it, revert <https://github.com/rust-lang/rust/pull/109984>.)
pub trait Decoder {
- // Primitive types:
fn read_usize(&mut self) -> usize;
fn read_u128(&mut self) -> u128;
fn read_u64(&mut self) -> u64;
fn read_u32(&mut self) -> u32;
fn read_u16(&mut self) -> u16;
fn read_u8(&mut self) -> u8;
+
fn read_isize(&mut self) -> isize;
fn read_i128(&mut self) -> i128;
fn read_i64(&mut self) -> i64;
fn read_i32(&mut self) -> i32;
fn read_i16(&mut self) -> i16;
- fn read_i8(&mut self) -> i8;
- fn read_bool(&mut self) -> bool;
- fn read_char(&mut self) -> char;
- fn read_str(&mut self) -> &str;
+
+ #[inline]
+ fn read_i8(&mut self) -> i8 {
+ self.read_u8() as i8
+ }
+
+ #[inline]
+ fn read_bool(&mut self) -> bool {
+ let value = self.read_u8();
+ value != 0
+ }
+
+ #[inline]
+ fn read_char(&mut self) -> char {
+ let bits = self.read_u32();
+ std::char::from_u32(bits).unwrap()
+ }
+
+ #[inline]
+ fn read_str(&mut self) -> &str {
+ let len = self.read_usize();
+ let bytes = self.read_raw_bytes(len + 1);
+ assert!(bytes[len] == STR_SENTINEL);
+ unsafe { std::str::from_utf8_unchecked(&bytes[..len]) }
+ }
+
fn read_raw_bytes(&mut self, len: usize) -> &[u8];
+
+ // Although there is an `emit_enum_variant` method in `Encoder`, the code
+ // patterns in decoding are different enough to encoding that there is no
+ // need for a corresponding `read_enum_variant` method here.
+
+ fn peek_byte(&self) -> u8;
+ fn position(&self) -> usize;
}
/// Trait for types that can be serialized