From b8852e89ced0a0cdf66963aba08382ff18fd2d4b Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Wed, 5 Feb 2014 08:52:54 -0800 Subject: pull extra::{serialize, ebml} into a separate libserialize crate - `extra::json` didn't make the cut, because of `extra::json` required dep on `extra::TreeMap`. If/when `extra::TreeMap` moves out of `extra`, then `extra::json` could move into `serialize` - `libextra`, `libsyntax` and `librustc` depend on the newly created `libserialize` - The extensions to various `extra` types like `DList`, `RingBuf`, `TreeMap` and `TreeSet` for `Encodable`/`Decodable` were moved into the respective modules in `extra` - There is some trickery, evident in `src/libextra/lib.rs` where a stub of `extra::serialize` is set up (in `src/libextra/serialize.rs`) for use in the stage0 build, where the snapshot rustc is still making deriving for `Encodable` and `Decodable` point at extra. Big props to @huonw for help working out the re-export solution for this extra: inline extra::serialize stub fix stuff clobbered in rebase + don't reexport serialize::serialize no more globs in libserialize syntax: fix import of libserialize traits librustc: fix bad imports in encoder/decoder add serialize dep to librustdoc fix failing run-pass tests w/ serialize dep adjust uuid dep more rebase de-clobbering for libserialize fixing tests, pushing libextra dep into cfg(test) fix doc code in extra::json adjust index.md links to serialize and uuid library --- src/doc/index.md | 5 +- src/libextra/dlist.rs | 27 + src/libextra/ebml.rs | 1113 -------------------- src/libextra/json.rs | 22 +- src/libextra/lib.rs | 13 +- src/libextra/ringbuf.rs | 27 + src/libextra/serialize.rs | 883 ---------------- src/libextra/treemap.rs | 67 ++ src/librustc/lib.rs | 1 + src/librustc/metadata/csearch.rs | 2 +- src/librustc/metadata/decoder.rs | 6 +- src/librustc/metadata/encoder.rs | 4 +- src/librustc/middle/astencode.rs | 12 +- src/librustdoc/lib.rs | 3 +- src/libserialize/ebml.rs | 1121 +++++++++++++++++++++ src/libserialize/lib.rs | 33 + src/libserialize/serialize.rs | 760 ++++++++++++++ src/libsyntax/ast.rs | 5 +- src/libsyntax/codemap.rs | 2 +- src/libsyntax/ext/deriving/decodable.rs | 7 +- src/libsyntax/ext/deriving/encodable.rs | 6 +- src/libsyntax/ext/deriving/generic.rs | 2 +- src/libsyntax/lib.rs | 1 + src/libsyntax/parse/mod.rs | 2 +- src/libsyntax/parse/token.rs | 2 +- src/libuuid/lib.rs | 9 +- src/test/run-pass/auto-encode.rs | 2 +- src/test/run-pass/deriving-encodable-decodable.rs | 10 +- src/test/run-pass/deriving-global.rs | 2 +- src/test/run-pass/issue-4016.rs | 5 +- src/test/run-pass/issue-4036.rs | 9 +- 31 files changed, 2114 insertions(+), 2049 deletions(-) delete mode 100644 src/libextra/ebml.rs delete mode 100644 src/libextra/serialize.rs create mode 100644 src/libserialize/ebml.rs create mode 100644 src/libserialize/lib.rs create mode 100644 src/libserialize/serialize.rs (limited to 'src') diff --git a/src/doc/index.md b/src/doc/index.md index 5aa92c9fec4..54b8b484693 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -41,9 +41,10 @@ li {list-style-type: none; } * [The `flate` compression library](flate/index.html) * [The `glob` file path matching library](glob/index.html) * [The `semver` version collation library](semver/index.html) -* [The `term` terminal-handling library](term/index.html) -* [The UUID library](uuid/index.html) +* [The `serialize` value encoding/decoding library](serialize/index.html) * [The `sync` library for concurrency-enabled mechanisms and primitives](sync/index.html) +* [The `term` terminal-handling library](term/index.html) +* [The `uuid` 128-bit universally unique identifier library](uuid/index.html) # Tooling diff --git a/src/libextra/dlist.rs b/src/libextra/dlist.rs index ee80fa1c4c4..88df73845d0 100644 --- a/src/libextra/dlist.rs +++ b/src/libextra/dlist.rs @@ -30,6 +30,8 @@ use std::iter; use container::Deque; +use serialize::{Encodable, Decodable, Encoder, Decoder}; + /// A doubly-linked list. pub struct DList { priv length: uint, @@ -628,6 +630,31 @@ impl Clone for DList { } } +impl< + S: Encoder, + T: Encodable +> Encodable for DList { + fn encode(&self, s: &mut S) { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + s.emit_seq_elt(i, |s| e.encode(s)); + } + }) + } +} + +impl> Decodable for DList { + fn decode(d: &mut D) -> DList { + let mut list = DList::new(); + d.read_seq(|d, len| { + for i in range(0u, len) { + list.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))); + } + }); + list + } +} + #[cfg(test)] mod tests { use container::Deque; diff --git a/src/libextra/ebml.rs b/src/libextra/ebml.rs deleted file mode 100644 index 1900313ab6c..00000000000 --- a/src/libextra/ebml.rs +++ /dev/null @@ -1,1113 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(missing_doc)]; - -use std::str; - -macro_rules! if_ok( ($e:expr) => ( - match $e { Ok(e) => e, Err(e) => { self.last_error = Err(e); return } } -) ) - -// Simple Extensible Binary Markup Language (ebml) reader and writer on a -// cursor model. See the specification here: -// http://www.matroska.org/technical/specs/rfc/index.html - -// Common data structures -#[deriving(Clone)] -pub struct Doc<'a> { - data: &'a [u8], - start: uint, - end: uint, -} - -impl<'doc> Doc<'doc> { - pub fn get<'a>(&'a self, tag: uint) -> Doc<'a> { - reader::get_doc(*self, tag) - } - - pub fn as_str_slice<'a>(&'a self) -> &'a str { - str::from_utf8(self.data.slice(self.start, self.end)).unwrap() - } - - pub fn as_str(&self) -> ~str { - self.as_str_slice().to_owned() - } -} - -pub struct TaggedDoc<'a> { - priv tag: uint, - doc: Doc<'a>, -} - -pub enum EbmlEncoderTag { - EsUint, // 0 - EsU64, // 1 - EsU32, // 2 - EsU16, // 3 - EsU8, // 4 - EsInt, // 5 - EsI64, // 6 - EsI32, // 7 - EsI16, // 8 - EsI8, // 9 - EsBool, // 10 - EsChar, // 11 - EsStr, // 12 - EsF64, // 13 - EsF32, // 14 - EsFloat, // 15 - EsEnum, // 16 - EsEnumVid, // 17 - EsEnumBody, // 18 - EsVec, // 19 - EsVecLen, // 20 - EsVecElt, // 21 - EsMap, // 22 - EsMapLen, // 23 - EsMapKey, // 24 - EsMapVal, // 25 - - EsOpaque, - - EsLabel, // Used only when debugging -} -// -------------------------------------- - -pub mod reader { - use std::char; - use super::*; - - use serialize; - - use std::cast::transmute; - use std::int; - use std::option::{None, Option, Some}; - use std::io::extensions::u64_from_be_bytes; - - // ebml reading - - pub struct Res { - val: uint, - next: uint - } - - #[inline(never)] - fn vuint_at_slow(data: &[u8], start: uint) -> Res { - let a = data[start]; - if a & 0x80u8 != 0u8 { - return Res {val: (a & 0x7fu8) as uint, next: start + 1u}; - } - if a & 0x40u8 != 0u8 { - return Res {val: ((a & 0x3fu8) as uint) << 8u | - (data[start + 1u] as uint), - next: start + 2u}; - } - if a & 0x20u8 != 0u8 { - return Res {val: ((a & 0x1fu8) as uint) << 16u | - (data[start + 1u] as uint) << 8u | - (data[start + 2u] as uint), - next: start + 3u}; - } - if a & 0x10u8 != 0u8 { - return Res {val: ((a & 0x0fu8) as uint) << 24u | - (data[start + 1u] as uint) << 16u | - (data[start + 2u] as uint) << 8u | - (data[start + 3u] as uint), - next: start + 4u}; - } - fail!("vint too big"); - } - - pub fn vuint_at(data: &[u8], start: uint) -> Res { - use std::ptr::offset; - use std::unstable::intrinsics::from_be32; - - if data.len() - start < 4 { - return vuint_at_slow(data, start); - } - - // Lookup table for parsing EBML Element IDs as per http://ebml.sourceforge.net/specs/ - // The Element IDs are parsed by reading a big endian u32 positioned at data[start]. - // Using the four most significant bits of the u32 we lookup in the table below how the - // element ID should be derived from it. - // - // The table stores tuples (shift, mask) where shift is the number the u32 should be right - // shifted with and mask is the value the right shifted value should be masked with. - // If for example the most significant bit is set this means it's a class A ID and the u32 - // should be right shifted with 24 and masked with 0x7f. Therefore we store (24, 0x7f) at - // index 0x8 - 0xF (four bit numbers where the most significant bit is set). - // - // By storing the number of shifts and masks in a table instead of checking in order if - // the most significant bit is set, the second most significant bit is set etc. we can - // replace up to three "and+branch" with a single table lookup which gives us a measured - // speedup of around 2x on x86_64. - static SHIFT_MASK_TABLE: [(u32, u32), ..16] = [ - (0, 0x0), (0, 0x0fffffff), - (8, 0x1fffff), (8, 0x1fffff), - (16, 0x3fff), (16, 0x3fff), (16, 0x3fff), (16, 0x3fff), - (24, 0x7f), (24, 0x7f), (24, 0x7f), (24, 0x7f), - (24, 0x7f), (24, 0x7f), (24, 0x7f), (24, 0x7f) - ]; - - unsafe { - let (ptr, _): (*u8, uint) = transmute(data); - let ptr = offset(ptr, start as int); - let ptr: *i32 = transmute(ptr); - let val = from_be32(*ptr) as u32; - - let i = (val >> 28u) as uint; - let (shift, mask) = SHIFT_MASK_TABLE[i]; - Res { - val: ((val >> shift) & mask) as uint, - next: start + (((32 - shift) >> 3) as uint) - } - } - } - - pub fn Doc<'a>(data: &'a [u8]) -> Doc<'a> { - Doc { data: data, start: 0u, end: data.len() } - } - - pub fn doc_at<'a>(data: &'a [u8], start: uint) -> TaggedDoc<'a> { - let elt_tag = vuint_at(data, start); - let elt_size = vuint_at(data, elt_tag.next); - let end = elt_size.next + elt_size.val; - TaggedDoc { - tag: elt_tag.val, - doc: Doc { data: data, start: elt_size.next, end: end } - } - } - - pub fn maybe_get_doc<'a>(d: Doc<'a>, tg: uint) -> Option> { - let mut pos = d.start; - while pos < d.end { - let elt_tag = vuint_at(d.data, pos); - let elt_size = vuint_at(d.data, elt_tag.next); - pos = elt_size.next + elt_size.val; - if elt_tag.val == tg { - return Some(Doc { data: d.data, start: elt_size.next, - end: pos }); - } - } - None - } - - pub fn get_doc<'a>(d: Doc<'a>, tg: uint) -> Doc<'a> { - match maybe_get_doc(d, tg) { - Some(d) => d, - None => { - error!("failed to find block with tag {}", tg); - fail!(); - } - } - } - - pub fn docs<'a>(d: Doc<'a>, it: |uint, Doc<'a>| -> bool) -> bool { - let mut pos = d.start; - while pos < d.end { - let elt_tag = vuint_at(d.data, pos); - let elt_size = vuint_at(d.data, elt_tag.next); - pos = elt_size.next + elt_size.val; - let doc = Doc { data: d.data, start: elt_size.next, end: pos }; - if !it(elt_tag.val, doc) { - return false; - } - } - return true; - } - - pub fn tagged_docs<'a>(d: Doc<'a>, tg: uint, it: |Doc<'a>| -> bool) -> bool { - let mut pos = d.start; - while pos < d.end { - let elt_tag = vuint_at(d.data, pos); - let elt_size = vuint_at(d.data, elt_tag.next); - pos = elt_size.next + elt_size.val; - if elt_tag.val == tg { - let doc = Doc { data: d.data, start: elt_size.next, - end: pos }; - if !it(doc) { - return false; - } - } - } - return true; - } - - pub fn with_doc_data<'a, T>(d: Doc<'a>, f: |x: &'a [u8]| -> T) -> T { - f(d.data.slice(d.start, d.end)) - } - - - pub fn doc_as_u8(d: Doc) -> u8 { - assert_eq!(d.end, d.start + 1u); - d.data[d.start] - } - - pub fn doc_as_u16(d: Doc) -> u16 { - assert_eq!(d.end, d.start + 2u); - u64_from_be_bytes(d.data, d.start, 2u) as u16 - } - - pub fn doc_as_u32(d: Doc) -> u32 { - assert_eq!(d.end, d.start + 4u); - u64_from_be_bytes(d.data, d.start, 4u) as u32 - } - - pub fn doc_as_u64(d: Doc) -> u64 { - assert_eq!(d.end, d.start + 8u); - u64_from_be_bytes(d.data, d.start, 8u) - } - - pub fn doc_as_i8(d: Doc) -> i8 { doc_as_u8(d) as i8 } - pub fn doc_as_i16(d: Doc) -> i16 { doc_as_u16(d) as i16 } - pub fn doc_as_i32(d: Doc) -> i32 { doc_as_u32(d) as i32 } - pub fn doc_as_i64(d: Doc) -> i64 { doc_as_u64(d) as i64 } - - pub struct Decoder<'a> { - priv parent: Doc<'a>, - priv pos: uint, - } - - pub fn Decoder<'a>(d: Doc<'a>) -> Decoder<'a> { - Decoder { - parent: d, - pos: d.start - } - } - - impl<'doc> Decoder<'doc> { - fn _check_label(&mut self, lbl: &str) { - if self.pos < self.parent.end { - let TaggedDoc { tag: r_tag, doc: r_doc } = - doc_at(self.parent.data, self.pos); - - if r_tag == (EsLabel as uint) { - self.pos = r_doc.end; - let str = r_doc.as_str_slice(); - if lbl != str { - fail!("Expected label {} but found {}", lbl, str); - } - } - } - } - - fn next_doc(&mut self, exp_tag: EbmlEncoderTag) -> Doc<'doc> { - debug!(". next_doc(exp_tag={:?})", exp_tag); - if self.pos >= self.parent.end { - fail!("no more documents in current node!"); - } - let TaggedDoc { tag: r_tag, doc: r_doc } = - doc_at(self.parent.data, self.pos); - debug!("self.parent={}-{} self.pos={} r_tag={} r_doc={}-{}", - self.parent.start, - self.parent.end, - self.pos, - r_tag, - r_doc.start, - r_doc.end); - if r_tag != (exp_tag as uint) { - fail!("expected EBML doc with tag {:?} but found tag {:?}", - exp_tag, r_tag); - } - if r_doc.end > self.parent.end { - fail!("invalid EBML, child extends to {:#x}, parent to {:#x}", - r_doc.end, self.parent.end); - } - self.pos = r_doc.end; - r_doc - } - - fn push_doc(&mut self, exp_tag: EbmlEncoderTag, - f: |&mut Decoder<'doc>| -> T) -> T { - let d = self.next_doc(exp_tag); - let old_parent = self.parent; - let old_pos = self.pos; - self.parent = d; - self.pos = d.start; - let r = f(self); - self.parent = old_parent; - self.pos = old_pos; - r - } - - fn _next_uint(&mut self, exp_tag: EbmlEncoderTag) -> uint { - let r = doc_as_u32(self.next_doc(exp_tag)); - debug!("_next_uint exp_tag={:?} result={}", exp_tag, r); - r as uint - } - - pub fn read_opaque(&mut self, op: |&mut Decoder<'doc>, Doc| -> R) -> R { - let doc = self.next_doc(EsOpaque); - - let (old_parent, old_pos) = (self.parent, self.pos); - self.parent = doc; - self.pos = doc.start; - - let result = op(self, doc); - - self.parent = old_parent; - self.pos = old_pos; - result - } - } - - impl<'doc> serialize::Decoder for Decoder<'doc> { - fn read_nil(&mut self) -> () { () } - - fn read_u64(&mut self) -> u64 { doc_as_u64(self.next_doc(EsU64)) } - fn read_u32(&mut self) -> u32 { doc_as_u32(self.next_doc(EsU32)) } - fn read_u16(&mut self) -> u16 { doc_as_u16(self.next_doc(EsU16)) } - fn read_u8 (&mut self) -> u8 { doc_as_u8 (self.next_doc(EsU8 )) } - fn read_uint(&mut self) -> uint { - let v = doc_as_u64(self.next_doc(EsUint)); - if v > (::std::uint::MAX as u64) { - fail!("uint {} too large for this architecture", v); - } - v as uint - } - - fn read_i64(&mut self) -> i64 { - doc_as_u64(self.next_doc(EsI64)) as i64 - } - fn read_i32(&mut self) -> i32 { - doc_as_u32(self.next_doc(EsI32)) as i32 - } - fn read_i16(&mut self) -> i16 { - doc_as_u16(self.next_doc(EsI16)) as i16 - } - fn read_i8 (&mut self) -> i8 { - doc_as_u8(self.next_doc(EsI8 )) as i8 - } - fn read_int(&mut self) -> int { - let v = doc_as_u64(self.next_doc(EsInt)) as i64; - if v > (int::MAX as i64) || v < (int::MIN as i64) { - debug!("FIXME \\#6122: Removing this makes this function miscompile"); - fail!("int {} out of range for this architecture", v); - } - v as int - } - - fn read_bool(&mut self) -> bool { - doc_as_u8(self.next_doc(EsBool)) != 0 - } - - fn read_f64(&mut self) -> f64 { - let bits = doc_as_u64(self.next_doc(EsF64)); - unsafe { transmute(bits) } - } - fn read_f32(&mut self) -> f32 { - let bits = doc_as_u32(self.next_doc(EsF32)); - unsafe { transmute(bits) } - } - fn read_char(&mut self) -> char { - char::from_u32(doc_as_u32(self.next_doc(EsChar))).unwrap() - } - fn read_str(&mut self) -> ~str { - self.next_doc(EsStr).as_str() - } - - // Compound types: - fn read_enum(&mut self, name: &str, f: |&mut Decoder<'doc>| -> T) -> T { - debug!("read_enum({})", name); - self._check_label(name); - - let doc = self.next_doc(EsEnum); - - let (old_parent, old_pos) = (self.parent, self.pos); - self.parent = doc; - self.pos = self.parent.start; - - let result = f(self); - - self.parent = old_parent; - self.pos = old_pos; - result - } - - fn read_enum_variant(&mut self, - _: &[&str], - f: |&mut Decoder<'doc>, uint| -> T) - -> T { - debug!("read_enum_variant()"); - let idx = self._next_uint(EsEnumVid); - debug!(" idx={}", idx); - - let doc = self.next_doc(EsEnumBody); - - let (old_parent, old_pos) = (self.parent, self.pos); - self.parent = doc; - self.pos = self.parent.start; - - let result = f(self, idx); - - self.parent = old_parent; - self.pos = old_pos; - result - } - - fn read_enum_variant_arg(&mut self, - idx: uint, - f: |&mut Decoder<'doc>| -> T) -> T { - debug!("read_enum_variant_arg(idx={})", idx); - f(self) - } - - fn read_enum_struct_variant(&mut self, - _: &[&str], - f: |&mut Decoder<'doc>, uint| -> T) - -> T { - debug!("read_enum_struct_variant()"); - let idx = self._next_uint(EsEnumVid); - debug!(" idx={}", idx); - - let doc = self.next_doc(EsEnumBody); - - let (old_parent, old_pos) = (self.parent, self.pos); - self.parent = doc; - self.pos = self.parent.start; - - let result = f(self, idx); - - self.parent = old_parent; - self.pos = old_pos; - result - } - - fn read_enum_struct_variant_field(&mut self, - name: &str, - idx: uint, - f: |&mut Decoder<'doc>| -> T) - -> T { - debug!("read_enum_struct_variant_arg(name={}, idx={})", name, idx); - f(self) - } - - fn read_struct(&mut self, - name: &str, - _: uint, - f: |&mut Decoder<'doc>| -> T) - -> T { - debug!("read_struct(name={})", name); - f(self) - } - - fn read_struct_field(&mut self, - name: &str, - idx: uint, - f: |&mut Decoder<'doc>| -> T) - -> T { - debug!("read_struct_field(name={}, idx={})", name, idx); - self._check_label(name); - f(self) - } - - fn read_tuple(&mut self, f: |&mut Decoder<'doc>, uint| -> T) -> T { - debug!("read_tuple()"); - self.read_seq(f) - } - - fn read_tuple_arg(&mut self, idx: uint, f: |&mut Decoder<'doc>| -> T) - -> T { - debug!("read_tuple_arg(idx={})", idx); - self.read_seq_elt(idx, f) - } - - fn read_tuple_struct(&mut self, - name: &str, - f: |&mut Decoder<'doc>, uint| -> T) - -> T { - debug!("read_tuple_struct(name={})", name); - self.read_tuple(f) - } - - fn read_tuple_struct_arg(&mut self, - idx: uint, - f: |&mut Decoder<'doc>| -> T) - -> T { - debug!("read_tuple_struct_arg(idx={})", idx); - self.read_tuple_arg(idx, f) - } - - fn read_option(&mut self, f: |&mut Decoder<'doc>, bool| -> T) -> T { - debug!("read_option()"); - self.read_enum("Option", |this| { - this.read_enum_variant(["None", "Some"], |this, idx| { - match idx { - 0 => f(this, false), - 1 => f(this, true), - _ => fail!(), - } - }) - }) - } - - fn read_seq(&mut self, f: |&mut Decoder<'doc>, uint| -> T) -> T { - debug!("read_seq()"); - self.push_doc(EsVec, |d| { - let len = d._next_uint(EsVecLen); - debug!(" len={}", len); - f(d, len) - }) - } - - fn read_seq_elt(&mut self, idx: uint, f: |&mut Decoder<'doc>| -> T) - -> T { - debug!("read_seq_elt(idx={})", idx); - self.push_doc(EsVecElt, f) - } - - fn read_map(&mut self, f: |&mut Decoder<'doc>, uint| -> T) -> T { - debug!("read_map()"); - self.push_doc(EsMap, |d| { - let len = d._next_uint(EsMapLen); - debug!(" len={}", len); - f(d, len) - }) - } - - fn read_map_elt_key(&mut self, idx: uint, f: |&mut Decoder<'doc>| -> T) - -> T { - debug!("read_map_elt_key(idx={})", idx); - self.push_doc(EsMapKey, f) - } - - fn read_map_elt_val(&mut self, idx: uint, f: |&mut Decoder<'doc>| -> T) - -> T { - debug!("read_map_elt_val(idx={})", idx); - self.push_doc(EsMapVal, f) - } - } -} - -pub mod writer { - use super::*; - - use std::cast; - use std::clone::Clone; - use std::io; - use std::io::{Writer, Seek}; - use std::io::MemWriter; - use std::io::extensions::u64_to_be_bytes; - - // ebml writing - pub struct Encoder<'a> { - // FIXME(#5665): this should take a trait object. Note that if you - // delete this comment you should consider removing the - // unwrap()'s below of the results of the calls to - // write(). We're guaranteed that writing into a MemWriter - // won't fail, but this is not true for all I/O streams in - // general. - writer: &'a mut MemWriter, - priv size_positions: ~[uint], - last_error: io::IoResult<()>, - } - - fn write_sized_vuint(w: &mut MemWriter, n: uint, size: uint) { - match size { - 1u => w.write(&[0x80u8 | (n as u8)]), - 2u => w.write(&[0x40u8 | ((n >> 8_u) as u8), n as u8]), - 3u => w.write(&[0x20u8 | ((n >> 16_u) as u8), (n >> 8_u) as u8, - n as u8]), - 4u => w.write(&[0x10u8 | ((n >> 24_u) as u8), (n >> 16_u) as u8, - (n >> 8_u) as u8, n as u8]), - _ => fail!("vint to write too big: {}", n) - }.unwrap() - } - - fn write_vuint(w: &mut MemWriter, n: uint) { - if n < 0x7f_u { write_sized_vuint(w, n, 1u); return; } - if n < 0x4000_u { write_sized_vuint(w, n, 2u); return; } - if n < 0x200000_u { write_sized_vuint(w, n, 3u); return; } - if n < 0x10000000_u { write_sized_vuint(w, n, 4u); return; } - fail!("vint to write too big: {}", n); - } - - pub fn Encoder<'a>(w: &'a mut MemWriter) -> Encoder<'a> { - let size_positions: ~[uint] = ~[]; - Encoder { - writer: w, - size_positions: size_positions, - last_error: Ok(()), - } - } - - // FIXME (#2741): Provide a function to write the standard ebml header. - impl<'a> Encoder<'a> { - /// FIXME(pcwalton): Workaround for badness in trans. DO NOT USE ME. - pub unsafe fn unsafe_clone(&self) -> Encoder<'a> { - Encoder { - writer: cast::transmute_copy(&self.writer), - size_positions: self.size_positions.clone(), - last_error: Ok(()), - } - } - - pub fn start_tag(&mut self, tag_id: uint) { - debug!("Start tag {}", tag_id); - - // Write the enum ID: - write_vuint(self.writer, tag_id); - - // Write a placeholder four-byte size. - self.size_positions.push(if_ok!(self.writer.tell()) as uint); - let zeroes: &[u8] = &[0u8, 0u8, 0u8, 0u8]; - if_ok!(self.writer.write(zeroes)); - } - - pub fn end_tag(&mut self) { - let last_size_pos = self.size_positions.pop().unwrap(); - let cur_pos = if_ok!(self.writer.tell()); - if_ok!(self.writer.seek(last_size_pos as i64, io::SeekSet)); - let size = (cur_pos as uint - last_size_pos - 4); - write_sized_vuint(self.writer, size, 4u); - if_ok!(self.writer.seek(cur_pos as i64, io::SeekSet)); - - debug!("End tag (size = {})", size); - } - - pub fn wr_tag(&mut self, tag_id: uint, blk: ||) { - self.start_tag(tag_id); - blk(); - self.end_tag(); - } - - pub fn wr_tagged_bytes(&mut self, tag_id: uint, b: &[u8]) { - write_vuint(self.writer, tag_id); - write_vuint(self.writer, b.len()); - self.writer.write(b).unwrap(); - } - - pub fn wr_tagged_u64(&mut self, tag_id: uint, v: u64) { - u64_to_be_bytes(v, 8u, |v| { - self.wr_tagged_bytes(tag_id, v); - }) - } - - pub fn wr_tagged_u32(&mut self, tag_id: uint, v: u32) { - u64_to_be_bytes(v as u64, 4u, |v| { - self.wr_tagged_bytes(tag_id, v); - }) - } - - pub fn wr_tagged_u16(&mut self, tag_id: uint, v: u16) { - u64_to_be_bytes(v as u64, 2u, |v| { - self.wr_tagged_bytes(tag_id, v); - }) - } - - pub fn wr_tagged_u8(&mut self, tag_id: uint, v: u8) { - self.wr_tagged_bytes(tag_id, &[v]); - } - - pub fn wr_tagged_i64(&mut self, tag_id: uint, v: i64) { - u64_to_be_bytes(v as u64, 8u, |v| { - self.wr_tagged_bytes(tag_id, v); - }) - } - - pub fn wr_tagged_i32(&mut self, tag_id: uint, v: i32) { - u64_to_be_bytes(v as u64, 4u, |v| { - self.wr_tagged_bytes(tag_id, v); - }) - } - - pub fn wr_tagged_i16(&mut self, tag_id: uint, v: i16) { - u64_to_be_bytes(v as u64, 2u, |v| { - self.wr_tagged_bytes(tag_id, v); - }) - } - - pub fn wr_tagged_i8(&mut self, tag_id: uint, v: i8) { - self.wr_tagged_bytes(tag_id, &[v as u8]); - } - - pub fn wr_tagged_str(&mut self, tag_id: uint, v: &str) { - self.wr_tagged_bytes(tag_id, v.as_bytes()); - } - - pub fn wr_bytes(&mut self, b: &[u8]) { - debug!("Write {} bytes", b.len()); - self.writer.write(b).unwrap(); - } - - pub fn wr_str(&mut self, s: &str) { - debug!("Write str: {}", s); - self.writer.write(s.as_bytes()).unwrap(); - } - } - - // FIXME (#2743): optionally perform "relaxations" on end_tag to more - // efficiently encode sizes; this is a fixed point iteration - - // Set to true to generate more debugging in EBML code. - // Totally lame approach. - static DEBUG: bool = true; - - impl<'a> Encoder<'a> { - // used internally to emit things like the vector length and so on - fn _emit_tagged_uint(&mut self, t: EbmlEncoderTag, v: uint) { - assert!(v <= 0xFFFF_FFFF_u); - self.wr_tagged_u32(t as uint, v as u32); - } - - fn _emit_label(&mut self, label: &str) { - // There are various strings that we have access to, such as - // the name of a record field, which do not actually appear in - // the encoded EBML (normally). This is just for - // efficiency. When debugging, though, we can emit such - // labels and then they will be checked by decoder to - // try and check failures more quickly. - if DEBUG { self.wr_tagged_str(EsLabel as uint, label) } - } - - pub fn emit_opaque(&mut self, f: |&mut Encoder|) { - self.start_tag(EsOpaque as uint); - f(self); - self.end_tag(); - } - } - - impl<'a> ::serialize::Encoder for Encoder<'a> { - fn emit_nil(&mut self) {} - - fn emit_uint(&mut self, v: uint) { - self.wr_tagged_u64(EsUint as uint, v as u64); - } - fn emit_u64(&mut self, v: u64) { - self.wr_tagged_u64(EsU64 as uint, v); - } - fn emit_u32(&mut self, v: u32) { - self.wr_tagged_u32(EsU32 as uint, v); - } - fn emit_u16(&mut self, v: u16) { - self.wr_tagged_u16(EsU16 as uint, v); - } - fn emit_u8(&mut self, v: u8) { - self.wr_tagged_u8(EsU8 as uint, v); - } - - fn emit_int(&mut self, v: int) { - self.wr_tagged_i64(EsInt as uint, v as i64); - } - fn emit_i64(&mut self, v: i64) { - self.wr_tagged_i64(EsI64 as uint, v); - } - fn emit_i32(&mut self, v: i32) { - self.wr_tagged_i32(EsI32 as uint, v); - } - fn emit_i16(&mut self, v: i16) { - self.wr_tagged_i16(EsI16 as uint, v); - } - fn emit_i8(&mut self, v: i8) { - self.wr_tagged_i8(EsI8 as uint, v); - } - - fn emit_bool(&mut self, v: bool) { - self.wr_tagged_u8(EsBool as uint, v as u8) - } - - fn emit_f64(&mut self, v: f64) { - let bits = unsafe { cast::transmute(v) }; - self.wr_tagged_u64(EsF64 as uint, bits); - } - fn emit_f32(&mut self, v: f32) { - let bits = unsafe { cast::transmute(v) }; - self.wr_tagged_u32(EsF32 as uint, bits); - } - fn emit_char(&mut self, v: char) { - self.wr_tagged_u32(EsChar as uint, v as u32); - } - - fn emit_str(&mut self, v: &str) { - self.wr_tagged_str(EsStr as uint, v) - } - - fn emit_enum(&mut self, name: &str, f: |&mut Encoder<'a>|) { - self._emit_label(name); - self.start_tag(EsEnum as uint); - f(self); - self.end_tag(); - } - - fn emit_enum_variant(&mut self, - _: &str, - v_id: uint, - _: uint, - f: |&mut Encoder<'a>|) { - self._emit_tagged_uint(EsEnumVid, v_id); - self.start_tag(EsEnumBody as uint); - f(self); - self.end_tag(); - } - - fn emit_enum_variant_arg(&mut self, _: uint, f: |&mut Encoder<'a>|) { - f(self) - } - - fn emit_enum_struct_variant(&mut self, - v_name: &str, - v_id: uint, - cnt: uint, - f: |&mut Encoder<'a>|) { - self.emit_enum_variant(v_name, v_id, cnt, f) - } - - fn emit_enum_struct_variant_field(&mut self, - _: &str, - idx: uint, - f: |&mut Encoder<'a>|) { - self.emit_enum_variant_arg(idx, f) - } - - fn emit_struct(&mut self, - _: &str, - _len: uint, - f: |&mut Encoder<'a>|) { - f(self) - } - - fn emit_struct_field(&mut self, - name: &str, - _: uint, - f: |&mut Encoder<'a>|) { - self._emit_label(name); - f(self) - } - - fn emit_tuple(&mut self, len: uint, f: |&mut Encoder<'a>|) { - self.emit_seq(len, f) - } - fn emit_tuple_arg(&mut self, idx: uint, f: |&mut Encoder<'a>|) { - self.emit_seq_elt(idx, f) - } - - fn emit_tuple_struct(&mut self, - _: &str, - len: uint, - f: |&mut Encoder<'a>|) { - self.emit_seq(len, f) - } - fn emit_tuple_struct_arg(&mut self, - idx: uint, - f: |&mut Encoder<'a>|) { - self.emit_seq_elt(idx, f) - } - - fn emit_option(&mut self, f: |&mut Encoder<'a>|) { - self.emit_enum("Option", f); - } - fn emit_option_none(&mut self) { - self.emit_enum_variant("None", 0, 0, |_| ()) - } - fn emit_option_some(&mut self, f: |&mut Encoder<'a>|) { - self.emit_enum_variant("Some", 1, 1, f) - } - - fn emit_seq(&mut self, len: uint, f: |&mut Encoder<'a>|) { - self.start_tag(EsVec as uint); - self._emit_tagged_uint(EsVecLen, len); - f(self); - self.end_tag(); - } - - fn emit_seq_elt(&mut self, _idx: uint, f: |&mut Encoder<'a>|) { - self.start_tag(EsVecElt as uint); - f(self); - self.end_tag(); - } - - fn emit_map(&mut self, len: uint, f: |&mut Encoder<'a>|) { - self.start_tag(EsMap as uint); - self._emit_tagged_uint(EsMapLen, len); - f(self); - self.end_tag(); - } - - fn emit_map_elt_key(&mut self, _idx: uint, f: |&mut Encoder<'a>|) { - self.start_tag(EsMapKey as uint); - f(self); - self.end_tag(); - } - - fn emit_map_elt_val(&mut self, _idx: uint, f: |&mut Encoder<'a>|) { - self.start_tag(EsMapVal as uint); - f(self); - self.end_tag(); - } - } -} - -// ___________________________________________________________________________ -// Testing - -#[cfg(test)] -mod tests { - use ebml::reader; - use ebml::writer; - use serialize::Encodable; - use serialize; - - use std::io::MemWriter; - use std::option::{None, Option, Some}; - - #[test] - fn test_vuint_at() { - let data = [ - 0x80, - 0xff, - 0x40, 0x00, - 0x7f, 0xff, - 0x20, 0x00, 0x00, - 0x3f, 0xff, 0xff, - 0x10, 0x00, 0x00, 0x00, - 0x1f, 0xff, 0xff, 0xff - ]; - - let mut res: reader::Res; - - // Class A - res = reader::vuint_at(data, 0); - assert_eq!(res.val, 0); - assert_eq!(res.next, 1); - res = reader::vuint_at(data, res.next); - assert_eq!(res.val, (1 << 7) - 1); - assert_eq!(res.next, 2); - - // Class B - res = reader::vuint_at(data, res.next); - assert_eq!(res.val, 0); - assert_eq!(res.next, 4); - res = reader::vuint_at(data, res.next); - assert_eq!(res.val, (1 << 14) - 1); - assert_eq!(res.next, 6); - - // Class C - res = reader::vuint_at(data, res.next); - assert_eq!(res.val, 0); - assert_eq!(res.next, 9); - res = reader::vuint_at(data, res.next); - assert_eq!(res.val, (1 << 21) - 1); - assert_eq!(res.next, 12); - - // Class D - res = reader::vuint_at(data, res.next); - assert_eq!(res.val, 0); - assert_eq!(res.next, 16); - res = reader::vuint_at(data, res.next); - assert_eq!(res.val, (1 << 28) - 1); - assert_eq!(res.next, 20); - } - - #[test] - fn test_option_int() { - fn test_v(v: Option) { - debug!("v == {:?}", v); - let mut wr = MemWriter::new(); - { - let mut ebml_w = writer::Encoder(&mut wr); - v.encode(&mut ebml_w); - } - let ebml_doc = reader::Doc(wr.get_ref()); - let mut deser = reader::Decoder(ebml_doc); - let v1 = serialize::Decodable::decode(&mut deser); - debug!("v1 == {:?}", v1); - assert_eq!(v, v1); - } - - test_v(Some(22)); - test_v(None); - test_v(Some(3)); - } -} - -#[cfg(test)] -mod bench { - use ebml::reader; - use test::BenchHarness; - - #[bench] - pub fn vuint_at_A_aligned(bh: &mut BenchHarness) { - use std::vec; - let data = vec::from_fn(4*100, |i| { - match i % 2 { - 0 => 0x80u8, - _ => i as u8, - } - }); - let mut sum = 0u; - bh.iter(|| { - let mut i = 0; - while i < data.len() { - sum += reader::vuint_at(data, i).val; - i += 4; - } - }); - } - - #[bench] - pub fn vuint_at_A_unaligned(bh: &mut BenchHarness) { - use std::vec; - let data = vec::from_fn(4*100+1, |i| { - match i % 2 { - 1 => 0x80u8, - _ => i as u8 - } - }); - let mut sum = 0u; - bh.iter(|| { - let mut i = 1; - while i < data.len() { - sum += reader::vuint_at(data, i).val; - i += 4; - } - }); - } - - #[bench] - pub fn vuint_at_D_aligned(bh: &mut BenchHarness) { - use std::vec; - let data = vec::from_fn(4*100, |i| { - match i % 4 { - 0 => 0x10u8, - 3 => i as u8, - _ => 0u8 - } - }); - let mut sum = 0u; - bh.iter(|| { - let mut i = 0; - while i < data.len() { - sum += reader::vuint_at(data, i).val; - i += 4; - } - }); - } - - #[bench] - pub fn vuint_at_D_unaligned(bh: &mut BenchHarness) { - use std::vec; - let data = vec::from_fn(4*100+1, |i| { - match i % 4 { - 1 => 0x10u8, - 0 => i as u8, - _ => 0u8 - } - }); - let mut sum = 0u; - bh.iter(|| { - let mut i = 1; - while i < data.len() { - sum += reader::vuint_at(data, i).val; - i += 4; - } - }); - } -} diff --git a/src/libextra/json.rs b/src/libextra/json.rs index ef8e0999521..8b082bf3056 100644 --- a/src/libextra/json.rs +++ b/src/libextra/json.rs @@ -51,17 +51,18 @@ A simple JSON document encoding a person, his/her age, address and phone numbers Rust provides a mechanism for low boilerplate encoding & decoding of values to and from JSON via the serialization API. -To be able to encode a piece of data, it must implement the `extra::serialize::Encodable` trait. -To be able to decode a piece of data, it must implement the `extra::serialize::Decodable` trait. +To be able to encode a piece of data, it must implement the `serialize::Encodable` trait. +To be able to decode a piece of data, it must implement the `serialize::Decodable` trait. The Rust compiler provides an annotation to automatically generate the code for these traits: `#[deriving(Decodable, Encodable)]` To encode using Encodable : ```rust +extern mod serialize; use extra::json; use std::io; -use extra::serialize::Encodable; +use serialize::Encodable; #[deriving(Encodable)] pub struct TestStruct { @@ -125,7 +126,8 @@ fn main() { To decode a json string using `Decodable` trait : ```rust -use extra::serialize::Decodable; +extern mod serialize; +use serialize::Decodable; #[deriving(Decodable)] pub struct MyStruct { @@ -150,8 +152,9 @@ Create a struct called TestStruct1 and serialize and deserialize it to and from using the serialization API, using the derived serialization code. ```rust +extern mod serialize; use extra::json; -use extra::serialize::{Encodable, Decodable}; +use serialize::{Encodable, Decodable}; #[deriving(Decodable, Encodable)] //generate Decodable, Encodable impl. pub struct TestStruct1 { @@ -181,9 +184,10 @@ This example use the ToJson impl to unserialize the json string. Example of `ToJson` trait implementation for TestStruct1. ```rust +extern mod serialize; use extra::json; use extra::json::ToJson; -use extra::serialize::{Encodable, Decodable}; +use serialize::{Encodable, Decodable}; use extra::treemap::TreeMap; #[deriving(Decodable, Encodable)] // generate Decodable, Encodable impl. @@ -312,7 +316,7 @@ impl<'a> Encoder<'a> { } /// Encode the specified struct into a json [u8] - pub fn buffer_encode>>(to_encode_object: &T) -> ~[u8] { + pub fn buffer_encode>>(to_encode_object: &T) -> ~[u8] { //Serialize the object in a string using a writer let mut m = MemWriter::new(); { @@ -323,7 +327,7 @@ impl<'a> Encoder<'a> { } /// Encode the specified struct into a json str - pub fn str_encode>>(to_encode_object: &T) -> ~str { + pub fn str_encode>>(to_encode_object: &T) -> ~str { let buff:~[u8] = Encoder::buffer_encode(to_encode_object); str::from_utf8_owned(buff).unwrap() } @@ -684,7 +688,7 @@ impl serialize::Encodable for Json { } } -impl Json{ +impl Json { /// Encodes a json value into a io::writer. Uses a single line. pub fn to_writer(&self, wr: &mut io::Writer) -> io::IoResult<()> { let mut encoder = Encoder::new(wr); diff --git a/src/libextra/lib.rs b/src/libextra/lib.rs index 401ece64a5d..37b4d3cc524 100644 --- a/src/libextra/lib.rs +++ b/src/libextra/lib.rs @@ -35,6 +35,17 @@ Rust extras are part of the standard Rust distribution. #[deny(missing_doc)]; extern mod sync; +#[cfg(not(stage0))] +extern mod serialize; + +#[cfg(stage0)] +pub mod serialize { + #[allow(missing_doc)]; + // Temp re-export until after a snapshot + extern mod serialize = "serialize"; + pub use self::serialize::{Encoder, Decoder, Encodable, Decodable, + EncoderHelpers, DecoderHelpers}; +} #[cfg(stage0)] macro_rules! if_ok ( @@ -62,7 +73,6 @@ pub mod lru_cache; // And ... other stuff pub mod url; -pub mod ebml; pub mod getopts; pub mod json; pub mod tempfile; @@ -85,7 +95,6 @@ mod unicode; // Compiler support modules pub mod test; -pub mod serialize; // A curious inner-module that's not exported that contains the binding // 'extra' so that macro-expanded references to extra::serialize and such diff --git a/src/libextra/ringbuf.rs b/src/libextra/ringbuf.rs index 4da35942935..17631f5bdff 100644 --- a/src/libextra/ringbuf.rs +++ b/src/libextra/ringbuf.rs @@ -19,6 +19,8 @@ use std::iter::{Rev, RandomAccessIterator}; use container::Deque; +use serialize::{Encodable, Decodable, Encoder, Decoder}; + static INITIAL_CAPACITY: uint = 8u; // 2^3 static MINIMUM_CAPACITY: uint = 2u; @@ -402,6 +404,31 @@ impl Extendable for RingBuf { } } +impl< + S: Encoder, + T: Encodable +> Encodable for RingBuf { + fn encode(&self, s: &mut S) { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + s.emit_seq_elt(i, |s| e.encode(s)); + } + }) + } +} + +impl> Decodable for RingBuf { + fn decode(d: &mut D) -> RingBuf { + let mut deque = RingBuf::new(); + d.read_seq(|d, len| { + for i in range(0u, len) { + deque.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))); + } + }); + deque + } +} + #[cfg(test)] mod tests { use container::Deque; diff --git a/src/libextra/serialize.rs b/src/libextra/serialize.rs deleted file mode 100644 index 9b1b1e0548e..00000000000 --- a/src/libextra/serialize.rs +++ /dev/null @@ -1,883 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Support code for encoding and decoding types. - -/* -Core encoding and decoding interfaces. -*/ - -#[allow(missing_doc)]; -#[forbid(non_camel_case_types)]; - - -use std::hashmap::{HashMap, HashSet}; -use std::rc::Rc; -use std::trie::{TrieMap, TrieSet}; -use std::vec; -use ringbuf::RingBuf; -use container::Deque; -use dlist::DList; -use treemap::{TreeMap, TreeSet}; - -pub trait Encoder { - // Primitive types: - fn emit_nil(&mut self); - fn emit_uint(&mut self, v: uint); - 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_int(&mut self, v: int); - 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_f64(&mut self, v: f64); - fn emit_f32(&mut self, v: f32); - fn emit_char(&mut self, v: char); - fn emit_str(&mut self, v: &str); - - // Compound types: - fn emit_enum(&mut self, name: &str, f: |&mut Self|); - - fn emit_enum_variant(&mut self, - v_name: &str, - v_id: uint, - len: uint, - f: |&mut Self|); - fn emit_enum_variant_arg(&mut self, a_idx: uint, f: |&mut Self|); - - fn emit_enum_struct_variant(&mut self, - v_name: &str, - v_id: uint, - len: uint, - f: |&mut Self|); - fn emit_enum_struct_variant_field(&mut self, - f_name: &str, - f_idx: uint, - f: |&mut Self|); - - fn emit_struct(&mut self, name: &str, len: uint, f: |&mut Self|); - fn emit_struct_field(&mut self, - f_name: &str, - f_idx: uint, - f: |&mut Self|); - - fn emit_tuple(&mut self, len: uint, f: |&mut Self|); - fn emit_tuple_arg(&mut self, idx: uint, f: |&mut Self|); - - fn emit_tuple_struct(&mut self, name: &str, len: uint, f: |&mut Self|); - fn emit_tuple_struct_arg(&mut self, f_idx: uint, f: |&mut Self|); - - // Specialized types: - fn emit_option(&mut self, f: |&mut Self|); - fn emit_option_none(&mut self); - fn emit_option_some(&mut self, f: |&mut Self|); - - fn emit_seq(&mut self, len: uint, f: |this: &mut Self|); - fn emit_seq_elt(&mut self, idx: uint, f: |this: &mut Self|); - - fn emit_map(&mut self, len: uint, f: |&mut Self|); - fn emit_map_elt_key(&mut self, idx: uint, f: |&mut Self|); - fn emit_map_elt_val(&mut self, idx: uint, f: |&mut Self|); -} - -pub trait Decoder { - // Primitive types: - fn read_nil(&mut self) -> (); - fn read_uint(&mut self) -> uint; - 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_int(&mut self) -> int; - 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_f64(&mut self) -> f64; - fn read_f32(&mut self) -> f32; - fn read_char(&mut self) -> char; - fn read_str(&mut self) -> ~str; - - // Compound types: - fn read_enum(&mut self, name: &str, f: |&mut Self| -> T) -> T; - - fn read_enum_variant(&mut self, - names: &[&str], - f: |&mut Self, uint| -> T) - -> T; - fn read_enum_variant_arg(&mut self, - a_idx: uint, - f: |&mut Self| -> T) - -> T; - - fn read_enum_struct_variant(&mut self, - names: &[&str], - f: |&mut Self, uint| -> T) - -> T; - fn read_enum_struct_variant_field(&mut self, - &f_name: &str, - f_idx: uint, - f: |&mut Self| -> T) - -> T; - - fn read_struct(&mut self, s_name: &str, len: uint, f: |&mut Self| -> T) - -> T; - fn read_struct_field(&mut self, - f_name: &str, - f_idx: uint, - f: |&mut Self| -> T) - -> T; - - fn read_tuple(&mut self, f: |&mut Self, uint| -> T) -> T; - fn read_tuple_arg(&mut self, a_idx: uint, f: |&mut Self| -> T) -> T; - - fn read_tuple_struct(&mut self, - s_name: &str, - f: |&mut Self, uint| -> T) - -> T; - fn read_tuple_struct_arg(&mut self, - a_idx: uint, - f: |&mut Self| -> T) - -> T; - - // Specialized types: - fn read_option(&mut self, f: |&mut Self, bool| -> T) -> T; - - fn read_seq(&mut self, f: |&mut Self, uint| -> T) -> T; - fn read_seq_elt(&mut self, idx: uint, f: |&mut Self| -> T) -> T; - - fn read_map(&mut self, f: |&mut Self, uint| -> T) -> T; - fn read_map_elt_key(&mut self, idx: uint, f: |&mut Self| -> T) -> T; - fn read_map_elt_val(&mut self, idx: uint, f: |&mut Self| -> T) -> T; -} - -pub trait Encodable { - fn encode(&self, s: &mut S); -} - -pub trait Decodable { - fn decode(d: &mut D) -> Self; -} - -impl Encodable for uint { - fn encode(&self, s: &mut S) { - s.emit_uint(*self) - } -} - -impl Decodable for uint { - fn decode(d: &mut D) -> uint { - d.read_uint() - } -} - -impl Encodable for u8 { - fn encode(&self, s: &mut S) { - s.emit_u8(*self) - } -} - -impl Decodable for u8 { - fn decode(d: &mut D) -> u8 { - d.read_u8() - } -} - -impl Encodable for u16 { - fn encode(&self, s: &mut S) { - s.emit_u16(*self) - } -} - -impl Decodable for u16 { - fn decode(d: &mut D) -> u16 { - d.read_u16() - } -} - -impl Encodable for u32 { - fn encode(&self, s: &mut S) { - s.emit_u32(*self) - } -} - -impl Decodable for u32 { - fn decode(d: &mut D) -> u32 { - d.read_u32() - } -} - -impl Encodable for u64 { - fn encode(&self, s: &mut S) { - s.emit_u64(*self) - } -} - -impl Decodable for u64 { - fn decode(d: &mut D) -> u64 { - d.read_u64() - } -} - -impl Encodable for int { - fn encode(&self, s: &mut S) { - s.emit_int(*self) - } -} - -impl Decodable for int { - fn decode(d: &mut D) -> int { - d.read_int() - } -} - -impl Encodable for i8 { - fn encode(&self, s: &mut S) { - s.emit_i8(*self) - } -} - -impl Decodable for i8 { - fn decode(d: &mut D) -> i8 { - d.read_i8() - } -} - -impl Encodable for i16 { - fn encode(&self, s: &mut S) { - s.emit_i16(*self) - } -} - -impl Decodable for i16 { - fn decode(d: &mut D) -> i16 { - d.read_i16() - } -} - -impl Encodable for i32 { - fn encode(&self, s: &mut S) { - s.emit_i32(*self) - } -} - -impl Decodable for i32 { - fn decode(d: &mut D) -> i32 { - d.read_i32() - } -} - -impl Encodable for i64 { - fn encode(&self, s: &mut S) { - s.emit_i64(*self) - } -} - -impl Decodable for i64 { - fn decode(d: &mut D) -> i64 { - d.read_i64() - } -} - -impl<'a, S:Encoder> Encodable for &'a str { - fn encode(&self, s: &mut S) { - s.emit_str(*self) - } -} - -impl Encodable for ~str { - fn encode(&self, s: &mut S) { - s.emit_str(*self) - } -} - -impl Decodable for ~str { - fn decode(d: &mut D) -> ~str { - d.read_str() - } -} - -impl Encodable for f32 { - fn encode(&self, s: &mut S) { - s.emit_f32(*self) - } -} - -impl Decodable for f32 { - fn decode(d: &mut D) -> f32 { - d.read_f32() - } -} - -impl Encodable for f64 { - fn encode(&self, s: &mut S) { - s.emit_f64(*self) - } -} - -impl Decodable for f64 { - fn decode(d: &mut D) -> f64 { - d.read_f64() - } -} - -impl Encodable for bool { - fn encode(&self, s: &mut S) { - s.emit_bool(*self) - } -} - -impl Decodable for bool { - fn decode(d: &mut D) -> bool { - d.read_bool() - } -} - -impl Encodable for char { - fn encode(&self, s: &mut S) { - s.emit_char(*self) - } -} - -impl Decodable for char { - fn decode(d: &mut D) -> char { - d.read_char() - } -} - -impl Encodable for () { - fn encode(&self, s: &mut S) { - s.emit_nil() - } -} - -impl Decodable for () { - fn decode(d: &mut D) -> () { - d.read_nil() - } -} - -impl<'a, S:Encoder,T:Encodable> Encodable for &'a T { - fn encode(&self, s: &mut S) { - (**self).encode(s) - } -} - -impl> Encodable for ~T { - fn encode(&self, s: &mut S) { - (**self).encode(s) - } -} - -impl> Decodable for ~T { - fn decode(d: &mut D) -> ~T { - ~Decodable::decode(d) - } -} - -impl> Encodable for @T { - fn encode(&self, s: &mut S) { - (**self).encode(s) - } -} - -impl> Encodable for Rc { - #[inline] - fn encode(&self, s: &mut S) { - self.borrow().encode(s) - } -} - -impl> Decodable for Rc { - #[inline] - fn decode(d: &mut D) -> Rc { - Rc::new(Decodable::decode(d)) - } -} - -impl + 'static> Decodable for @T { - fn decode(d: &mut D) -> @T { - @Decodable::decode(d) - } -} - -impl<'a, S:Encoder,T:Encodable> Encodable for &'a [T] { - fn encode(&self, s: &mut S) { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s)) - } - }) - } -} - -impl> Encodable for ~[T] { - fn encode(&self, s: &mut S) { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s)) - } - }) - } -} - -impl> Decodable for ~[T] { - fn decode(d: &mut D) -> ~[T] { - d.read_seq(|d, len| { - vec::from_fn(len, |i| { - d.read_seq_elt(i, |d| Decodable::decode(d)) - }) - }) - } -} - -impl> Encodable for Option { - fn encode(&self, s: &mut S) { - s.emit_option(|s| { - match *self { - None => s.emit_option_none(), - Some(ref v) => s.emit_option_some(|s| v.encode(s)), - } - }) - } -} - -impl> Decodable for Option { - fn decode(d: &mut D) -> Option { - d.read_option(|d, b| { - if b { - Some(Decodable::decode(d)) - } else { - None - } - }) - } -} - -impl,T1:Encodable> Encodable for (T0, T1) { - fn encode(&self, s: &mut S) { - match *self { - (ref t0, ref t1) => { - s.emit_seq(2, |s| { - s.emit_seq_elt(0, |s| t0.encode(s)); - s.emit_seq_elt(1, |s| t1.encode(s)); - }) - } - } - } -} - -impl,T1:Decodable> Decodable for (T0, T1) { - fn decode(d: &mut D) -> (T0, T1) { - d.read_seq(|d, len| { - assert_eq!(len, 2); - ( - d.read_seq_elt(0, |d| Decodable::decode(d)), - d.read_seq_elt(1, |d| Decodable::decode(d)) - ) - }) - } -} - -impl< - S: Encoder, - T0: Encodable, - T1: Encodable, - T2: Encodable -> Encodable for (T0, T1, T2) { - fn encode(&self, s: &mut S) { - match *self { - (ref t0, ref t1, ref t2) => { - s.emit_seq(3, |s| { - s.emit_seq_elt(0, |s| t0.encode(s)); - s.emit_seq_elt(1, |s| t1.encode(s)); - s.emit_seq_elt(2, |s| t2.encode(s)); - }) - } - } - } -} - -impl< - D: Decoder, - T0: Decodable, - T1: Decodable, - T2: Decodable -> Decodable for (T0, T1, T2) { - fn decode(d: &mut D) -> (T0, T1, T2) { - d.read_seq(|d, len| { - assert_eq!(len, 3); - ( - d.read_seq_elt(0, |d| Decodable::decode(d)), - d.read_seq_elt(1, |d| Decodable::decode(d)), - d.read_seq_elt(2, |d| Decodable::decode(d)) - ) - }) - } -} - -impl< - S: Encoder, - T0: Encodable, - T1: Encodable, - T2: Encodable, - T3: Encodable -> Encodable for (T0, T1, T2, T3) { - fn encode(&self, s: &mut S) { - match *self { - (ref t0, ref t1, ref t2, ref t3) => { - s.emit_seq(4, |s| { - s.emit_seq_elt(0, |s| t0.encode(s)); - s.emit_seq_elt(1, |s| t1.encode(s)); - s.emit_seq_elt(2, |s| t2.encode(s)); - s.emit_seq_elt(3, |s| t3.encode(s)); - }) - } - } - } -} - -impl< - D: Decoder, - T0: Decodable, - T1: Decodable, - T2: Decodable, - T3: Decodable -> Decodable for (T0, T1, T2, T3) { - fn decode(d: &mut D) -> (T0, T1, T2, T3) { - d.read_seq(|d, len| { - assert_eq!(len, 4); - ( - d.read_seq_elt(0, |d| Decodable::decode(d)), - d.read_seq_elt(1, |d| Decodable::decode(d)), - d.read_seq_elt(2, |d| Decodable::decode(d)), - d.read_seq_elt(3, |d| Decodable::decode(d)) - ) - }) - } -} - -impl< - S: Encoder, - T0: Encodable, - T1: Encodable, - T2: Encodable, - T3: Encodable, - T4: Encodable -> Encodable for (T0, T1, T2, T3, T4) { - fn encode(&self, s: &mut S) { - match *self { - (ref t0, ref t1, ref t2, ref t3, ref t4) => { - s.emit_seq(5, |s| { - s.emit_seq_elt(0, |s| t0.encode(s)); - s.emit_seq_elt(1, |s| t1.encode(s)); - s.emit_seq_elt(2, |s| t2.encode(s)); - s.emit_seq_elt(3, |s| t3.encode(s)); - s.emit_seq_elt(4, |s| t4.encode(s)); - }) - } - } - } -} - -impl< - D: Decoder, - T0: Decodable, - T1: Decodable, - T2: Decodable, - T3: Decodable, - T4: Decodable -> Decodable for (T0, T1, T2, T3, T4) { - fn decode(d: &mut D) -> (T0, T1, T2, T3, T4) { - d.read_seq(|d, len| { - assert_eq!(len, 5); - ( - d.read_seq_elt(0, |d| Decodable::decode(d)), - d.read_seq_elt(1, |d| Decodable::decode(d)), - d.read_seq_elt(2, |d| Decodable::decode(d)), - d.read_seq_elt(3, |d| Decodable::decode(d)), - d.read_seq_elt(4, |d| Decodable::decode(d)) - ) - }) - } -} - -impl< - S: Encoder, - T: Encodable -> Encodable for DList { - fn encode(&self, s: &mut S) { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s)); - } - }) - } -} - -impl> Decodable for DList { - fn decode(d: &mut D) -> DList { - let mut list = DList::new(); - d.read_seq(|d, len| { - for i in range(0u, len) { - list.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))); - } - }); - list - } -} - -impl< - S: Encoder, - T: Encodable -> Encodable for RingBuf { - fn encode(&self, s: &mut S) { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s)); - } - }) - } -} - -impl> Decodable for RingBuf { - fn decode(d: &mut D) -> RingBuf { - let mut deque = RingBuf::new(); - d.read_seq(|d, len| { - for i in range(0u, len) { - deque.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))); - } - }); - deque - } -} - -impl< - E: Encoder, - K: Encodable + Hash + IterBytes + Eq, - V: Encodable -> Encodable for HashMap { - fn encode(&self, e: &mut E) { - e.emit_map(self.len(), |e| { - let mut i = 0; - for (key, val) in self.iter() { - e.emit_map_elt_key(i, |e| key.encode(e)); - e.emit_map_elt_val(i, |e| val.encode(e)); - i += 1; - } - }) - } -} - -impl< - D: Decoder, - K: Decodable + Hash + IterBytes + Eq, - V: Decodable -> Decodable for HashMap { - fn decode(d: &mut D) -> HashMap { - d.read_map(|d, len| { - let mut map = HashMap::with_capacity(len); - for i in range(0u, len) { - let key = d.read_map_elt_key(i, |d| Decodable::decode(d)); - let val = d.read_map_elt_val(i, |d| Decodable::decode(d)); - map.insert(key, val); - } - map - }) - } -} - -impl< - S: Encoder, - T: Encodable + Hash + IterBytes + Eq -> Encodable for HashSet { - fn encode(&self, s: &mut S) { - s.emit_seq(self.len(), |s| { - let mut i = 0; - for e in self.iter() { - s.emit_seq_elt(i, |s| e.encode(s)); - i += 1; - } - }) - } -} - -impl< - D: Decoder, - T: Decodable + Hash + IterBytes + Eq -> Decodable for HashSet { - fn decode(d: &mut D) -> HashSet { - d.read_seq(|d, len| { - let mut set = HashSet::with_capacity(len); - for i in range(0u, len) { - set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))); - } - set - }) - } -} - -impl< - E: Encoder, - V: Encodable -> Encodable for TrieMap { - fn encode(&self, e: &mut E) { - e.emit_map(self.len(), |e| { - for (i, (key, val)) in self.iter().enumerate() { - e.emit_map_elt_key(i, |e| key.encode(e)); - e.emit_map_elt_val(i, |e| val.encode(e)); - } - }); - } -} - -impl< - D: Decoder, - V: Decodable -> Decodable for TrieMap { - fn decode(d: &mut D) -> TrieMap { - d.read_map(|d, len| { - let mut map = TrieMap::new(); - for i in range(0u, len) { - let key = d.read_map_elt_key(i, |d| Decodable::decode(d)); - let val = d.read_map_elt_val(i, |d| Decodable::decode(d)); - map.insert(key, val); - } - map - }) - } -} - -impl Encodable for TrieSet { - fn encode(&self, s: &mut S) { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s)); - } - }) - } -} - -impl Decodable for TrieSet { - fn decode(d: &mut D) -> TrieSet { - d.read_seq(|d, len| { - let mut set = TrieSet::new(); - for i in range(0u, len) { - set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))); - } - set - }) - } -} - -impl< - E: Encoder, - K: Encodable + Eq + TotalOrd, - V: Encodable + Eq -> Encodable for TreeMap { - fn encode(&self, e: &mut E) { - e.emit_map(self.len(), |e| { - let mut i = 0; - for (key, val) in self.iter() { - e.emit_map_elt_key(i, |e| key.encode(e)); - e.emit_map_elt_val(i, |e| val.encode(e)); - i += 1; - } - }) - } -} - -impl< - D: Decoder, - K: Decodable + Eq + TotalOrd, - V: Decodable + Eq -> Decodable for TreeMap { - fn decode(d: &mut D) -> TreeMap { - d.read_map(|d, len| { - let mut map = TreeMap::new(); - for i in range(0u, len) { - let key = d.read_map_elt_key(i, |d| Decodable::decode(d)); - let val = d.read_map_elt_val(i, |d| Decodable::decode(d)); - map.insert(key, val); - } - map - }) - } -} - -impl< - S: Encoder, - T: Encodable + Eq + TotalOrd -> Encodable for TreeSet { - fn encode(&self, s: &mut S) { - s.emit_seq(self.len(), |s| { - let mut i = 0; - for e in self.iter() { - s.emit_seq_elt(i, |s| e.encode(s)); - i += 1; - } - }) - } -} - -impl< - D: Decoder, - T: Decodable + Eq + TotalOrd -> Decodable for TreeSet { - fn decode(d: &mut D) -> TreeSet { - d.read_seq(|d, len| { - let mut set = TreeSet::new(); - for i in range(0u, len) { - set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))); - } - set - }) - } -} - -// ___________________________________________________________________________ -// Helper routines -// -// In some cases, these should eventually be coded as traits. - -pub trait EncoderHelpers { - fn emit_from_vec(&mut self, v: &[T], f: |&mut Self, v: &T|); -} - -impl EncoderHelpers for S { - fn emit_from_vec(&mut self, v: &[T], f: |&mut S, &T|) { - self.emit_seq(v.len(), |this| { - for (i, e) in v.iter().enumerate() { - this.emit_seq_elt(i, |this| { - f(this, e) - }) - } - }) - } -} - -pub trait DecoderHelpers { - fn read_to_vec(&mut self, f: |&mut Self| -> T) -> ~[T]; -} - -impl DecoderHelpers for D { - fn read_to_vec(&mut self, f: |&mut D| -> T) -> ~[T] { - self.read_seq(|this, len| { - vec::from_fn(len, |i| { - this.read_seq_elt(i, |this| f(this)) - }) - }) - } -} diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index 6605ea00c44..449e72dd0ec 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -17,6 +17,8 @@ use std::iter::{Peekable}; use std::cmp::Ordering; use std::ptr; +use serialize::{Encodable, Decodable, Encoder, Decoder}; + // This is implemented as an AA tree, which is a simplified variation of // a red-black tree where red (horizontal) nodes can only be added // as a right child. The time complexity is the same, and re-balancing @@ -1004,6 +1006,71 @@ impl Extendable for TreeSet { } } +impl< + E: Encoder, + K: Encodable + Eq + TotalOrd, + V: Encodable + Eq +> Encodable for TreeMap { + fn encode(&self, e: &mut E) { + e.emit_map(self.len(), |e| { + let mut i = 0; + for (key, val) in self.iter() { + e.emit_map_elt_key(i, |e| key.encode(e)); + e.emit_map_elt_val(i, |e| val.encode(e)); + i += 1; + } + }) + } +} + +impl< + D: Decoder, + K: Decodable + Eq + TotalOrd, + V: Decodable + Eq +> Decodable for TreeMap { + fn decode(d: &mut D) -> TreeMap { + d.read_map(|d, len| { + let mut map = TreeMap::new(); + for i in range(0u, len) { + let key = d.read_map_elt_key(i, |d| Decodable::decode(d)); + let val = d.read_map_elt_val(i, |d| Decodable::decode(d)); + map.insert(key, val); + } + map + }) + } +} + +impl< + S: Encoder, + T: Encodable + Eq + TotalOrd +> Encodable for TreeSet { + fn encode(&self, s: &mut S) { + s.emit_seq(self.len(), |s| { + let mut i = 0; + for e in self.iter() { + s.emit_seq_elt(i, |s| e.encode(s)); + i += 1; + } + }) + } +} + +impl< + D: Decoder, + T: Decodable + Eq + TotalOrd +> Decodable for TreeSet { + fn decode(d: &mut D) -> TreeSet { + d.read_seq(|d, len| { + let mut set = TreeSet::new(); + for i in range(0u, len) { + set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))); + } + set + }) + } +} + #[cfg(test)] mod test_treemap { diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index d4a6c29752d..52ddc8c8108 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -35,6 +35,7 @@ extern mod extra; extern mod flate; extern mod arena; extern mod syntax; +extern mod serialize; extern mod sync; use back::link; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 1a65b326bbd..8a6ba824dcb 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -18,8 +18,8 @@ use middle::ty; use middle::typeck; use std::vec; +use reader = serialize::ebml::reader; use std::rc::Rc; -use reader = extra::ebml::reader; use syntax::ast; use syntax::ast_map; use syntax::diagnostic::expect; diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 8ba98e84dfa..d18017d0043 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -31,9 +31,9 @@ use std::io::extensions::u64_from_be_bytes; use std::option; use std::rc::Rc; use std::vec; -use extra::ebml::reader; -use extra::ebml; -use extra::serialize::Decodable; +use serialize::ebml::reader; +use serialize::ebml; +use serialize::Decodable; use syntax::ast_map; use syntax::attr; use syntax::parse::token::{IdentInterner, special_idents}; diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index d56d211b713..ba33f57309f 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -22,7 +22,7 @@ use middle::ty; use middle::typeck; use middle; -use extra::serialize::Encodable; +use serialize::Encodable; use std::cast; use std::cell::{Cell, RefCell}; use std::hashmap::{HashMap, HashSet}; @@ -45,7 +45,7 @@ use syntax::parse::token; use syntax::visit::Visitor; use syntax::visit; use syntax; -use writer = extra::ebml::writer; +use writer = serialize::ebml::writer; // used by astencode: type abbrev_map = @RefCell>; diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 29ea3475d34..8adbd37462b 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -37,12 +37,12 @@ use std::cast; use std::io::Seek; use std::rc::Rc; -use extra::ebml::reader; -use extra::ebml; -use extra::serialize; -use extra::serialize::{Encoder, Encodable, EncoderHelpers, DecoderHelpers}; -use extra::serialize::{Decoder, Decodable}; -use writer = extra::ebml::writer; +use serialize::ebml::reader; +use serialize::ebml; +use serialize; +use serialize::{Encoder, Encodable, EncoderHelpers, DecoderHelpers}; +use serialize::{Decoder, Decodable}; +use writer = serialize::ebml::writer; #[cfg(test)] use syntax::parse; #[cfg(test)] use syntax::print::pprust; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index bf096a7e49b..7256e8923fa 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -18,6 +18,7 @@ extern mod syntax; extern mod rustc; extern mod extra; +extern mod serialize; extern mod sync; use std::local_data; @@ -27,7 +28,7 @@ use std::str; use extra::getopts; use extra::getopts::groups; use extra::json; -use extra::serialize::{Decodable, Encodable}; +use serialize::{Decodable, Encodable}; use extra::time; pub mod clean; diff --git a/src/libserialize/ebml.rs b/src/libserialize/ebml.rs new file mode 100644 index 00000000000..9d1c099c6f0 --- /dev/null +++ b/src/libserialize/ebml.rs @@ -0,0 +1,1121 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[allow(missing_doc)]; + +use std::str; + +macro_rules! if_ok( ($e:expr) => ( + match $e { Ok(e) => e, Err(e) => { self.last_error = Err(e); return } } +) ) + +// Simple Extensible Binary Markup Language (ebml) reader and writer on a +// cursor model. See the specification here: +// http://www.matroska.org/technical/specs/rfc/index.html + +// Common data structures +#[deriving(Clone)] +pub struct Doc<'a> { + data: &'a [u8], + start: uint, + end: uint, +} + +impl<'doc> Doc<'doc> { + pub fn get<'a>(&'a self, tag: uint) -> Doc<'a> { + reader::get_doc(*self, tag) + } + + pub fn as_str_slice<'a>(&'a self) -> &'a str { + str::from_utf8(self.data.slice(self.start, self.end)).unwrap() + } + + pub fn as_str(&self) -> ~str { + self.as_str_slice().to_owned() + } +} + +pub struct TaggedDoc<'a> { + priv tag: uint, + doc: Doc<'a>, +} + +pub enum EbmlEncoderTag { + EsUint, // 0 + EsU64, // 1 + EsU32, // 2 + EsU16, // 3 + EsU8, // 4 + EsInt, // 5 + EsI64, // 6 + EsI32, // 7 + EsI16, // 8 + EsI8, // 9 + EsBool, // 10 + EsChar, // 11 + EsStr, // 12 + EsF64, // 13 + EsF32, // 14 + EsFloat, // 15 + EsEnum, // 16 + EsEnumVid, // 17 + EsEnumBody, // 18 + EsVec, // 19 + EsVecLen, // 20 + EsVecElt, // 21 + EsMap, // 22 + EsMapLen, // 23 + EsMapKey, // 24 + EsMapVal, // 25 + + EsOpaque, + + EsLabel, // Used only when debugging +} +// -------------------------------------- + +pub mod reader { + use std::char; + + use std::cast::transmute; + use std::int; + use std::option::{None, Option, Some}; + use std::io::extensions::u64_from_be_bytes; + + use serialize; + + use super::{ EsVec, EsMap, EsEnum, EsVecLen, EsVecElt, EsMapLen, EsMapKey, + EsEnumVid, EsU64, EsU32, EsU16, EsU8, EsInt, EsI64, EsI32, EsI16, EsI8, + EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal, EsEnumBody, EsUint, + EsOpaque, EsLabel, EbmlEncoderTag, Doc, TaggedDoc }; + + // ebml reading + + pub struct Res { + val: uint, + next: uint + } + + #[inline(never)] + fn vuint_at_slow(data: &[u8], start: uint) -> Res { + let a = data[start]; + if a & 0x80u8 != 0u8 { + return Res {val: (a & 0x7fu8) as uint, next: start + 1u}; + } + if a & 0x40u8 != 0u8 { + return Res {val: ((a & 0x3fu8) as uint) << 8u | + (data[start + 1u] as uint), + next: start + 2u}; + } + if a & 0x20u8 != 0u8 { + return Res {val: ((a & 0x1fu8) as uint) << 16u | + (data[start + 1u] as uint) << 8u | + (data[start + 2u] as uint), + next: start + 3u}; + } + if a & 0x10u8 != 0u8 { + return Res {val: ((a & 0x0fu8) as uint) << 24u | + (data[start + 1u] as uint) << 16u | + (data[start + 2u] as uint) << 8u | + (data[start + 3u] as uint), + next: start + 4u}; + } + fail!("vint too big"); + } + + pub fn vuint_at(data: &[u8], start: uint) -> Res { + use std::ptr::offset; + use std::unstable::intrinsics::from_be32; + + if data.len() - start < 4 { + return vuint_at_slow(data, start); + } + + // Lookup table for parsing EBML Element IDs as per http://ebml.sourceforge.net/specs/ + // The Element IDs are parsed by reading a big endian u32 positioned at data[start]. + // Using the four most significant bits of the u32 we lookup in the table below how the + // element ID should be derived from it. + // + // The table stores tuples (shift, mask) where shift is the number the u32 should be right + // shifted with and mask is the value the right shifted value should be masked with. + // If for example the most significant bit is set this means it's a class A ID and the u32 + // should be right shifted with 24 and masked with 0x7f. Therefore we store (24, 0x7f) at + // index 0x8 - 0xF (four bit numbers where the most significant bit is set). + // + // By storing the number of shifts and masks in a table instead of checking in order if + // the most significant bit is set, the second most significant bit is set etc. we can + // replace up to three "and+branch" with a single table lookup which gives us a measured + // speedup of around 2x on x86_64. + static SHIFT_MASK_TABLE: [(u32, u32), ..16] = [ + (0, 0x0), (0, 0x0fffffff), + (8, 0x1fffff), (8, 0x1fffff), + (16, 0x3fff), (16, 0x3fff), (16, 0x3fff), (16, 0x3fff), + (24, 0x7f), (24, 0x7f), (24, 0x7f), (24, 0x7f), + (24, 0x7f), (24, 0x7f), (24, 0x7f), (24, 0x7f) + ]; + + unsafe { + let (ptr, _): (*u8, uint) = transmute(data); + let ptr = offset(ptr, start as int); + let ptr: *i32 = transmute(ptr); + let val = from_be32(*ptr) as u32; + + let i = (val >> 28u) as uint; + let (shift, mask) = SHIFT_MASK_TABLE[i]; + Res { + val: ((val >> shift) & mask) as uint, + next: start + (((32 - shift) >> 3) as uint) + } + } + } + + pub fn Doc<'a>(data: &'a [u8]) -> Doc<'a> { + Doc { data: data, start: 0u, end: data.len() } + } + + pub fn doc_at<'a>(data: &'a [u8], start: uint) -> TaggedDoc<'a> { + let elt_tag = vuint_at(data, start); + let elt_size = vuint_at(data, elt_tag.next); + let end = elt_size.next + elt_size.val; + TaggedDoc { + tag: elt_tag.val, + doc: Doc { data: data, start: elt_size.next, end: end } + } + } + + pub fn maybe_get_doc<'a>(d: Doc<'a>, tg: uint) -> Option> { + let mut pos = d.start; + while pos < d.end { + let elt_tag = vuint_at(d.data, pos); + let elt_size = vuint_at(d.data, elt_tag.next); + pos = elt_size.next + elt_size.val; + if elt_tag.val == tg { + return Some(Doc { data: d.data, start: elt_size.next, + end: pos }); + } + } + None + } + + pub fn get_doc<'a>(d: Doc<'a>, tg: uint) -> Doc<'a> { + match maybe_get_doc(d, tg) { + Some(d) => d, + None => { + error!("failed to find block with tag {}", tg); + fail!(); + } + } + } + + pub fn docs<'a>(d: Doc<'a>, it: |uint, Doc<'a>| -> bool) -> bool { + let mut pos = d.start; + while pos < d.end { + let elt_tag = vuint_at(d.data, pos); + let elt_size = vuint_at(d.data, elt_tag.next); + pos = elt_size.next + elt_size.val; + let doc = Doc { data: d.data, start: elt_size.next, end: pos }; + if !it(elt_tag.val, doc) { + return false; + } + } + return true; + } + + pub fn tagged_docs<'a>(d: Doc<'a>, tg: uint, it: |Doc<'a>| -> bool) -> bool { + let mut pos = d.start; + while pos < d.end { + let elt_tag = vuint_at(d.data, pos); + let elt_size = vuint_at(d.data, elt_tag.next); + pos = elt_size.next + elt_size.val; + if elt_tag.val == tg { + let doc = Doc { data: d.data, start: elt_size.next, + end: pos }; + if !it(doc) { + return false; + } + } + } + return true; + } + + pub fn with_doc_data<'a, T>(d: Doc<'a>, f: |x: &'a [u8]| -> T) -> T { + f(d.data.slice(d.start, d.end)) + } + + + pub fn doc_as_u8(d: Doc) -> u8 { + assert_eq!(d.end, d.start + 1u); + d.data[d.start] + } + + pub fn doc_as_u16(d: Doc) -> u16 { + assert_eq!(d.end, d.start + 2u); + u64_from_be_bytes(d.data, d.start, 2u) as u16 + } + + pub fn doc_as_u32(d: Doc) -> u32 { + assert_eq!(d.end, d.start + 4u); + u64_from_be_bytes(d.data, d.start, 4u) as u32 + } + + pub fn doc_as_u64(d: Doc) -> u64 { + assert_eq!(d.end, d.start + 8u); + u64_from_be_bytes(d.data, d.start, 8u) + } + + pub fn doc_as_i8(d: Doc) -> i8 { doc_as_u8(d) as i8 } + pub fn doc_as_i16(d: Doc) -> i16 { doc_as_u16(d) as i16 } + pub fn doc_as_i32(d: Doc) -> i32 { doc_as_u32(d) as i32 } + pub fn doc_as_i64(d: Doc) -> i64 { doc_as_u64(d) as i64 } + + pub struct Decoder<'a> { + priv parent: Doc<'a>, + priv pos: uint, + } + + pub fn Decoder<'a>(d: Doc<'a>) -> Decoder<'a> { + Decoder { + parent: d, + pos: d.start + } + } + + impl<'doc> Decoder<'doc> { + fn _check_label(&mut self, lbl: &str) { + if self.pos < self.parent.end { + let TaggedDoc { tag: r_tag, doc: r_doc } = + doc_at(self.parent.data, self.pos); + + if r_tag == (EsLabel as uint) { + self.pos = r_doc.end; + let str = r_doc.as_str_slice(); + if lbl != str { + fail!("Expected label {} but found {}", lbl, str); + } + } + } + } + + fn next_doc(&mut self, exp_tag: EbmlEncoderTag) -> Doc<'doc> { + debug!(". next_doc(exp_tag={:?})", exp_tag); + if self.pos >= self.parent.end { + fail!("no more documents in current node!"); + } + let TaggedDoc { tag: r_tag, doc: r_doc } = + doc_at(self.parent.data, self.pos); + debug!("self.parent={}-{} self.pos={} r_tag={} r_doc={}-{}", + self.parent.start, + self.parent.end, + self.pos, + r_tag, + r_doc.start, + r_doc.end); + if r_tag != (exp_tag as uint) { + fail!("expected EBML doc with tag {:?} but found tag {:?}", + exp_tag, r_tag); + } + if r_doc.end > self.parent.end { + fail!("invalid EBML, child extends to {:#x}, parent to {:#x}", + r_doc.end, self.parent.end); + } + self.pos = r_doc.end; + r_doc + } + + fn push_doc(&mut self, exp_tag: EbmlEncoderTag, + f: |&mut Decoder<'doc>| -> T) -> T { + let d = self.next_doc(exp_tag); + let old_parent = self.parent; + let old_pos = self.pos; + self.parent = d; + self.pos = d.start; + let r = f(self); + self.parent = old_parent; + self.pos = old_pos; + r + } + + fn _next_uint(&mut self, exp_tag: EbmlEncoderTag) -> uint { + let r = doc_as_u32(self.next_doc(exp_tag)); + debug!("_next_uint exp_tag={:?} result={}", exp_tag, r); + r as uint + } + + pub fn read_opaque(&mut self, op: |&mut Decoder<'doc>, Doc| -> R) -> R { + let doc = self.next_doc(EsOpaque); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = doc.start; + + let result = op(self, doc); + + self.parent = old_parent; + self.pos = old_pos; + result + } + } + + impl<'doc> serialize::Decoder for Decoder<'doc> { + fn read_nil(&mut self) -> () { () } + + fn read_u64(&mut self) -> u64 { doc_as_u64(self.next_doc(EsU64)) } + fn read_u32(&mut self) -> u32 { doc_as_u32(self.next_doc(EsU32)) } + fn read_u16(&mut self) -> u16 { doc_as_u16(self.next_doc(EsU16)) } + fn read_u8 (&mut self) -> u8 { doc_as_u8 (self.next_doc(EsU8 )) } + fn read_uint(&mut self) -> uint { + let v = doc_as_u64(self.next_doc(EsUint)); + if v > (::std::uint::MAX as u64) { + fail!("uint {} too large for this architecture", v); + } + v as uint + } + + fn read_i64(&mut self) -> i64 { + doc_as_u64(self.next_doc(EsI64)) as i64 + } + fn read_i32(&mut self) -> i32 { + doc_as_u32(self.next_doc(EsI32)) as i32 + } + fn read_i16(&mut self) -> i16 { + doc_as_u16(self.next_doc(EsI16)) as i16 + } + fn read_i8 (&mut self) -> i8 { + doc_as_u8(self.next_doc(EsI8 )) as i8 + } + fn read_int(&mut self) -> int { + let v = doc_as_u64(self.next_doc(EsInt)) as i64; + if v > (int::MAX as i64) || v < (int::MIN as i64) { + debug!("FIXME \\#6122: Removing this makes this function miscompile"); + fail!("int {} out of range for this architecture", v); + } + v as int + } + + fn read_bool(&mut self) -> bool { + doc_as_u8(self.next_doc(EsBool)) != 0 + } + + fn read_f64(&mut self) -> f64 { + let bits = doc_as_u64(self.next_doc(EsF64)); + unsafe { transmute(bits) } + } + fn read_f32(&mut self) -> f32 { + let bits = doc_as_u32(self.next_doc(EsF32)); + unsafe { transmute(bits) } + } + fn read_char(&mut self) -> char { + char::from_u32(doc_as_u32(self.next_doc(EsChar))).unwrap() + } + fn read_str(&mut self) -> ~str { + self.next_doc(EsStr).as_str() + } + + // Compound types: + fn read_enum(&mut self, name: &str, f: |&mut Decoder<'doc>| -> T) -> T { + debug!("read_enum({})", name); + self._check_label(name); + + let doc = self.next_doc(EsEnum); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = f(self); + + self.parent = old_parent; + self.pos = old_pos; + result + } + + fn read_enum_variant(&mut self, + _: &[&str], + f: |&mut Decoder<'doc>, uint| -> T) + -> T { + debug!("read_enum_variant()"); + let idx = self._next_uint(EsEnumVid); + debug!(" idx={}", idx); + + let doc = self.next_doc(EsEnumBody); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = f(self, idx); + + self.parent = old_parent; + self.pos = old_pos; + result + } + + fn read_enum_variant_arg(&mut self, + idx: uint, + f: |&mut Decoder<'doc>| -> T) -> T { + debug!("read_enum_variant_arg(idx={})", idx); + f(self) + } + + fn read_enum_struct_variant(&mut self, + _: &[&str], + f: |&mut Decoder<'doc>, uint| -> T) + -> T { + debug!("read_enum_struct_variant()"); + let idx = self._next_uint(EsEnumVid); + debug!(" idx={}", idx); + + let doc = self.next_doc(EsEnumBody); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = f(self, idx); + + self.parent = old_parent; + self.pos = old_pos; + result + } + + fn read_enum_struct_variant_field(&mut self, + name: &str, + idx: uint, + f: |&mut Decoder<'doc>| -> T) + -> T { + debug!("read_enum_struct_variant_arg(name={}, idx={})", name, idx); + f(self) + } + + fn read_struct(&mut self, + name: &str, + _: uint, + f: |&mut Decoder<'doc>| -> T) + -> T { + debug!("read_struct(name={})", name); + f(self) + } + + fn read_struct_field(&mut self, + name: &str, + idx: uint, + f: |&mut Decoder<'doc>| -> T) + -> T { + debug!("read_struct_field(name={}, idx={})", name, idx); + self._check_label(name); + f(self) + } + + fn read_tuple(&mut self, f: |&mut Decoder<'doc>, uint| -> T) -> T { + debug!("read_tuple()"); + self.read_seq(f) + } + + fn read_tuple_arg(&mut self, idx: uint, f: |&mut Decoder<'doc>| -> T) + -> T { + debug!("read_tuple_arg(idx={})", idx); + self.read_seq_elt(idx, f) + } + + fn read_tuple_struct(&mut self, + name: &str, + f: |&mut Decoder<'doc>, uint| -> T) + -> T { + debug!("read_tuple_struct(name={})", name); + self.read_tuple(f) + } + + fn read_tuple_struct_arg(&mut self, + idx: uint, + f: |&mut Decoder<'doc>| -> T) + -> T { + debug!("read_tuple_struct_arg(idx={})", idx); + self.read_tuple_arg(idx, f) + } + + fn read_option(&mut self, f: |&mut Decoder<'doc>, bool| -> T) -> T { + debug!("read_option()"); + self.read_enum("Option", |this| { + this.read_enum_variant(["None", "Some"], |this, idx| { + match idx { + 0 => f(this, false), + 1 => f(this, true), + _ => fail!(), + } + }) + }) + } + + fn read_seq(&mut self, f: |&mut Decoder<'doc>, uint| -> T) -> T { + debug!("read_seq()"); + self.push_doc(EsVec, |d| { + let len = d._next_uint(EsVecLen); + debug!(" len={}", len); + f(d, len) + }) + } + + fn read_seq_elt(&mut self, idx: uint, f: |&mut Decoder<'doc>| -> T) + -> T { + debug!("read_seq_elt(idx={})", idx); + self.push_doc(EsVecElt, f) + } + + fn read_map(&mut self, f: |&mut Decoder<'doc>, uint| -> T) -> T { + debug!("read_map()"); + self.push_doc(EsMap, |d| { + let len = d._next_uint(EsMapLen); + debug!(" len={}", len); + f(d, len) + }) + } + + fn read_map_elt_key(&mut self, idx: uint, f: |&mut Decoder<'doc>| -> T) + -> T { + debug!("read_map_elt_key(idx={})", idx); + self.push_doc(EsMapKey, f) + } + + fn read_map_elt_val(&mut self, idx: uint, f: |&mut Decoder<'doc>| -> T) + -> T { + debug!("read_map_elt_val(idx={})", idx); + self.push_doc(EsMapVal, f) + } + } +} + +pub mod writer { + use std::cast; + use std::clone::Clone; + use std::io; + use std::io::{Writer, Seek}; + use std::io::MemWriter; + use std::io::extensions::u64_to_be_bytes; + + use super::{ EsVec, EsMap, EsEnum, EsVecLen, EsVecElt, EsMapLen, EsMapKey, + EsEnumVid, EsU64, EsU32, EsU16, EsU8, EsInt, EsI64, EsI32, EsI16, EsI8, + EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal, EsEnumBody, EsUint, + EsOpaque, EsLabel, EbmlEncoderTag }; + + use serialize; + + // ebml writing + pub struct Encoder<'a> { + // FIXME(#5665): this should take a trait object. Note that if you + // delete this comment you should consider removing the + // unwrap()'s below of the results of the calls to + // write(). We're guaranteed that writing into a MemWriter + // won't fail, but this is not true for all I/O streams in + // general. + writer: &'a mut MemWriter, + priv size_positions: ~[uint], + last_error: io::IoResult<()>, + } + + fn write_sized_vuint(w: &mut MemWriter, n: uint, size: uint) { + match size { + 1u => w.write(&[0x80u8 | (n as u8)]), + 2u => w.write(&[0x40u8 | ((n >> 8_u) as u8), n as u8]), + 3u => w.write(&[0x20u8 | ((n >> 16_u) as u8), (n >> 8_u) as u8, + n as u8]), + 4u => w.write(&[0x10u8 | ((n >> 24_u) as u8), (n >> 16_u) as u8, + (n >> 8_u) as u8, n as u8]), + _ => fail!("vint to write too big: {}", n) + }.unwrap() + } + + fn write_vuint(w: &mut MemWriter, n: uint) { + if n < 0x7f_u { write_sized_vuint(w, n, 1u); return; } + if n < 0x4000_u { write_sized_vuint(w, n, 2u); return; } + if n < 0x200000_u { write_sized_vuint(w, n, 3u); return; } + if n < 0x10000000_u { write_sized_vuint(w, n, 4u); return; } + fail!("vint to write too big: {}", n); + } + + pub fn Encoder<'a>(w: &'a mut MemWriter) -> Encoder<'a> { + let size_positions: ~[uint] = ~[]; + Encoder { + writer: w, + size_positions: size_positions, + last_error: Ok(()), + } + } + + // FIXME (#2741): Provide a function to write the standard ebml header. + impl<'a> Encoder<'a> { + /// FIXME(pcwalton): Workaround for badness in trans. DO NOT USE ME. + pub unsafe fn unsafe_clone(&self) -> Encoder<'a> { + Encoder { + writer: cast::transmute_copy(&self.writer), + size_positions: self.size_positions.clone(), + last_error: Ok(()), + } + } + + pub fn start_tag(&mut self, tag_id: uint) { + debug!("Start tag {}", tag_id); + + // Write the enum ID: + write_vuint(self.writer, tag_id); + + // Write a placeholder four-byte size. + self.size_positions.push(if_ok!(self.writer.tell()) as uint); + let zeroes: &[u8] = &[0u8, 0u8, 0u8, 0u8]; + if_ok!(self.writer.write(zeroes)); + } + + pub fn end_tag(&mut self) { + let last_size_pos = self.size_positions.pop().unwrap(); + let cur_pos = if_ok!(self.writer.tell()); + if_ok!(self.writer.seek(last_size_pos as i64, io::SeekSet)); + let size = (cur_pos as uint - last_size_pos - 4); + write_sized_vuint(self.writer, size, 4u); + if_ok!(self.writer.seek(cur_pos as i64, io::SeekSet)); + + debug!("End tag (size = {})", size); + } + + pub fn wr_tag(&mut self, tag_id: uint, blk: ||) { + self.start_tag(tag_id); + blk(); + self.end_tag(); + } + + pub fn wr_tagged_bytes(&mut self, tag_id: uint, b: &[u8]) { + write_vuint(self.writer, tag_id); + write_vuint(self.writer, b.len()); + self.writer.write(b).unwrap(); + } + + pub fn wr_tagged_u64(&mut self, tag_id: uint, v: u64) { + u64_to_be_bytes(v, 8u, |v| { + self.wr_tagged_bytes(tag_id, v); + }) + } + + pub fn wr_tagged_u32(&mut self, tag_id: uint, v: u32) { + u64_to_be_bytes(v as u64, 4u, |v| { + self.wr_tagged_bytes(tag_id, v); + }) + } + + pub fn wr_tagged_u16(&mut self, tag_id: uint, v: u16) { + u64_to_be_bytes(v as u64, 2u, |v| { + self.wr_tagged_bytes(tag_id, v); + }) + } + + pub fn wr_tagged_u8(&mut self, tag_id: uint, v: u8) { + self.wr_tagged_bytes(tag_id, &[v]); + } + + pub fn wr_tagged_i64(&mut self, tag_id: uint, v: i64) { + u64_to_be_bytes(v as u64, 8u, |v| { + self.wr_tagged_bytes(tag_id, v); + }) + } + + pub fn wr_tagged_i32(&mut self, tag_id: uint, v: i32) { + u64_to_be_bytes(v as u64, 4u, |v| { + self.wr_tagged_bytes(tag_id, v); + }) + } + + pub fn wr_tagged_i16(&mut self, tag_id: uint, v: i16) { + u64_to_be_bytes(v as u64, 2u, |v| { + self.wr_tagged_bytes(tag_id, v); + }) + } + + pub fn wr_tagged_i8(&mut self, tag_id: uint, v: i8) { + self.wr_tagged_bytes(tag_id, &[v as u8]); + } + + pub fn wr_tagged_str(&mut self, tag_id: uint, v: &str) { + self.wr_tagged_bytes(tag_id, v.as_bytes()); + } + + pub fn wr_bytes(&mut self, b: &[u8]) { + debug!("Write {} bytes", b.len()); + self.writer.write(b).unwrap(); + } + + pub fn wr_str(&mut self, s: &str) { + debug!("Write str: {}", s); + self.writer.write(s.as_bytes()).unwrap(); + } + } + + // FIXME (#2743): optionally perform "relaxations" on end_tag to more + // efficiently encode sizes; this is a fixed point iteration + + // Set to true to generate more debugging in EBML code. + // Totally lame approach. + static DEBUG: bool = true; + + impl<'a> Encoder<'a> { + // used internally to emit things like the vector length and so on + fn _emit_tagged_uint(&mut self, t: EbmlEncoderTag, v: uint) { + assert!(v <= 0xFFFF_FFFF_u); + self.wr_tagged_u32(t as uint, v as u32); + } + + fn _emit_label(&mut self, label: &str) { + // There are various strings that we have access to, such as + // the name of a record field, which do not actually appear in + // the encoded EBML (normally). This is just for + // efficiency. When debugging, though, we can emit such + // labels and then they will be checked by decoder to + // try and check failures more quickly. + if DEBUG { self.wr_tagged_str(EsLabel as uint, label) } + } + + pub fn emit_opaque(&mut self, f: |&mut Encoder|) { + self.start_tag(EsOpaque as uint); + f(self); + self.end_tag(); + } + } + + impl<'a> serialize::Encoder for Encoder<'a> { + fn emit_nil(&mut self) {} + + fn emit_uint(&mut self, v: uint) { + self.wr_tagged_u64(EsUint as uint, v as u64); + } + fn emit_u64(&mut self, v: u64) { + self.wr_tagged_u64(EsU64 as uint, v); + } + fn emit_u32(&mut self, v: u32) { + self.wr_tagged_u32(EsU32 as uint, v); + } + fn emit_u16(&mut self, v: u16) { + self.wr_tagged_u16(EsU16 as uint, v); + } + fn emit_u8(&mut self, v: u8) { + self.wr_tagged_u8(EsU8 as uint, v); + } + + fn emit_int(&mut self, v: int) { + self.wr_tagged_i64(EsInt as uint, v as i64); + } + fn emit_i64(&mut self, v: i64) { + self.wr_tagged_i64(EsI64 as uint, v); + } + fn emit_i32(&mut self, v: i32) { + self.wr_tagged_i32(EsI32 as uint, v); + } + fn emit_i16(&mut self, v: i16) { + self.wr_tagged_i16(EsI16 as uint, v); + } + fn emit_i8(&mut self, v: i8) { + self.wr_tagged_i8(EsI8 as uint, v); + } + + fn emit_bool(&mut self, v: bool) { + self.wr_tagged_u8(EsBool as uint, v as u8) + } + + fn emit_f64(&mut self, v: f64) { + let bits = unsafe { cast::transmute(v) }; + self.wr_tagged_u64(EsF64 as uint, bits); + } + fn emit_f32(&mut self, v: f32) { + let bits = unsafe { cast::transmute(v) }; + self.wr_tagged_u32(EsF32 as uint, bits); + } + fn emit_char(&mut self, v: char) { + self.wr_tagged_u32(EsChar as uint, v as u32); + } + + fn emit_str(&mut self, v: &str) { + self.wr_tagged_str(EsStr as uint, v) + } + + fn emit_enum(&mut self, name: &str, f: |&mut Encoder<'a>|) { + self._emit_label(name); + self.start_tag(EsEnum as uint); + f(self); + self.end_tag(); + } + + fn emit_enum_variant(&mut self, + _: &str, + v_id: uint, + _: uint, + f: |&mut Encoder<'a>|) { + self._emit_tagged_uint(EsEnumVid, v_id); + self.start_tag(EsEnumBody as uint); + f(self); + self.end_tag(); + } + + fn emit_enum_variant_arg(&mut self, _: uint, f: |&mut Encoder<'a>|) { + f(self) + } + + fn emit_enum_struct_variant(&mut self, + v_name: &str, + v_id: uint, + cnt: uint, + f: |&mut Encoder<'a>|) { + self.emit_enum_variant(v_name, v_id, cnt, f) + } + + fn emit_enum_struct_variant_field(&mut self, + _: &str, + idx: uint, + f: |&mut Encoder<'a>|) { + self.emit_enum_variant_arg(idx, f) + } + + fn emit_struct(&mut self, + _: &str, + _len: uint, + f: |&mut Encoder<'a>|) { + f(self) + } + + fn emit_struct_field(&mut self, + name: &str, + _: uint, + f: |&mut Encoder<'a>|) { + self._emit_label(name); + f(self) + } + + fn emit_tuple(&mut self, len: uint, f: |&mut Encoder<'a>|) { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: uint, f: |&mut Encoder<'a>|) { + self.emit_seq_elt(idx, f) + } + + fn emit_tuple_struct(&mut self, + _: &str, + len: uint, + f: |&mut Encoder<'a>|) { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, + idx: uint, + f: |&mut Encoder<'a>|) { + self.emit_seq_elt(idx, f) + } + + fn emit_option(&mut self, f: |&mut Encoder<'a>|) { + self.emit_enum("Option", f); + } + fn emit_option_none(&mut self) { + self.emit_enum_variant("None", 0, 0, |_| ()) + } + fn emit_option_some(&mut self, f: |&mut Encoder<'a>|) { + self.emit_enum_variant("Some", 1, 1, f) + } + + fn emit_seq(&mut self, len: uint, f: |&mut Encoder<'a>|) { + self.start_tag(EsVec as uint); + self._emit_tagged_uint(EsVecLen, len); + f(self); + self.end_tag(); + } + + fn emit_seq_elt(&mut self, _idx: uint, f: |&mut Encoder<'a>|) { + self.start_tag(EsVecElt as uint); + f(self); + self.end_tag(); + } + + fn emit_map(&mut self, len: uint, f: |&mut Encoder<'a>|) { + self.start_tag(EsMap as uint); + self._emit_tagged_uint(EsMapLen, len); + f(self); + self.end_tag(); + } + + fn emit_map_elt_key(&mut self, _idx: uint, f: |&mut Encoder<'a>|) { + self.start_tag(EsMapKey as uint); + f(self); + self.end_tag(); + } + + fn emit_map_elt_val(&mut self, _idx: uint, f: |&mut Encoder<'a>|) { + self.start_tag(EsMapVal as uint); + f(self); + self.end_tag(); + } + } +} + +// ___________________________________________________________________________ +// Testing + +#[cfg(test)] +mod tests { + use ebml::reader; + use ebml::writer; + use {Encodable, Decodable}; + + use std::io::MemWriter; + use std::option::{None, Option, Some}; + + #[test] + fn test_vuint_at() { + let data = [ + 0x80, + 0xff, + 0x40, 0x00, + 0x7f, 0xff, + 0x20, 0x00, 0x00, + 0x3f, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, + 0x1f, 0xff, 0xff, 0xff + ]; + + let mut res: reader::Res; + + // Class A + res = reader::vuint_at(data, 0); + assert_eq!(res.val, 0); + assert_eq!(res.next, 1); + res = reader::vuint_at(data, res.next); + assert_eq!(res.val, (1 << 7) - 1); + assert_eq!(res.next, 2); + + // Class B + res = reader::vuint_at(data, res.next); + assert_eq!(res.val, 0); + assert_eq!(res.next, 4); + res = reader::vuint_at(data, res.next); + assert_eq!(res.val, (1 << 14) - 1); + assert_eq!(res.next, 6); + + // Class C + res = reader::vuint_at(data, res.next); + assert_eq!(res.val, 0); + assert_eq!(res.next, 9); + res = reader::vuint_at(data, res.next); + assert_eq!(res.val, (1 << 21) - 1); + assert_eq!(res.next, 12); + + // Class D + res = reader::vuint_at(data, res.next); + assert_eq!(res.val, 0); + assert_eq!(res.next, 16); + res = reader::vuint_at(data, res.next); + assert_eq!(res.val, (1 << 28) - 1); + assert_eq!(res.next, 20); + } + + #[test] + fn test_option_int() { + fn test_v(v: Option) { + debug!("v == {:?}", v); + let mut wr = MemWriter::new(); + { + let mut ebml_w = writer::Encoder(&mut wr); + v.encode(&mut ebml_w); + } + let ebml_doc = reader::Doc(wr.get_ref()); + let mut deser = reader::Decoder(ebml_doc); + let v1 = Decodable::decode(&mut deser); + debug!("v1 == {:?}", v1); + assert_eq!(v, v1); + } + + test_v(Some(22)); + test_v(None); + test_v(Some(3)); + } +} + +#[cfg(test)] +mod bench { + use ebml::reader; + use extra::test::BenchHarness; + + #[bench] + pub fn vuint_at_A_aligned(bh: &mut BenchHarness) { + use std::vec; + let data = vec::from_fn(4*100, |i| { + match i % 2 { + 0 => 0x80u8, + _ => i as u8, + } + }); + let mut sum = 0u; + bh.iter(|| { + let mut i = 0; + while i < data.len() { + sum += reader::vuint_at(data, i).val; + i += 4; + } + }); + } + + #[bench] + pub fn vuint_at_A_unaligned(bh: &mut BenchHarness) { + use std::vec; + let data = vec::from_fn(4*100+1, |i| { + match i % 2 { + 1 => 0x80u8, + _ => i as u8 + } + }); + let mut sum = 0u; + bh.iter(|| { + let mut i = 1; + while i < data.len() { + sum += reader::vuint_at(data, i).val; + i += 4; + } + }); + } + + #[bench] + pub fn vuint_at_D_aligned(bh: &mut BenchHarness) { + use std::vec; + let data = vec::from_fn(4*100, |i| { + match i % 4 { + 0 => 0x10u8, + 3 => i as u8, + _ => 0u8 + } + }); + let mut sum = 0u; + bh.iter(|| { + let mut i = 0; + while i < data.len() { + sum += reader::vuint_at(data, i).val; + i += 4; + } + }); + } + + #[bench] + pub fn vuint_at_D_unaligned(bh: &mut BenchHarness) { + use std::vec; + let data = vec::from_fn(4*100+1, |i| { + match i % 4 { + 1 => 0x10u8, + 0 => i as u8, + _ => 0u8 + } + }); + let mut sum = 0u; + bh.iter(|| { + let mut i = 1; + while i < data.len() { + sum += reader::vuint_at(data, i).val; + i += 4; + } + }); + } +} diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs new file mode 100644 index 00000000000..5f473b25369 --- /dev/null +++ b/src/libserialize/lib.rs @@ -0,0 +1,33 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Support code for encoding and decoding types. + +/* +Core encoding and decoding interfaces. +*/ + +#[crate_id = "serialize#0.10-pre"]; +#[crate_type = "rlib"]; +#[crate_type = "dylib"]; +#[license = "MIT/ASL2"]; +#[allow(missing_doc)]; +#[forbid(non_camel_case_types)]; +#[feature(macro_rules,managed_boxes)]; + +// test harness access +#[cfg(test)] +extern mod extra; + +pub use self::serialize::{Decoder, Encoder, Decodable, Encodable, + DecoderHelpers, EncoderHelpers}; + +mod serialize; +pub mod ebml; diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs new file mode 100644 index 00000000000..c4f0a7a1830 --- /dev/null +++ b/src/libserialize/serialize.rs @@ -0,0 +1,760 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Support code for encoding and decoding types. + +/* +Core encoding and decoding interfaces. +*/ + +use std::hashmap::{HashMap, HashSet}; +use std::rc::Rc; +use std::trie::{TrieMap, TrieSet}; +use std::vec; + +pub trait Encoder { + // Primitive types: + fn emit_nil(&mut self); + fn emit_uint(&mut self, v: uint); + 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_int(&mut self, v: int); + 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_f64(&mut self, v: f64); + fn emit_f32(&mut self, v: f32); + fn emit_char(&mut self, v: char); + fn emit_str(&mut self, v: &str); + + // Compound types: + fn emit_enum(&mut self, name: &str, f: |&mut Self|); + + fn emit_enum_variant(&mut self, + v_name: &str, + v_id: uint, + len: uint, + f: |&mut Self|); + fn emit_enum_variant_arg(&mut self, a_idx: uint, f: |&mut Self|); + + fn emit_enum_struct_variant(&mut self, + v_name: &str, + v_id: uint, + len: uint, + f: |&mut Self|); + fn emit_enum_struct_variant_field(&mut self, + f_name: &str, + f_idx: uint, + f: |&mut Self|); + + fn emit_struct(&mut self, name: &str, len: uint, f: |&mut Self|); + fn emit_struct_field(&mut self, + f_name: &str, + f_idx: uint, + f: |&mut Self|); + + fn emit_tuple(&mut self, len: uint, f: |&mut Self|); + fn emit_tuple_arg(&mut self, idx: uint, f: |&mut Self|); + + fn emit_tuple_struct(&mut self, name: &str, len: uint, f: |&mut Self|); + fn emit_tuple_struct_arg(&mut self, f_idx: uint, f: |&mut Self|); + + // Specialized types: + fn emit_option(&mut self, f: |&mut Self|); + fn emit_option_none(&mut self); + fn emit_option_some(&mut self, f: |&mut Self|); + + fn emit_seq(&mut self, len: uint, f: |this: &mut Self|); + fn emit_seq_elt(&mut self, idx: uint, f: |this: &mut Self|); + + fn emit_map(&mut self, len: uint, f: |&mut Self|); + fn emit_map_elt_key(&mut self, idx: uint, f: |&mut Self|); + fn emit_map_elt_val(&mut self, idx: uint, f: |&mut Self|); +} + +pub trait Decoder { + // Primitive types: + fn read_nil(&mut self) -> (); + fn read_uint(&mut self) -> uint; + 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_int(&mut self) -> int; + 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_f64(&mut self) -> f64; + fn read_f32(&mut self) -> f32; + fn read_char(&mut self) -> char; + fn read_str(&mut self) -> ~str; + + // Compound types: + fn read_enum(&mut self, name: &str, f: |&mut Self| -> T) -> T; + + fn read_enum_variant(&mut self, + names: &[&str], + f: |&mut Self, uint| -> T) + -> T; + fn read_enum_variant_arg(&mut self, + a_idx: uint, + f: |&mut Self| -> T) + -> T; + + fn read_enum_struct_variant(&mut self, + names: &[&str], + f: |&mut Self, uint| -> T) + -> T; + fn read_enum_struct_variant_field(&mut self, + &f_name: &str, + f_idx: uint, + f: |&mut Self| -> T) + -> T; + + fn read_struct(&mut self, s_name: &str, len: uint, f: |&mut Self| -> T) + -> T; + fn read_struct_field(&mut self, + f_name: &str, + f_idx: uint, + f: |&mut Self| -> T) + -> T; + + fn read_tuple(&mut self, f: |&mut Self, uint| -> T) -> T; + fn read_tuple_arg(&mut self, a_idx: uint, f: |&mut Self| -> T) -> T; + + fn read_tuple_struct(&mut self, + s_name: &str, + f: |&mut Self, uint| -> T) + -> T; + fn read_tuple_struct_arg(&mut self, + a_idx: uint, + f: |&mut Self| -> T) + -> T; + + // Specialized types: + fn read_option(&mut self, f: |&mut Self, bool| -> T) -> T; + + fn read_seq(&mut self, f: |&mut Self, uint| -> T) -> T; + fn read_seq_elt(&mut self, idx: uint, f: |&mut Self| -> T) -> T; + + fn read_map(&mut self, f: |&mut Self, uint| -> T) -> T; + fn read_map_elt_key(&mut self, idx: uint, f: |&mut Self| -> T) -> T; + fn read_map_elt_val(&mut self, idx: uint, f: |&mut Self| -> T) -> T; +} + +pub trait Encodable { + fn encode(&self, s: &mut S); +} + +pub trait Decodable { + fn decode(d: &mut D) -> Self; +} + +impl Encodable for uint { + fn encode(&self, s: &mut S) { + s.emit_uint(*self) + } +} + +impl Decodable for uint { + fn decode(d: &mut D) -> uint { + d.read_uint() + } +} + +impl Encodable for u8 { + fn encode(&self, s: &mut S) { + s.emit_u8(*self) + } +} + +impl Decodable for u8 { + fn decode(d: &mut D) -> u8 { + d.read_u8() + } +} + +impl Encodable for u16 { + fn encode(&self, s: &mut S) { + s.emit_u16(*self) + } +} + +impl Decodable for u16 { + fn decode(d: &mut D) -> u16 { + d.read_u16() + } +} + +impl Encodable for u32 { + fn encode(&self, s: &mut S) { + s.emit_u32(*self) + } +} + +impl Decodable for u32 { + fn decode(d: &mut D) -> u32 { + d.read_u32() + } +} + +impl Encodable for u64 { + fn encode(&self, s: &mut S) { + s.emit_u64(*self) + } +} + +impl Decodable for u64 { + fn decode(d: &mut D) -> u64 { + d.read_u64() + } +} + +impl Encodable for int { + fn encode(&self, s: &mut S) { + s.emit_int(*self) + } +} + +impl Decodable for int { + fn decode(d: &mut D) -> int { + d.read_int() + } +} + +impl Encodable for i8 { + fn encode(&self, s: &mut S) { + s.emit_i8(*self) + } +} + +impl Decodable for i8 { + fn decode(d: &mut D) -> i8 { + d.read_i8() + } +} + +impl Encodable for i16 { + fn encode(&self, s: &mut S) { + s.emit_i16(*self) + } +} + +impl Decodable for i16 { + fn decode(d: &mut D) -> i16 { + d.read_i16() + } +} + +impl Encodable for i32 { + fn encode(&self, s: &mut S) { + s.emit_i32(*self) + } +} + +impl Decodable for i32 { + fn decode(d: &mut D) -> i32 { + d.read_i32() + } +} + +impl Encodable for i64 { + fn encode(&self, s: &mut S) { + s.emit_i64(*self) + } +} + +impl Decodable for i64 { + fn decode(d: &mut D) -> i64 { + d.read_i64() + } +} + +impl<'a, S:Encoder> Encodable for &'a str { + fn encode(&self, s: &mut S) { + s.emit_str(*self) + } +} + +impl Encodable for ~str { + fn encode(&self, s: &mut S) { + s.emit_str(*self) + } +} + +impl Decodable for ~str { + fn decode(d: &mut D) -> ~str { + d.read_str() + } +} + +impl Encodable for f32 { + fn encode(&self, s: &mut S) { + s.emit_f32(*self) + } +} + +impl Decodable for f32 { + fn decode(d: &mut D) -> f32 { + d.read_f32() + } +} + +impl Encodable for f64 { + fn encode(&self, s: &mut S) { + s.emit_f64(*self) + } +} + +impl Decodable for f64 { + fn decode(d: &mut D) -> f64 { + d.read_f64() + } +} + +impl Encodable for bool { + fn encode(&self, s: &mut S) { + s.emit_bool(*self) + } +} + +impl Decodable for bool { + fn decode(d: &mut D) -> bool { + d.read_bool() + } +} + +impl Encodable for char { + fn encode(&self, s: &mut S) { + s.emit_char(*self) + } +} + +impl Decodable for char { + fn decode(d: &mut D) -> char { + d.read_char() + } +} + +impl Encodable for () { + fn encode(&self, s: &mut S) { + s.emit_nil() + } +} + +impl Decodable for () { + fn decode(d: &mut D) -> () { + d.read_nil() + } +} + +impl<'a, S:Encoder,T:Encodable> Encodable for &'a T { + fn encode(&self, s: &mut S) { + (**self).encode(s) + } +} + +impl> Encodable for ~T { + fn encode(&self, s: &mut S) { + (**self).encode(s) + } +} + +impl> Decodable for ~T { + fn decode(d: &mut D) -> ~T { + ~Decodable::decode(d) + } +} + +impl> Encodable for @T { + fn encode(&self, s: &mut S) { + (**self).encode(s) + } +} + +impl> Encodable for Rc { + #[inline] + fn encode(&self, s: &mut S) { + self.borrow().encode(s) + } +} + +impl> Decodable for Rc { + #[inline] + fn decode(d: &mut D) -> Rc { + Rc::new(Decodable::decode(d)) + } +} + +impl + 'static> Decodable for @T { + fn decode(d: &mut D) -> @T { + @Decodable::decode(d) + } +} + +impl<'a, S:Encoder,T:Encodable> Encodable for &'a [T] { + fn encode(&self, s: &mut S) { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + s.emit_seq_elt(i, |s| e.encode(s)) + } + }) + } +} + +impl> Encodable for ~[T] { + fn encode(&self, s: &mut S) { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + s.emit_seq_elt(i, |s| e.encode(s)) + } + }) + } +} + +impl> Decodable for ~[T] { + fn decode(d: &mut D) -> ~[T] { + d.read_seq(|d, len| { + vec::from_fn(len, |i| { + d.read_seq_elt(i, |d| Decodable::decode(d)) + }) + }) + } +} + +impl> Encodable for Option { + fn encode(&self, s: &mut S) { + s.emit_option(|s| { + match *self { + None => s.emit_option_none(), + Some(ref v) => s.emit_option_some(|s| v.encode(s)), + } + }) + } +} + +impl> Decodable for Option { + fn decode(d: &mut D) -> Option { + d.read_option(|d, b| { + if b { + Some(Decodable::decode(d)) + } else { + None + } + }) + } +} + +impl,T1:Encodable> Encodable for (T0, T1) { + fn encode(&self, s: &mut S) { + match *self { + (ref t0, ref t1) => { + s.emit_seq(2, |s| { + s.emit_seq_elt(0, |s| t0.encode(s)); + s.emit_seq_elt(1, |s| t1.encode(s)); + }) + } + } + } +} + +impl,T1:Decodable> Decodable for (T0, T1) { + fn decode(d: &mut D) -> (T0, T1) { + d.read_seq(|d, len| { + assert_eq!(len, 2); + ( + d.read_seq_elt(0, |d| Decodable::decode(d)), + d.read_seq_elt(1, |d| Decodable::decode(d)) + ) + }) + } +} + +impl< + S: Encoder, + T0: Encodable, + T1: Encodable, + T2: Encodable +> Encodable for (T0, T1, T2) { + fn encode(&self, s: &mut S) { + match *self { + (ref t0, ref t1, ref t2) => { + s.emit_seq(3, |s| { + s.emit_seq_elt(0, |s| t0.encode(s)); + s.emit_seq_elt(1, |s| t1.encode(s)); + s.emit_seq_elt(2, |s| t2.encode(s)); + }) + } + } + } +} + +impl< + D: Decoder, + T0: Decodable, + T1: Decodable, + T2: Decodable +> Decodable for (T0, T1, T2) { + fn decode(d: &mut D) -> (T0, T1, T2) { + d.read_seq(|d, len| { + assert_eq!(len, 3); + ( + d.read_seq_elt(0, |d| Decodable::decode(d)), + d.read_seq_elt(1, |d| Decodable::decode(d)), + d.read_seq_elt(2, |d| Decodable::decode(d)) + ) + }) + } +} + +impl< + S: Encoder, + T0: Encodable, + T1: Encodable, + T2: Encodable, + T3: Encodable +> Encodable for (T0, T1, T2, T3) { + fn encode(&self, s: &mut S) { + match *self { + (ref t0, ref t1, ref t2, ref t3) => { + s.emit_seq(4, |s| { + s.emit_seq_elt(0, |s| t0.encode(s)); + s.emit_seq_elt(1, |s| t1.encode(s)); + s.emit_seq_elt(2, |s| t2.encode(s)); + s.emit_seq_elt(3, |s| t3.encode(s)); + }) + } + } + } +} + +impl< + D: Decoder, + T0: Decodable, + T1: Decodable, + T2: Decodable, + T3: Decodable +> Decodable for (T0, T1, T2, T3) { + fn decode(d: &mut D) -> (T0, T1, T2, T3) { + d.read_seq(|d, len| { + assert_eq!(len, 4); + ( + d.read_seq_elt(0, |d| Decodable::decode(d)), + d.read_seq_elt(1, |d| Decodable::decode(d)), + d.read_seq_elt(2, |d| Decodable::decode(d)), + d.read_seq_elt(3, |d| Decodable::decode(d)) + ) + }) + } +} + +impl< + S: Encoder, + T0: Encodable, + T1: Encodable, + T2: Encodable, + T3: Encodable, + T4: Encodable +> Encodable for (T0, T1, T2, T3, T4) { + fn encode(&self, s: &mut S) { + match *self { + (ref t0, ref t1, ref t2, ref t3, ref t4) => { + s.emit_seq(5, |s| { + s.emit_seq_elt(0, |s| t0.encode(s)); + s.emit_seq_elt(1, |s| t1.encode(s)); + s.emit_seq_elt(2, |s| t2.encode(s)); + s.emit_seq_elt(3, |s| t3.encode(s)); + s.emit_seq_elt(4, |s| t4.encode(s)); + }) + } + } + } +} + +impl< + D: Decoder, + T0: Decodable, + T1: Decodable, + T2: Decodable, + T3: Decodable, + T4: Decodable +> Decodable for (T0, T1, T2, T3, T4) { + fn decode(d: &mut D) -> (T0, T1, T2, T3, T4) { + d.read_seq(|d, len| { + assert_eq!(len, 5); + ( + d.read_seq_elt(0, |d| Decodable::decode(d)), + d.read_seq_elt(1, |d| Decodable::decode(d)), + d.read_seq_elt(2, |d| Decodable::decode(d)), + d.read_seq_elt(3, |d| Decodable::decode(d)), + d.read_seq_elt(4, |d| Decodable::decode(d)) + ) + }) + } +} + +impl< + E: Encoder, + K: Encodable + Hash + IterBytes + Eq, + V: Encodable +> Encodable for HashMap { + fn encode(&self, e: &mut E) { + e.emit_map(self.len(), |e| { + let mut i = 0; + for (key, val) in self.iter() { + e.emit_map_elt_key(i, |e| key.encode(e)); + e.emit_map_elt_val(i, |e| val.encode(e)); + i += 1; + } + }) + } +} + +impl< + D: Decoder, + K: Decodable + Hash + IterBytes + Eq, + V: Decodable +> Decodable for HashMap { + fn decode(d: &mut D) -> HashMap { + d.read_map(|d, len| { + let mut map = HashMap::with_capacity(len); + for i in range(0u, len) { + let key = d.read_map_elt_key(i, |d| Decodable::decode(d)); + let val = d.read_map_elt_val(i, |d| Decodable::decode(d)); + map.insert(key, val); + } + map + }) + } +} + +impl< + S: Encoder, + T: Encodable + Hash + IterBytes + Eq +> Encodable for HashSet { + fn encode(&self, s: &mut S) { + s.emit_seq(self.len(), |s| { + let mut i = 0; + for e in self.iter() { + s.emit_seq_elt(i, |s| e.encode(s)); + i += 1; + } + }) + } +} + +impl< + D: Decoder, + T: Decodable + Hash + IterBytes + Eq +> Decodable for HashSet { + fn decode(d: &mut D) -> HashSet { + d.read_seq(|d, len| { + let mut set = HashSet::with_capacity(len); + for i in range(0u, len) { + set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))); + } + set + }) + } +} + +impl< + E: Encoder, + V: Encodable +> Encodable for TrieMap { + fn encode(&self, e: &mut E) { + e.emit_map(self.len(), |e| { + for (i, (key, val)) in self.iter().enumerate() { + e.emit_map_elt_key(i, |e| key.encode(e)); + e.emit_map_elt_val(i, |e| val.encode(e)); + } + }); + } +} + +impl< + D: Decoder, + V: Decodable +> Decodable for TrieMap { + fn decode(d: &mut D) -> TrieMap { + d.read_map(|d, len| { + let mut map = TrieMap::new(); + for i in range(0u, len) { + let key = d.read_map_elt_key(i, |d| Decodable::decode(d)); + let val = d.read_map_elt_val(i, |d| Decodable::decode(d)); + map.insert(key, val); + } + map + }) + } +} + +impl Encodable for TrieSet { + fn encode(&self, s: &mut S) { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + s.emit_seq_elt(i, |s| e.encode(s)); + } + }) + } +} + +impl Decodable for TrieSet { + fn decode(d: &mut D) -> TrieSet { + d.read_seq(|d, len| { + let mut set = TrieSet::new(); + for i in range(0u, len) { + set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))); + } + set + }) + } +} + +// ___________________________________________________________________________ +// Helper routines +// +// In some cases, these should eventually be coded as traits. + +pub trait EncoderHelpers { + fn emit_from_vec(&mut self, v: &[T], f: |&mut Self, v: &T|); +} + +impl EncoderHelpers for S { + fn emit_from_vec(&mut self, v: &[T], f: |&mut S, &T|) { + self.emit_seq(v.len(), |this| { + for (i, e) in v.iter().enumerate() { + this.emit_seq_elt(i, |this| { + f(this, e) + }) + } + }) + } +} + +pub trait DecoderHelpers { + fn read_to_vec(&mut self, f: |&mut Self| -> T) -> ~[T]; +} + +impl DecoderHelpers for D { + fn read_to_vec(&mut self, f: |&mut D| -> T) -> ~[T] { + self.read_seq(|this, len| { + vec::from_fn(len, |i| { + this.read_seq_elt(i, |this| f(this)) + }) + }) + } +} diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 228329cbda1..abfd119acbb 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -22,7 +22,7 @@ use std::hashmap::HashMap; use std::option::Option; use std::rc::Rc; use std::to_str::ToStr; -use extra::serialize::{Encodable, Decodable, Encoder, Decoder}; +use serialize::{Encodable, Decodable, Encoder, Decoder}; /// A pointer abstraction. FIXME(eddyb) #10676 use Rc in the future. pub type P = @T; @@ -1204,6 +1204,7 @@ pub enum InlinedItem { #[cfg(test)] mod test { + use serialize; use extra; use codemap::*; use super::*; @@ -1230,6 +1231,6 @@ mod test { }, }; // doesn't matter which encoder we use.... - let _f = (@e as @extra::serialize::Encodable); + let _f = (@e as @serialize::Encodable); } } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 2ada3ac16ea..a6c1a373d88 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -23,7 +23,7 @@ source code snippets, etc. use std::cell::RefCell; use std::cmp; -use extra::serialize::{Encodable, Decodable, Encoder, Decoder}; +use serialize::{Encodable, Decodable, Encoder, Decoder}; pub trait Pos { fn from_uint(n: uint) -> Self; diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index 019a4dfe7cc..ad7b3a2e950 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -28,12 +28,12 @@ pub fn expand_deriving_decodable(cx: &ExtCtxt, let trait_def = TraitDef { cx: cx, span: span, - path: Path::new_(~["extra", "serialize", "Decodable"], None, + path: Path::new_(~["serialize", "Decodable"], None, ~[~Literal(Path::new_local("__D"))], true), additional_bounds: ~[], generics: LifetimeBounds { lifetimes: ~[], - bounds: ~[("__D", ~[Path::new(~["extra", "serialize", "Decoder"])])], + bounds: ~[("__D", ~[Path::new(~["serialize", "Decoder"])])], }, methods: ~[ MethodDef { @@ -56,8 +56,7 @@ pub fn expand_deriving_decodable(cx: &ExtCtxt, fn decodable_substructure(cx: &ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr { let decoder = substr.nonself_args[0]; - let recurse = ~[cx.ident_of("extra"), - cx.ident_of("serialize"), + let recurse = ~[cx.ident_of("serialize"), cx.ident_of("Decodable"), cx.ident_of("decode")]; // throw an underscore in front to suppress unused variable warnings diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index c50c9f18389..66b744ecbcb 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -22,7 +22,7 @@ For example, a type like: would generate two implementations like: -impl Encodable for Node { +impl Encodable for Node { fn encode(&self, s: &S) { s.emit_struct("Node", 1, || { s.emit_field("id", 0, || s.emit_uint(self.id)) @@ -89,12 +89,12 @@ pub fn expand_deriving_encodable(cx: &ExtCtxt, let trait_def = TraitDef { cx: cx, span: span, - path: Path::new_(~["extra", "serialize", "Encodable"], None, + path: Path::new_(~["serialize", "Encodable"], None, ~[~Literal(Path::new_local("__E"))], true), additional_bounds: ~[], generics: LifetimeBounds { lifetimes: ~[], - bounds: ~[("__E", ~[Path::new(~["extra", "serialize", "Encoder"])])], + bounds: ~[("__E", ~[Path::new(~["serialize", "Encoder"])])], }, methods: ~[ MethodDef { diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index 8eaff592765..992ee3175ed 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -204,7 +204,7 @@ pub struct TraitDef<'a> { /// other than the current trait additional_bounds: ~[Ty<'a>], - /// Any extra lifetimes and/or bounds, e.g. `D: extra::serialize::Decoder` + /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder` generics: LifetimeBounds<'a>, methods: ~[MethodDef<'a>] diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index bcad19f2122..3f305a4eb0e 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -33,6 +33,7 @@ This API is completely unstable and subject to change. #[deny(non_camel_case_types)]; extern mod extra; +extern mod serialize; extern mod term; pub mod util { diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 328f0e7f221..faebd97e7c2 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -284,7 +284,7 @@ pub fn maybe_aborted(result: T, mut p: Parser) -> T { #[cfg(test)] mod test { use super::*; - use extra::serialize::Encodable; + use serialize::Encodable; use extra; use std::io; use std::io::MemWriter; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index f1dd844fc7c..090774ec76f 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -15,7 +15,7 @@ use parse::token; use util::interner::{RcStr, StrInterner}; use util::interner; -use extra::serialize::{Decodable, Decoder, Encodable, Encoder}; +use serialize::{Decodable, Decoder, Encodable, Encoder}; use std::cast; use std::char; use std::fmt; diff --git a/src/libuuid/lib.rs b/src/libuuid/lib.rs index 60e69af324e..1951c52237f 100644 --- a/src/libuuid/lib.rs +++ b/src/libuuid/lib.rs @@ -59,7 +59,10 @@ Examples of string representations: #[crate_type = "dylib"]; #[license = "MIT/ASL2"]; +// test harness access +#[cfg(test)] extern mod extra; +extern mod serialize; use std::str; use std::vec; @@ -73,7 +76,7 @@ use std::cmp::Eq; use std::cast::{transmute,transmute_copy}; use std::to_bytes::{IterBytes, Cb}; -use extra::serialize::{Encoder, Encodable, Decoder, Decodable}; +use serialize::{Encoder, Encodable, Decoder, Decodable}; /// A 128-bit (16 byte) buffer containing the ID pub type UuidBytes = [u8, ..16]; @@ -784,8 +787,8 @@ mod test { #[test] fn test_serialize_round_trip() { - use extra::ebml; - use extra::serialize::{Encodable, Decodable}; + use serialize::ebml; + use serialize::{Encodable, Decodable}; let u = Uuid::new_v4(); let mut wr = MemWriter::new(); diff --git a/src/test/run-pass/auto-encode.rs b/src/test/run-pass/auto-encode.rs index f3af7d652cd..027b329b178 100644 --- a/src/test/run-pass/auto-encode.rs +++ b/src/test/run-pass/auto-encode.rs @@ -26,7 +26,7 @@ use EBWriter = extra::ebml::writer; use std::cmp::Eq; use std::cmp; use std::io; -use extra::serialize::{Decodable, Encodable}; +use serialize::{Decodable, Encodable}; use extra::time; fn test_ebml<'a, A: diff --git a/src/test/run-pass/deriving-encodable-decodable.rs b/src/test/run-pass/deriving-encodable-decodable.rs index 444790bcce9..dedacd92535 100644 --- a/src/test/run-pass/deriving-encodable-decodable.rs +++ b/src/test/run-pass/deriving-encodable-decodable.rs @@ -16,14 +16,14 @@ #[feature(struct_variant, managed_boxes)]; -extern mod extra; +extern mod serialize; use std::io::MemWriter; use std::rand::{random, Rand}; -use extra::serialize::{Encodable, Decodable}; -use extra::ebml; -use extra::ebml::writer::Encoder; -use extra::ebml::reader::Decoder; +use serialize::{Encodable, Decodable}; +use serialize::ebml; +use serialize::ebml::writer::Encoder; +use serialize::ebml::reader::Decoder; #[deriving(Encodable, Decodable, Eq, Rand)] struct A; diff --git a/src/test/run-pass/deriving-global.rs b/src/test/run-pass/deriving-global.rs index ce51e2dcd70..a7a3784877c 100644 --- a/src/test/run-pass/deriving-global.rs +++ b/src/test/run-pass/deriving-global.rs @@ -11,7 +11,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern mod extra; // {En,De}codable +extern mod serialize; // {En,De}codable mod submod { // if any of these are implemented without global calls for any // function calls, then being in a submodule will (correctly) diff --git a/src/test/run-pass/issue-4016.rs b/src/test/run-pass/issue-4016.rs index c1f40d302c8..87a52de2269 100644 --- a/src/test/run-pass/issue-4016.rs +++ b/src/test/run-pass/issue-4016.rs @@ -9,10 +9,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-fast + extern mod extra; +extern mod serialize; use extra::json; -use extra::serialize::Decodable; +use serialize::Decodable; trait JD : Decodable { } diff --git a/src/test/run-pass/issue-4036.rs b/src/test/run-pass/issue-4036.rs index 5665bff571e..b746e524d7f 100644 --- a/src/test/run-pass/issue-4036.rs +++ b/src/test/run-pass/issue-4036.rs @@ -8,15 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-fast + // Issue #4036: Test for an issue that arose around fixing up type inference // byproducts in vtable records. extern mod extra; -use self::extra::json; -use self::extra::serialize; +extern mod serialize; +use extra::json; +use serialize::Decodable; pub fn main() { let json = json::from_str("[1]").unwrap(); let mut decoder = json::Decoder::new(json); - let _x: ~[int] = serialize::Decodable::decode(&mut decoder); + let _x: ~[int] = Decodable::decode(&mut decoder); } -- cgit 1.4.1-3-g733a5