]>
Commit | Line | Data |
---|---|---|
c34b1796 | 1 | // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT |
1a4d82fc JJ |
2 | // file at the top-level directory of this distribution and at |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
c34b1796 AL |
11 | //! Really Bad Markup Language (rbml) is an internal serialization format of rustc. |
12 | //! This is not intended to be used by users. | |
1a4d82fc | 13 | //! |
c34b1796 AL |
14 | //! Originally based on the Extensible Binary Markup Language |
15 | //! (ebml; http://www.matroska.org/technical/specs/rfc/index.html), | |
16 | //! it is now a separate format tuned for the rust object metadata. | |
17 | //! | |
18 | //! # Encoding | |
19 | //! | |
20 | //! RBML document consists of the tag, length and data. | |
21 | //! The encoded data can contain multiple RBML documents concatenated. | |
22 | //! | |
23 | //! **Tags** are a hint for the following data. | |
24 | //! Tags are a number from 0x000 to 0xfff, where 0xf0 through 0xff is reserved. | |
25 | //! Tags less than 0xf0 are encoded in one literal byte. | |
26 | //! Tags greater than 0xff are encoded in two big-endian bytes, | |
27 | //! where the tag number is ORed with 0xf000. (E.g. tag 0x123 = `f1 23`) | |
28 | //! | |
29 | //! **Lengths** encode the length of the following data. | |
30 | //! It is a variable-length unsigned isize, and one of the following forms: | |
31 | //! | |
32 | //! - `80` through `fe` for lengths up to 0x7e; | |
33 | //! - `40 ff` through `7f ff` for lengths up to 0x3fff; | |
34 | //! - `20 40 00` through `3f ff ff` for lengths up to 0x1fffff; | |
35 | //! - `10 20 00 00` through `1f ff ff ff` for lengths up to 0xfffffff. | |
36 | //! | |
37 | //! The "overlong" form is allowed so that the length can be encoded | |
38 | //! without the prior knowledge of the encoded data. | |
39 | //! For example, the length 0 can be represented either by `80`, `40 00`, | |
40 | //! `20 00 00` or `10 00 00 00`. | |
41 | //! The encoder tries to minimize the length if possible. | |
42 | //! Also, some predefined tags listed below are so commonly used that | |
43 | //! their lengths are omitted ("implicit length"). | |
44 | //! | |
45 | //! **Data** can be either binary bytes or zero or more nested RBML documents. | |
46 | //! Nested documents cannot overflow, and should be entirely contained | |
47 | //! within a parent document. | |
48 | //! | |
49 | //! # Predefined Tags | |
50 | //! | |
51 | //! Most RBML tags are defined by the application. | |
52 | //! (For the rust object metadata, see also `rustc::metadata::common`.) | |
53 | //! RBML itself does define a set of predefined tags however, | |
54 | //! intended for the auto-serialization implementation. | |
55 | //! | |
56 | //! Predefined tags with an implicit length: | |
57 | //! | |
58 | //! - `U8` (`00`): 1-byte unsigned integer. | |
59 | //! - `U16` (`01`): 2-byte big endian unsigned integer. | |
60 | //! - `U32` (`02`): 4-byte big endian unsigned integer. | |
61 | //! - `U64` (`03`): 8-byte big endian unsigned integer. | |
62 | //! Any of `U*` tags can be used to encode primitive unsigned integer types, | |
63 | //! as long as it is no greater than the actual size. | |
64 | //! For example, `u8` can only be represented via the `U8` tag. | |
65 | //! | |
66 | //! - `I8` (`04`): 1-byte signed integer. | |
67 | //! - `I16` (`05`): 2-byte big endian signed integer. | |
68 | //! - `I32` (`06`): 4-byte big endian signed integer. | |
69 | //! - `I64` (`07`): 8-byte big endian signed integer. | |
70 | //! Similar to `U*` tags. Always uses two's complement encoding. | |
71 | //! | |
72 | //! - `Bool` (`08`): 1-byte boolean value, `00` for false and `01` for true. | |
73 | //! | |
74 | //! - `Char` (`09`): 4-byte big endian Unicode scalar value. | |
75 | //! Surrogate pairs or out-of-bound values are invalid. | |
76 | //! | |
77 | //! - `F32` (`0a`): 4-byte big endian unsigned integer representing | |
78 | //! IEEE 754 binary32 floating-point format. | |
79 | //! - `F64` (`0b`): 8-byte big endian unsigned integer representing | |
80 | //! IEEE 754 binary64 floating-point format. | |
81 | //! | |
82 | //! - `Sub8` (`0c`): 1-byte unsigned integer for supplementary information. | |
83 | //! - `Sub32` (`0d`): 4-byte unsigned integer for supplementary information. | |
84 | //! Those two tags normally occur as the first subdocument of certain tags, | |
85 | //! namely `Enum`, `Vec` and `Map`, to provide a variant or size information. | |
86 | //! They can be used interchangeably. | |
87 | //! | |
88 | //! Predefined tags with an explicit length: | |
89 | //! | |
90 | //! - `Str` (`10`): A UTF-8-encoded string. | |
91 | //! | |
92 | //! - `Enum` (`11`): An enum. | |
93 | //! The first subdocument should be `Sub*` tags with a variant ID. | |
94 | //! Subsequent subdocuments, if any, encode variant arguments. | |
95 | //! | |
96 | //! - `Vec` (`12`): A vector (sequence). | |
97 | //! - `VecElt` (`13`): A vector element. | |
98 | //! The first subdocument should be `Sub*` tags with the number of elements. | |
99 | //! Subsequent subdocuments should be `VecElt` tag per each element. | |
100 | //! | |
101 | //! - `Map` (`14`): A map (associated array). | |
102 | //! - `MapKey` (`15`): A key part of the map entry. | |
103 | //! - `MapVal` (`16`): A value part of the map entry. | |
104 | //! The first subdocument should be `Sub*` tags with the number of entries. | |
105 | //! Subsequent subdocuments should be an alternating sequence of | |
106 | //! `MapKey` and `MapVal` tags per each entry. | |
107 | //! | |
108 | //! - `Opaque` (`17`): An opaque, custom-format tag. | |
109 | //! Used to wrap ordinary custom tags or data in the auto-serialized context. | |
110 | //! Rustc typically uses this to encode type informations. | |
111 | //! | |
112 | //! First 0x20 tags are reserved by RBML; custom tags start at 0x20. | |
1a4d82fc | 113 | |
c34b1796 AL |
114 | // Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364) |
115 | #![cfg_attr(stage0, feature(custom_attribute))] | |
1a4d82fc | 116 | #![crate_name = "rbml"] |
85aaf69f | 117 | #![unstable(feature = "rustc_private")] |
1a4d82fc JJ |
118 | #![staged_api] |
119 | #![crate_type = "rlib"] | |
120 | #![crate_type = "dylib"] | |
121 | #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", | |
62682a34 | 122 | html_favicon_url = "https://doc.rust-lang.org/favicon.ico", |
1a4d82fc JJ |
123 | html_root_url = "http://doc.rust-lang.org/nightly/", |
124 | html_playground_url = "http://play.rust-lang.org/")] | |
85aaf69f | 125 | |
85aaf69f SL |
126 | #![feature(rustc_private)] |
127 | #![feature(staged_api)] | |
62682a34 | 128 | #![feature(slice_bytes)] |
1a4d82fc | 129 | |
c34b1796 AL |
130 | #![cfg_attr(test, feature(test))] |
131 | ||
1a4d82fc JJ |
132 | extern crate serialize; |
133 | #[macro_use] extern crate log; | |
134 | ||
135 | #[cfg(test)] extern crate test; | |
136 | ||
137 | pub use self::EbmlEncoderTag::*; | |
138 | pub use self::Error::*; | |
139 | ||
140 | use std::str; | |
85aaf69f | 141 | use std::fmt; |
1a4d82fc | 142 | |
1a4d82fc JJ |
143 | /// Common data structures |
144 | #[derive(Clone, Copy)] | |
145 | pub struct Doc<'a> { | |
146 | pub data: &'a [u8], | |
c34b1796 AL |
147 | pub start: usize, |
148 | pub end: usize, | |
1a4d82fc JJ |
149 | } |
150 | ||
151 | impl<'doc> Doc<'doc> { | |
152 | pub fn new(data: &'doc [u8]) -> Doc<'doc> { | |
85aaf69f | 153 | Doc { data: data, start: 0, end: data.len() } |
1a4d82fc JJ |
154 | } |
155 | ||
c34b1796 | 156 | pub fn get<'a>(&'a self, tag: usize) -> Doc<'a> { |
1a4d82fc JJ |
157 | reader::get_doc(*self, tag) |
158 | } | |
159 | ||
c34b1796 AL |
160 | pub fn is_empty(&self) -> bool { |
161 | self.start == self.end | |
162 | } | |
163 | ||
1a4d82fc JJ |
164 | pub fn as_str_slice<'a>(&'a self) -> &'a str { |
165 | str::from_utf8(&self.data[self.start..self.end]).unwrap() | |
166 | } | |
167 | ||
168 | pub fn as_str(&self) -> String { | |
169 | self.as_str_slice().to_string() | |
170 | } | |
171 | } | |
172 | ||
173 | pub struct TaggedDoc<'a> { | |
c34b1796 | 174 | tag: usize, |
1a4d82fc JJ |
175 | pub doc: Doc<'a>, |
176 | } | |
177 | ||
c34b1796 | 178 | #[derive(Copy, Clone, Debug)] |
1a4d82fc | 179 | pub enum EbmlEncoderTag { |
c34b1796 AL |
180 | // tags 00..1f are reserved for auto-serialization. |
181 | // first NUM_IMPLICIT_TAGS tags are implicitly sized and lengths are not encoded. | |
182 | ||
183 | EsU8 = 0x00, // + 1 byte | |
184 | EsU16 = 0x01, // + 2 bytes | |
185 | EsU32 = 0x02, // + 4 bytes | |
186 | EsU64 = 0x03, // + 8 bytes | |
187 | EsI8 = 0x04, // + 1 byte | |
188 | EsI16 = 0x05, // + 2 bytes | |
189 | EsI32 = 0x06, // + 4 bytes | |
190 | EsI64 = 0x07, // + 8 bytes | |
191 | EsBool = 0x08, // + 1 byte | |
192 | EsChar = 0x09, // + 4 bytes | |
193 | EsF32 = 0x0a, // + 4 bytes | |
194 | EsF64 = 0x0b, // + 8 bytes | |
195 | EsSub8 = 0x0c, // + 1 byte | |
196 | EsSub32 = 0x0d, // + 4 bytes | |
197 | // 0x0e and 0x0f are reserved | |
198 | ||
199 | EsStr = 0x10, | |
200 | EsEnum = 0x11, // encodes the variant id as the first EsSub* | |
201 | EsVec = 0x12, // encodes the # of elements as the first EsSub* | |
202 | EsVecElt = 0x13, | |
203 | EsMap = 0x14, // encodes the # of pairs as the first EsSub* | |
204 | EsMapKey = 0x15, | |
205 | EsMapVal = 0x16, | |
206 | EsOpaque = 0x17, | |
1a4d82fc JJ |
207 | } |
208 | ||
c34b1796 AL |
209 | const NUM_TAGS: usize = 0x1000; |
210 | const NUM_IMPLICIT_TAGS: usize = 0x0e; | |
211 | ||
212 | static TAG_IMPLICIT_LEN: [i8; NUM_IMPLICIT_TAGS] = [ | |
213 | 1, 2, 4, 8, // EsU* | |
214 | 1, 2, 4, 8, // ESI* | |
215 | 1, // EsBool | |
216 | 4, // EsChar | |
217 | 4, 8, // EsF* | |
218 | 1, 4, // EsSub* | |
219 | ]; | |
220 | ||
85aaf69f | 221 | #[derive(Debug)] |
1a4d82fc | 222 | pub enum Error { |
c34b1796 AL |
223 | IntTooBig(usize), |
224 | InvalidTag(usize), | |
1a4d82fc | 225 | Expected(String), |
c34b1796 | 226 | IoError(std::io::Error), |
1a4d82fc JJ |
227 | ApplicationError(String) |
228 | } | |
85aaf69f SL |
229 | |
230 | impl fmt::Display for Error { | |
231 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
232 | // FIXME: this should be a more useful display form | |
233 | fmt::Debug::fmt(self, f) | |
234 | } | |
235 | } | |
1a4d82fc JJ |
236 | // -------------------------------------- |
237 | ||
238 | pub mod reader { | |
239 | use std::char; | |
240 | ||
85aaf69f | 241 | use std::isize; |
1a4d82fc | 242 | use std::mem::transmute; |
c34b1796 | 243 | use std::slice::bytes; |
1a4d82fc JJ |
244 | |
245 | use serialize; | |
246 | ||
c34b1796 AL |
247 | use super::{ ApplicationError, EsVec, EsMap, EsEnum, EsSub8, EsSub32, |
248 | EsVecElt, EsMapKey, EsU64, EsU32, EsU16, EsU8, EsI64, | |
1a4d82fc | 249 | EsI32, EsI16, EsI8, EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal, |
c34b1796 AL |
250 | EsOpaque, EbmlEncoderTag, Doc, TaggedDoc, |
251 | Error, IntTooBig, InvalidTag, Expected, NUM_IMPLICIT_TAGS, TAG_IMPLICIT_LEN }; | |
1a4d82fc JJ |
252 | |
253 | pub type DecodeResult<T> = Result<T, Error>; | |
254 | // rbml reading | |
255 | ||
256 | macro_rules! try_or { | |
257 | ($e:expr, $r:expr) => ( | |
258 | match $e { | |
259 | Ok(e) => e, | |
260 | Err(e) => { | |
261 | debug!("ignored error: {:?}", e); | |
262 | return $r | |
263 | } | |
264 | } | |
265 | ) | |
266 | } | |
267 | ||
c34b1796 | 268 | #[derive(Copy, Clone)] |
1a4d82fc | 269 | pub struct Res { |
c34b1796 AL |
270 | pub val: usize, |
271 | pub next: usize | |
272 | } | |
273 | ||
274 | pub fn tag_at(data: &[u8], start: usize) -> DecodeResult<Res> { | |
275 | let v = data[start] as usize; | |
276 | if v < 0xf0 { | |
277 | Ok(Res { val: v, next: start + 1 }) | |
278 | } else if v > 0xf0 { | |
279 | Ok(Res { val: ((v & 0xf) << 8) | data[start + 1] as usize, next: start + 2 }) | |
280 | } else { | |
281 | // every tag starting with byte 0xf0 is an overlong form, which is prohibited. | |
282 | Err(InvalidTag(v)) | |
283 | } | |
1a4d82fc JJ |
284 | } |
285 | ||
286 | #[inline(never)] | |
c34b1796 | 287 | fn vuint_at_slow(data: &[u8], start: usize) -> DecodeResult<Res> { |
1a4d82fc | 288 | let a = data[start]; |
c34b1796 AL |
289 | if a & 0x80 != 0 { |
290 | return Ok(Res {val: (a & 0x7f) as usize, next: start + 1}); | |
1a4d82fc | 291 | } |
c34b1796 AL |
292 | if a & 0x40 != 0 { |
293 | return Ok(Res {val: ((a & 0x3f) as usize) << 8 | | |
294 | (data[start + 1] as usize), | |
85aaf69f | 295 | next: start + 2}); |
1a4d82fc | 296 | } |
c34b1796 AL |
297 | if a & 0x20 != 0 { |
298 | return Ok(Res {val: ((a & 0x1f) as usize) << 16 | | |
299 | (data[start + 1] as usize) << 8 | | |
300 | (data[start + 2] as usize), | |
85aaf69f | 301 | next: start + 3}); |
1a4d82fc | 302 | } |
c34b1796 AL |
303 | if a & 0x10 != 0 { |
304 | return Ok(Res {val: ((a & 0x0f) as usize) << 24 | | |
305 | (data[start + 1] as usize) << 16 | | |
306 | (data[start + 2] as usize) << 8 | | |
307 | (data[start + 3] as usize), | |
85aaf69f | 308 | next: start + 4}); |
1a4d82fc | 309 | } |
c34b1796 | 310 | Err(IntTooBig(a as usize)) |
1a4d82fc JJ |
311 | } |
312 | ||
c34b1796 | 313 | pub fn vuint_at(data: &[u8], start: usize) -> DecodeResult<Res> { |
1a4d82fc JJ |
314 | if data.len() - start < 4 { |
315 | return vuint_at_slow(data, start); | |
316 | } | |
317 | ||
c34b1796 AL |
318 | // Lookup table for parsing EBML Element IDs as per |
319 | // http://ebml.sourceforge.net/specs/ The Element IDs are parsed by | |
320 | // reading a big endian u32 positioned at data[start]. Using the four | |
321 | // most significant bits of the u32 we lookup in the table below how | |
322 | // the element ID should be derived from it. | |
1a4d82fc | 323 | // |
c34b1796 AL |
324 | // The table stores tuples (shift, mask) where shift is the number the |
325 | // u32 should be right shifted with and mask is the value the right | |
326 | // shifted value should be masked with. If for example the most | |
327 | // significant bit is set this means it's a class A ID and the u32 | |
328 | // should be right shifted with 24 and masked with 0x7f. Therefore we | |
329 | // store (24, 0x7f) at index 0x8 - 0xF (four bit numbers where the most | |
330 | // significant bit is set). | |
1a4d82fc | 331 | // |
c34b1796 AL |
332 | // By storing the number of shifts and masks in a table instead of |
333 | // checking in order if the most significant bit is set, the second | |
334 | // most significant bit is set etc. we can replace up to three | |
335 | // "and+branch" with a single table lookup which gives us a measured | |
1a4d82fc | 336 | // speedup of around 2x on x86_64. |
c34b1796 | 337 | static SHIFT_MASK_TABLE: [(usize, u32); 16] = [ |
1a4d82fc JJ |
338 | (0, 0x0), (0, 0x0fffffff), |
339 | (8, 0x1fffff), (8, 0x1fffff), | |
340 | (16, 0x3fff), (16, 0x3fff), (16, 0x3fff), (16, 0x3fff), | |
341 | (24, 0x7f), (24, 0x7f), (24, 0x7f), (24, 0x7f), | |
342 | (24, 0x7f), (24, 0x7f), (24, 0x7f), (24, 0x7f) | |
343 | ]; | |
344 | ||
345 | unsafe { | |
c34b1796 AL |
346 | let ptr = data.as_ptr().offset(start as isize) as *const u32; |
347 | let val = u32::from_be(*ptr); | |
1a4d82fc | 348 | |
c34b1796 | 349 | let i = (val >> 28) as usize; |
1a4d82fc JJ |
350 | let (shift, mask) = SHIFT_MASK_TABLE[i]; |
351 | Ok(Res { | |
c34b1796 AL |
352 | val: ((val >> shift) & mask) as usize, |
353 | next: start + ((32 - shift) >> 3), | |
1a4d82fc JJ |
354 | }) |
355 | } | |
356 | } | |
357 | ||
c34b1796 AL |
358 | pub fn tag_len_at(data: &[u8], tag: Res) -> DecodeResult<Res> { |
359 | if tag.val < NUM_IMPLICIT_TAGS && TAG_IMPLICIT_LEN[tag.val] >= 0 { | |
360 | Ok(Res { val: TAG_IMPLICIT_LEN[tag.val] as usize, next: tag.next }) | |
361 | } else { | |
362 | vuint_at(data, tag.next) | |
363 | } | |
364 | } | |
365 | ||
366 | pub fn doc_at<'a>(data: &'a [u8], start: usize) -> DecodeResult<TaggedDoc<'a>> { | |
367 | let elt_tag = try!(tag_at(data, start)); | |
368 | let elt_size = try!(tag_len_at(data, elt_tag)); | |
1a4d82fc JJ |
369 | let end = elt_size.next + elt_size.val; |
370 | Ok(TaggedDoc { | |
371 | tag: elt_tag.val, | |
372 | doc: Doc { data: data, start: elt_size.next, end: end } | |
373 | }) | |
374 | } | |
375 | ||
c34b1796 | 376 | pub fn maybe_get_doc<'a>(d: Doc<'a>, tg: usize) -> Option<Doc<'a>> { |
1a4d82fc JJ |
377 | let mut pos = d.start; |
378 | while pos < d.end { | |
c34b1796 AL |
379 | let elt_tag = try_or!(tag_at(d.data, pos), None); |
380 | let elt_size = try_or!(tag_len_at(d.data, elt_tag), None); | |
1a4d82fc JJ |
381 | pos = elt_size.next + elt_size.val; |
382 | if elt_tag.val == tg { | |
383 | return Some(Doc { data: d.data, start: elt_size.next, | |
384 | end: pos }); | |
385 | } | |
386 | } | |
387 | None | |
388 | } | |
389 | ||
c34b1796 | 390 | pub fn get_doc<'a>(d: Doc<'a>, tg: usize) -> Doc<'a> { |
1a4d82fc JJ |
391 | match maybe_get_doc(d, tg) { |
392 | Some(d) => d, | |
393 | None => { | |
394 | error!("failed to find block with tag {:?}", tg); | |
395 | panic!(); | |
396 | } | |
397 | } | |
398 | } | |
399 | ||
62682a34 SL |
400 | pub fn docs<'a>(d: Doc<'a>) -> DocsIterator<'a> { |
401 | DocsIterator { | |
402 | d: d | |
403 | } | |
404 | } | |
405 | ||
406 | pub struct DocsIterator<'a> { | |
407 | d: Doc<'a>, | |
408 | } | |
409 | ||
410 | impl<'a> Iterator for DocsIterator<'a> { | |
411 | type Item = (usize, Doc<'a>); | |
412 | ||
413 | fn next(&mut self) -> Option<(usize, Doc<'a>)> { | |
414 | if self.d.start >= self.d.end { | |
415 | return None; | |
1a4d82fc | 416 | } |
62682a34 SL |
417 | |
418 | let elt_tag = try_or!(tag_at(self.d.data, self.d.start), { | |
419 | self.d.start = self.d.end; | |
420 | None | |
421 | }); | |
422 | let elt_size = try_or!(tag_len_at(self.d.data, elt_tag), { | |
423 | self.d.start = self.d.end; | |
424 | None | |
425 | }); | |
426 | ||
427 | let end = elt_size.next + elt_size.val; | |
428 | let doc = Doc { | |
429 | data: self.d.data, | |
430 | start: elt_size.next, | |
431 | end: end, | |
432 | }; | |
433 | ||
434 | self.d.start = end; | |
435 | return Some((elt_tag.val, doc)); | |
1a4d82fc | 436 | } |
1a4d82fc JJ |
437 | } |
438 | ||
62682a34 SL |
439 | pub fn tagged_docs<'a>(d: Doc<'a>, tag: usize) -> TaggedDocsIterator<'a> { |
440 | TaggedDocsIterator { | |
441 | iter: docs(d), | |
442 | tag: tag, | |
443 | } | |
444 | } | |
445 | ||
446 | pub struct TaggedDocsIterator<'a> { | |
447 | iter: DocsIterator<'a>, | |
448 | tag: usize, | |
449 | } | |
450 | ||
451 | impl<'a> Iterator for TaggedDocsIterator<'a> { | |
452 | type Item = Doc<'a>; | |
453 | ||
454 | fn next(&mut self) -> Option<Doc<'a>> { | |
455 | while let Some((tag, doc)) = self.iter.next() { | |
456 | if tag == self.tag { | |
457 | return Some(doc); | |
1a4d82fc JJ |
458 | } |
459 | } | |
62682a34 | 460 | None |
1a4d82fc | 461 | } |
1a4d82fc JJ |
462 | } |
463 | ||
464 | pub fn with_doc_data<T, F>(d: Doc, f: F) -> T where | |
465 | F: FnOnce(&[u8]) -> T, | |
466 | { | |
467 | f(&d.data[d.start..d.end]) | |
468 | } | |
469 | ||
470 | ||
471 | pub fn doc_as_u8(d: Doc) -> u8 { | |
85aaf69f | 472 | assert_eq!(d.end, d.start + 1); |
1a4d82fc JJ |
473 | d.data[d.start] |
474 | } | |
475 | ||
476 | pub fn doc_as_u16(d: Doc) -> u16 { | |
85aaf69f | 477 | assert_eq!(d.end, d.start + 2); |
c34b1796 AL |
478 | let mut b = [0; 2]; |
479 | bytes::copy_memory(&d.data[d.start..d.end], &mut b); | |
480 | unsafe { (*(b.as_ptr() as *const u16)).to_be() } | |
1a4d82fc JJ |
481 | } |
482 | ||
483 | pub fn doc_as_u32(d: Doc) -> u32 { | |
85aaf69f | 484 | assert_eq!(d.end, d.start + 4); |
c34b1796 AL |
485 | let mut b = [0; 4]; |
486 | bytes::copy_memory(&d.data[d.start..d.end], &mut b); | |
487 | unsafe { (*(b.as_ptr() as *const u32)).to_be() } | |
1a4d82fc JJ |
488 | } |
489 | ||
490 | pub fn doc_as_u64(d: Doc) -> u64 { | |
85aaf69f | 491 | assert_eq!(d.end, d.start + 8); |
c34b1796 AL |
492 | let mut b = [0; 8]; |
493 | bytes::copy_memory(&d.data[d.start..d.end], &mut b); | |
494 | unsafe { (*(b.as_ptr() as *const u64)).to_be() } | |
1a4d82fc JJ |
495 | } |
496 | ||
497 | pub fn doc_as_i8(d: Doc) -> i8 { doc_as_u8(d) as i8 } | |
498 | pub fn doc_as_i16(d: Doc) -> i16 { doc_as_u16(d) as i16 } | |
499 | pub fn doc_as_i32(d: Doc) -> i32 { doc_as_u32(d) as i32 } | |
500 | pub fn doc_as_i64(d: Doc) -> i64 { doc_as_u64(d) as i64 } | |
501 | ||
502 | pub struct Decoder<'a> { | |
503 | parent: Doc<'a>, | |
c34b1796 | 504 | pos: usize, |
1a4d82fc JJ |
505 | } |
506 | ||
507 | impl<'doc> Decoder<'doc> { | |
508 | pub fn new(d: Doc<'doc>) -> Decoder<'doc> { | |
509 | Decoder { | |
510 | parent: d, | |
511 | pos: d.start | |
512 | } | |
513 | } | |
514 | ||
1a4d82fc JJ |
515 | fn next_doc(&mut self, exp_tag: EbmlEncoderTag) -> DecodeResult<Doc<'doc>> { |
516 | debug!(". next_doc(exp_tag={:?})", exp_tag); | |
517 | if self.pos >= self.parent.end { | |
518 | return Err(Expected(format!("no more documents in \ | |
519 | current node!"))); | |
520 | } | |
521 | let TaggedDoc { tag: r_tag, doc: r_doc } = | |
522 | try!(doc_at(self.parent.data, self.pos)); | |
523 | debug!("self.parent={:?}-{:?} self.pos={:?} r_tag={:?} r_doc={:?}-{:?}", | |
524 | self.parent.start, | |
525 | self.parent.end, | |
526 | self.pos, | |
527 | r_tag, | |
528 | r_doc.start, | |
529 | r_doc.end); | |
c34b1796 | 530 | if r_tag != (exp_tag as usize) { |
1a4d82fc JJ |
531 | return Err(Expected(format!("expected EBML doc with tag {:?} but \ |
532 | found tag {:?}", exp_tag, r_tag))); | |
533 | } | |
534 | if r_doc.end > self.parent.end { | |
535 | return Err(Expected(format!("invalid EBML, child extends to \ | |
536 | {:#x}, parent to {:#x}", | |
537 | r_doc.end, self.parent.end))); | |
538 | } | |
539 | self.pos = r_doc.end; | |
540 | Ok(r_doc) | |
541 | } | |
542 | ||
543 | fn push_doc<T, F>(&mut self, exp_tag: EbmlEncoderTag, f: F) -> DecodeResult<T> where | |
544 | F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>, | |
545 | { | |
546 | let d = try!(self.next_doc(exp_tag)); | |
547 | let old_parent = self.parent; | |
548 | let old_pos = self.pos; | |
549 | self.parent = d; | |
550 | self.pos = d.start; | |
551 | let r = try!(f(self)); | |
552 | self.parent = old_parent; | |
553 | self.pos = old_pos; | |
554 | Ok(r) | |
555 | } | |
556 | ||
c34b1796 AL |
557 | fn _next_sub(&mut self) -> DecodeResult<usize> { |
558 | // empty vector/map optimization | |
559 | if self.parent.is_empty() { | |
560 | return Ok(0); | |
561 | } | |
562 | ||
563 | let TaggedDoc { tag: r_tag, doc: r_doc } = | |
564 | try!(doc_at(self.parent.data, self.pos)); | |
565 | let r = if r_tag == (EsSub8 as usize) { | |
566 | doc_as_u8(r_doc) as usize | |
567 | } else if r_tag == (EsSub32 as usize) { | |
568 | doc_as_u32(r_doc) as usize | |
569 | } else { | |
570 | return Err(Expected(format!("expected EBML doc with tag {:?} or {:?} but \ | |
571 | found tag {:?}", EsSub8, EsSub32, r_tag))); | |
572 | }; | |
573 | if r_doc.end > self.parent.end { | |
574 | return Err(Expected(format!("invalid EBML, child extends to \ | |
575 | {:#x}, parent to {:#x}", | |
576 | r_doc.end, self.parent.end))); | |
577 | } | |
578 | self.pos = r_doc.end; | |
579 | debug!("_next_sub result={:?}", r); | |
580 | Ok(r) | |
581 | } | |
582 | ||
583 | // variable-length unsigned integer with different tags. | |
584 | // `first_tag` should be a tag for u8 or i8. | |
585 | // `last_tag` should be the largest allowed integer tag with the matching signedness. | |
586 | // all tags between them should be valid, in the order of u8, u16, u32 and u64. | |
587 | fn _next_int(&mut self, | |
588 | first_tag: EbmlEncoderTag, | |
589 | last_tag: EbmlEncoderTag) -> DecodeResult<u64> { | |
590 | if self.pos >= self.parent.end { | |
591 | return Err(Expected(format!("no more documents in \ | |
592 | current node!"))); | |
593 | } | |
594 | ||
595 | let TaggedDoc { tag: r_tag, doc: r_doc } = | |
596 | try!(doc_at(self.parent.data, self.pos)); | |
597 | let r = if first_tag as usize <= r_tag && r_tag <= last_tag as usize { | |
598 | match r_tag - first_tag as usize { | |
599 | 0 => doc_as_u8(r_doc) as u64, | |
600 | 1 => doc_as_u16(r_doc) as u64, | |
601 | 2 => doc_as_u32(r_doc) as u64, | |
602 | 3 => doc_as_u64(r_doc), | |
603 | _ => unreachable!(), | |
604 | } | |
605 | } else { | |
606 | return Err(Expected(format!("expected EBML doc with tag {:?} through {:?} but \ | |
607 | found tag {:?}", first_tag, last_tag, r_tag))); | |
608 | }; | |
609 | if r_doc.end > self.parent.end { | |
610 | return Err(Expected(format!("invalid EBML, child extends to \ | |
611 | {:#x}, parent to {:#x}", | |
612 | r_doc.end, self.parent.end))); | |
613 | } | |
614 | self.pos = r_doc.end; | |
615 | debug!("_next_int({:?}, {:?}) result={:?}", first_tag, last_tag, r); | |
616 | Ok(r) | |
1a4d82fc JJ |
617 | } |
618 | ||
619 | pub fn read_opaque<R, F>(&mut self, op: F) -> DecodeResult<R> where | |
620 | F: FnOnce(&mut Decoder, Doc) -> DecodeResult<R>, | |
621 | { | |
622 | let doc = try!(self.next_doc(EsOpaque)); | |
623 | ||
624 | let (old_parent, old_pos) = (self.parent, self.pos); | |
625 | self.parent = doc; | |
626 | self.pos = doc.start; | |
627 | ||
628 | let result = try!(op(self, doc)); | |
629 | ||
630 | self.parent = old_parent; | |
631 | self.pos = old_pos; | |
632 | Ok(result) | |
633 | } | |
634 | } | |
635 | ||
636 | impl<'doc> serialize::Decoder for Decoder<'doc> { | |
637 | type Error = Error; | |
638 | fn read_nil(&mut self) -> DecodeResult<()> { Ok(()) } | |
639 | ||
c34b1796 AL |
640 | fn read_u64(&mut self) -> DecodeResult<u64> { self._next_int(EsU8, EsU64) } |
641 | fn read_u32(&mut self) -> DecodeResult<u32> { Ok(try!(self._next_int(EsU8, EsU32)) as u32) } | |
642 | fn read_u16(&mut self) -> DecodeResult<u16> { Ok(try!(self._next_int(EsU8, EsU16)) as u16) } | |
643 | fn read_u8(&mut self) -> DecodeResult<u8> { Ok(doc_as_u8(try!(self.next_doc(EsU8)))) } | |
644 | fn read_uint(&mut self) -> DecodeResult<usize> { | |
645 | let v = try!(self._next_int(EsU8, EsU64)); | |
85aaf69f | 646 | if v > (::std::usize::MAX as u64) { |
c34b1796 | 647 | Err(IntTooBig(v as usize)) |
1a4d82fc | 648 | } else { |
c34b1796 | 649 | Ok(v as usize) |
1a4d82fc JJ |
650 | } |
651 | } | |
652 | ||
c34b1796 AL |
653 | fn read_i64(&mut self) -> DecodeResult<i64> { Ok(try!(self._next_int(EsI8, EsI64)) as i64) } |
654 | fn read_i32(&mut self) -> DecodeResult<i32> { Ok(try!(self._next_int(EsI8, EsI32)) as i32) } | |
655 | fn read_i16(&mut self) -> DecodeResult<i16> { Ok(try!(self._next_int(EsI8, EsI16)) as i16) } | |
656 | fn read_i8(&mut self) -> DecodeResult<i8> { Ok(doc_as_u8(try!(self.next_doc(EsI8))) as i8) } | |
657 | fn read_int(&mut self) -> DecodeResult<isize> { | |
658 | let v = try!(self._next_int(EsI8, EsI64)) as i64; | |
85aaf69f | 659 | if v > (isize::MAX as i64) || v < (isize::MIN as i64) { |
1a4d82fc | 660 | debug!("FIXME \\#6122: Removing this makes this function miscompile"); |
c34b1796 | 661 | Err(IntTooBig(v as usize)) |
1a4d82fc | 662 | } else { |
c34b1796 | 663 | Ok(v as isize) |
1a4d82fc JJ |
664 | } |
665 | } | |
666 | ||
667 | fn read_bool(&mut self) -> DecodeResult<bool> { | |
668 | Ok(doc_as_u8(try!(self.next_doc(EsBool))) != 0) | |
669 | } | |
670 | ||
671 | fn read_f64(&mut self) -> DecodeResult<f64> { | |
672 | let bits = doc_as_u64(try!(self.next_doc(EsF64))); | |
673 | Ok(unsafe { transmute(bits) }) | |
674 | } | |
675 | fn read_f32(&mut self) -> DecodeResult<f32> { | |
676 | let bits = doc_as_u32(try!(self.next_doc(EsF32))); | |
677 | Ok(unsafe { transmute(bits) }) | |
678 | } | |
679 | fn read_char(&mut self) -> DecodeResult<char> { | |
680 | Ok(char::from_u32(doc_as_u32(try!(self.next_doc(EsChar)))).unwrap()) | |
681 | } | |
682 | fn read_str(&mut self) -> DecodeResult<String> { | |
683 | Ok(try!(self.next_doc(EsStr)).as_str()) | |
684 | } | |
685 | ||
686 | // Compound types: | |
687 | fn read_enum<T, F>(&mut self, name: &str, f: F) -> DecodeResult<T> where | |
688 | F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>, | |
689 | { | |
690 | debug!("read_enum({})", name); | |
1a4d82fc JJ |
691 | |
692 | let doc = try!(self.next_doc(EsEnum)); | |
693 | ||
694 | let (old_parent, old_pos) = (self.parent, self.pos); | |
695 | self.parent = doc; | |
696 | self.pos = self.parent.start; | |
697 | ||
698 | let result = try!(f(self)); | |
699 | ||
700 | self.parent = old_parent; | |
701 | self.pos = old_pos; | |
702 | Ok(result) | |
703 | } | |
704 | ||
705 | fn read_enum_variant<T, F>(&mut self, _: &[&str], | |
706 | mut f: F) -> DecodeResult<T> | |
c34b1796 | 707 | where F: FnMut(&mut Decoder<'doc>, usize) -> DecodeResult<T>, |
1a4d82fc JJ |
708 | { |
709 | debug!("read_enum_variant()"); | |
c34b1796 | 710 | let idx = try!(self._next_sub()); |
1a4d82fc JJ |
711 | debug!(" idx={}", idx); |
712 | ||
c34b1796 | 713 | f(self, idx) |
1a4d82fc JJ |
714 | } |
715 | ||
c34b1796 | 716 | fn read_enum_variant_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T> where |
1a4d82fc JJ |
717 | F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>, |
718 | { | |
719 | debug!("read_enum_variant_arg(idx={})", idx); | |
720 | f(self) | |
721 | } | |
722 | ||
723 | fn read_enum_struct_variant<T, F>(&mut self, _: &[&str], | |
724 | mut f: F) -> DecodeResult<T> | |
c34b1796 | 725 | where F: FnMut(&mut Decoder<'doc>, usize) -> DecodeResult<T>, |
1a4d82fc JJ |
726 | { |
727 | debug!("read_enum_struct_variant()"); | |
c34b1796 | 728 | let idx = try!(self._next_sub()); |
1a4d82fc JJ |
729 | debug!(" idx={}", idx); |
730 | ||
c34b1796 | 731 | f(self, idx) |
1a4d82fc JJ |
732 | } |
733 | ||
734 | fn read_enum_struct_variant_field<T, F>(&mut self, | |
735 | name: &str, | |
c34b1796 | 736 | idx: usize, |
1a4d82fc JJ |
737 | f: F) |
738 | -> DecodeResult<T> where | |
739 | F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>, | |
740 | { | |
741 | debug!("read_enum_struct_variant_arg(name={}, idx={})", name, idx); | |
742 | f(self) | |
743 | } | |
744 | ||
c34b1796 | 745 | fn read_struct<T, F>(&mut self, name: &str, _: usize, f: F) -> DecodeResult<T> where |
1a4d82fc JJ |
746 | F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>, |
747 | { | |
748 | debug!("read_struct(name={})", name); | |
749 | f(self) | |
750 | } | |
751 | ||
c34b1796 | 752 | fn read_struct_field<T, F>(&mut self, name: &str, idx: usize, f: F) -> DecodeResult<T> where |
1a4d82fc JJ |
753 | F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>, |
754 | { | |
755 | debug!("read_struct_field(name={}, idx={})", name, idx); | |
1a4d82fc JJ |
756 | f(self) |
757 | } | |
758 | ||
c34b1796 | 759 | fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) -> DecodeResult<T> where |
1a4d82fc JJ |
760 | F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>, |
761 | { | |
762 | debug!("read_tuple()"); | |
763 | self.read_seq(move |d, len| { | |
764 | if len == tuple_len { | |
765 | f(d) | |
766 | } else { | |
767 | Err(Expected(format!("Expected tuple of length `{}`, \ | |
768 | found tuple of length `{}`", tuple_len, len))) | |
769 | } | |
770 | }) | |
771 | } | |
772 | ||
c34b1796 | 773 | fn read_tuple_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T> where |
1a4d82fc JJ |
774 | F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>, |
775 | { | |
776 | debug!("read_tuple_arg(idx={})", idx); | |
777 | self.read_seq_elt(idx, f) | |
778 | } | |
779 | ||
c34b1796 | 780 | fn read_tuple_struct<T, F>(&mut self, name: &str, len: usize, f: F) -> DecodeResult<T> where |
1a4d82fc JJ |
781 | F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>, |
782 | { | |
783 | debug!("read_tuple_struct(name={})", name); | |
784 | self.read_tuple(len, f) | |
785 | } | |
786 | ||
787 | fn read_tuple_struct_arg<T, F>(&mut self, | |
c34b1796 | 788 | idx: usize, |
1a4d82fc JJ |
789 | f: F) |
790 | -> DecodeResult<T> where | |
791 | F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>, | |
792 | { | |
793 | debug!("read_tuple_struct_arg(idx={})", idx); | |
794 | self.read_tuple_arg(idx, f) | |
795 | } | |
796 | ||
797 | fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T> where | |
798 | F: FnMut(&mut Decoder<'doc>, bool) -> DecodeResult<T>, | |
799 | { | |
800 | debug!("read_option()"); | |
801 | self.read_enum("Option", move |this| { | |
802 | this.read_enum_variant(&["None", "Some"], move |this, idx| { | |
803 | match idx { | |
804 | 0 => f(this, false), | |
805 | 1 => f(this, true), | |
806 | _ => { | |
807 | Err(Expected(format!("Expected None or Some"))) | |
808 | } | |
809 | } | |
810 | }) | |
811 | }) | |
812 | } | |
813 | ||
814 | fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T> where | |
c34b1796 | 815 | F: FnOnce(&mut Decoder<'doc>, usize) -> DecodeResult<T>, |
1a4d82fc JJ |
816 | { |
817 | debug!("read_seq()"); | |
818 | self.push_doc(EsVec, move |d| { | |
c34b1796 | 819 | let len = try!(d._next_sub()); |
1a4d82fc JJ |
820 | debug!(" len={}", len); |
821 | f(d, len) | |
822 | }) | |
823 | } | |
824 | ||
c34b1796 | 825 | fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T> where |
1a4d82fc JJ |
826 | F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>, |
827 | { | |
828 | debug!("read_seq_elt(idx={})", idx); | |
829 | self.push_doc(EsVecElt, f) | |
830 | } | |
831 | ||
832 | fn read_map<T, F>(&mut self, f: F) -> DecodeResult<T> where | |
c34b1796 | 833 | F: FnOnce(&mut Decoder<'doc>, usize) -> DecodeResult<T>, |
1a4d82fc JJ |
834 | { |
835 | debug!("read_map()"); | |
836 | self.push_doc(EsMap, move |d| { | |
c34b1796 | 837 | let len = try!(d._next_sub()); |
1a4d82fc JJ |
838 | debug!(" len={}", len); |
839 | f(d, len) | |
840 | }) | |
841 | } | |
842 | ||
c34b1796 | 843 | fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T> where |
1a4d82fc JJ |
844 | F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>, |
845 | { | |
846 | debug!("read_map_elt_key(idx={})", idx); | |
847 | self.push_doc(EsMapKey, f) | |
848 | } | |
849 | ||
c34b1796 | 850 | fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T> where |
1a4d82fc JJ |
851 | F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>, |
852 | { | |
853 | debug!("read_map_elt_val(idx={})", idx); | |
854 | self.push_doc(EsMapVal, f) | |
855 | } | |
856 | ||
857 | fn error(&mut self, err: &str) -> Error { | |
858 | ApplicationError(err.to_string()) | |
859 | } | |
860 | } | |
861 | } | |
862 | ||
863 | pub mod writer { | |
1a4d82fc | 864 | use std::mem; |
c34b1796 AL |
865 | use std::io::prelude::*; |
866 | use std::io::{self, SeekFrom, Cursor}; | |
867 | use std::slice::bytes; | |
1a4d82fc | 868 | |
c34b1796 AL |
869 | use super::{ EsVec, EsMap, EsEnum, EsSub8, EsSub32, EsVecElt, EsMapKey, |
870 | EsU64, EsU32, EsU16, EsU8, EsI64, EsI32, EsI16, EsI8, | |
871 | EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal, | |
872 | EsOpaque, NUM_IMPLICIT_TAGS, NUM_TAGS }; | |
1a4d82fc JJ |
873 | |
874 | use serialize; | |
875 | ||
876 | ||
c34b1796 | 877 | pub type EncodeResult = io::Result<()>; |
1a4d82fc JJ |
878 | |
879 | // rbml writing | |
c34b1796 AL |
880 | pub struct Encoder<'a> { |
881 | pub writer: &'a mut Cursor<Vec<u8>>, | |
882 | size_positions: Vec<u64>, | |
883 | relax_limit: u64, // do not move encoded bytes before this position | |
1a4d82fc JJ |
884 | } |
885 | ||
c34b1796 AL |
886 | fn write_tag<W: Write>(w: &mut W, n: usize) -> EncodeResult { |
887 | if n < 0xf0 { | |
888 | w.write_all(&[n as u8]) | |
889 | } else if 0x100 <= n && n < NUM_TAGS { | |
890 | w.write_all(&[0xf0 | (n >> 8) as u8, n as u8]) | |
891 | } else { | |
892 | Err(io::Error::new(io::ErrorKind::Other, | |
893 | &format!("invalid tag: {}", n)[..])) | |
894 | } | |
895 | } | |
896 | ||
897 | fn write_sized_vuint<W: Write>(w: &mut W, n: usize, size: usize) -> EncodeResult { | |
1a4d82fc | 898 | match size { |
c34b1796 AL |
899 | 1 => w.write_all(&[0x80 | (n as u8)]), |
900 | 2 => w.write_all(&[0x40 | ((n >> 8) as u8), n as u8]), | |
901 | 3 => w.write_all(&[0x20 | ((n >> 16) as u8), (n >> 8) as u8, | |
1a4d82fc | 902 | n as u8]), |
c34b1796 | 903 | 4 => w.write_all(&[0x10 | ((n >> 24) as u8), (n >> 16) as u8, |
85aaf69f | 904 | (n >> 8) as u8, n as u8]), |
c34b1796 AL |
905 | _ => Err(io::Error::new(io::ErrorKind::Other, |
906 | &format!("isize too big: {}", n)[..])) | |
1a4d82fc JJ |
907 | } |
908 | } | |
909 | ||
c34b1796 | 910 | fn write_vuint<W: Write>(w: &mut W, n: usize) -> EncodeResult { |
85aaf69f SL |
911 | if n < 0x7f { return write_sized_vuint(w, n, 1); } |
912 | if n < 0x4000 { return write_sized_vuint(w, n, 2); } | |
913 | if n < 0x200000 { return write_sized_vuint(w, n, 3); } | |
914 | if n < 0x10000000 { return write_sized_vuint(w, n, 4); } | |
c34b1796 AL |
915 | Err(io::Error::new(io::ErrorKind::Other, |
916 | &format!("isize too big: {}", n)[..])) | |
1a4d82fc JJ |
917 | } |
918 | ||
c34b1796 AL |
919 | impl<'a> Encoder<'a> { |
920 | pub fn new(w: &'a mut Cursor<Vec<u8>>) -> Encoder<'a> { | |
1a4d82fc JJ |
921 | Encoder { |
922 | writer: w, | |
923 | size_positions: vec!(), | |
c34b1796 | 924 | relax_limit: 0, |
1a4d82fc JJ |
925 | } |
926 | } | |
927 | ||
928 | /// FIXME(pcwalton): Workaround for badness in trans. DO NOT USE ME. | |
c34b1796 | 929 | pub unsafe fn unsafe_clone(&self) -> Encoder<'a> { |
1a4d82fc JJ |
930 | Encoder { |
931 | writer: mem::transmute_copy(&self.writer), | |
932 | size_positions: self.size_positions.clone(), | |
c34b1796 | 933 | relax_limit: self.relax_limit, |
1a4d82fc JJ |
934 | } |
935 | } | |
936 | ||
c34b1796 | 937 | pub fn start_tag(&mut self, tag_id: usize) -> EncodeResult { |
1a4d82fc | 938 | debug!("Start tag {:?}", tag_id); |
c34b1796 | 939 | assert!(tag_id >= NUM_IMPLICIT_TAGS); |
1a4d82fc JJ |
940 | |
941 | // Write the enum ID: | |
c34b1796 | 942 | try!(write_tag(self.writer, tag_id)); |
1a4d82fc JJ |
943 | |
944 | // Write a placeholder four-byte size. | |
c34b1796 AL |
945 | let cur_pos = try!(self.writer.seek(SeekFrom::Current(0))); |
946 | self.size_positions.push(cur_pos); | |
947 | let zeroes: &[u8] = &[0, 0, 0, 0]; | |
85aaf69f | 948 | self.writer.write_all(zeroes) |
1a4d82fc JJ |
949 | } |
950 | ||
951 | pub fn end_tag(&mut self) -> EncodeResult { | |
952 | let last_size_pos = self.size_positions.pop().unwrap(); | |
c34b1796 AL |
953 | let cur_pos = try!(self.writer.seek(SeekFrom::Current(0))); |
954 | try!(self.writer.seek(SeekFrom::Start(last_size_pos))); | |
955 | let size = (cur_pos - last_size_pos - 4) as usize; | |
956 | ||
957 | // relax the size encoding for small tags (bigger tags are costly to move). | |
958 | // we should never try to move the stable positions, however. | |
959 | const RELAX_MAX_SIZE: usize = 0x100; | |
960 | if size <= RELAX_MAX_SIZE && last_size_pos >= self.relax_limit { | |
961 | // we can't alter the buffer in place, so have a temporary buffer | |
962 | let mut buf = [0u8; RELAX_MAX_SIZE]; | |
963 | { | |
964 | let last_size_pos = last_size_pos as usize; | |
965 | let data = &self.writer.get_ref()[last_size_pos+4..cur_pos as usize]; | |
966 | bytes::copy_memory(data, &mut buf); | |
967 | } | |
968 | ||
969 | // overwrite the size and data and continue | |
970 | try!(write_vuint(self.writer, size)); | |
971 | try!(self.writer.write_all(&buf[..size])); | |
972 | } else { | |
973 | // overwrite the size with an overlong encoding and skip past the data | |
974 | try!(write_sized_vuint(self.writer, size, 4)); | |
975 | try!(self.writer.seek(SeekFrom::Start(cur_pos))); | |
976 | } | |
1a4d82fc JJ |
977 | |
978 | debug!("End tag (size = {:?})", size); | |
c34b1796 | 979 | Ok(()) |
1a4d82fc JJ |
980 | } |
981 | ||
c34b1796 | 982 | pub fn wr_tag<F>(&mut self, tag_id: usize, blk: F) -> EncodeResult where |
1a4d82fc JJ |
983 | F: FnOnce() -> EncodeResult, |
984 | { | |
985 | try!(self.start_tag(tag_id)); | |
986 | try!(blk()); | |
987 | self.end_tag() | |
988 | } | |
989 | ||
c34b1796 AL |
990 | pub fn wr_tagged_bytes(&mut self, tag_id: usize, b: &[u8]) -> EncodeResult { |
991 | assert!(tag_id >= NUM_IMPLICIT_TAGS); | |
992 | try!(write_tag(self.writer, tag_id)); | |
1a4d82fc | 993 | try!(write_vuint(self.writer, b.len())); |
85aaf69f | 994 | self.writer.write_all(b) |
1a4d82fc JJ |
995 | } |
996 | ||
c34b1796 AL |
997 | pub fn wr_tagged_u64(&mut self, tag_id: usize, v: u64) -> EncodeResult { |
998 | let bytes: [u8; 8] = unsafe { mem::transmute(v.to_be()) }; | |
999 | self.wr_tagged_bytes(tag_id, &bytes) | |
1a4d82fc JJ |
1000 | } |
1001 | ||
c34b1796 AL |
1002 | pub fn wr_tagged_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult{ |
1003 | let bytes: [u8; 4] = unsafe { mem::transmute(v.to_be()) }; | |
1004 | self.wr_tagged_bytes(tag_id, &bytes) | |
1a4d82fc JJ |
1005 | } |
1006 | ||
c34b1796 AL |
1007 | pub fn wr_tagged_u16(&mut self, tag_id: usize, v: u16) -> EncodeResult { |
1008 | let bytes: [u8; 2] = unsafe { mem::transmute(v.to_be()) }; | |
1009 | self.wr_tagged_bytes(tag_id, &bytes) | |
1a4d82fc JJ |
1010 | } |
1011 | ||
c34b1796 | 1012 | pub fn wr_tagged_u8(&mut self, tag_id: usize, v: u8) -> EncodeResult { |
1a4d82fc JJ |
1013 | self.wr_tagged_bytes(tag_id, &[v]) |
1014 | } | |
1015 | ||
c34b1796 AL |
1016 | pub fn wr_tagged_i64(&mut self, tag_id: usize, v: i64) -> EncodeResult { |
1017 | self.wr_tagged_u64(tag_id, v as u64) | |
1a4d82fc JJ |
1018 | } |
1019 | ||
c34b1796 AL |
1020 | pub fn wr_tagged_i32(&mut self, tag_id: usize, v: i32) -> EncodeResult { |
1021 | self.wr_tagged_u32(tag_id, v as u32) | |
1a4d82fc JJ |
1022 | } |
1023 | ||
c34b1796 AL |
1024 | pub fn wr_tagged_i16(&mut self, tag_id: usize, v: i16) -> EncodeResult { |
1025 | self.wr_tagged_u16(tag_id, v as u16) | |
1a4d82fc JJ |
1026 | } |
1027 | ||
c34b1796 | 1028 | pub fn wr_tagged_i8(&mut self, tag_id: usize, v: i8) -> EncodeResult { |
1a4d82fc JJ |
1029 | self.wr_tagged_bytes(tag_id, &[v as u8]) |
1030 | } | |
1031 | ||
c34b1796 | 1032 | pub fn wr_tagged_str(&mut self, tag_id: usize, v: &str) -> EncodeResult { |
1a4d82fc JJ |
1033 | self.wr_tagged_bytes(tag_id, v.as_bytes()) |
1034 | } | |
1035 | ||
c34b1796 AL |
1036 | // for auto-serialization |
1037 | fn wr_tagged_raw_bytes(&mut self, tag_id: usize, b: &[u8]) -> EncodeResult { | |
1038 | try!(write_tag(self.writer, tag_id)); | |
1039 | self.writer.write_all(b) | |
1040 | } | |
1041 | ||
1042 | fn wr_tagged_raw_u64(&mut self, tag_id: usize, v: u64) -> EncodeResult { | |
1043 | let bytes: [u8; 8] = unsafe { mem::transmute(v.to_be()) }; | |
1044 | self.wr_tagged_raw_bytes(tag_id, &bytes) | |
1045 | } | |
1046 | ||
1047 | fn wr_tagged_raw_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult{ | |
1048 | let bytes: [u8; 4] = unsafe { mem::transmute(v.to_be()) }; | |
1049 | self.wr_tagged_raw_bytes(tag_id, &bytes) | |
1050 | } | |
1051 | ||
1052 | fn wr_tagged_raw_u16(&mut self, tag_id: usize, v: u16) -> EncodeResult { | |
1053 | let bytes: [u8; 2] = unsafe { mem::transmute(v.to_be()) }; | |
1054 | self.wr_tagged_raw_bytes(tag_id, &bytes) | |
1055 | } | |
1056 | ||
1057 | fn wr_tagged_raw_u8(&mut self, tag_id: usize, v: u8) -> EncodeResult { | |
1058 | self.wr_tagged_raw_bytes(tag_id, &[v]) | |
1059 | } | |
1060 | ||
1061 | fn wr_tagged_raw_i64(&mut self, tag_id: usize, v: i64) -> EncodeResult { | |
1062 | self.wr_tagged_raw_u64(tag_id, v as u64) | |
1063 | } | |
1064 | ||
1065 | fn wr_tagged_raw_i32(&mut self, tag_id: usize, v: i32) -> EncodeResult { | |
1066 | self.wr_tagged_raw_u32(tag_id, v as u32) | |
1067 | } | |
1068 | ||
1069 | fn wr_tagged_raw_i16(&mut self, tag_id: usize, v: i16) -> EncodeResult { | |
1070 | self.wr_tagged_raw_u16(tag_id, v as u16) | |
1071 | } | |
1072 | ||
1073 | fn wr_tagged_raw_i8(&mut self, tag_id: usize, v: i8) -> EncodeResult { | |
1074 | self.wr_tagged_raw_bytes(tag_id, &[v as u8]) | |
1075 | } | |
1076 | ||
1a4d82fc JJ |
1077 | pub fn wr_bytes(&mut self, b: &[u8]) -> EncodeResult { |
1078 | debug!("Write {:?} bytes", b.len()); | |
85aaf69f | 1079 | self.writer.write_all(b) |
1a4d82fc JJ |
1080 | } |
1081 | ||
1082 | pub fn wr_str(&mut self, s: &str) -> EncodeResult { | |
1083 | debug!("Write str: {:?}", s); | |
85aaf69f | 1084 | self.writer.write_all(s.as_bytes()) |
1a4d82fc | 1085 | } |
1a4d82fc | 1086 | |
c34b1796 AL |
1087 | /// Returns the current position while marking it stable, i.e. |
1088 | /// generated bytes so far wouldn't be affected by relaxation. | |
1089 | pub fn mark_stable_position(&mut self) -> u64 { | |
1090 | let pos = self.writer.seek(SeekFrom::Current(0)).unwrap(); | |
1091 | if self.relax_limit < pos { | |
1092 | self.relax_limit = pos; | |
1093 | } | |
1094 | pos | |
1a4d82fc | 1095 | } |
c34b1796 | 1096 | } |
1a4d82fc | 1097 | |
c34b1796 AL |
1098 | impl<'a> Encoder<'a> { |
1099 | // used internally to emit things like the vector length and so on | |
1100 | fn _emit_tagged_sub(&mut self, v: usize) -> EncodeResult { | |
9346a6ac AL |
1101 | if v as u8 as usize == v { |
1102 | self.wr_tagged_raw_u8(EsSub8 as usize, v as u8) | |
1103 | } else if v as u32 as usize == v { | |
1104 | self.wr_tagged_raw_u32(EsSub32 as usize, v as u32) | |
c34b1796 AL |
1105 | } else { |
1106 | Err(io::Error::new(io::ErrorKind::Other, | |
1107 | &format!("length or variant id too big: {}", | |
1108 | v)[..])) | |
1109 | } | |
1a4d82fc JJ |
1110 | } |
1111 | ||
1112 | pub fn emit_opaque<F>(&mut self, f: F) -> EncodeResult where | |
c34b1796 | 1113 | F: FnOnce(&mut Encoder) -> EncodeResult, |
1a4d82fc | 1114 | { |
c34b1796 | 1115 | try!(self.start_tag(EsOpaque as usize)); |
1a4d82fc JJ |
1116 | try!(f(self)); |
1117 | self.end_tag() | |
1118 | } | |
1119 | } | |
1120 | ||
c34b1796 AL |
1121 | impl<'a> serialize::Encoder for Encoder<'a> { |
1122 | type Error = io::Error; | |
1a4d82fc JJ |
1123 | |
1124 | fn emit_nil(&mut self) -> EncodeResult { | |
1125 | Ok(()) | |
1126 | } | |
1127 | ||
c34b1796 AL |
1128 | fn emit_uint(&mut self, v: usize) -> EncodeResult { |
1129 | self.emit_u64(v as u64) | |
1a4d82fc JJ |
1130 | } |
1131 | fn emit_u64(&mut self, v: u64) -> EncodeResult { | |
9346a6ac AL |
1132 | if v as u32 as u64 == v { |
1133 | self.emit_u32(v as u32) | |
1134 | } else { | |
1135 | self.wr_tagged_raw_u64(EsU64 as usize, v) | |
c34b1796 | 1136 | } |
1a4d82fc JJ |
1137 | } |
1138 | fn emit_u32(&mut self, v: u32) -> EncodeResult { | |
9346a6ac AL |
1139 | if v as u16 as u32 == v { |
1140 | self.emit_u16(v as u16) | |
1141 | } else { | |
1142 | self.wr_tagged_raw_u32(EsU32 as usize, v) | |
c34b1796 | 1143 | } |
1a4d82fc JJ |
1144 | } |
1145 | fn emit_u16(&mut self, v: u16) -> EncodeResult { | |
9346a6ac AL |
1146 | if v as u8 as u16 == v { |
1147 | self.emit_u8(v as u8) | |
1148 | } else { | |
1149 | self.wr_tagged_raw_u16(EsU16 as usize, v) | |
c34b1796 | 1150 | } |
1a4d82fc JJ |
1151 | } |
1152 | fn emit_u8(&mut self, v: u8) -> EncodeResult { | |
c34b1796 | 1153 | self.wr_tagged_raw_u8(EsU8 as usize, v) |
1a4d82fc JJ |
1154 | } |
1155 | ||
c34b1796 AL |
1156 | fn emit_int(&mut self, v: isize) -> EncodeResult { |
1157 | self.emit_i64(v as i64) | |
1a4d82fc JJ |
1158 | } |
1159 | fn emit_i64(&mut self, v: i64) -> EncodeResult { | |
9346a6ac AL |
1160 | if v as i32 as i64 == v { |
1161 | self.emit_i32(v as i32) | |
1162 | } else { | |
1163 | self.wr_tagged_raw_i64(EsI64 as usize, v) | |
c34b1796 | 1164 | } |
1a4d82fc JJ |
1165 | } |
1166 | fn emit_i32(&mut self, v: i32) -> EncodeResult { | |
9346a6ac AL |
1167 | if v as i16 as i32 == v { |
1168 | self.emit_i16(v as i16) | |
1169 | } else { | |
1170 | self.wr_tagged_raw_i32(EsI32 as usize, v) | |
c34b1796 | 1171 | } |
1a4d82fc JJ |
1172 | } |
1173 | fn emit_i16(&mut self, v: i16) -> EncodeResult { | |
9346a6ac AL |
1174 | if v as i8 as i16 == v { |
1175 | self.emit_i8(v as i8) | |
1176 | } else { | |
1177 | self.wr_tagged_raw_i16(EsI16 as usize, v) | |
c34b1796 | 1178 | } |
1a4d82fc JJ |
1179 | } |
1180 | fn emit_i8(&mut self, v: i8) -> EncodeResult { | |
c34b1796 | 1181 | self.wr_tagged_raw_i8(EsI8 as usize, v) |
1a4d82fc JJ |
1182 | } |
1183 | ||
1184 | fn emit_bool(&mut self, v: bool) -> EncodeResult { | |
c34b1796 | 1185 | self.wr_tagged_raw_u8(EsBool as usize, v as u8) |
1a4d82fc JJ |
1186 | } |
1187 | ||
1188 | fn emit_f64(&mut self, v: f64) -> EncodeResult { | |
1189 | let bits = unsafe { mem::transmute(v) }; | |
c34b1796 | 1190 | self.wr_tagged_raw_u64(EsF64 as usize, bits) |
1a4d82fc JJ |
1191 | } |
1192 | fn emit_f32(&mut self, v: f32) -> EncodeResult { | |
1193 | let bits = unsafe { mem::transmute(v) }; | |
c34b1796 | 1194 | self.wr_tagged_raw_u32(EsF32 as usize, bits) |
1a4d82fc JJ |
1195 | } |
1196 | fn emit_char(&mut self, v: char) -> EncodeResult { | |
c34b1796 | 1197 | self.wr_tagged_raw_u32(EsChar as usize, v as u32) |
1a4d82fc JJ |
1198 | } |
1199 | ||
1200 | fn emit_str(&mut self, v: &str) -> EncodeResult { | |
c34b1796 | 1201 | self.wr_tagged_str(EsStr as usize, v) |
1a4d82fc JJ |
1202 | } |
1203 | ||
c34b1796 AL |
1204 | fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult where |
1205 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, | |
1a4d82fc | 1206 | { |
c34b1796 | 1207 | try!(self.start_tag(EsEnum as usize)); |
1a4d82fc JJ |
1208 | try!(f(self)); |
1209 | self.end_tag() | |
1210 | } | |
1211 | ||
1212 | fn emit_enum_variant<F>(&mut self, | |
1213 | _: &str, | |
c34b1796 AL |
1214 | v_id: usize, |
1215 | _: usize, | |
1a4d82fc | 1216 | f: F) -> EncodeResult where |
c34b1796 | 1217 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, |
1a4d82fc | 1218 | { |
c34b1796 AL |
1219 | try!(self._emit_tagged_sub(v_id)); |
1220 | f(self) | |
1a4d82fc JJ |
1221 | } |
1222 | ||
c34b1796 AL |
1223 | fn emit_enum_variant_arg<F>(&mut self, _: usize, f: F) -> EncodeResult where |
1224 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, | |
1a4d82fc JJ |
1225 | { |
1226 | f(self) | |
1227 | } | |
1228 | ||
1229 | fn emit_enum_struct_variant<F>(&mut self, | |
1230 | v_name: &str, | |
c34b1796 AL |
1231 | v_id: usize, |
1232 | cnt: usize, | |
1a4d82fc | 1233 | f: F) -> EncodeResult where |
c34b1796 | 1234 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, |
1a4d82fc JJ |
1235 | { |
1236 | self.emit_enum_variant(v_name, v_id, cnt, f) | |
1237 | } | |
1238 | ||
1239 | fn emit_enum_struct_variant_field<F>(&mut self, | |
1240 | _: &str, | |
c34b1796 | 1241 | idx: usize, |
1a4d82fc | 1242 | f: F) -> EncodeResult where |
c34b1796 | 1243 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, |
1a4d82fc JJ |
1244 | { |
1245 | self.emit_enum_variant_arg(idx, f) | |
1246 | } | |
1247 | ||
c34b1796 AL |
1248 | fn emit_struct<F>(&mut self, _: &str, _len: usize, f: F) -> EncodeResult where |
1249 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, | |
1a4d82fc JJ |
1250 | { |
1251 | f(self) | |
1252 | } | |
1253 | ||
c34b1796 AL |
1254 | fn emit_struct_field<F>(&mut self, _name: &str, _: usize, f: F) -> EncodeResult where |
1255 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, | |
1a4d82fc | 1256 | { |
1a4d82fc JJ |
1257 | f(self) |
1258 | } | |
1259 | ||
c34b1796 AL |
1260 | fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult where |
1261 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, | |
1a4d82fc JJ |
1262 | { |
1263 | self.emit_seq(len, f) | |
1264 | } | |
c34b1796 AL |
1265 | fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where |
1266 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, | |
1a4d82fc JJ |
1267 | { |
1268 | self.emit_seq_elt(idx, f) | |
1269 | } | |
1270 | ||
c34b1796 AL |
1271 | fn emit_tuple_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult where |
1272 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, | |
1a4d82fc JJ |
1273 | { |
1274 | self.emit_seq(len, f) | |
1275 | } | |
c34b1796 AL |
1276 | fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where |
1277 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, | |
1a4d82fc JJ |
1278 | { |
1279 | self.emit_seq_elt(idx, f) | |
1280 | } | |
1281 | ||
1282 | fn emit_option<F>(&mut self, f: F) -> EncodeResult where | |
c34b1796 | 1283 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, |
1a4d82fc JJ |
1284 | { |
1285 | self.emit_enum("Option", f) | |
1286 | } | |
1287 | fn emit_option_none(&mut self) -> EncodeResult { | |
1288 | self.emit_enum_variant("None", 0, 0, |_| Ok(())) | |
1289 | } | |
1290 | fn emit_option_some<F>(&mut self, f: F) -> EncodeResult where | |
c34b1796 | 1291 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, |
1a4d82fc JJ |
1292 | { |
1293 | ||
1294 | self.emit_enum_variant("Some", 1, 1, f) | |
1295 | } | |
1296 | ||
c34b1796 AL |
1297 | fn emit_seq<F>(&mut self, len: usize, f: F) -> EncodeResult where |
1298 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, | |
1a4d82fc | 1299 | { |
c34b1796 AL |
1300 | if len == 0 { |
1301 | // empty vector optimization | |
1302 | return self.wr_tagged_bytes(EsVec as usize, &[]); | |
1303 | } | |
1a4d82fc | 1304 | |
c34b1796 AL |
1305 | try!(self.start_tag(EsVec as usize)); |
1306 | try!(self._emit_tagged_sub(len)); | |
1a4d82fc JJ |
1307 | try!(f(self)); |
1308 | self.end_tag() | |
1309 | } | |
1310 | ||
c34b1796 AL |
1311 | fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) -> EncodeResult where |
1312 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, | |
1a4d82fc JJ |
1313 | { |
1314 | ||
c34b1796 | 1315 | try!(self.start_tag(EsVecElt as usize)); |
1a4d82fc JJ |
1316 | try!(f(self)); |
1317 | self.end_tag() | |
1318 | } | |
1319 | ||
c34b1796 AL |
1320 | fn emit_map<F>(&mut self, len: usize, f: F) -> EncodeResult where |
1321 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, | |
1a4d82fc | 1322 | { |
c34b1796 AL |
1323 | if len == 0 { |
1324 | // empty map optimization | |
1325 | return self.wr_tagged_bytes(EsMap as usize, &[]); | |
1326 | } | |
1a4d82fc | 1327 | |
c34b1796 AL |
1328 | try!(self.start_tag(EsMap as usize)); |
1329 | try!(self._emit_tagged_sub(len)); | |
1a4d82fc JJ |
1330 | try!(f(self)); |
1331 | self.end_tag() | |
1332 | } | |
1333 | ||
c34b1796 AL |
1334 | fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> EncodeResult where |
1335 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, | |
1a4d82fc JJ |
1336 | { |
1337 | ||
c34b1796 | 1338 | try!(self.start_tag(EsMapKey as usize)); |
1a4d82fc JJ |
1339 | try!(f(self)); |
1340 | self.end_tag() | |
1341 | } | |
1342 | ||
c34b1796 AL |
1343 | fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult where |
1344 | F: FnOnce(&mut Encoder<'a>) -> EncodeResult, | |
1a4d82fc | 1345 | { |
c34b1796 | 1346 | try!(self.start_tag(EsMapVal as usize)); |
1a4d82fc JJ |
1347 | try!(f(self)); |
1348 | self.end_tag() | |
1349 | } | |
1350 | } | |
1351 | } | |
1352 | ||
1353 | // ___________________________________________________________________________ | |
1354 | // Testing | |
1355 | ||
1356 | #[cfg(test)] | |
1357 | mod tests { | |
1358 | use super::{Doc, reader, writer}; | |
1a4d82fc JJ |
1359 | |
1360 | use serialize::{Encodable, Decodable}; | |
1361 | ||
c34b1796 | 1362 | use std::io::Cursor; |
1a4d82fc JJ |
1363 | |
1364 | #[test] | |
1365 | fn test_vuint_at() { | |
1366 | let data = &[ | |
1367 | 0x80, | |
1368 | 0xff, | |
1369 | 0x40, 0x00, | |
1370 | 0x7f, 0xff, | |
1371 | 0x20, 0x00, 0x00, | |
1372 | 0x3f, 0xff, 0xff, | |
1373 | 0x10, 0x00, 0x00, 0x00, | |
1374 | 0x1f, 0xff, 0xff, 0xff | |
1375 | ]; | |
1376 | ||
1377 | let mut res: reader::Res; | |
1378 | ||
1379 | // Class A | |
1380 | res = reader::vuint_at(data, 0).unwrap(); | |
1381 | assert_eq!(res.val, 0); | |
1382 | assert_eq!(res.next, 1); | |
1383 | res = reader::vuint_at(data, res.next).unwrap(); | |
1384 | assert_eq!(res.val, (1 << 7) - 1); | |
1385 | assert_eq!(res.next, 2); | |
1386 | ||
1387 | // Class B | |
1388 | res = reader::vuint_at(data, res.next).unwrap(); | |
1389 | assert_eq!(res.val, 0); | |
1390 | assert_eq!(res.next, 4); | |
1391 | res = reader::vuint_at(data, res.next).unwrap(); | |
1392 | assert_eq!(res.val, (1 << 14) - 1); | |
1393 | assert_eq!(res.next, 6); | |
1394 | ||
1395 | // Class C | |
1396 | res = reader::vuint_at(data, res.next).unwrap(); | |
1397 | assert_eq!(res.val, 0); | |
1398 | assert_eq!(res.next, 9); | |
1399 | res = reader::vuint_at(data, res.next).unwrap(); | |
1400 | assert_eq!(res.val, (1 << 21) - 1); | |
1401 | assert_eq!(res.next, 12); | |
1402 | ||
1403 | // Class D | |
1404 | res = reader::vuint_at(data, res.next).unwrap(); | |
1405 | assert_eq!(res.val, 0); | |
1406 | assert_eq!(res.next, 16); | |
1407 | res = reader::vuint_at(data, res.next).unwrap(); | |
1408 | assert_eq!(res.val, (1 << 28) - 1); | |
1409 | assert_eq!(res.next, 20); | |
1410 | } | |
1411 | ||
1412 | #[test] | |
1413 | fn test_option_int() { | |
c34b1796 | 1414 | fn test_v(v: Option<isize>) { |
1a4d82fc | 1415 | debug!("v == {:?}", v); |
c34b1796 | 1416 | let mut wr = Cursor::new(Vec::new()); |
1a4d82fc JJ |
1417 | { |
1418 | let mut rbml_w = writer::Encoder::new(&mut wr); | |
1419 | let _ = v.encode(&mut rbml_w); | |
1420 | } | |
1421 | let rbml_doc = Doc::new(wr.get_ref()); | |
1422 | let mut deser = reader::Decoder::new(rbml_doc); | |
1423 | let v1 = Decodable::decode(&mut deser).unwrap(); | |
1424 | debug!("v1 == {:?}", v1); | |
1425 | assert_eq!(v, v1); | |
1426 | } | |
1427 | ||
1428 | test_v(Some(22)); | |
1429 | test_v(None); | |
1430 | test_v(Some(3)); | |
1431 | } | |
1432 | } | |
1433 | ||
1434 | #[cfg(test)] | |
1435 | mod bench { | |
1436 | #![allow(non_snake_case)] | |
1437 | use test::Bencher; | |
1438 | use super::reader; | |
1439 | ||
1440 | #[bench] | |
1441 | pub fn vuint_at_A_aligned(b: &mut Bencher) { | |
c34b1796 | 1442 | let data = (0..4*100).map(|i| { |
1a4d82fc | 1443 | match i % 2 { |
c34b1796 | 1444 | 0 => 0x80, |
1a4d82fc JJ |
1445 | _ => i as u8, |
1446 | } | |
1447 | }).collect::<Vec<_>>(); | |
85aaf69f | 1448 | let mut sum = 0; |
1a4d82fc JJ |
1449 | b.iter(|| { |
1450 | let mut i = 0; | |
1451 | while i < data.len() { | |
85aaf69f | 1452 | sum += reader::vuint_at(&data, i).unwrap().val; |
1a4d82fc JJ |
1453 | i += 4; |
1454 | } | |
1455 | }); | |
1456 | } | |
1457 | ||
1458 | #[bench] | |
1459 | pub fn vuint_at_A_unaligned(b: &mut Bencher) { | |
c34b1796 | 1460 | let data = (0..4*100+1).map(|i| { |
1a4d82fc | 1461 | match i % 2 { |
c34b1796 | 1462 | 1 => 0x80, |
1a4d82fc JJ |
1463 | _ => i as u8 |
1464 | } | |
1465 | }).collect::<Vec<_>>(); | |
85aaf69f | 1466 | let mut sum = 0; |
1a4d82fc JJ |
1467 | b.iter(|| { |
1468 | let mut i = 1; | |
1469 | while i < data.len() { | |
85aaf69f | 1470 | sum += reader::vuint_at(&data, i).unwrap().val; |
1a4d82fc JJ |
1471 | i += 4; |
1472 | } | |
1473 | }); | |
1474 | } | |
1475 | ||
1476 | #[bench] | |
1477 | pub fn vuint_at_D_aligned(b: &mut Bencher) { | |
c34b1796 | 1478 | let data = (0..4*100).map(|i| { |
1a4d82fc | 1479 | match i % 4 { |
c34b1796 | 1480 | 0 => 0x10, |
1a4d82fc | 1481 | 3 => i as u8, |
c34b1796 | 1482 | _ => 0 |
1a4d82fc JJ |
1483 | } |
1484 | }).collect::<Vec<_>>(); | |
85aaf69f | 1485 | let mut sum = 0; |
1a4d82fc JJ |
1486 | b.iter(|| { |
1487 | let mut i = 0; | |
1488 | while i < data.len() { | |
85aaf69f | 1489 | sum += reader::vuint_at(&data, i).unwrap().val; |
1a4d82fc JJ |
1490 | i += 4; |
1491 | } | |
1492 | }); | |
1493 | } | |
1494 | ||
1495 | #[bench] | |
1496 | pub fn vuint_at_D_unaligned(b: &mut Bencher) { | |
c34b1796 | 1497 | let data = (0..4*100+1).map(|i| { |
1a4d82fc | 1498 | match i % 4 { |
c34b1796 | 1499 | 1 => 0x10, |
1a4d82fc | 1500 | 0 => i as u8, |
c34b1796 | 1501 | _ => 0 |
1a4d82fc JJ |
1502 | } |
1503 | }).collect::<Vec<_>>(); | |
85aaf69f | 1504 | let mut sum = 0; |
1a4d82fc JJ |
1505 | b.iter(|| { |
1506 | let mut i = 1; | |
1507 | while i < data.len() { | |
85aaf69f | 1508 | sum += reader::vuint_at(&data, i).unwrap().val; |
1a4d82fc JJ |
1509 | i += 4; |
1510 | } | |
1511 | }); | |
1512 | } | |
1513 | } |