Bug 1473266 - Remove in-tree newline_if_not_empty. r=Yoric,glandium
authorTooru Fujisawa <arai_a@mac.com>
Thu, 26 Jul 2018 15:24:06 +0900
changeset 483633 4a8c948386952cc801a93d60f0eee6c161bd1105
parent 483632 2a31d9153471c831fb251ab5c57064c793d9f98a
child 483634 5d4ad6db1723f3d17bca98a9c0599ed5e7185769
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersYoric, glandium
bugs1473266
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1473266 - Remove in-tree newline_if_not_empty. r=Yoric,glandium
Cargo.lock
js/src/frontend/BinToken.h
js/src/frontend/binsource/Cargo.toml
js/src/frontend/binsource/src/main.rs
third_party/rust/binjs_meta/.cargo-checksum.json
third_party/rust/binjs_meta/Cargo.toml
third_party/rust/binjs_meta/examples/generate_spidermonkey.rs
third_party/rust/binjs_meta/src/export.rs
third_party/rust/binjs_meta/src/import.rs
third_party/rust/binjs_meta/src/util.rs
third_party/rust/itertools-0.6.5/.cargo-checksum.json
third_party/rust/itertools-0.6.5/.travis.yml
third_party/rust/itertools-0.6.5/Cargo.toml
third_party/rust/itertools-0.6.5/LICENSE-APACHE
third_party/rust/itertools-0.6.5/LICENSE-MIT
third_party/rust/itertools-0.6.5/Makefile
third_party/rust/itertools-0.6.5/README.rst
third_party/rust/itertools-0.6.5/benches/bench1.rs
third_party/rust/itertools-0.6.5/benches/extra/mod.rs
third_party/rust/itertools-0.6.5/benches/extra/zipslices.rs
third_party/rust/itertools-0.6.5/benches/tuple_combinations.rs
third_party/rust/itertools-0.6.5/benches/tuples.rs
third_party/rust/itertools-0.6.5/custom.css
third_party/rust/itertools-0.6.5/examples/iris.data
third_party/rust/itertools-0.6.5/examples/iris.rs
third_party/rust/itertools-0.6.5/src/adaptors/mod.rs
third_party/rust/itertools-0.6.5/src/adaptors/multipeek.rs
third_party/rust/itertools-0.6.5/src/concat_impl.rs
third_party/rust/itertools-0.6.5/src/cons_tuples_impl.rs
third_party/rust/itertools-0.6.5/src/diff.rs
third_party/rust/itertools-0.6.5/src/format.rs
third_party/rust/itertools-0.6.5/src/free.rs
third_party/rust/itertools-0.6.5/src/groupbylazy.rs
third_party/rust/itertools-0.6.5/src/impl_macros.rs
third_party/rust/itertools-0.6.5/src/intersperse.rs
third_party/rust/itertools-0.6.5/src/kmerge_impl.rs
third_party/rust/itertools-0.6.5/src/lib.rs
third_party/rust/itertools-0.6.5/src/minmax.rs
third_party/rust/itertools-0.6.5/src/pad_tail.rs
third_party/rust/itertools-0.6.5/src/peeking_take_while.rs
third_party/rust/itertools-0.6.5/src/process_results_impl.rs
third_party/rust/itertools-0.6.5/src/rciter_impl.rs
third_party/rust/itertools-0.6.5/src/repeatn.rs
third_party/rust/itertools-0.6.5/src/size_hint.rs
third_party/rust/itertools-0.6.5/src/sources.rs
third_party/rust/itertools-0.6.5/src/tee.rs
third_party/rust/itertools-0.6.5/src/tuple_impl.rs
third_party/rust/itertools-0.6.5/src/with_position.rs
third_party/rust/itertools-0.6.5/src/zip_eq_impl.rs
third_party/rust/itertools-0.6.5/src/zip_longest.rs
third_party/rust/itertools-0.6.5/src/ziptuple.rs
third_party/rust/itertools-0.6.5/tests/peeking_take_while.rs
third_party/rust/itertools-0.6.5/tests/quick.rs
third_party/rust/itertools-0.6.5/tests/tests.rs
third_party/rust/itertools-0.6.5/tests/tuples.rs
third_party/rust/itertools-0.6.5/tests/zip.rs
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -176,30 +176,30 @@ dependencies = [
  "proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "which 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "binjs_meta"
-version = "0.3.6"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "Inflector 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "webidl 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "binsource"
 version = "0.1.0"
 dependencies = [
- "binjs_meta 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "binjs_meta 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "webidl 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "yaml-rust 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -944,24 +944,16 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "itertools"
-version = "0.6.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "itertools"
 version = "0.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "itoa"
@@ -2546,17 +2538,17 @@ dependencies = [
 "checksum ascii-canvas 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b385d69402821a1c254533a011a312531cbcc0e3e24f19bbb4747a5a2daf37e2"
 "checksum atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21"
 "checksum atty 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d0fd4c0631f06448cc45a6bbb3b710ebb7ff8ccb96a0800c994afe23a70d5df2"
 "checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
 "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9"
 "checksum binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88ceb0d16c4fd0e42876e298d7d3ce3780dd9ebdcbe4199816a32c77e08597ff"
 "checksum bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bda13183df33055cbb84b847becce220d392df502ebe7a4a78d7021771ed94d0"
 "checksum bindgen 0.37.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1b25ab82877ea8fe6ce1ce1f8ac54361f0218bad900af9eb11803994bf67c221"
-"checksum binjs_meta 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9fcfc86eecb125147e907529a5f1ac7978f6f26d20a52b82a7e053da5faefbc3"
+"checksum binjs_meta 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fd7ca5635f1c6f94aaef7de76cb834c5920578355ce41dbcaf731b7ebe348518"
 "checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c"
 "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f"
 "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
 "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
 "checksum bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80b13e2ab064ff3aa0bdbf1eff533f9822dc37899821f5f98c67f263eab51707"
 "checksum boxfnonce 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8380105befe91099e6f69206164072c05bc92427ff6aa8a5171388317346dd75"
 "checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9"
 "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
@@ -2622,17 +2614,16 @@ dependencies = [
 "checksum gleam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d41e7ac812597988fdae31c9baec3c6d35cadb8ad9ab88a9bf9c0f119ed66c2"
 "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
 "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07"
 "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
 "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2"
 "checksum ident_case 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9826188e666f2ed92071d2dadef6edc430b11b158b5b2b3f4babbcc891eaaa"
 "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
 "checksum iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29d062ee61fccdf25be172e70f34c9f6efc597e1fb8f6526e8437b2046ab26be"
-"checksum itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3f2be4da1690a039e9ae5fd575f706a63ad5a2120f161b1d653c9da3930dd21"
 "checksum itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b07332223953b5051bceb67e8c4700aa65291535568e1f12408c43c4a42c0394"
 "checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
 "checksum khronos_api 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "037ab472c33f67b5fbd3e9163a2645319e5356fcd355efa6d4eb7fff4bbcb554"
 "checksum lalrpop 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88035943c3cfbb897a499a556212b2b053574f32b4238b71b61625bc470f80aa"
 "checksum lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4fd87be4a815fd373e02773983940f0d75fb26fde8c098e9e45f7af03154c0"
 "checksum lalrpop-snap 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f244285324e4e33d486910b66fd3b7cb37e2072c5bf63319f506fe99ed72650"
 "checksum lalrpop-util 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "de408fd50dea8ad7a77107144983a25c7fdabf5f8faf707a6e020d68874ed06c"
--- a/js/src/frontend/BinToken.h
+++ b/js/src/frontend/BinToken.h
@@ -269,17 +269,17 @@ const size_t BINKIND_LIMIT = 183;
  * ```c++
  * #define WITH_VARIANT(CPP_NAME, SPEC_NAME) ...
  * FOR_EACH_BIN_VARIANT(WITH_VARIANT)
  * ```
  *
  * (sorted by alphabetical order)
  */
 #define FOR_EACH_BIN_FIELD(F) \
-    F(Offset, "_offset") \
+    F(Skip, "_skip") \
     F(Alternate, "alternate") \
     F(Arguments, "arguments") \
     F(Binding, "binding") \
     F(BindingScope, "bindingScope") \
     F(Body, "body") \
     F(BodyScope, "bodyScope") \
     F(Callee, "callee") \
     F(CapturedNames, "capturedNames") \
--- a/js/src/frontend/binsource/Cargo.toml
+++ b/js/src/frontend/binsource/Cargo.toml
@@ -1,13 +1,13 @@
 [package]
 name = "binsource"
 version = "0.1.0"
 authors = ["David Teller <D.O.Teller@gmail.com>"]
 
 [dependencies]
-binjs_meta = "^0.3.6"
+binjs_meta = "^0.3.8"
 clap = "^2"
 env_logger = "^0.5.6"
 itertools = "^0.7.6"
 log = "0.4.1"
 yaml-rust = "^0.4"
 webidl = "^0.6.0"
--- a/js/src/frontend/binsource/src/main.rs
+++ b/js/src/frontend/binsource/src/main.rs
@@ -16,32 +16,16 @@ use std::fs::*;
 use std::io::{ Read, Write };
 use std::path::Path;
 use std::rc::Rc;
 
 use clap::{ App, Arg };
 
 use itertools::Itertools;
 
-/// A string or string-like construction that can be appended newline.
-trait NewLineIfNotEmpty {
-    /// Append newline if the string is not empty.
-    fn newline_if_not_empty(&self) -> String;
-}
-impl<T> NewLineIfNotEmpty for T where T: ToStr {
-    fn newline_if_not_empty(&self) -> String {
-        let str = self.to_str();
-        if str.len() == 0 {
-            "".to_string()
-        } else {
-            format!("{}\n", str)
-        }
-    }
-}
-
 /// Rules for generating the code for parsing a single field
 /// of a node.
 ///
 /// Extracted from the yaml file.
 #[derive(Clone, Default)]
 struct FieldRules {
     /// Declaring the variable to hold the contents of that field.
     declare: Option<String>,
--- a/third_party/rust/binjs_meta/.cargo-checksum.json
+++ b/third_party/rust/binjs_meta/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"9e018f77dc9cd8ba5c268eedd0fe34a3b6a5b68a660a9adf223d9227d2db853e","README.md":"17e5ed3a3bd9b898e73c3056711daabe1238fe9682d24d255f8263fae4eb783d","examples/generate_spidermonkey.rs":"e65aeec6bc288bba720c51e5af1f9034245b019bd637b265982d1c156e04dde4","src/export.rs":"1ee8b16339d34519ecae745ce22f5ee970a1fdfa3b4326e94876bbac25e2b918","src/import.rs":"3c1d2faf80636ff55913b300f0bfcda650ed71e4ee7ab7d9acf31ebf388b436a","src/lib.rs":"d4ea18ec850054a817c6b91ed52412a2f2f39639628e5918dee688d829d3ed4b","src/spec.rs":"15a22ecea4dc3473e34c6cfe121e95edb1a83cfa5e264245e10d19f68456ac72","src/util.rs":"f38a09cee2260912a849968d89dc76f6d01abcd41fbc01138001b86579a5b408"},"package":"9fcfc86eecb125147e907529a5f1ac7978f6f26d20a52b82a7e053da5faefbc3"}
\ No newline at end of file
+{"files":{"Cargo.toml":"e32d2641e2dcfeda5cd201df66d5910e5e37fb59b2bc84e82dbf14b53dcb52f1","README.md":"17e5ed3a3bd9b898e73c3056711daabe1238fe9682d24d255f8263fae4eb783d","examples/generate_spidermonkey.rs":"a831abf8d7a1ab73c5d70a9e8517b8af1df492589a2f180698145ac5d46d7102","src/export.rs":"dba92bc4864178b0265e954334303e156827edb9585ce0640ac866c0aff0c9f4","src/import.rs":"50c9e2a399286f0bd86e5fef9f1c8968564cb1db75a86a7472f2f59fd17247d3","src/lib.rs":"d4ea18ec850054a817c6b91ed52412a2f2f39639628e5918dee688d829d3ed4b","src/spec.rs":"15a22ecea4dc3473e34c6cfe121e95edb1a83cfa5e264245e10d19f68456ac72","src/util.rs":"1d934eec75d9dee44289f9a9a9e67c96dd6205367430b9bcf9fc66e730bf6eb0"},"package":"fd7ca5635f1c6f94aaef7de76cb834c5920578355ce41dbcaf731b7ebe348518"}
\ No newline at end of file
--- a/third_party/rust/binjs_meta/Cargo.toml
+++ b/third_party/rust/binjs_meta/Cargo.toml
@@ -7,30 +7,30 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "binjs_meta"
-version = "0.3.6"
+version = "0.3.8"
 authors = ["David Teller <D.O.Teller@gmail.com>"]
 description = "Part of binjs-ref. Tools for manipulating grammars. You probably do not want to use this crate directly unless you're writing an encoder, decoder or parser generator for binjs."
 homepage = "https://binast.github.io/ecmascript-binary-ast/"
 readme = "README.md"
 keywords = ["javascript", "js", "binjs", "ast"]
 categories = ["compression", "parsing", "web-programming"]
 license = "MIT"
 repository = "https://github.com/binast/binjs-ref"
 [dependencies.Inflector]
 version = "^0.11"
 
 [dependencies.itertools]
-version = "^0.6"
+version = "^0.7"
 
 [dependencies.log]
 version = "^0.4"
 
 [dependencies.webidl]
 version = "^0.6"
 [dev-dependencies.clap]
 version = "^2"
--- a/third_party/rust/binjs_meta/examples/generate_spidermonkey.rs
+++ b/third_party/rust/binjs_meta/examples/generate_spidermonkey.rs
@@ -1,254 +1,433 @@
+// !!!! WARNING !!!!
+// This is a snapshot of the code generator for SpiderMonkey, for demonstrating
+// how to use binjs_meta crate in order to generate a parser.
+//
+// The latest version of this code is available as
+// js/src/frontend/binsource/src/main.rs in the following repository:
+//   https://hg.mozilla.org/mozilla-central/
+
 extern crate binjs_meta;
 extern crate clap;
 extern crate env_logger;
 extern crate itertools;
 #[macro_use] extern crate log;
 extern crate webidl;
 extern crate yaml_rust;
 
-use binjs_meta::export::{ TypeDeanonymizer, TypeName };
+use binjs_meta::export::{ ToWebidl, TypeDeanonymizer, TypeName };
 use binjs_meta::import::Importer;
 use binjs_meta::spec::*;
-use binjs_meta::util::*;
+use binjs_meta::util:: { Reindentable, ToCases, ToStr };
 
 use std::collections::{ HashMap, HashSet };
 use std::fs::*;
-use std::io::*;
+use std::io::{ Read, Write };
 
-use clap::*;
+use clap::{ App, Arg };
 
 use itertools::Itertools;
 
+/// Rules for generating the code for parsing a single field
+/// of a node.
+///
+/// Extracted from the yaml file.
 #[derive(Clone, Default)]
-pub struct FieldParsingRules {
-    pub declare: Option<String>,
+struct FieldRules {
+    /// Declaring the variable to hold the contents of that field.
+    declare: Option<String>,
+
     /// Replace the declaration and assignation.
-    pub replace: Option<String>,
-    pub before_field: Option<String>,
-    pub after_field: Option<String>,
-    pub block_before_field: Option<String>,
-    pub block_after_field: Option<String>,
+    replace: Option<String>,
+
+    /// Things to add before the field, typically for checking invariants.
+    before_field: Option<String>,
+
+    /// Things to add after the field, typically for checking invariants.
+    after_field: Option<String>,
+
+    /// Things to add before the field, as part of a block, typically for
+    /// putting guard values on the stack.
+    block_before_field: Option<String>,
+
+    /// Things to add before the field, as part of a block, typically for
+    /// cleanup.
+    block_after_field: Option<String>,
 }
+
+/// Rules for generating the code for parsing a full node
+/// of a node.
+///
+/// Extracted from the yaml file.
 #[derive(Clone, Default)]
-pub struct NodeParsingRules {
+struct NodeRules {
     /// This node inherits from another node.
-    pub inherits: Option<NodeName>,
+    inherits: Option<NodeName>,
 
     /// Override the result type for the method.
-    pub type_ok: Option<String>,
+    type_ok: Option<String>,
 
-    pub start: Option<String>,
+    /// Stuff to add at start.
+    init: Option<String>,
 
-    /// Append to a list. Used only for lists.
-    pub append: Option<String>,
+    /// How to append to a list. Used only for lists.
+    append: Option<String>,
 
     /// Custom per-field treatment. Used only for interfaces.
-    pub by_field: HashMap<FieldName, FieldParsingRules>,
-    pub build_result: Option<String>,
+    by_field: HashMap<FieldName, FieldRules>,
+
+    /// How to build the result, eventually.
+    build_result: Option<String>,
+}
+
+/// Rules for generating entire files.
+///
+/// Extracted from the yaml file.
+#[derive(Default)]
+struct GlobalRules {
+    /// Header to add at the start of the .cpp file.
+    cpp_header: Option<String>,
+
+    /// Header to add at the end of the .cpp file.
+    cpp_footer: Option<String>,
+
+    /// Header to add at the start of the .hpp file
+    /// defining the class data/methods.
+    hpp_class_header: Option<String>,
+
+    /// Header to add at the start of the .hpp file.
+    /// defining the tokens.
+    hpp_tokens_header: Option<String>,
+
+    /// Footer to add at the start of the .hpp file.
+    /// defining the tokens.
+    hpp_tokens_footer: Option<String>,
+
+    /// Documentation for the `BinKind` class enum.
+    hpp_tokens_kind_doc: Option<String>,
+
+    /// Documentation for the `BinField` class enum.
+    hpp_tokens_field_doc: Option<String>,
+
+    /// Documentation for the `BinVariant` class enum.
+    hpp_tokens_variants_doc: Option<String>,
+
+    /// Per-node rules.
+    per_node: HashMap<NodeName, NodeRules>,
 }
-impl GenerationRules {
-    fn get(&self, name: &NodeName) -> NodeParsingRules {
+impl GlobalRules {
+    fn new(syntax: &Spec, yaml: &yaml_rust::yaml::Yaml) -> Self {
+        let rules = yaml.as_hash()
+            .expect("Rules are not a dictionary");
+
+        let mut cpp_header = None;
+        let mut cpp_footer = None;
+        let mut hpp_class_header = None;
+        let mut hpp_tokens_header = None;
+        let mut hpp_tokens_footer = None;
+        let mut hpp_tokens_kind_doc = None;
+        let mut hpp_tokens_field_doc = None;
+        let mut hpp_tokens_variants_doc = None;
+        let mut per_node = HashMap::new();
+
+        for (node_key, node_entries) in rules.iter() {
+            let node_key = node_key.as_str()
+                .expect("Could not convert node_key to string");
+
+            match node_key {
+                "cpp" => {
+                    update_rule(&mut cpp_header, &node_entries["header"])
+                        .unwrap_or_else(|_| panic!("Rule cpp.header must be a string"));
+                    update_rule(&mut cpp_footer, &node_entries["footer"])
+                        .unwrap_or_else(|_| panic!("Rule cpp.footer must be a string"));
+                    continue;
+                }
+                "hpp" => {
+                    update_rule(&mut hpp_class_header, &node_entries["class"]["header"])
+                        .unwrap_or_else(|_| panic!("Rule hpp.class.header must be a string"));
+                    update_rule(&mut hpp_tokens_header, &node_entries["tokens"]["header"])
+                        .unwrap_or_else(|_| panic!("Rule hpp.tokens.header must be a string"));
+                    update_rule(&mut hpp_tokens_footer, &node_entries["tokens"]["footer"])
+                        .unwrap_or_else(|_| panic!("Rule hpp.tokens.footer must be a string"));
+                    update_rule(&mut hpp_tokens_kind_doc, &node_entries["tokens"]["kind"]["doc"])
+                        .unwrap_or_else(|_| panic!("Rule hpp.tokens.kind.doc must be a string"));
+                    update_rule(&mut hpp_tokens_field_doc, &node_entries["tokens"]["field"]["doc"])
+                        .unwrap_or_else(|_| panic!("Rule hpp.tokens.field.doc must be a string"));
+                    update_rule(&mut hpp_tokens_variants_doc, &node_entries["tokens"]["variants"]["doc"])
+                        .unwrap_or_else(|_| panic!("Rule hpp.tokens.variants.doc must be a string"));
+                    continue;
+                }
+                _ => {}
+            }
+
+
+            let node_name = syntax.get_node_name(&node_key)
+                .unwrap_or_else(|| panic!("Unknown node name {}", node_key));
+
+            let hash = node_entries.as_hash()
+                .unwrap_or_else(|| panic!("Node {} isn't a dictionary"));
+
+            let mut node_rule = NodeRules::default();
+            for (node_item_key, node_item_entry) in hash {
+                let as_string = node_item_key.as_str()
+                    .unwrap_or_else(|| panic!("Keys for rule {} must be strings", node_key));
+                match as_string {
+                    "inherits" => {
+                        let name = node_item_entry.as_str()
+                            .unwrap_or_else(|| panic!("Rule {}.{} must be a string", node_key, as_string));
+                        let inherits = syntax.get_node_name(name)
+                            .unwrap_or_else(|| panic!("Unknown node name {}", node_key));
+                        node_rule.inherits = Some(inherits).cloned();
+                    }
+                    "init" => {
+                        update_rule(&mut node_rule.init, node_item_entry)
+                            .unwrap_or_else(|()| panic!("Rule {}.{} must be a string", node_key, as_string));
+                    }
+                    "build" => {
+                        update_rule(&mut node_rule.build_result, node_item_entry)
+                            .unwrap_or_else(|()| panic!("Rule {}.{} must be a string", node_key, as_string));
+                    }
+                    "append" => {
+                        update_rule(&mut node_rule.append, node_item_entry)
+                            .unwrap_or_else(|()| panic!("Rule {}.{} must be a string", node_key, as_string));
+                    }
+                    "type-ok" => {
+                        update_rule(&mut node_rule.type_ok, node_item_entry)
+                            .unwrap_or_else(|()| panic!("Rule {}.{} must be a string", node_key, as_string));
+                    }
+                    "fields" => {
+                        let fields = node_item_entry.as_hash()
+                            .unwrap_or_else(|| panic!("Rule {}.fields must be a hash, got {:?}", node_key, node_entries["fields"]));
+                        for (field_key, field_entry) in fields {
+                            let field_key = field_key.as_str()
+                                .unwrap_or_else(|| panic!("In rule {}, field entries must be field names",
+                                    node_key))
+                                .to_string();
+                            let field_name = syntax.get_field_name(&field_key)
+                                .unwrap_or_else(|| panic!("In rule {}, can't find field {}",
+                                    node_key,
+                                    field_key));
+
+                            let mut field_rule = FieldRules::default();
+                            for (field_config_key, field_config_entry) in field_entry.as_hash()
+                                .unwrap_or_else(|| panic!("Rule {}.fields.{} must be a hash", node_key, field_key))
+                            {
+                                let field_config_key = field_config_key.as_str()
+                                    .expect("Expected a string as a key");
+                                match field_config_key
+                                {
+                                    "block" => {
+                                        update_rule(&mut field_rule.declare, &field_config_entry["declare"])
+                                            .unwrap_or_else(|()| panic!("Rule {}.fields.{}.{}.{} must be a string", node_key, field_key, field_config_key, "declare"));
+
+                                        update_rule(&mut field_rule.replace, &field_config_entry["replace"])
+                                            .unwrap_or_else(|()| panic!("Rule {}.fields.{}.{}.{} must be a string", node_key, field_key, field_config_key, "replace"));
+
+                                        update_rule(&mut field_rule.block_before_field, &field_config_entry["before"])
+                                            .unwrap_or_else(|()| panic!("Rule {}.fields.{}.{}.{} must be a string", node_key, field_key, field_config_key, "before"));
+
+                                        update_rule(&mut field_rule.block_after_field, &field_config_entry["after"])
+                                            .unwrap_or_else(|()| panic!("Rule {}.fields.{}.{}.{} must be a string", node_key, field_key, field_config_key, "after"));
+                                    }
+                                    "before" => {
+                                        update_rule(&mut field_rule.before_field, &field_config_entry)
+                                            .unwrap_or_else(|()| panic!("Rule {}.fields.{}.{} must be a string", node_key, field_key, field_config_key));
+                                    }
+                                    "after" => {
+                                        update_rule(&mut field_rule.after_field, &field_config_entry)
+                                            .unwrap_or_else(|()| panic!("Rule {}.fields.{}.{} must be a string", node_key, field_key, field_config_key));
+                                    }
+                                    _ => {
+                                        panic!("Unexpected {}.fields.{}.{}", node_key, field_key, field_config_key)
+                                    }
+                                }
+                            }
+                            node_rule.by_field.insert(field_name.clone(), field_rule);
+                        }
+                    }
+                    _ => panic!("Unexpected node_item_key {}.{}", node_key, as_string)
+                }
+            }
+
+            per_node.insert(node_name.clone(), node_rule);
+        }
+
+        Self {
+            cpp_header,
+            cpp_footer,
+            hpp_class_header,
+            hpp_tokens_header,
+            hpp_tokens_footer,
+            hpp_tokens_kind_doc,
+            hpp_tokens_field_doc,
+            hpp_tokens_variants_doc,
+            per_node,
+        }
+    }
+    fn get(&self, name: &NodeName) -> NodeRules {
         let mut rules = self.per_node.get(name)
             .cloned()
             .unwrap_or_default();
-        let inherits = rules.inherits.clone();
-        if let Some(ref parent) = inherits {
-            let NodeParsingRules {
-                inherits,
+        if let Some(ref parent) = rules.inherits {
+            let NodeRules {
+                inherits: _,
                 type_ok,
-                start,
+                init,
                 append,
                 by_field,
                 build_result,
             } = self.get(parent);
-            if rules.inherits.is_none() {
-                rules.inherits = inherits;
-            }
             if rules.type_ok.is_none() {
                 rules.type_ok = type_ok;
             }
-            if rules.start.is_none() {
-                rules.start = start;
+            if rules.init.is_none() {
+                rules.init = init;
             }
             if rules.append.is_none() {
                 rules.append = append;
             }
             if rules.build_result.is_none() {
                 rules.build_result = build_result;
             }
             for (key, value) in by_field {
                 rules.by_field.entry(key)
                     .or_insert(value);
             }
         }
         rules
     }
 }
-#[derive(Default)]
-pub struct GenerationRules {
-    cpp_header: Option<String>,
-    cpp_footer: Option<String>,
-    hpp_class_header: Option<String>,
-    hpp_tokens_header: Option<String>,
-    hpp_tokens_footer: Option<String>,
-    hpp_tokens_kind_doc: Option<String>,
-    hpp_tokens_field_doc: Option<String>,
-    hpp_tokens_variant_doc: Option<String>,
-    per_node: HashMap<NodeName, NodeParsingRules>,
+
+/// The inforamtion used to generate a list parser.
+struct ListParserData {
+    /// Name of the node.
+    name: NodeName,
+
+    /// If `true`, supports empty lists.
+    supports_empty: bool,
+
+    /// Name of the elements in the list.
+    elements: NodeName,
 }
 
-struct ToWebidl;
-impl ToWebidl {
-    pub fn spec(spec: &TypeSpec, prefix: &str, indent: &str) -> String {
-        match *spec {
-            TypeSpec::Array { ref contents, supports_empty: false } =>
-                format!("[NonEmpty] FrozenArray<{}>", Self::type_(&*contents, prefix, indent)),
-            TypeSpec::Array { ref contents, supports_empty: true } =>
-                format!("FrozenArray<{}>", Self::type_(&*contents, prefix, indent)),
-            TypeSpec::Offset =>
-                "offset".to_string(),
-            TypeSpec::Boolean =>
-                "bool".to_string(),
-            TypeSpec::String =>
-                "string".to_string(),
-            TypeSpec::Number =>
-                "number".to_string(),
-            TypeSpec::NamedType(ref name) =>
-                name.to_str().to_string(),
-            TypeSpec::TypeSum(ref sum) => {
-                format!("({})", sum.types()
-                    .iter()
-                    .map(|x| Self::spec(x, "", indent))
-                    .format(" or "))
-            }
-            TypeSpec::Void => "void".to_string()
-        }
-    }
+/// The inforamtion used to generate a parser for an optional data structure.
+struct OptionParserData {
+    /// Name of the node.
+    name: NodeName,
 
-    pub fn type_(type_: &Type, prefix: &str, indent: &str) -> String {
-        let pretty_type = Self::spec(type_.spec(), prefix, indent);
-        format!("{}{}", pretty_type, if type_.is_optional() { "?" } else { "" })
-    }
+    /// Name of the element that may be contained.
+    elements: NodeName,
+}
 
-    pub fn interface(interface: &Interface, prefix: &str, indent: &str) -> String {
-        let mut result = format!("{prefix} interface {name} : Node {{\n", prefix=prefix, name=interface.name().to_str());
-        {
-            let prefix = format!("{prefix}{indent}",
-                prefix=prefix,
-                indent=indent);
-            for field in interface.contents().fields() {
-                if let Some(ref doc) = field.doc() {
-                    result.push_str(&format!("{prefix}// {doc}\n", prefix = prefix, doc = doc));
-                }
-                result.push_str(&format!("{prefix}{description} {name};\n",
-                    prefix = prefix,
-                    name = field.name().to_str(),
-                    description = Self::type_(field.type_(), &prefix, indent)
-                ));
-                if field.doc().is_some() {
-                    result.push_str("\n");
-                }
-            }
-        }
-        result.push_str(&format!("{prefix} }}\n", prefix=prefix));
-        result
-    }
-}
-pub struct CPPExporter {
+/// The actual exporter.
+struct CPPExporter {
+    /// The syntax to export.
     syntax: Spec,
-    rules: GenerationRules,
-    list_parsers_to_generate: Vec<(NodeName, (/* supports_empty */ bool, NodeName))>,
-    option_parsers_to_generate: Vec<(NodeName, NodeName)>,
+
+    /// Rules, as specified in yaml.
+    rules: GlobalRules,
+
+    /// All parsers of lists.
+    list_parsers_to_generate: Vec<ListParserData>,
 
-    /// A mapping from string enum symbol (e.g. "delete")
-    /// to its name in BinVariant (e.g. "UnaryOperatorDelete").
+    /// All parsers of options.
+    option_parsers_to_generate: Vec<OptionParserData>,
+
+    /// A mapping from symbol (e.g. `+`, `-`, `instanceof`, ...) to the
+    /// name of the symbol as part of `enum class BinVariant`
+    /// (e.g. `UnaryOperatorDelete`).
     variants_by_symbol: HashMap<String, String>,
 }
 
 impl CPPExporter {
-    pub fn new(deanonymizer: TypeDeanonymizer, options: SpecOptions) -> Self {
-        let syntax = deanonymizer.into_spec(options);
-
+    fn new(syntax: Spec, rules: GlobalRules) -> Self {
         let mut list_parsers_to_generate = vec![];
         let mut option_parsers_to_generate = vec![];
         for (parser_node_name, typedef) in syntax.typedefs_by_name() {
             if typedef.is_optional() {
-                let content_name = TypeName::type_spec(typedef.spec()); // FIXME: Wait, do we have an implementation of type names in two places?
+                let content_name = TypeName::type_spec(typedef.spec());
                 let content_node_name = syntax.get_node_name(&content_name)
                     .unwrap_or_else(|| panic!("While generating an option parser, could not find node name {}", content_name))
                     .clone();
                 debug!(target: "generate_spidermonkey", "CPPExporter::new adding optional typedef {:?} => {:?} => {:?}",
                     parser_node_name,
                     content_name,
                     content_node_name);
-                option_parsers_to_generate.push((parser_node_name.clone(), content_node_name));
+                option_parsers_to_generate.push(OptionParserData {
+                    name: parser_node_name.clone(),
+                    elements: content_node_name
+                });
             } else if let TypeSpec::Array { ref contents, ref supports_empty } = *typedef.spec() {
-                let content_name = TypeName::type_(&**contents); // FIXME: Wait, do we have an implementation of type names in two places?
+                let content_name = TypeName::type_(&**contents);
                 let content_node_name = syntax.get_node_name(&content_name)
                     .unwrap_or_else(|| panic!("While generating an array parser, could not find node name {}", content_name))
                     .clone();
-                list_parsers_to_generate.push((parser_node_name.clone(), (*supports_empty, content_node_name)));
+                list_parsers_to_generate.push(ListParserData {
+                    name: parser_node_name.clone(),
+                    supports_empty: *supports_empty,
+                    elements: content_node_name
+                });
             }
         }
-        list_parsers_to_generate.sort_by(|a, b| str::cmp(a.0.to_str(), b.0.to_str()));
-        option_parsers_to_generate.sort_by(|a, b| str::cmp(a.0.to_str(), b.0.to_str()));
+        list_parsers_to_generate.sort_by(|a, b| str::cmp(a.name.to_str(), b.name.to_str()));
+        option_parsers_to_generate.sort_by(|a, b| str::cmp(a.name.to_str(), b.name.to_str()));
 
         // Prepare variant_by_symbol, which will let us lookup the BinVariant name of
         // a symbol. Since some symbols can appear in several enums (e.g. "+"
         // is both a unary and a binary operator), we need to collect all the
-        // string enums that contain each symbol and come up with a unique name.
-        let mut enum_by_string : HashMap<String, Vec<std::rc::Rc<String>>> = HashMap::new();
+        // string enums that contain each symbol and come up with a unique name
+        // (note that there is no guarantee of unicity – if collisions show up,
+        // we may need to tweak the name generation algorithm).
+        let mut enum_by_string : HashMap<String, Vec<NodeName>> = HashMap::new();
         for (name, enum_) in syntax.string_enums_by_name().iter() {
-            let name = std::rc::Rc::new(name.to_string().clone());
             for string in enum_.strings().iter() {
                 let vec = enum_by_string.entry(string.clone())
                     .or_insert_with(|| vec![]);
                 vec.push(name.clone());
             }
         }
         let variants_by_symbol = enum_by_string.drain()
             .map(|(string, names)| {
                 let expanded = format!("{names}{symbol}",
-                    names = names.iter().format("Or"),
+                    names = names.iter()
+                        .map(NodeName::to_str)
+                        .sorted()
+                        .into_iter()
+                        .format("Or"),
                     symbol = string.to_cpp_enum_case());
                 (string, expanded)
             })
             .collect();
 
         CPPExporter {
             syntax,
-            rules: GenerationRules::default(),
+            rules,
             list_parsers_to_generate,
             option_parsers_to_generate,
             variants_by_symbol,
         }
     }
 
-    fn set_export_rules(&mut self, rules: GenerationRules) {
-        self.rules = rules;
-    }
-}
+// ----- Generating the header
 
-// ----- Generating the header
-impl CPPExporter {
+    /// Get the type representing a success for parsing this node.
     fn get_type_ok(&self, name: &NodeName, default: &str) -> String {
         let rules_for_this_interface = self.rules.get(name);
         // If the override is provided, use it.
         if let Some(ref type_ok) = rules_for_this_interface.type_ok {
             return type_ok.to_string()
         }
         default.to_string()
     }
 
     fn get_method_signature(&self, name: &NodeName, default_type_ok: &str, prefix: &str, args: &str) -> String {
         let type_ok = self.get_type_ok(name, default_type_ok);
         let kind = name.to_class_cases();
-        format!("    JS::Result<{type_ok}> parse{prefix}{kind}({args});",
+        format!("    JS::Result<{type_ok}> parse{prefix}{kind}({args});\n",
             prefix = prefix,
             type_ok = type_ok,
             kind = kind,
             args = args,
         )
     }
 
     fn get_method_definition_start(&self, name: &NodeName, default_type_ok: &str, prefix: &str, args: &str) -> String {
@@ -270,84 +449,80 @@ impl CPPExporter {
         buffer.push_str("\n\n");
         if self.rules.hpp_tokens_kind_doc.is_some() {
             buffer.push_str(&self.rules.hpp_tokens_kind_doc.reindent(""));
         }
 
         let node_names = self.syntax.node_names()
             .keys()
             .sorted();
-        buffer.push_str(&format!("\n#define FOR_EACH_BIN_KIND(F) \\\n{nodes}",
+        buffer.push_str(&format!("\n#define FOR_EACH_BIN_KIND(F) \\\n{nodes}\n",
             nodes = node_names.iter()
-                .map(|name| format!("    F({name}, {name})",
-                    name = name))
+                .map(|name| format!("    F({enum_name}, \"{spec_name}\")",
+                    enum_name = name.to_cpp_enum_case(),
+                    spec_name = name))
                 .format(" \\\n")));
         buffer.push_str("
-
-
 enum class BinKind {
 #define EMIT_ENUM(name, _) name,
     FOR_EACH_BIN_KIND(EMIT_ENUM)
 #undef EMIT_ENUM
 };
 ");
 
-        buffer.push_str(&format!("\n// The number of distinct values of BinKind.\nconst size_t BINKIND_LIMIT = {};\n", self.syntax.node_names().len()));
+        buffer.push_str(&format!("\n// The number of distinct values of BinKind.\nconst size_t BINKIND_LIMIT = {};\n\n\n", self.syntax.node_names().len()));
         buffer.push_str("\n\n");
         if self.rules.hpp_tokens_field_doc.is_some() {
             buffer.push_str(&self.rules.hpp_tokens_field_doc.reindent(""));
         }
 
         let field_names = self.syntax.field_names()
             .keys()
             .sorted();
-        buffer.push_str(&format!("\n#define FOR_EACH_BIN_FIELD(F) \\\n{nodes}",
+        buffer.push_str(&format!("\n#define FOR_EACH_BIN_FIELD(F) \\\n{nodes}\n",
             nodes = field_names.iter()
-                .map(|name| format!("    F({enum_name}, {spec_name})",
+                .map(|name| format!("    F({enum_name}, \"{spec_name}\")",
                     spec_name = name,
                     enum_name = name.to_cpp_enum_case()))
                 .format(" \\\n")));
         buffer.push_str("
-
-
 enum class BinField {
 #define EMIT_ENUM(name, _) name,
     FOR_EACH_BIN_FIELD(EMIT_ENUM)
 #undef EMIT_ENUM
 };
 ");
-        buffer.push_str(&format!("\n// The number of distinct values of BinField.\nconst size_t BINFIELD_LIMIT = {};\n", self.syntax.field_names().len()));
+        buffer.push_str(&format!("\n// The number of distinct values of BinField.\nconst size_t BINFIELD_LIMIT = {};\n\n\n", self.syntax.field_names().len()));
 
-        if self.rules.hpp_tokens_variant_doc.is_some() {
-            buffer.push_str(&self.rules.hpp_tokens_variant_doc.reindent(""));
+        if self.rules.hpp_tokens_variants_doc.is_some() {
+            buffer.push_str(&self.rules.hpp_tokens_variants_doc.reindent(""));
         }
-
-        let mut enum_variants = self.variants_by_symbol
+        let enum_variants : Vec<_> = self.variants_by_symbol
             .iter()
             .sorted_by(|&(ref symbol_1, ref name_1), &(ref symbol_2, ref name_2)| {
                 Ord::cmp(name_1, name_2)
                     .then_with(|| Ord::cmp(symbol_1, symbol_2))
             });
 
-        buffer.push_str(&format!("\n#define FOR_EACH_BIN_VARIANT(F) \\\n{nodes}",
-            nodes = enum_variants.drain(..)
+        buffer.push_str(&format!("\n#define FOR_EACH_BIN_VARIANT(F) \\\n{nodes}\n",
+            nodes = enum_variants.into_iter()
                 .map(|(symbol, name)| format!("    F({variant_name}, \"{spec_name}\")",
                     spec_name = symbol,
                     variant_name = name))
                 .format(" \\\n")));
+
         buffer.push_str("
-
-
 enum class BinVariant {
 #define EMIT_ENUM(name, _) name,
     FOR_EACH_BIN_VARIANT(EMIT_ENUM)
 #undef EMIT_ENUM
 };
 ");
-        buffer.push_str(&format!("\n// The number of distinct values of BinVariant.\nconst size_t BINVARIANT_LIMIT = {};\n", enum_variants.len()));
+        buffer.push_str(&format!("\n// The number of distinct values of BinVariant.\nconst size_t BINVARIANT_LIMIT = {};\n\n\n",
+            self.variants_by_symbol.len()));
 
         buffer.push_str(&self.rules.hpp_tokens_footer.reindent(""));
         buffer.push_str("\n");
     }
 
     /// Declare string enums
     fn export_declare_string_enums_classes(&self, buffer: &mut String) {
         buffer.push_str("\n\n// ----- Declaring string enums (by lexicographical order)\n");
@@ -373,22 +548,20 @@ enum class BinVariant {
             .iter()
             .sorted_by(|a, b| a.0.cmp(&b.0));
         buffer.push_str("\n\n// ----- Sums of interfaces (by lexicographical order)\n");
         buffer.push_str("// Implementations are autogenerated\n");
         buffer.push_str("// `ParseNode*` may never be nullptr\n");
         for &(ref name, _) in &sums_of_interfaces {
             let rendered = self.get_method_signature(name, "ParseNode*", "", "");
             buffer.push_str(&rendered.reindent(""));
-            buffer.push_str("\n");
         }
         for (name, _) in sums_of_interfaces {
             let rendered = self.get_method_signature(name, "ParseNode*", "Sum", "const size_t start, const BinKind kind, const BinFields& fields");
             buffer.push_str(&rendered.reindent(""));
-            buffer.push_str("\n");
         }
     }
 
     fn export_declare_single_interface_methods(&self, buffer: &mut String) {
         buffer.push_str("\n\n// ----- Interfaces (by lexicographical order)\n");
         buffer.push_str("// Implementations are autogenerated\n");
         buffer.push_str("// `ParseNode*` may never be nullptr\n");
         let interfaces_by_name = self.syntax.interfaces_by_name()
@@ -428,52 +601,52 @@ enum class BinVariant {
             buffer.push_str(&rendered.reindent(""));
             buffer.push_str("\n");
         }
     }
 
     fn export_declare_list_methods(&self, buffer: &mut String) {
         buffer.push_str("\n\n// ----- Lists (by lexicographical order)\n");
         buffer.push_str("// Implementations are autogenerated\n");
-        for &(ref kind, _) in &self.list_parsers_to_generate {
-            let rendered = self.get_method_signature(kind, "ParseNode*", "", "");
+        for parser in &self.list_parsers_to_generate {
+            let rendered = self.get_method_signature(&parser.name, "ParseNode*", "", "");
             buffer.push_str(&rendered.reindent(""));
             buffer.push_str("\n");
         }
     }
 
     fn export_declare_option_methods(&self, buffer: &mut String) {
         buffer.push_str("\n\n// ----- Default values (by lexicographical order)\n");
         buffer.push_str("// Implementations are autogenerated\n");
-        for &(ref kind, _) in &self.option_parsers_to_generate {
-            let rendered = self.get_method_signature(kind, "ParseNode*", "", "");
+        for parser in &self.option_parsers_to_generate {
+            let rendered = self.get_method_signature(&parser.name, "ParseNode*", "", "");
             buffer.push_str(&rendered.reindent(""));
             buffer.push_str("\n");
         }
     }
 
     fn generate_autogenerated_warning(&self) -> String {
         let warning = format!("// This file was autogenerated by binjs_generate_spidermonkey,
 // please DO NOT EDIT BY HAND.
 ");
         warning
     }
 
     /// Generate C++ headers for SpiderMonkey
-    pub fn to_spidermonkey_token_hpp(&self) -> String {
+    fn to_spidermonkey_token_hpp(&self) -> String {
         let mut buffer = String::new();
 
         buffer.push_str(&self.generate_autogenerated_warning());
 
         self.export_declare_kinds_and_fields_enums(&mut buffer);
 
         buffer.push_str("\n");
         buffer
     }
-    pub fn to_spidermonkey_class_hpp(&self) -> String {
+    fn to_spidermonkey_class_hpp(&self) -> String {
         let mut buffer = String::new();
 
         buffer.push_str(&self.generate_autogenerated_warning());
 
         buffer.push_str(&self.rules.hpp_class_header.reindent(""));
         buffer.push_str("\n");
 
         self.export_declare_string_enums_classes(&mut buffer);
@@ -500,66 +673,79 @@ impl CPPExporter {
                 .format("\n    "),
             name = name.to_str());
 
         // Generate outer method
         buffer.push_str(&format!("{bnf}
 {first_line}
 {{
     BinKind kind;
-    BinFields fields((cx_));
+    BinFields fields(cx_);
     AutoTaggedTuple guard(*tokenizer_);
     const auto start = tokenizer_->offset();
 
     MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
-    MOZ_TRY_DECL(result, parseSum{kind}(start, kind, fields));
+    BINJS_MOZ_TRY_DECL(result, parseSum{kind}(start, kind, fields));
 
     MOZ_TRY(guard.done());
     return result;
 }}\n",
                 bnf = rendered_bnf,
                 kind = kind,
                 first_line = self.get_method_definition_start(name, "ParseNode*", "", "")
         ));
 
         // Generate inner method
         let mut buffer_cases = String::new();
         for node in nodes {
             buffer_cases.push_str(&format!("
-      case BinKind::{kind}:
-        MOZ_TRY_VAR(result, parseInterface{kind}(start, kind, fields));
+      case BinKind::{variant_name}:
+        MOZ_TRY_VAR(result, parseInterface{class_name}(start, kind, fields));
         break;",
-                kind = node.to_class_cases()));
-            }
-            buffer.push_str(&format!("\n{first_line}
+                class_name = node.to_class_cases(),
+                variant_name = node.to_cpp_enum_case()));
+        }
+        buffer.push_str(&format!("\n{first_line}
 {{
     {type_ok} result;
     switch(kind) {{{cases}
       default:
         return raiseInvalidKind(\"{kind}\", kind);
     }}
     return result;
 }}
 
 ",
-        kind = kind,
-        cases = buffer_cases,
-        first_line = self.get_method_definition_start(name, "ParseNode*", "Sum", "const size_t start, const BinKind kind, const BinFields& fields"),
-        type_ok = self.get_type_ok(name, "ParseNode*")
-    ));
+            kind = kind,
+            cases = buffer_cases,
+            first_line = self.get_method_definition_start(name, "ParseNode*", "Sum", "const size_t start, const BinKind kind, const BinFields& fields"),
+            type_ok = self.get_type_ok(name, "ParseNode*")
+        ));
     }
 
     /// Generate the implementation of a single list parser
-    fn generate_implement_list(&self, buffer: &mut String, name: &NodeName, supports_empty: bool, contents: &NodeName) {
-        let rules_for_this_list = self.rules.get(name);
-        let kind = name.to_class_cases();
-        let first_line = self.get_method_definition_start(name, "ParseNode*", "", "");
+    fn generate_implement_list(&self, buffer: &mut String, parser: &ListParserData) {
+        let rules_for_this_list = self.rules.get(&parser.name);
 
-        let init = match rules_for_this_list.start {
+        // Warn if some rules are unused.
+        for &(condition, name) in &[
+            (rules_for_this_list.build_result.is_some(), "build:"),
+            (rules_for_this_list.type_ok.is_some(), "type-ok:"),
+            (rules_for_this_list.by_field.len() > 0, "fields:"),
+        ] {
+            if condition {
+                warn!("In {}, rule `{}` was specified but is ignored.", parser.name, name);
+            }
+        }
+
+        let kind = parser.name.to_class_cases();
+        let first_line = self.get_method_definition_start(&parser.name, "ParseNode*", "", "");
+
+        let init = match rules_for_this_list.init {
             Some(str) => str.reindent("    "),
             None => {
                 // We cannot generate the method if we don't know how to initialize the list.
                 let rendered = format!("
 {first_line}
 {{
     return raiseError(\"FIXME: Not implemented yet ({kind})\");
 }}\n",
@@ -581,175 +767,202 @@ impl CPPExporter {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
     MOZ_TRY(tokenizer_->enterList(length, guard));{empty_check}
 {init}
 
     for (uint32_t i = 0; i < length; ++i) {{
-        MOZ_TRY_DECL(item, parse{inner}());
+        BINJS_MOZ_TRY_DECL(item, parse{inner}());
 {append}
     }}
 
     MOZ_TRY(guard.done());
     return result;
 }}\n",
             first_line = first_line,
             empty_check =
-                if supports_empty {
+                if parser.supports_empty {
                     "".to_string()
                 } else {
                     format!("\n    if (length == 0)\n         return raiseEmpty(\"{kind}\");\n",
                         kind = kind)
                 },
-            inner = contents.to_class_cases(),
+            inner = parser.elements.to_class_cases(),
             init = init,
             append = append);
         buffer.push_str(&rendered);
     }
 
-    fn generate_implement_option(&self, buffer: &mut String, name: &NodeName, contents: &NodeName) {
+    fn generate_implement_option(&self, buffer: &mut String, parser: &OptionParserData) {
         debug!(target: "generate_spidermonkey", "Implementing optional value {} backed by {}",
-            name.to_str(), contents.to_str());
+            parser.name.to_str(), parser.elements.to_str());
+
+        let rules_for_this_node = self.rules.get(&parser.name);
 
-        let rules_for_this_node = self.rules.get(name);
+        // Warn if some rules are unused.
+        for &(condition, name) in &[
+            (rules_for_this_node.build_result.is_some(), "build:"),
+            (rules_for_this_node.append.is_some(), "append:"),
+            (rules_for_this_node.by_field.len() > 0, "fields:"),
+        ] {
+            if condition {
+                warn!("In {}, rule `{}` was specified but is ignored.", parser.name, name);
+            }
+        }
 
-        let type_ok = self.get_type_ok(name, "ParseNode*");
+        let type_ok = self.get_type_ok(&parser.name, "ParseNode*");
         let default_value =
             if type_ok == "Ok" {
                 "Ok()"
             } else {
                 "nullptr"
             }.to_string();
 
         // At this stage, thanks to deanonymization, `contents`
         // is something like `OptionalFooBar`.
         let named_implementation =
-            if let Some(NamedType::Typedef(ref typedef)) = self.syntax.get_type_by_name(&name) {
+            if let Some(NamedType::Typedef(ref typedef)) = self.syntax.get_type_by_name(&parser.name) {
                 assert!(typedef.is_optional());
                 if let TypeSpec::NamedType(ref named) = *typedef.spec() {
                     self.syntax.get_type_by_name(named)
-                        .unwrap()
+                        .unwrap_or_else(|| panic!("Internal error: Could not find type {}, which should have been generated.", named.to_str()))
                 } else {
-                    panic!()
+                    panic!("Internal error: In {}, type {:?} should have been a named type",
+                        parser.name.to_str(),
+                        typedef);
                 }
             } else {
-                panic!()
+                panic!("Internal error: In {}, there should be a type with that name",
+                    parser.name.to_str());
             };
         match named_implementation {
             NamedType::Interface(_) => {
                 buffer.push_str(&format!("{first_line}
 {{
     BinKind kind;
-    BinFields fields((cx_));
+    BinFields fields(cx_);
     AutoTaggedTuple guard(*tokenizer_);
 
     MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     {type_ok} result;
     if (kind == BinKind::{null}) {{
         result = {default_value};
     }} else {{
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseInterface{contents}(start, kind, fields));
     }}
     MOZ_TRY(guard.done());
 
     return result;
 }}
 
 ",
-                    first_line = self.get_method_definition_start(name, "ParseNode*", "", ""),
-                    null = self.syntax.get_null_name().to_str(),
-                    contents = contents.to_class_cases(),
+                    first_line = self.get_method_definition_start(&parser.name, "ParseNode*", "", ""),
+                    null = self.syntax.get_null_name().to_cpp_enum_case(),
+                    contents = parser.elements.to_class_cases(),
                     type_ok = type_ok,
                     default_value = default_value,
                 ));
             }
             NamedType::Typedef(ref type_) => {
                 match type_.spec() {
                     &TypeSpec::TypeSum(_) => {
                 buffer.push_str(&format!("{first_line}
 {{
     BinKind kind;
-    BinFields fields((cx_));
+    BinFields fields(cx_);
     AutoTaggedTuple guard(*tokenizer_);
 
     MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     {type_ok} result;
-    if (kind == BinKind::_Null) {{
+    if (kind == BinKind::{null}) {{
         result = {default_value};
     }} else {{
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseSum{contents}(start, kind, fields));
     }}
     MOZ_TRY(guard.done());
 
     return result;
 }}
 
 ",
-                            first_line = self.get_method_definition_start(name, "ParseNode*", "", ""),
-                            contents = contents.to_class_cases(),
+                            first_line = self.get_method_definition_start(&parser.name, "ParseNode*", "", ""),
+                            contents = parser.elements.to_class_cases(),
                             type_ok = type_ok,
                             default_value = default_value,
+                            null = self.syntax.get_null_name().to_cpp_enum_case(),
                         ));
                     }
                     &TypeSpec::String => {
-                        let build_result = rules_for_this_node.start.reindent("    ");
+                        let build_result = rules_for_this_node.init.reindent("    ");
+                        let first_line = self.get_method_definition_start(&parser.name, "ParseNode*", "", "");
+                        if build_result.len() == 0 {
+                            buffer.push_str(&format!("{first_line}
+{{
+    return raiseError(\"FIXME: Not implemented yet ({kind})\");
+}}
 
-                        buffer.push_str(&format!("{first_line}
+",
+                                first_line = first_line,
+                                kind = parser.name.to_str()));
+                        } else {
+                            buffer.push_str(&format!("{first_line}
 {{
-    RootedAtom string((cx_));
-    MOZ_TRY_VAR(string, tokenizer_->readMaybeAtom());
+    BINJS_MOZ_TRY_DECL(result, tokenizer_->readMaybeAtom());
 
 {build}
 
-    {return_}
+    return result;
 }}
 
 ",
-                            first_line = self.get_method_definition_start(name, "ParseNode*", "", ""),
-                            build = build_result,
-                            return_ = if build_result.len() == 0 {
-                                format!("return raiseError(\"FIXME: Not implemented yet ({kind})\");\n",
-                                    kind = name.to_str())
-                            } else {
-                                "return result;".to_string()
-                            }
-                        ));
+                                first_line = first_line,
+                                build = build_result,
+                            ));
+                        }
                     }
                     _else => unimplemented!("{:?}", _else)
                 }
             }
             NamedType::StringEnum(_) => {
                 unimplemented!()
             }
         }
     }
 
     fn generate_implement_interface(&self, buffer: &mut String, name: &NodeName, interface: &Interface) {
         let rules_for_this_interface = self.rules.get(name);
 
+        for &(condition, rule_name) in &[
+            (rules_for_this_interface.append.is_some(), "build:"),
+        ] {
+            if condition {
+                warn!("In {}, rule `{}` was specified but is ignored.", name, rule_name);
+            }
+        }
+
         // Generate comments
         let comment = format!("\n/*\n{}*/\n", ToWebidl::interface(interface, "", "    "));
         buffer.push_str(&comment);
 
         // Generate public method
         let kind = name.to_class_cases();
         buffer.push_str(&format!("{first_line}
 {{
     BinKind kind;
     BinFields fields(cx_);
     AutoTaggedTuple guard(*tokenizer_);
 
     MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     const auto start = tokenizer_->offset();
 
-    MOZ_TRY_DECL(result, parseInterface{kind}(start, kind, fields));
+    BINJS_MOZ_TRY_DECL(result, parseInterface{kind}(start, kind, fields));
     MOZ_TRY(guard.done());
 
     return result;
 }}
 
 ",
             first_line = self.get_method_definition_start(name, "ParseNode*", "", ""),
             kind = kind
@@ -762,58 +975,57 @@ impl CPPExporter {
         let fields_type_list = format!("{{ {} }}", interface.contents()
             .fields()
             .iter()
             .map(|field| format!("BinField::{}", field.name().to_cpp_enum_case()))
             .format(", "));
 
         let mut fields_implem = String::new();
         for field in interface.contents().fields() {
-            let rules_for_this_field = rules_for_this_interface.by_field.get(field.name());
-            let needs_block = if let Some(ref rule) = rules_for_this_field {
-                rule.block_before_field.is_some() || rule.block_after_field.is_some()
-            } else {
-                false
-            };
+            let rules_for_this_field = rules_for_this_interface.by_field.get(field.name())
+                .cloned()
+                .unwrap_or_default();
+            let needs_block = rules_for_this_field.block_before_field.is_some() || rules_for_this_field.block_after_field.is_some();
 
             let var_name = field.name().to_cpp_field_case();
             let (decl_var, parse_var) = match field.type_().get_primitive(&self.syntax) {
                 Some(IsNullable { is_nullable: false, content: Primitive::Number }) => {
                     if needs_block {
                         (Some(format!("double {var_name};", var_name = var_name)),
                             Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readDouble());", var_name = var_name)))
                     } else {
                         (None,
-                            Some(format!("MOZ_TRY_DECL({var_name}, tokenizer_->readDouble());", var_name = var_name)))
+                            Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_->readDouble());", var_name = var_name)))
                     }
                 }
                 Some(IsNullable { is_nullable: false, content: Primitive::Boolean }) => {
                     if needs_block {
                         (Some(format!("bool {var_name};", var_name = var_name)),
                         Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readBool());", var_name = var_name)))
                     } else {
                         (None,
-                        Some(format!("MOZ_TRY_DECL({var_name}, tokenizer_->readBool());", var_name = var_name)))
+                        Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_->readBool());", var_name = var_name)))
                     }
                 }
                 Some(IsNullable { is_nullable: false, content: Primitive::Offset }) => {
                     if needs_block {
                         (Some(format!("uint32_t {var_name};", var_name = var_name)),
                         Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readOffset());", var_name = var_name)))
                     } else {
                         (None,
-                        Some(format!("MOZ_TRY_DECL({var_name}, tokenizer_->readOffset());", var_name = var_name)))
+                        Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_->readOffset());", var_name = var_name)))
                     }
                 }
                 Some(IsNullable { content: Primitive::Void, .. }) => {
+                    warn!("Internal error: We shouldn't have any `void` types at this stage.");
                     (Some(format!("// Skipping void field {}", field.name().to_str())),
                         None)
                 }
                 Some(IsNullable { is_nullable: false, content: Primitive::String }) => {
-                    (Some(format!("RootedAtom {var_name}((cx_));", var_name = var_name)),
+                    (Some(format!("RootedAtom {var_name}(cx_);", var_name = var_name)),
                         Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readAtom());", var_name = var_name)))
                 }
                 Some(IsNullable { content: Primitive::Interface(ref interface), ..})
                     if &self.get_type_ok(interface.name(), "?") == "Ok" =>
                 {
                     // Special case: `Ok` means that we shouldn't bind the return value.
                     let typename = TypeName::type_(field.type_());
                     (None,
@@ -827,32 +1039,41 @@ impl CPPExporter {
                             var_name = var_name,
                             typename = typename)),
                             Some(format!("MOZ_TRY_VAR({var_name}, parse{typename}());",
                             var_name = var_name,
                             typename = typename)
                         ))
                     } else {
                         (None,
-                            Some(format!("MOZ_TRY_DECL({var_name}, parse{typename}());",
+                            Some(format!("BINJS_MOZ_TRY_DECL({var_name}, parse{typename}());",
                             var_name = var_name,
                             typename = typename)))
                     }
                 }
             };
 
-            let rendered = if let Some(ref rule) = rules_for_this_field {
-                if rule.replace.is_some() {
-                    rule.replace.reindent("    ")
+            let rendered = {
+                if rules_for_this_field.replace.is_some() {
+                    for &(condition, rule_name) in &[
+                        (rules_for_this_field.before_field.is_some(), "before:"),
+                        (rules_for_this_field.after_field.is_some(), "after:"),
+                        (rules_for_this_field.declare.is_some(), "declare:"),
+                    ] {
+                        if condition {
+                            warn!("In {}, rule `{}` was specified but is ignored because `replace:` is also specified.", name, rule_name);
+                        }
+                    }
+                    rules_for_this_field.replace.reindent("    ")
                         .newline()
                 } else {
-                    let before_field = rule.before_field.reindent("    ");
-                    let after_field = rule.after_field.reindent("    ");
-                    let decl_var = if rule.declare.is_some() {
-                        rule.declare.reindent("    ")
+                    let before_field = rules_for_this_field.before_field.reindent("    ");
+                    let after_field = rules_for_this_field.after_field.reindent("    ");
+                    let decl_var = if rules_for_this_field.declare.is_some() {
+                        rules_for_this_field.declare.reindent("    ")
                     } else {
                         decl_var.reindent("    ")
                     };
                     if needs_block {
                         let parse_var = parse_var.reindent("        ");
                         format!("{before_field}
 {decl_var}
     {{
@@ -860,45 +1081,39 @@ impl CPPExporter {
 {parse_var}
 {block_after_field}
     }}
 {after_field}",
                             before_field = before_field.reindent("    "),
                             decl_var = decl_var.reindent("    "),
                             parse_var = parse_var.reindent("        "),
                             after_field = after_field.reindent("    "),
-                            block_before_field = rule.block_before_field.reindent("        "),
-                            block_after_field = rule.block_after_field.reindent("        "))
+                            block_before_field = rules_for_this_field.block_before_field.reindent("        "),
+                            block_after_field = rules_for_this_field.block_after_field.reindent("        "))
                     } else {
+                        // We have a before_field and an after_field. This will create newlines
+                        // for them.
                         format!("
 {before_field}
 {decl_var}
 {parse_var}
 {after_field}
 ",
                             before_field = before_field.reindent("    "),
                             decl_var = decl_var.reindent("    "),
                             parse_var = parse_var.reindent("    "),
                             after_field = after_field.reindent("    "))
                     }
                 }
-            } else {
-                format!("
-{decl_var}
-{parse_var}
-",
-                    decl_var = decl_var.reindent("    "),
-                    parse_var = parse_var.reindent("    "))
             };
             fields_implem.push_str(&rendered);
         }
 
-        let (start, build_result) =
-            (rules_for_this_interface.start.reindent("    "),
-             rules_for_this_interface.build_result.reindent("    "));
+        let init = rules_for_this_interface.init.reindent("    ");
+        let build_result = rules_for_this_interface.build_result.reindent("    ");
 
         if build_result == "" {
             buffer.push_str(&format!("{first_line}
 {{
     return raiseError(\"FIXME: Not implemented yet ({})\");
 }}
 
 ",
@@ -910,52 +1125,54 @@ impl CPPExporter {
                 format!("MOZ_TRY(tokenizer_->checkFields0(kind, fields));")
             } else {
                 format!("MOZ_TRY(tokenizer_->checkFields(kind, fields, {fields_type_list}));",
                     fields_type_list = fields_type_list)
             };
             buffer.push_str(&format!("{first_line}
 {{
     MOZ_ASSERT(kind == BinKind::{kind});
+    CheckRecursionLimit(cx_);
+
     {check_fields}
 {pre}{fields_implem}
 {post}
     return result;
 }}
 
 ",
                 check_fields = check_fields,
                 fields_implem = fields_implem,
-                pre = start,
+                pre = init,
                 post = build_result,
-                kind = kind,
+                kind = name.to_cpp_enum_case(),
                 first_line = first_line,
             ));
         }
     }
 
     /// Generate C++ code for SpiderMonkey
-    pub fn to_spidermonkey_cpp(&self) -> String {
+    fn to_spidermonkey_cpp(&self) -> String {
         let mut buffer = String::new();
 
         buffer.push_str(&self.generate_autogenerated_warning());
 
         // 0. Header
         buffer.push_str(&self.rules.cpp_header.reindent(""));
         buffer.push_str("\n");
 
         // 1. Typesums
         buffer.push_str("\n\n// ----- Sums of interfaces (autogenerated, by lexicographical order)\n");
         buffer.push_str("// Sums of sums are flattened.\n");
 
         let sums_of_interfaces = self.syntax.resolved_sums_of_interfaces_by_name()
             .iter()
             .sorted_by(|a, b| a.0.cmp(&b.0));
 
-        for &(ref name, ref nodes) in sums_of_interfaces.iter() {
+        for (name, nodes) in sums_of_interfaces {
             self.generate_implement_sum(&mut buffer, name, nodes);
         }
 
         // 2. Single interfaces
         buffer.push_str("\n\n// ----- Interfaces (autogenerated, by lexicographical order)\n");
         buffer.push_str("// When fields have a non-trivial type, implementation is deanonymized and delegated to another parser.\n");
         let interfaces_by_name = self.syntax.interfaces_by_name()
             .iter()
@@ -976,17 +1193,17 @@ impl CPPExporter {
 {cases}
       default:
         return raiseInvalidVariant(\"{kind}\", variant);
     }}",
                     kind = kind,
                     cases = enum_.strings()
                         .iter()
                         .map(|symbol| {
-                            format!("      case BinVariant::{binvariant_variant}:
+                            format!("    case BinVariant::{binvariant_variant}:
         return {kind}::{specialized_variant};",
                                 kind = kind,
                                 specialized_variant = symbol.to_cpp_enum_case(),
                                 binvariant_variant  = self.variants_by_symbol.get(symbol)
                                     .unwrap()
                             )
                         })
                         .format("\n")
@@ -996,67 +1213,67 @@ impl CPPExporter {
                     kind = kind,
                     cases = enum_.strings()
                             .iter()
                             .map(|s| format!("    \"{}\"", s))
                             .format(",\n")
                 );
                 buffer.push_str(&format!("{rendered_doc}{first_line}
 {{
-    MOZ_TRY_DECL(variant, tokenizer_->readVariant());
+    BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());
 
 {convert}
 }}
 
 ",
                     rendered_doc = rendered_doc,
                     convert = convert,
                     first_line = self.get_method_definition_start(kind, &format!("typename BinASTParser<Tok>::{kind}", kind = kind), "", "")
                 ));
             }
         }
 
         // 4. Lists
         buffer.push_str("\n\n// ----- Lists (autogenerated, by lexicographical order)\n");
-        for &(ref name, (supports_empty, ref contents)) in &self.list_parsers_to_generate {
-            self.generate_implement_list(&mut buffer, name, supports_empty, contents);
+        for parser in &self.list_parsers_to_generate {
+            self.generate_implement_list(&mut buffer, parser);
         }
 
         // 5. Optional values
         buffer.push_str("\n\n    // ----- Default values (by lexicographical order)\n");
-        for &(ref name, ref contents) in &self.option_parsers_to_generate {
-            self.generate_implement_option(&mut buffer, name, contents);
+        for parser in &self.option_parsers_to_generate {
+            self.generate_implement_option(&mut buffer, parser);
         }
 
         buffer.push_str("\n");
         buffer.push_str(&self.rules.cpp_footer.reindent(""));
         buffer.push_str("\n");
 
         buffer
     }
 }
 
-fn update_rule(rule: &mut Option<String>, entry: &yaml_rust::Yaml) -> Option<Option<()>> {
+fn update_rule(rule: &mut Option<String>, entry: &yaml_rust::Yaml) -> Result<Option<()>, ()> {
     if entry.is_badvalue() {
-        return Some(None)
+        return Ok(None)
     } else if let Some(as_str) = entry.as_str() {
         *rule = Some(as_str.to_string());
-        Some(Some(()))
+        Ok(Some(()))
     } else {
-        None
+        Err(())
     }
 }
 
 
 fn main() {
     env_logger::init();
 
-    let matches = App::new("BinJS import from webidl")
+    let matches = App::new("BinAST C++ parser generator")
         .author("David Teller, <dteller@mozilla.com>")
-        .about("Import a webidl defining the syntax of JavaScript.")
+        .about("Converts an webidl syntax definition and a yaml set of rules into the C++ source code of a parser.")
         .args(&[
             Arg::with_name("INPUT.webidl")
                 .required(true)
                 .help("Input webidl file to use. Must be a webidl source file."),
             Arg::with_name("INPUT.yaml")
                 .required(true)
                 .help("Input rules file to use. Must be a yaml source file."),
             Arg::with_name("OUT_HEADER_CLASS_FILE")
@@ -1069,205 +1286,64 @@ fn main() {
                 .required(true)
                 .takes_value(true)
                 .help("Output token file (.h)"),
             Arg::with_name("OUT_IMPL_FILE")
                 .long("out-impl")
                 .required(true)
                 .takes_value(true)
                 .help("Output implementation file (.cpp)"),
-            Arg::with_name("OUT_WEBIDL_FILE")
-                .long("out-webidl")
-                .required(false)
-                .takes_value(true)
-                .help("Path to copy the webidl source"),
-            Arg::with_name("OUT_YAML_FILE")
-                .long("out-yaml")
-                .required(false)
-                .takes_value(true)
-                .help("Path to copy the yaml source"),
         ])
     .get_matches();
 
     let source_path = matches.value_of("INPUT.webidl")
         .expect("Expected INPUT.webidl");
 
     let mut file = File::open(source_path)
         .expect("Could not open source");
     let mut source = String::new();
     file.read_to_string(&mut source)
         .expect("Could not read source");
 
     println!("...parsing webidl");
-    let parser = webidl::Parser::new();
-    let ast = parser.parse_string(&source)
+    let ast = webidl::parse_string(&source)
         .expect("Could not parse source");
 
     println!("...verifying grammar");
     let mut builder = Importer::import(&ast);
     let fake_root = builder.node_name("@@ROOT@@"); // Unused
     let null = builder.node_name(""); // Used
     builder.add_interface(&null)
         .unwrap();
     let syntax = builder.into_spec(SpecOptions {
         root: &fake_root,
         null: &null,
     });
 
+    let deanonymizer = TypeDeanonymizer::new(&syntax);
     let syntax_options = SpecOptions {
         root: &fake_root,
         null: &null,
     };
-
-    let deanonymizer = TypeDeanonymizer::new(&syntax);
-
-    let mut generation_rules = GenerationRules::default();
-    if let Some(rules_source_path) = matches.value_of("INPUT.yaml") {
-        println!("...generating rules");
-        let mut file = File::open(rules_source_path)
-            .expect("Could not open rules");
-        let mut data = String::new();
-        file.read_to_string(&mut data)
-            .expect("Could not read rules");
-
-        let yaml = yaml_rust::YamlLoader::load_from_str(&data)
-            .expect("Could not parse rules");
-        assert_eq!(yaml.len(), 1);
-        let rules = yaml[0].as_hash()
-            .expect("Rules are not a dictionary");
-
-        for (node_key, node_entries) in rules.iter() {
-            let node_key = node_key.as_str()
-                .expect("Could not convert node_key to string");
-
-            match node_key {
-                "cpp" => {
-                    update_rule(&mut generation_rules.cpp_header, &node_entries["header"])
-                        .unwrap_or_else(|| panic!("Rule cpp.header must be a string"));
-                    update_rule(&mut generation_rules.cpp_footer, &node_entries["footer"])
-                        .unwrap_or_else(|| panic!("Rule cpp.footer must be a string"));
-                    continue;
-                }
-                "hpp" => {
-                    update_rule(&mut generation_rules.hpp_class_header, &node_entries["class"]["header"])
-                        .unwrap_or_else(|| panic!("Rule hpp.class.header must be a string"));
-                    update_rule(&mut generation_rules.hpp_tokens_header, &node_entries["tokens"]["header"])
-                        .unwrap_or_else(|| panic!("Rule hpp.tokens.header must be a string"));
-                    update_rule(&mut generation_rules.hpp_tokens_footer, &node_entries["tokens"]["footer"])
-                        .unwrap_or_else(|| panic!("Rule hpp.tokens.footer must be a string"));
-                    update_rule(&mut generation_rules.hpp_tokens_kind_doc, &node_entries["tokens"]["kind"]["doc"])
-                        .unwrap_or_else(|| panic!("Rule hpp.tokens.kind.doc must be a string"));
-                    update_rule(&mut generation_rules.hpp_tokens_variant_doc, &node_entries["tokens"]["variant"]["doc"])
-                        .unwrap_or_else(|| panic!("Rule hpp.tokens.variant.doc must be a string"));
-                    update_rule(&mut generation_rules.hpp_tokens_field_doc, &node_entries["tokens"]["field"]["doc"])
-                        .unwrap_or_else(|| panic!("Rule hpp.tokens.field.doc must be a string"));
-                    continue;
-                }
-                _ => {}
-            }
-
-
-            let node_name = deanonymizer.get_node_name(&node_key)
-                .unwrap_or_else(|| panic!("Unknown node name {}", node_key));
-
-            let hash = node_entries.as_hash()
-                .unwrap_or_else(|| panic!("Node {} isn't a dictionary"));
+    let new_syntax = deanonymizer.into_spec(syntax_options);
 
-            let mut node_rule = NodeParsingRules::default();
-            for (node_item_key, node_item_entry) in hash {
-                let as_string = node_item_key.as_str()
-                    .unwrap_or_else(|| panic!("Keys for rule {} must be strings", node_key));
-                match as_string {
-                    "inherits" => {
-                        let name = node_item_entry.as_str()
-                            .unwrap_or_else(|| panic!("Rule {}.{} must be a string", node_key, as_string));
-                        let inherits = deanonymizer.get_node_name(name)
-                            .unwrap_or_else(|| panic!("Unknown node name {}", node_key));
-                        node_rule.inherits = Some(inherits);
-                    }
-                    "init" => {
-                        update_rule(&mut node_rule.start, node_item_entry)
-                            .unwrap_or_else(|| panic!("Rule {}.{} must be a string", node_key, as_string));
-                    }
-                    "build" => {
-                        update_rule(&mut node_rule.build_result, node_item_entry)
-                            .unwrap_or_else(|| panic!("Rule {}.{} must be a string", node_key, as_string));
-                    }
-                    "append" => {
-                        update_rule(&mut node_rule.append, node_item_entry)
-                            .unwrap_or_else(|| panic!("Rule {}.{} must be a string", node_key, as_string));
-                    }
-                    "type-ok" => {
-                        update_rule(&mut node_rule.type_ok, node_item_entry)
-                            .unwrap_or_else(|| panic!("Rule {}.{} must be a string", node_key, as_string));
-                    }
-                    "fields" => {
-                        let fields = node_item_entry.as_hash()
-                            .unwrap_or_else(|| panic!("Rule {}.fields must be a hash, got {:?}", node_key, node_entries["fields"]));
-                        for (field_key, field_entry) in fields {
-                            let field_key = field_key.as_str()
-                                .unwrap_or_else(|| panic!("In rule {}, field entries must be field names",
-                                    node_key))
-                                .to_string();
-                            let field_name = syntax.get_field_name(&field_key)
-                                .unwrap_or_else(|| panic!("In rule {}, can't find field {}",
-                                    node_key,
-                                    field_key));
+    let rules_source_path = matches.value_of("INPUT.yaml").unwrap();
+    println!("...generating rules");
+    let mut file = File::open(rules_source_path)
+        .expect("Could not open rules");
+    let mut data = String::new();
+    file.read_to_string(&mut data)
+        .expect("Could not read rules");
 
-                            let mut field_rule = FieldParsingRules::default();
-                            for (field_config_key, field_config_entry) in field_entry.as_hash()
-                                .unwrap_or_else(|| panic!("Rule {}.fields.{} must be a hash", node_key, field_key))
-                            {
-                                let field_config_key = field_config_key.as_str()
-                                    .expect("Expected a string as a key");
-                                match field_config_key
-                                {
-                                    "block" => {
-                                        update_rule(&mut field_rule.declare, &field_config_entry["declare"])
-                                            .unwrap_or_else(|| panic!("Rule {}.fields.{}.{}.{} must be a string", node_key, field_key, field_config_key, "declare"));
-
-                                        update_rule(&mut field_rule.replace, &field_config_entry["replace"])
-                                            .unwrap_or_else(|| panic!("Rule {}.fields.{}.{}.{} must be a string", node_key, field_key, field_config_key, "replace"));
-
-                                        update_rule(&mut field_rule.block_before_field, &field_config_entry["before"])
-                                            .unwrap_or_else(|| panic!("Rule {}.fields.{}.{}.{} must be a string", node_key, field_key, field_config_key, "before"));
+    let yaml = yaml_rust::YamlLoader::load_from_str(&data)
+        .expect("Could not parse rules");
+    assert_eq!(yaml.len(), 1);
 
-                                        update_rule(&mut field_rule.block_after_field, &field_config_entry["after"])
-                                            .unwrap_or_else(|| panic!("Rule {}.fields.{}.{}.{} must be a string", node_key, field_key, field_config_key, "after"));
-                                    }
-                                    "before" => {
-                                        update_rule(&mut field_rule.before_field, &field_config_entry)
-                                            .unwrap_or_else(|| panic!("Rule {}.fields.{}.{} must be a string", node_key, field_key, field_config_key));
-                                    }
-                                    "after" => {
-                                        update_rule(&mut field_rule.after_field, &field_config_entry)
-                                            .unwrap_or_else(|| panic!("Rule {}.fields.{}.{} must be a string", node_key, field_key, field_config_key));
-                                    }
-                                    _ => {
-                                        panic!("Unexpected {}.fields.{}.{}", node_key, field_key, field_config_key)
-                                    }
-                                }
-                            }
-                            node_rule.by_field.insert(field_name.clone(), field_rule);
-                        }
-                    }
-                    _ => panic!("Unexpected node_item_key {}.{}", node_key, as_string)
-                }
-            }
-
-            generation_rules.per_node.insert(node_name.clone(), node_rule);
-            // FIXME: Check that rules are only for interfaces.
-        }
-    } else {
-        println!("...skipping rules");
-    }
-
-    let mut exporter = CPPExporter::new(deanonymizer,
-        syntax_options);
-    exporter.set_export_rules(generation_rules);
+    let global_rules = GlobalRules::new(&new_syntax, &yaml[0]);
+    let exporter = CPPExporter::new(new_syntax, global_rules);
 
     let write_to = |description, arg, data: &String| {
         let dest_path = matches.value_of(arg)
             .unwrap();
         println!("...exporting {description}: {path}",
             description = description,
             path = dest_path);
         let mut dest = File::create(&dest_path)
@@ -1285,9 +1361,9 @@ fn main() {
     write_to("C++ class header code", "OUT_HEADER_CLASS_FILE",
         &exporter.to_spidermonkey_class_hpp());
     write_to("C++ token header code", "OUT_TOKEN_FILE",
         &exporter.to_spidermonkey_token_hpp());
     write_to("C++ token implementation code", "OUT_IMPL_FILE",
         &exporter.to_spidermonkey_cpp());
 
     println!("...done");
-}
\ No newline at end of file
+}
--- a/third_party/rust/binjs_meta/src/export.rs
+++ b/third_party/rust/binjs_meta/src/export.rs
@@ -1,12 +1,12 @@
 use spec::*;
 use util::*;
 
-use std::collections::{ HashSet };
+use std::collections::{ HashMap, HashSet };
 
 use itertools::Itertools;
 
 /// A tool designed to replace all anonymous types in a specification
 /// of the language by explicitly named types.
 ///
 /// Consider the following mini-specifications for JSON:
 ///
@@ -56,42 +56,51 @@ use itertools::Itertools;
 /// typedef FrozenArray<OptionalValue> ListOfOptionalValue;
 /// typedef Value? Optionalvalue;
 /// ```
 ///
 /// This deanonymization lets us cleanly define intermediate data structures and/or parsers
 /// implementing the webidl specification.
 pub struct TypeDeanonymizer {
     builder: SpecBuilder,
+
+    /// When we encounter `typedef (A or B) C`
+    /// and `typedef (C or D) E`, we deanonymize into
+    /// `typedef (A or B or D) E`.
+    ///
+    /// This maintains the relationship that `E` (value)
+    /// contains `C` (key).
+    supersums_of: HashMap<NodeName, HashSet<NodeName>>,
 }
 impl TypeDeanonymizer {
     /// Create an empty TypeDeanonymizer.
     pub fn new(spec: &Spec) -> Self {
         let mut result = TypeDeanonymizer {
             builder: SpecBuilder::new(),
+            supersums_of: HashMap::new(),
         };
         // Copy field names
         for (_, name) in spec.field_names() {
             result.builder.import_field_name(name)
         }
 
-        // We may need to introduce name `offset`, we'll se.
-        let mut field_offset = None;
+        // We may need to introduce name `_skip`, we'll see.
+        let mut field_skip = None;
 
         // Copy and deanonymize interfaces.
         for (name, interface) in spec.interfaces_by_name() {
             result.builder.import_node_name(name);
             // Collect interfaces to copy them into the `builder`
             // and walk through their fields to deanonymize types.
 
             let mut fields = vec![];
-            // If the interface is skippable, introduce a first invisible field `_offset`.
+            // If the interface is skippable, introduce a first invisible field `_skip`.
             if interface.is_skippable() {
-                let name = field_offset.get_or_insert_with(||
-                    result.builder.field_name("_offset")
+                let name = field_skip.get_or_insert_with(||
+                    result.builder.field_name("_skip")
                 );
                 fields.push(Field::new(
                     name.clone(),
                     Type::offset().required()
                 ))
             }
 
             // Copy other fields.
@@ -101,16 +110,17 @@ impl TypeDeanonymizer {
             }
 
             // Copy the declaration.
             let mut declaration = result.builder.add_interface(name)
                 .unwrap();
             for field in fields.drain(..) {
                 declaration.with_field(field.name(), field.type_().clone());
             }
+            declaration.with_skippable(interface.is_skippable());
         }
         // Copy and deanonymize typedefs
         for (name, definition) in spec.typedefs_by_name() {
             result.builder.import_node_name(name);
             if result.builder.get_typedef(name).is_some() {
                 // Already imported by following links.
                 continue
             }
@@ -128,16 +138,20 @@ impl TypeDeanonymizer {
                 declaration.with_string(&string);
             }
         }
         debug!(target: "export_utils", "Names: {:?}", result.builder.names().keys().format(", "));
 
         result
     }
 
+    pub fn supersums(&self) -> &HashMap<NodeName, HashSet<NodeName>> {
+        &self.supersums_of
+    }
+
     /// Convert into a new specification.
     pub fn into_spec(self, options: SpecOptions) -> Spec {
         self.builder.into_spec(options)
     }
 
     /// If `name` is the name of a (deanonymized) type, return the corresponding type.
     pub fn get_node_name(&self, name: &str) -> Option<NodeName> {
         self.builder.get_node_name(name)
@@ -273,32 +287,44 @@ impl TypeDeanonymizer {
                 } else {
                     debug!(target: "export_utils", "import_typespec: Attempting to redefine typedef {name}", name = my_name.to_str());
                 }
                 (None, my_name)
             }
             TypeSpec::TypeSum(ref sum) => {
                 let mut full_sum = HashSet::new();
                 let mut names = vec![];
+                let mut subsums = vec![];
                 for sub_type in sum.types() {
                     let (mut sub_sum, name) = self.import_typespec(spec, sub_type, None);
                     let mut sub_sum = sub_sum.unwrap_or_else(
                         || panic!("While treating {:?}, attempting to create a sum containing {}, which isn't an interface or a sum of interfaces", type_spec, name)
                     );
+                    if sub_sum.len() > 1 {
+                        // The subtype is itself a sum.
+                        subsums.push(name.clone())
+                    }
                     names.push(name);
                     for item in sub_sum.drain() {
                         full_sum.insert(item);
                     }
                 }
                 let my_name =
                     match public_name {
                         None => self.builder.node_name(&format!("{}",
-                            names.drain(..).format("Or"))),
+                            names.drain(..)
+                                .format("Or"))),
                         Some(ref name) => name.clone()
                     };
+                for subsum_name in subsums {
+                    // So, `my_name` is a superset of `subsum_name`.
+                    let mut supersum_entry = self.supersums_of.entry(subsum_name.clone())
+                        .or_insert_with(|| HashSet::new());
+                    supersum_entry.insert(my_name.clone());
+                }
                 let sum : Vec<_> = full_sum.iter()
                     .map(Type::named)
                     .collect();
                 let deanonymized = Type::sum(&sum).required();
                 if let Some(ref mut typedef) = self.builder.add_typedef(&my_name) {
                     debug!(target: "export_utils", "import_typespec: Defining {name} (name to sum)", name = my_name.to_str());
                     typedef.with_type(deanonymized.clone());
                 } else {
--- a/third_party/rust/binjs_meta/src/import.rs
+++ b/third_party/rust/binjs_meta/src/import.rs
@@ -8,18 +8,17 @@ pub struct Importer {
 impl Importer {
     /// Import an AST into a SpecBuilder.
     ///
     /// ```
     /// extern crate binjs_meta;
     /// extern crate webidl;
     /// use webidl;
     ///
-    /// let parser = webidl::Parser::new();
-    /// let ast = parser.parse_string("
+    /// let ast = webidl::parse_string("
     ///    [Skippable] interface SkippableFoo {
     ///       attribute EagerFoo eager;
     ///    };
     ///    interface EagerFoo {
     ///       attribute bool value;
     ///    };
     /// ").expect("Could not parse");
     ///
--- a/third_party/rust/binjs_meta/src/util.rs
+++ b/third_party/rust/binjs_meta/src/util.rs
@@ -3,16 +3,26 @@
 extern crate inflector;
 
 pub trait ToStr {
     /// Return the value as a `str`.
     fn to_str(&self) -> &str;
     fn newline(&self) -> String {
         format!("{}\n", self.to_str())
     }
+
+    /// Append newline if the string is not empty.
+    fn newline_if_not_empty(&self) -> String {
+        let s = self.to_str();
+        if s.len() == 0 {
+            "".to_string()
+        } else {
+            format!("{}\n", s)
+        }
+    }
 }
 
 impl<'a> ToStr for &'a str {
     fn to_str(&self) -> &str {
         *self
     }
 }
 
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/.cargo-checksum.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{"files":{".travis.yml":"bf38c750b27b6e5a61894b904951f581db1e38b8ab13f9b658d0cbf93fe5274a","Cargo.toml":"a9110e72ddc1ad03c0d7f1045039b08a6d12136db46936a8d09eab6d4b6153b8","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7576269ea71f767b99297934c0b2367532690f8c4badc695edf8e04ab6a1e545","Makefile":"13f1c5b88a7b946b5813f7231df2933b6b19b223e9e2d3fa63ad681192f984b5","README.rst":"b333982845acfe7eacdbf5d3d6da866ffc0cd9d60e857c8b1d4d2f59532b2b3e","benches/bench1.rs":"c8fa84d18c891cbccb9df0b40fe1c69b0aa6b303e84d5a3093c94699e0532ae3","benches/extra/mod.rs":"4c5b03e74fc5b02383500c9da9fd6550262706ee569d70d085700f6d0b5749ba","benches/extra/zipslices.rs":"108dd488de366b2d83fb6bcc603ecbf9a017e165ac19d03440074fa244af3fb2","benches/tuple_combinations.rs":"8c14e9341d92e5cfd5f9a067d11088b37b003e82635d1ab3a8e5290e3ef83eed","benches/tuples.rs":"412a952f08bb03695952d5cfd57949dcf28be8b99e3c6653994bdb8af9654653","custom.css":"03d2316d325a09f03f0fae54d24b64f784518a8249432edbd60e01436be900d5","examples/iris.data":"596ffd580471ca4d4880f8e439c7281f3b50d8249a5960353cb200b1490f63a0","examples/iris.rs":"3996ca0a62762aec2b102f0f4244fe90d4b4354286d68d80cdc40e35f4352ba3","src/adaptors/mod.rs":"5918eb5e3bfff6d93361001004ce628092c19818e2b645d8ab44e06fea34f8b5","src/adaptors/multipeek.rs":"2b2f3b796b5664e3561a9ffabd16ea2971020cea13e1fb2ce5fd6e995934b4ab","src/concat_impl.rs":"276339b00588f54c25f8ffbe0ae3c0031f7e52fb53c6578554a0bde1681b58a5","src/cons_tuples_impl.rs":"1ccd5c024e9b5a9b2caa477671e18d6cbae530fcca114742f02b8b05b0ac353e","src/diff.rs":"921e2b867d7b32ffedc72a5eb780811322d14d1e0883a608b9028a2afcad0df2","src/format.rs":"412fbe02f12311c6fbcec1044f57ad6991783f5a3f323b9c391accfe4915106f","src/free.rs":"2c3e853dda297f4227cd7ecd37402a99c36169884ffbdfe823d296b0c8d16d33","src/groupbylazy.rs":"36a0f72232dbe54dfede33ea6d5740a648edc15ac4044b4f6492cac9946030ed","src/impl_macros.rs":"eb0bb3f70ec1bcaffa6110ae4134c777951ed1e5f48d8c811dbf0a597dc48faa","src/intersperse.rs":"8338a5b61ff5d2eb306ef7142578406f3ae4e4c7b2a8adcaa293a07c2299735b","src/kmerge_impl.rs":"e7902ccf6b811417e4dd9314964944beb08c2908e76396ff977227a7a350a16f","src/lib.rs":"385b2f3b8308f7a7c2b0de2eb29202c1b7f510edf450869b69e96903ac11e2ad","src/minmax.rs":"4668a7f824fbc133599f43ffb6f7283e5bd603e07df2d8176abc6f25d6af9db0","src/pad_tail.rs":"3a2b2f7fd38cac690eab3e1fa00e4f87df9fbf0bf87c7b3d68359d0c9b9f7f61","src/peeking_take_while.rs":"5d06552aa630217ab86fd4d191e2aaaf523e5320fc796e2f9d7f89f6230ade79","src/process_results_impl.rs":"bab4884ca7e472302484be9f2ffea1b3b79f08a84b40a41c280f1e5bbf1048b4","src/rciter_impl.rs":"449262cb5c2d1e9affe0b4020f1c28aa316a3718afe094667b79bbff1557d5e6","src/repeatn.rs":"ddcfdf0e0f6a4bc59f1f0fdba65d9ca09e1dfe10edb05ed7f6da486e904ffd3d","src/size_hint.rs":"c1d35b422a696cf3d63e7c90d8f9fdf01a304cf8156e914287c4ef48fea62dd3","src/sources.rs":"e1b644fc5ab2d09decbf0a547cff3953b4f195df28c2febb3f3fed2ec8401d46","src/tee.rs":"86b1da0697360091ae5de53a64cd8efb927b88c41c7fff5dec5814702c5bac31","src/tuple_impl.rs":"eb312789ea532cbfd31acabbcf7b4745b9935ff0b08e75f8e8c29445e558ea4d","src/with_position.rs":"8af04f26d9b89a2597fc10ad52c0feb61cb852dbf988b93d397f3300a6e70965","src/zip_eq_impl.rs":"95e493deeadd640751f5c49f55008bd31218978f38396967bc4a356f6f11d209","src/zip_longest.rs":"e463c58d5feebe5a0ed7964705ffedc6ec9a89ca2567a374cc8ceaf206249d5a","src/ziptuple.rs":"463f102add23ffa0702ec5ef110aae6c132267151fad66566b724fff7ebfa458","tests/peeking_take_while.rs":"a2ae6474e09620a47bb8a6e3c62929261e72c52881370adb2d22e89aa9e9aec8","tests/quick.rs":"e5f35e0d6b35b2b5df71e1e64299018a234c1ffbf0e38a6a541249810cef6402","tests/tests.rs":"adc905de07ec04dbbbd774891fde269407184a6b2c986d8ec5b0b466a2b36f79","tests/tuples.rs":"f8c8892c3c44dde0910eaf26f1756ddc62e264498245e5b0070a6912dc8c101c","tests/zip.rs":"fe213d70c4fa114cb4d1930a6b971f4af617a239041ddb87e6b5a9bbe62261b8"},"package":"d3f2be4da1690a039e9ae5fd575f706a63ad5a2120f161b1d653c9da3930dd21"}
\ No newline at end of file
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/.travis.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-language: rust
-sudo: false
-matrix:
-  include:
-    - rust: 1.12.0
-    - rust: stable
-    - rust: beta
-    - rust: nightly
-      env:
-       - BENCH=1
-branches:
-  only:
-    - master
-script:
-  - |
-      cargo build --verbose --features "$FEATURES" &&
-      cargo test --verbose --features "$FEATURES" &&
-      ([ "$BENCH" != 1 ] || cargo bench --verbose --features "$FEATURES")
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/Cargo.toml
+++ /dev/null
@@ -1,41 +0,0 @@
-# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
-#
-# When uploading crates to the registry Cargo will automatically
-# "normalize" Cargo.toml files for maximal compatibility
-# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g. crates.io) dependencies
-#
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
-
-[package]
-name = "itertools"
-version = "0.6.5"
-authors = ["bluss"]
-description = "Extra iterator adaptors, iterator methods, free functions, and macros."
-documentation = "https://docs.rs/itertools/"
-keywords = ["iterator", "data-structure", "zip", "product", "group-by"]
-categories = ["algorithms", "rust-patterns"]
-license = "MIT/Apache-2.0"
-repository = "https://github.com/bluss/rust-itertools"
-[package.metadata.release]
-no-dev-version = true
-[profile.bench]
-debug = true
-
-[lib]
-test = false
-bench = false
-[dependencies.either]
-version = "1.0"
-default-features = false
-[dev-dependencies.permutohedron]
-version = "0.2"
-
-[dev-dependencies.quickcheck]
-version = "0.4"
-default-features = false
-
-[features]
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/LICENSE-APACHE
+++ /dev/null
@@ -1,201 +0,0 @@
-                              Apache License
-                        Version 2.0, January 2004
-                     http://www.apache.org/licenses/
-
-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-1. Definitions.
-
-   "License" shall mean the terms and conditions for use, reproduction,
-   and distribution as defined by Sections 1 through 9 of this document.
-
-   "Licensor" shall mean the copyright owner or entity authorized by
-   the copyright owner that is granting the License.
-
-   "Legal Entity" shall mean the union of the acting entity and all
-   other entities that control, are controlled by, or are under common
-   control with that entity. For the purposes of this definition,
-   "control" means (i) the power, direct or indirect, to cause the
-   direction or management of such entity, whether by contract or
-   otherwise, or (ii) ownership of fifty percent (50%) or more of the
-   outstanding shares, or (iii) beneficial ownership of such entity.
-
-   "You" (or "Your") shall mean an individual or Legal Entity
-   exercising permissions granted by this License.
-
-   "Source" form shall mean the preferred form for making modifications,
-   including but not limited to software source code, documentation
-   source, and configuration files.
-
-   "Object" form shall mean any form resulting from mechanical
-   transformation or translation of a Source form, including but
-   not limited to compiled object code, generated documentation,
-   and conversions to other media types.
-
-   "Work" shall mean the work of authorship, whether in Source or
-   Object form, made available under the License, as indicated by a
-   copyright notice that is included in or attached to the work
-   (an example is provided in the Appendix below).
-
-   "Derivative Works" shall mean any work, whether in Source or Object
-   form, that is based on (or derived from) the Work and for which the
-   editorial revisions, annotations, elaborations, or other modifications
-   represent, as a whole, an original work of authorship. For the purposes
-   of this License, Derivative Works shall not include works that remain
-   separable from, or merely link (or bind by name) to the interfaces of,
-   the Work and Derivative Works thereof.
-
-   "Contribution" shall mean any work of authorship, including
-   the original version of the Work and any modifications or additions
-   to that Work or Derivative Works thereof, that is intentionally
-   submitted to Licensor for inclusion in the Work by the copyright owner
-   or by an individual or Legal Entity authorized to submit on behalf of
-   the copyright owner. For the purposes of this definition, "submitted"
-   means any form of electronic, verbal, or written communication sent
-   to the Licensor or its representatives, including but not limited to
-   communication on electronic mailing lists, source code control systems,
-   and issue tracking systems that are managed by, or on behalf of, the
-   Licensor for the purpose of discussing and improving the Work, but
-   excluding communication that is conspicuously marked or otherwise
-   designated in writing by the copyright owner as "Not a Contribution."
-
-   "Contributor" shall mean Licensor and any individual or Legal Entity
-   on behalf of whom a Contribution has been received by Licensor and
-   subsequently incorporated within the Work.
-
-2. Grant of Copyright License. Subject to the terms and conditions of
-   this License, each Contributor hereby grants to You a perpetual,
-   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-   copyright license to reproduce, prepare Derivative Works of,
-   publicly display, publicly perform, sublicense, and distribute the
-   Work and such Derivative Works in Source or Object form.
-
-3. Grant of Patent License. Subject to the terms and conditions of
-   this License, each Contributor hereby grants to You a perpetual,
-   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-   (except as stated in this section) patent license to make, have made,
-   use, offer to sell, sell, import, and otherwise transfer the Work,
-   where such license applies only to those patent claims licensable
-   by such Contributor that are necessarily infringed by their
-   Contribution(s) alone or by combination of their Contribution(s)
-   with the Work to which such Contribution(s) was submitted. If You
-   institute patent litigation against any entity (including a
-   cross-claim or counterclaim in a lawsuit) alleging that the Work
-   or a Contribution incorporated within the Work constitutes direct
-   or contributory patent infringement, then any patent licenses
-   granted to You under this License for that Work shall terminate
-   as of the date such litigation is filed.
-
-4. Redistribution. You may reproduce and distribute copies of the
-   Work or Derivative Works thereof in any medium, with or without
-   modifications, and in Source or Object form, provided that You
-   meet the following conditions:
-
-   (a) You must give any other recipients of the Work or
-       Derivative Works a copy of this License; and
-
-   (b) You must cause any modified files to carry prominent notices
-       stating that You changed the files; and
-
-   (c) You must retain, in the Source form of any Derivative Works
-       that You distribute, all copyright, patent, trademark, and
-       attribution notices from the Source form of the Work,
-       excluding those notices that do not pertain to any part of
-       the Derivative Works; and
-
-   (d) If the Work includes a "NOTICE" text file as part of its
-       distribution, then any Derivative Works that You distribute must
-       include a readable copy of the attribution notices contained
-       within such NOTICE file, excluding those notices that do not
-       pertain to any part of the Derivative Works, in at least one
-       of the following places: within a NOTICE text file distributed
-       as part of the Derivative Works; within the Source form or
-       documentation, if provided along with the Derivative Works; or,
-       within a display generated by the Derivative Works, if and
-       wherever such third-party notices normally appear. The contents
-       of the NOTICE file are for informational purposes only and
-       do not modify the License. You may add Your own attribution
-       notices within Derivative Works that You distribute, alongside
-       or as an addendum to the NOTICE text from the Work, provided
-       that such additional attribution notices cannot be construed
-       as modifying the License.
-
-   You may add Your own copyright statement to Your modifications and
-   may provide additional or different license terms and conditions
-   for use, reproduction, or distribution of Your modifications, or
-   for any such Derivative Works as a whole, provided Your use,
-   reproduction, and distribution of the Work otherwise complies with
-   the conditions stated in this License.
-
-5. Submission of Contributions. Unless You explicitly state otherwise,
-   any Contribution intentionally submitted for inclusion in the Work
-   by You to the Licensor shall be under the terms and conditions of
-   this License, without any additional terms or conditions.
-   Notwithstanding the above, nothing herein shall supersede or modify
-   the terms of any separate license agreement you may have executed
-   with Licensor regarding such Contributions.
-
-6. Trademarks. This License does not grant permission to use the trade
-   names, trademarks, service marks, or product names of the Licensor,
-   except as required for reasonable and customary use in describing the
-   origin of the Work and reproducing the content of the NOTICE file.
-
-7. Disclaimer of Warranty. Unless required by applicable law or
-   agreed to in writing, Licensor provides the Work (and each
-   Contributor provides its Contributions) on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-   implied, including, without limitation, any warranties or conditions
-   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-   PARTICULAR PURPOSE. You are solely responsible for determining the
-   appropriateness of using or redistributing the Work and assume any
-   risks associated with Your exercise of permissions under this License.
-
-8. Limitation of Liability. In no event and under no legal theory,
-   whether in tort (including negligence), contract, or otherwise,
-   unless required by applicable law (such as deliberate and grossly
-   negligent acts) or agreed to in writing, shall any Contributor be
-   liable to You for damages, including any direct, indirect, special,
-   incidental, or consequential damages of any character arising as a
-   result of this License or out of the use or inability to use the
-   Work (including but not limited to damages for loss of goodwill,
-   work stoppage, computer failure or malfunction, or any and all
-   other commercial damages or losses), even if such Contributor
-   has been advised of the possibility of such damages.
-
-9. Accepting Warranty or Additional Liability. While redistributing
-   the Work or Derivative Works thereof, You may choose to offer,
-   and charge a fee for, acceptance of support, warranty, indemnity,
-   or other liability obligations and/or rights consistent with this
-   License. However, in accepting such obligations, You may act only
-   on Your own behalf and on Your sole responsibility, not on behalf
-   of any other Contributor, and only if You agree to indemnify,
-   defend, and hold each Contributor harmless for any liability
-   incurred by, or claims asserted against, such Contributor by reason
-   of your accepting any such warranty or additional liability.
-
-END OF TERMS AND CONDITIONS
-
-APPENDIX: How to apply the Apache License to your work.
-
-   To apply the Apache License to your work, attach the following
-   boilerplate notice, with the fields enclosed by brackets "[]"
-   replaced with your own identifying information. (Don't include
-   the brackets!)  The text should be enclosed in the appropriate
-   comment syntax for the file format. We also recommend that a
-   file or class name and description of purpose be included on the
-   same "printed page" as the copyright notice for easier
-   identification within third-party archives.
-
-Copyright [yyyy] [name of copyright owner]
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-	http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/LICENSE-MIT
+++ /dev/null
@@ -1,25 +0,0 @@
-Copyright (c) 2015
-
-Permission is hereby granted, free of charge, to any
-person obtaining a copy of this software and associated
-documentation files (the "Software"), to deal in the
-Software without restriction, including without
-limitation the rights to use, copy, modify, merge,
-publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software
-is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice
-shall be included in all copies or substantial portions
-of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
-ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
-TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
-PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
-IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/Makefile
+++ /dev/null
@@ -1,34 +0,0 @@
-DOCCRATES = itertools
-
-# deps to delete the generated docs
-RMDOCS =
-
-FEATURES =
-
-VERSIONS = $(patsubst %,target/VERS/%,$(DOCCRATES))
-
-docs: mkdocs subst $(RMDOCS)
-
-# https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html
-$(VERSIONS): Cargo.toml
-	mkdir -p $(@D)
-	cargo pkgid $(@F) | sed -e "s/.*#\(\|.*:\)//" > "$@"
-
-$(DOCCRATES): %: target/VERS/%
-	# Put in the crate version into the docs
-	find ./doc/$@ -name "*.html" -exec sed -i -e "s/<title>\(.*\) - Rust/<title>$@ $(shell cat $<) - \1 - Rust/g" {} \;
-
-subst: $(DOCCRATES)
-
-mkdocs: Cargo.toml
-	cargo doc --features=$(FEATURES) --no-deps
-	rm -rf ./doc
-	cp -r ./target/doc ./doc
-	- cat ./custom.css >> doc/main.css
-
-$(RMDOCS): mkdocs
-	rm -r ./doc/$@
-	sed -i "/searchIndex\['$@'\]/d" doc/search-index.js
-
-
-.PHONY: docs mkdocs subst $(DOCCRATES) $(RMDOCS)
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/README.rst
+++ /dev/null
@@ -1,415 +0,0 @@
-
-Itertools
-=========
-
-Extra iterator adaptors, functions and macros.
-
-Please read the `API documentation here`__
-
-__ https://docs.rs/itertools/
-
-|build_status|_ |crates|_
-
-.. |build_status| image:: https://travis-ci.org/bluss/rust-itertools.svg?branch=master
-.. _build_status: https://travis-ci.org/bluss/rust-itertools
-
-.. |crates| image:: http://meritbadge.herokuapp.com/itertools
-.. _crates: https://crates.io/crates/itertools
-
-How to use with cargo:
-
-.. code:: toml
-
-    [dependencies]
-    itertools = "0.6.3"
-
-How to use in your crate:
-
-.. code:: rust
-
-    #[macro_use] extern crate itertools;
-
-    use itertools::Itertools;
-
-How to contribute:
-
-- Fix a bug or implement a new thing
-- Include tests for your new feature, preferably a quickcheck test
-- Make a Pull Request
-
-
-Recent Changes
---------------
-
-- 0.6.5
-
-  - Fix bug in ``.cartesian_product()``'s fold (which only was visible for
-    unfused iterators).
-
-- 0.6.4
-
-  - Add specific ``fold`` implementations for ``.cartesian_product()`` and
-    ``cons_tuples()``, which improves their performance in fold, foreach, and
-    iterator consumers derived from them.
-
-- 0.6.3
-
-  - Add iterator adaptor ``.positions(predicate)`` by @tmccombs
-
-- 0.6.2
-
-  - Add function ``process_results`` which can “lift” a function of the regular
-    values of an iterator so that it can process the ``Ok`` values from an
-    iterator of ``Results`` instead, by @shepmaster
-  - Add iterator method ``.concat()`` which combines all iterator elements
-    into a single collection using the ``Extend`` trait, by @srijs
-
-- 0.6.1
-
-  - Better size hint testing and subsequent size hint bugfixes by @rkarp.
-    Fixes bugs in product, interleave_shortest size hints.
-  - New iterator method ``.all_equal()`` by @phimuemue
-
-- 0.6.0
-
-  - Deprecated names were removed in favour of their replacements
-  - ``.flatten()`` does not implement double ended iteration anymore
-  - ``.fold_while()`` uses ``&mut self`` and returns ``FoldWhile<T>``, for
-    composability (#168)
-  - ``.foreach()`` and ``.fold1()`` use ``self``, like ``.fold()`` does.
-  - ``.combinations(0)`` now produces a single empty vector. (#174)
-
-- 0.5.10
-
-  - Add itertools method ``.kmerge_by()`` (and corresponding free function)
-  - Relaxed trait requirement of ``.kmerge()`` and ``.minmax()`` to PartialOrd.
-
-- 0.5.9
-
-  - Add multipeek method ``.reset_peek()``
-  - Add categories
-
-- 0.5.8
-
-  - Add iterator adaptor ``.peeking_take_while()`` and its trait ``PeekingNext``.
-
-- 0.5.7
-
-  - Add iterator adaptor ``.with_position()``
-  - Fix multipeek's performance for long peeks by using ``VecDeque``.
-
-- 0.5.6
-
-  - Add ``.map_results()``
-
-- 0.5.5
-
-  - Many more adaptors now implement ``Debug``
-  - Add free function constructor ``repeat_n``. ``RepeatN::new`` is now
-    deprecated.
-
-- 0.5.4
-
-  - Add infinite generator function ``iterate``, that takes a seed and a
-    closure.
-
-- 0.5.3
-
-  - Special-cased ``.fold()`` for flatten and put back. ``.foreach()``
-    now uses fold on the iterator, to pick up any iterator specific loop
-    implementation.
-  - ``.combinations(n)`` asserts up front that ``n != 0``, instead of
-    running into an error on the second iterator element.
-
-- 0.5.2
-
-  - Add ``.tuples::<T>()`` that iterates by two, three or four elements at
-    a time (where ``T`` is a tuple type).
-  - Add ``.tuple_windows::<T>()`` that iterates using a window of the
-    two, three or four most recent elements.
-  - Add ``.next_tuple::<T>()`` method, that picks the next two, three or four
-    elements in one go.
-  - ``.interleave()`` now has an accurate size hint.
-
-- 0.5.1
-
-  - Workaround module/function name clash that made racer crash on completing
-    itertools. Only internal changes needed.
-
-- 0.5.0
-
-  - `Release announcement <http://bluss.github.io/rust/2016/09/26/itertools-0.5.0/>`_
-  - Renamed:
-
-    - combinations is now tuple_combinations
-    - combinations_n to combinations
-    - group_by_lazy, chunks_lazy to group_by, chunks
-    - Unfold::new to unfold()
-    - RepeatCall::new to repeat_call()
-    - Zip::new to multizip
-    - PutBack::new, PutBackN::new to put_back, put_back_n
-    - PutBack::with_value is now a builder setter, not a constructor
-    - MultiPeek::new, .multipeek() to multipeek()
-    - format to format_with and format_default to format
-    - .into_rc() to rciter
-    - ``Partition`` enum is now ``Either``
-
-  - Module reorganization:
-
-    - All iterator structs are under ``itertools::structs`` but also
-      reexported to the top level, for backwards compatibility
-    - All free functions are reexported at the root, ``itertools::free`` will
-      be removed in the next version
-
-  - Removed:
-
-    - ZipSlices, use .zip() instead
-    - .enumerate_from(), ZipTrusted, due to being unstable
-    - .mend_slices(), moved to crate odds
-    - Stride, StrideMut, moved to crate odds
-    - linspace(), moved to crate itertools-num
-    - .sort_by(), use .sorted_by()
-    - .is_empty_hint(), use .size_hint()
-    - .dropn(), use .dropping()
-    - .map_fn(), use .map()
-    - .slice(), use .take() / .skip()
-    - helper traits in misc
-    - ``new`` constructors on iterator structs, use Itertools trait or free
-      functions instead
-    - ``itertools::size_hint`` is now private
-
-  - Behaviour changes:
-
-    - format and format_with helpers now panic if you try to format them more
-      than once.
-    - ``repeat_call`` is not double ended anymore
-
-  - New features:
-
-    - tuple flattening iterator is constructible with ``cons_tuples``
-    - itertools reexports ``Either`` from the ``either`` crate. ``Either<L, R>``
-      is an iterator when ``L, R`` are.
-    - ``MinMaxResult`` now implements Copy and Clone
-    - tuple_combinations supports 1-4 tuples of combinations (previously just 2)
-
-- 0.4.19
-
-  - Add ``.minmax_by()``
-  - Add ``itertools::free::cloned``
-  - Add ``itertools::free::rciter``
-  - Improve ``.step(n)`` slightly to take advantage of specialized Fuse better.
-
-- 0.4.18
-
-  - Only changes related to the "unstable" crate feature. This feature is more
-    or less deprecated.
-
-    - Use deprecated warnings when unstable is enabled. .enumerate_from() will
-      be removed imminently since it's using a deprecated libstd trait.
-
-- 0.4.17
-
-  - Fix bug in .kmerge() that caused it to often produce the wrong order (#134)
-
-- 0.4.16
-
-  - Improve precision of the interleave_shortest adaptor's size hint (it is
-    now computed exactly when possible).
-
-- 0.4.15
-
-  - Fixup on top of the workaround in 0.4.14. A function in itertools::free was
-    removed by mistake and now it is added back again.
-
-- 0.4.14
-
-  - Workaround an upstream regression in a rust nightly build that broke
-    compilation of of itertools::free::{interleave, merge}
-
-- 0.4.13
-
-  - Add .minmax() and .minmax_by_key(), iterator methods for finding both minimum
-    and maximum in one scan.
-  - Add .format_default(), a simpler version of .format() (lazy formatting
-    for iterators).
-
-- 0.4.12
-
-  - Add .zip_eq(), an adaptor like .zip() except it ensures iterators
-    of inequal length don't pass silently (instead it panics).
-  - Add .fold_while(), an iterator method that is a fold that
-    can short-circuit.
-  - Add .partition_map(), an iterator method that can separate elements
-    into two collections.
-
-- 0.4.11
-
-  - Add .get() for Stride{,Mut} and .get_mut() for StrideMut
-
-- 0.4.10
-
-  - Improve performance of .kmerge()
-
-- 0.4.9
-
-  - Add k-ary merge adaptor .kmerge()
-  - Fix a bug in .islice() with ranges a..b where a > b.
-
-- 0.4.8
-
-  - Implement Clone, Debug for Linspace
-
-- 0.4.7
-
-  - Add function diff_with() that compares two iterators
-  - Add .combinations_n(), an n-ary combinations iterator
-  - Add methods PutBack::with_value and PutBack::into_parts.
-
-- 0.4.6
-
-  - Add method .sorted()
-  - Add module ``itertools::free`` with free function variants of common
-    iterator adaptors and methods.
-    For example ``enumerate(iterable)``, ``rev(iterable)``, and so on.
-
-- 0.4.5
-
-  - Add .flatten()
-
-- 0.4.4
-
-  - Allow composing ZipSlices with itself
-
-- 0.4.3
-
-  - Write iproduct!() as a single expression; this allows temporary values
-    in its arguments.
-
-- 0.4.2
-
-  - Add .fold_options()
-  - Require Rust 1.1 or later
-
-- 0.4.1
-
-  - Update .dropping() to take advantage of .nth()
-
-- 0.4.0
-
-  - .merge(), .unique() and .dedup() now perform better due to not using
-    function pointers
-  - Add free functions enumerate() and rev()
-  - Breaking changes:
-
-    - Return types of .merge() and .merge_by() renamed and changed
-    - Method Merge::new removed
-    - .merge_by() now takes a closure that returns bool.
-    - Return type of .dedup() changed
-    - Return type of .mend_slices() changed
-    - Return type of .unique() changed
-    - Removed function times(), struct Times: use a range instead
-    - Removed deprecated macro icompr!()
-    - Removed deprecated FnMap and method .fn_map(): use .map_fn()
-    - .interleave_shortest() is no longer guaranteed to act like fused
-
-- 0.3.25
-
-  - Rename .sort_by() to .sorted_by(). Old name is deprecated.
-  - Fix well-formedness warnings from RFC 1214, no user visible impact
-
-- 0.3.24
-
-  - Improve performance of .merge()'s ordering function slightly
-
-- 0.3.23
-
-  - Added .chunks(), similar to (and based on) .group_by_lazy().
-  - Tweak linspace to match numpy.linspace and make it double ended.
-
-- 0.3.22
-
-  - Added ZipSlices, a fast zip for slices
-
-- 0.3.21
-
-  - Remove `Debug` impl for `Format`, it will have different use later
-
-- 0.3.20
-
-  - Optimize .group_by_lazy()
-
-- 0.3.19
-
-  - Added .group_by_lazy(), a possibly nonallocating group by
-  - Added .format(), a nonallocating formatting helper for iterators
-  - Remove uses of RandomAccessIterator since it has been deprecated in rust.
-
-- 0.3.17
-
-  - Added (adopted) Unfold from rust
-
-- 0.3.16
-
-  - Added adaptors .unique(), .unique_by()
-
-- 0.3.15
-
-  - Added method .sort_by()
-
-- 0.3.14
-
-  - Added adaptor .while_some()
-
-- 0.3.13
-
-  - Added adaptor .interleave_shortest()
-  - Added adaptor .pad_using()
-
-- 0.3.11
-
-  - Added assert_equal function
-
-- 0.3.10
-
-  - Bugfix .combinations() size_hint.
-
-- 0.3.8
-
-  - Added source RepeatCall
-
-- 0.3.7
-
-  - Added adaptor PutBackN
-  - Added adaptor .combinations()
-
-- 0.3.6
-
-  - Added itertools::partition, partition a sequence in place based on a predicate.
-  - Deprecate icompr!() with no replacement.
-
-- 0.3.5
-
-  - .map_fn() replaces deprecated .fn_map().
-
-- 0.3.4
-
-  - .take_while_ref() *by-ref adaptor*
-  - .coalesce() *adaptor*
-  - .mend_slices() *adaptor*
-
-- 0.3.3
-
-  - .dropping_back() *method*
-  - .fold1() *method*
-  - .is_empty_hint() *method*
-
-License
--------
-
-Dual-licensed to be compatible with the Rust project.
-
-Licensed under the Apache License, Version 2.0
-http://www.apache.org/licenses/LICENSE-2.0 or the MIT license
-http://opensource.org/licenses/MIT, at your
-option. This file may not be copied, modified, or distributed
-except according to those terms.
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/benches/bench1.rs
+++ /dev/null
@@ -1,703 +0,0 @@
-#![feature(test)]
-
-extern crate test;
-#[macro_use] extern crate itertools;
-
-use test::{black_box};
-use itertools::Itertools;
-
-use itertools::free::cloned;
-
-use std::iter::repeat;
-use std::cmp;
-use std::ops::Add;
-
-mod extra;
-
-use extra::ZipSlices;
-
-#[bench]
-fn slice_iter(b: &mut test::Bencher)
-{
-    let xs: Vec<_> = repeat(1i32).take(20).collect();
-    b.iter(|| for elt in xs.iter() {
-        test::black_box(elt);
-    })
-}
-
-#[bench]
-fn slice_iter_rev(b: &mut test::Bencher)
-{
-    let xs: Vec<_> = repeat(1i32).take(20).collect();
-    b.iter(|| for elt in xs.iter().rev() {
-        test::black_box(elt);
-    })
-}
-
-#[bench]
-fn zip_default_zip(b: &mut test::Bencher)
-{
-    let xs = vec![0; 1024];
-    let ys = vec![0; 768];
-    let xs = black_box(xs);
-    let ys = black_box(ys);
-
-    b.iter(|| {
-        for (&x, &y) in xs.iter().zip(&ys) {
-            test::black_box(x);
-            test::black_box(y);
-        }
-    })
-}
-
-#[bench]
-fn zipdot_i32_default_zip(b: &mut test::Bencher)
-{
-    let xs = vec![2; 1024];
-    let ys = vec![2; 768];
-    let xs = black_box(xs);
-    let ys = black_box(ys);
-
-    b.iter(|| {
-        let mut s = 0;
-        for (&x, &y) in xs.iter().zip(&ys) {
-            s += x * y;
-        }
-        s
-    })
-}
-
-#[bench]
-fn zipdot_f32_default_zip(b: &mut test::Bencher)
-{
-    let xs = vec![2f32; 1024];
-    let ys = vec![2f32; 768];
-    let xs = black_box(xs);
-    let ys = black_box(ys);
-
-    b.iter(|| {
-        let mut s = 0.;
-        for (&x, &y) in xs.iter().zip(&ys) {
-            s += x * y;
-        }
-        s
-    })
-}
-
-#[bench]
-fn zip_default_zip3(b: &mut test::Bencher)
-{
-    let xs = vec![0; 1024];
-    let ys = vec![0; 768];
-    let zs = vec![0; 766];
-    let xs = black_box(xs);
-    let ys = black_box(ys);
-    let zs = black_box(zs);
-
-    b.iter(|| {
-        for ((&x, &y), &z) in xs.iter().zip(&ys).zip(&zs) {
-            test::black_box(x);
-            test::black_box(y);
-            test::black_box(z);
-        }
-    })
-}
-
-/*
-#[bench]
-fn zip_slices_ziptuple(b: &mut test::Bencher)
-{
-    let xs = vec![0; 1024];
-    let ys = vec![0; 768];
-
-    b.iter(|| {
-        let xs = black_box(&xs);
-        let ys = black_box(&ys);
-        for (&x, &y) in Zip::new((xs, ys)) {
-            test::black_box(x);
-            test::black_box(y);
-        }
-    })
-}
-*/
-
-#[bench]
-fn zipslices(b: &mut test::Bencher)
-{
-    let xs = vec![0; 1024];
-    let ys = vec![0; 768];
-    let xs = black_box(xs);
-    let ys = black_box(ys);
-
-    b.iter(|| {
-        for (&x, &y) in ZipSlices::new(&xs, &ys) {
-            test::black_box(x);
-            test::black_box(y);
-        }
-    })
-}
-
-#[bench]
-fn zipslices_mut(b: &mut test::Bencher)
-{
-    let xs = vec![0; 1024];
-    let ys = vec![0; 768];
-    let xs = black_box(xs);
-    let mut ys = black_box(ys);
-
-    b.iter(|| {
-        for (&x, &mut y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) {
-            test::black_box(x);
-            test::black_box(y);
-        }
-    })
-}
-
-#[bench]
-fn zipdot_i32_zipslices(b: &mut test::Bencher)
-{
-    let xs = vec![2; 1024];
-    let ys = vec![2; 768];
-    let xs = black_box(xs);
-    let ys = black_box(ys);
-
-    b.iter(|| {
-        let mut s = 0i32;
-        for (&x, &y) in ZipSlices::new(&xs, &ys) {
-            s += x * y;
-        }
-        s
-    })
-}
-
-#[bench]
-fn zipdot_f32_zipslices(b: &mut test::Bencher)
-{
-    let xs = vec![2f32; 1024];
-    let ys = vec![2f32; 768];
-    let xs = black_box(xs);
-    let ys = black_box(ys);
-
-    b.iter(|| {
-        let mut s = 0.;
-        for (&x, &y) in ZipSlices::new(&xs, &ys) {
-            s += x * y;
-        }
-        s
-    })
-}
-
-
-#[bench]
-fn zip_checked_counted_loop(b: &mut test::Bencher)
-{
-    let xs = vec![0; 1024];
-    let ys = vec![0; 768];
-    let xs = black_box(xs);
-    let ys = black_box(ys);
-
-    b.iter(|| {
-        // Must slice to equal lengths, and then bounds checks are eliminated!
-        let len = cmp::min(xs.len(), ys.len());
-        let xs = &xs[..len];
-        let ys = &ys[..len];
-
-        for i in 0..len {
-            let x = xs[i];
-            let y = ys[i];
-            test::black_box(x);
-            test::black_box(y);
-        }
-    })
-}
-
-#[bench]
-fn zipdot_i32_checked_counted_loop(b: &mut test::Bencher)
-{
-    let xs = vec![2; 1024];
-    let ys = vec![2; 768];
-    let xs = black_box(xs);
-    let ys = black_box(ys);
-
-    b.iter(|| {
-        // Must slice to equal lengths, and then bounds checks are eliminated!
-        let len = cmp::min(xs.len(), ys.len());
-        let xs = &xs[..len];
-        let ys = &ys[..len];
-
-        let mut s = 0i32;
-
-        for i in 0..len {
-            s += xs[i] * ys[i];
-        }
-        s
-    })
-}
-
-#[bench]
-fn zipdot_f32_checked_counted_loop(b: &mut test::Bencher)
-{
-    let xs = vec![2f32; 1024];
-    let ys = vec![2f32; 768];
-    let xs = black_box(xs);
-    let ys = black_box(ys);
-
-    b.iter(|| {
-        // Must slice to equal lengths, and then bounds checks are eliminated!
-        let len = cmp::min(xs.len(), ys.len());
-        let xs = &xs[..len];
-        let ys = &ys[..len];
-
-        let mut s = 0.;
-
-        for i in 0..len {
-            s += xs[i] * ys[i];
-        }
-        s
-    })
-}
-
-#[bench]
-fn zipdot_f32_checked_counted_unrolled_loop(b: &mut test::Bencher)
-{
-    let xs = vec![2f32; 1024];
-    let ys = vec![2f32; 768];
-    let xs = black_box(xs);
-    let ys = black_box(ys);
-
-    b.iter(|| {
-        // Must slice to equal lengths, and then bounds checks are eliminated!
-        let len = cmp::min(xs.len(), ys.len());
-        let mut xs = &xs[..len];
-        let mut ys = &ys[..len];
-
-        let mut s = 0.;
-        let (mut p0, mut p1, mut p2, mut p3, mut p4, mut p5, mut p6, mut p7) =
-            (0., 0., 0., 0., 0., 0., 0., 0.);
-
-        // how to unroll and have bounds checks eliminated (by cristicbz)
-        // split sum into eight parts to enable vectorization (by bluss)
-        while xs.len() >= 8 {
-            p0 += xs[0] * ys[0];
-            p1 += xs[1] * ys[1];
-            p2 += xs[2] * ys[2];
-            p3 += xs[3] * ys[3];
-            p4 += xs[4] * ys[4];
-            p5 += xs[5] * ys[5];
-            p6 += xs[6] * ys[6];
-            p7 += xs[7] * ys[7];
-
-            xs = &xs[8..];
-            ys = &ys[8..];
-        }
-        s += p0 + p4;
-        s += p1 + p5;
-        s += p2 + p6;
-        s += p3 + p7;
-
-        for i in 0..xs.len() {
-            s += xs[i] * ys[i];
-        }
-        s
-    })
-}
-
-#[bench]
-fn zip_unchecked_counted_loop(b: &mut test::Bencher)
-{
-    let xs = vec![0; 1024];
-    let ys = vec![0; 768];
-    let xs = black_box(xs);
-    let ys = black_box(ys);
-
-    b.iter(|| {
-        let len = cmp::min(xs.len(), ys.len());
-        for i in 0..len {
-            unsafe {
-            let x = *xs.get_unchecked(i);
-            let y = *ys.get_unchecked(i);
-            test::black_box(x);
-            test::black_box(y);
-            }
-        }
-    })
-}
-
-#[bench]
-fn zipdot_i32_unchecked_counted_loop(b: &mut test::Bencher)
-{
-    let xs = vec![2; 1024];
-    let ys = vec![2; 768];
-    let xs = black_box(xs);
-    let ys = black_box(ys);
-
-    b.iter(|| {
-        let len = cmp::min(xs.len(), ys.len());
-        let mut s = 0i32;
-        for i in 0..len {
-            unsafe {
-            let x = *xs.get_unchecked(i);
-            let y = *ys.get_unchecked(i);
-            s += x * y;
-            }
-        }
-        s
-    })
-}
-
-#[bench]
-fn zipdot_f32_unchecked_counted_loop(b: &mut test::Bencher)
-{
-    let xs = vec![2.; 1024];
-    let ys = vec![2.; 768];
-    let xs = black_box(xs);
-    let ys = black_box(ys);
-
-    b.iter(|| {
-        let len = cmp::min(xs.len(), ys.len());
-        let mut s = 0f32;
-        for i in 0..len {
-            unsafe {
-            let x = *xs.get_unchecked(i);
-            let y = *ys.get_unchecked(i);
-            s += x * y;
-            }
-        }
-        s
-    })
-}
-
-#[bench]
-fn zip_unchecked_counted_loop3(b: &mut test::Bencher)
-{
-    let xs = vec![0; 1024];
-    let ys = vec![0; 768];
-    let zs = vec![0; 766];
-    let xs = black_box(xs);
-    let ys = black_box(ys);
-    let zs = black_box(zs);
-
-    b.iter(|| {
-        let len = cmp::min(xs.len(), cmp::min(ys.len(), zs.len()));
-        for i in 0..len {
-            unsafe {
-            let x = *xs.get_unchecked(i);
-            let y = *ys.get_unchecked(i);
-            let z = *zs.get_unchecked(i);
-            test::black_box(x);
-            test::black_box(y);
-            test::black_box(z);
-            }
-        }
-    })
-}
-
-#[bench]
-fn group_by_lazy_1(b: &mut test::Bencher) {
-    let mut data = vec![0; 1024];
-    for (index, elt) in data.iter_mut().enumerate() {
-        *elt = index / 10;
-    }
-
-    let data = test::black_box(data);
-
-    b.iter(|| {
-        for (_key, group) in &data.iter().group_by(|elt| **elt) {
-            for elt in group {
-                test::black_box(elt);
-            }
-        }
-    })
-}
-
-#[bench]
-fn group_by_lazy_2(b: &mut test::Bencher) {
-    let mut data = vec![0; 1024];
-    for (index, elt) in data.iter_mut().enumerate() {
-        *elt = index / 2;
-    }
-
-    let data = test::black_box(data);
-
-    b.iter(|| {
-        for (_key, group) in &data.iter().group_by(|elt| **elt) {
-            for elt in group {
-                test::black_box(elt);
-            }
-        }
-    })
-}
-
-#[bench]
-fn slice_chunks(b: &mut test::Bencher) {
-    let data = vec![0; 1024];
-
-    let data = test::black_box(data);
-    let sz = test::black_box(10);
-
-    b.iter(|| {
-        for group in data.chunks(sz) {
-            for elt in group {
-                test::black_box(elt);
-            }
-        }
-    })
-}
-
-#[bench]
-fn chunks_lazy_1(b: &mut test::Bencher) {
-    let data = vec![0; 1024];
-
-    let data = test::black_box(data);
-    let sz = test::black_box(10);
-
-    b.iter(|| {
-        for group in &data.iter().chunks(sz) {
-            for elt in group {
-                test::black_box(elt);
-            }
-        }
-    })
-}
-
-#[bench]
-fn equal(b: &mut test::Bencher) {
-    let data = vec![7; 1024];
-    let l = data.len();
-    let alpha = test::black_box(&data[1..]);
-    let beta = test::black_box(&data[..l - 1]);
-    b.iter(|| {
-        itertools::equal(alpha, beta)
-    })
-}
-
-#[bench]
-fn merge_default(b: &mut test::Bencher) {
-    let mut data1 = vec![0; 1024];
-    let mut data2 = vec![0; 800];
-    let mut x = 0;
-    for (_, elt) in data1.iter_mut().enumerate() {
-        *elt = x;
-        x += 1;
-    }
-
-    let mut y = 0;
-    for (i, elt) in data2.iter_mut().enumerate() {
-        *elt += y;
-        if i % 3 == 0 {
-            y += 3;
-        } else {
-            y += 0;
-        }
-    }
-    let data1 = test::black_box(data1);
-    let data2 = test::black_box(data2);
-    b.iter(|| {
-        data1.iter().merge(&data2).count()
-    })
-}
-
-#[bench]
-fn merge_by_cmp(b: &mut test::Bencher) {
-    let mut data1 = vec![0; 1024];
-    let mut data2 = vec![0; 800];
-    let mut x = 0;
-    for (_, elt) in data1.iter_mut().enumerate() {
-        *elt = x;
-        x += 1;
-    }
-
-    let mut y = 0;
-    for (i, elt) in data2.iter_mut().enumerate() {
-        *elt += y;
-        if i % 3 == 0 {
-            y += 3;
-        } else {
-            y += 0;
-        }
-    }
-    let data1 = test::black_box(data1);
-    let data2 = test::black_box(data2);
-    b.iter(|| {
-        data1.iter().merge_by(&data2, PartialOrd::le).count()
-    })
-}
-
-#[bench]
-fn merge_by_lt(b: &mut test::Bencher) {
-    let mut data1 = vec![0; 1024];
-    let mut data2 = vec![0; 800];
-    let mut x = 0;
-    for (_, elt) in data1.iter_mut().enumerate() {
-        *elt = x;
-        x += 1;
-    }
-
-    let mut y = 0;
-    for (i, elt) in data2.iter_mut().enumerate() {
-        *elt += y;
-        if i % 3 == 0 {
-            y += 3;
-        } else {
-            y += 0;
-        }
-    }
-    let data1 = test::black_box(data1);
-    let data2 = test::black_box(data2);
-    b.iter(|| {
-        data1.iter().merge_by(&data2, |a, b| a <= b).count()
-    })
-}
-
-#[bench]
-fn kmerge_default(b: &mut test::Bencher) {
-    let mut data1 = vec![0; 1024];
-    let mut data2 = vec![0; 800];
-    let mut x = 0;
-    for (_, elt) in data1.iter_mut().enumerate() {
-        *elt = x;
-        x += 1;
-    }
-
-    let mut y = 0;
-    for (i, elt) in data2.iter_mut().enumerate() {
-        *elt += y;
-        if i % 3 == 0 {
-            y += 3;
-        } else {
-            y += 0;
-        }
-    }
-    let data1 = test::black_box(data1);
-    let data2 = test::black_box(data2);
-    let its = &[data1.iter(), data2.iter()];
-    b.iter(|| {
-        its.iter().cloned().kmerge().count()
-    })
-}
-
-#[bench]
-fn kmerge_tenway(b: &mut test::Bencher) {
-    let mut data = vec![0; 10240];
-
-    let mut state = 1729u16;
-    fn rng(state: &mut u16) -> u16 {
-        let new = state.wrapping_mul(31421) + 6927;
-        *state = new;
-        new
-    }
-
-    for elt in &mut data {
-        *elt = rng(&mut state);
-    }
-
-    let mut chunks = Vec::new();
-    let mut rest = &mut data[..];
-    while rest.len() > 0 {
-        let chunk_len = 1 + rng(&mut state) % 512;
-        let chunk_len = cmp::min(rest.len(), chunk_len as usize);
-        let (fst, tail) = {rest}.split_at_mut(chunk_len);
-        fst.sort();
-        chunks.push(fst.iter().cloned());
-        rest = tail;
-    }
-
-    // println!("Chunk lengths: {}", chunks.iter().format_with(", ", |elt, f| f(&elt.len())));
-
-    b.iter(|| {
-        chunks.iter().cloned().kmerge().count()
-    })
-}
-
-
-fn fast_integer_sum<I>(iter: I) -> I::Item
-    where I: IntoIterator,
-          I::Item: Default + Add<Output=I::Item>
-{
-    iter.into_iter().fold(<_>::default(), |x, y| x + y)
-}
-
-
-#[bench]
-fn step_vec_2(b: &mut test::Bencher) {
-    let v = vec![0; 1024];
-    b.iter(|| {
-        fast_integer_sum(cloned(v.iter().step(2)))
-    });
-}
-
-#[bench]
-fn step_vec_10(b: &mut test::Bencher) {
-    let v = vec![0; 1024];
-    b.iter(|| {
-        fast_integer_sum(cloned(v.iter().step(10)))
-    });
-}
-
-#[bench]
-fn step_range_2(b: &mut test::Bencher) {
-    let v = black_box(0..1024);
-    b.iter(|| {
-        fast_integer_sum(v.clone().step(2))
-    });
-}
-
-#[bench]
-fn step_range_10(b: &mut test::Bencher) {
-    let v = black_box(0..1024);
-    b.iter(|| {
-        fast_integer_sum(v.clone().step(10))
-    });
-}
-
-#[bench]
-fn cartesian_product_iterator(b: &mut test::Bencher)
-{
-    let xs = vec![0; 16];
-
-    b.iter(|| {
-        let mut sum = 0;
-        for (&x, &y, &z) in iproduct!(&xs, &xs, &xs) {
-            sum += x;
-            sum += y;
-            sum += z;
-        }
-        sum
-    })
-}
-
-#[bench]
-fn cartesian_product_fold(b: &mut test::Bencher)
-{
-    let xs = vec![0; 16];
-
-    b.iter(|| {
-        let mut sum = 0;
-        iproduct!(&xs, &xs, &xs).fold((), |(), (&x, &y, &z)| {
-            sum += x;
-            sum += y;
-            sum += z;
-        });
-        sum
-    })
-}
-
-#[bench]
-fn cartesian_product_nested_for(b: &mut test::Bencher)
-{
-    let xs = vec![0; 16];
-
-    b.iter(|| {
-        let mut sum = 0;
-        for &x in &xs {
-            for &y in &xs {
-                for &z in &xs {
-                    sum += x;
-                    sum += y;
-                    sum += z;
-                }
-            }
-        }
-        sum
-    })
-}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/benches/extra/mod.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-pub use self::zipslices::ZipSlices;
-mod zipslices;
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/benches/extra/zipslices.rs
+++ /dev/null
@@ -1,189 +0,0 @@
-use std::cmp;
-
-// Note: There are different ways to implement ZipSlices.
-// This version performed the best in benchmarks.
-//
-// I also implemented a version with three pointes (tptr, tend, uptr),
-// that mimiced slice::Iter and only checked bounds by using tptr == tend,
-// but that was inferior to this solution.
-
-/// An iterator which iterates two slices simultaneously.
-///
-/// `ZipSlices` acts like a double-ended `.zip()` iterator.
-///
-/// It was intended to be more efficient than `.zip()`, and it was, then
-/// rustc changed how it optimizes so it can not promise improved performance
-/// at this time.
-///
-/// Note that elements past the end of the shortest of the two slices are ignored.
-///
-/// Iterator element type for `ZipSlices<T, U>` is `(T::Item, U::Item)`. For example,
-/// for a `ZipSlices<&'a [A], &'b mut [B]>`, the element type is `(&'a A, &'b mut B)`.
-#[derive(Clone)]
-pub struct ZipSlices<T, U> {
-    t: T,
-    u: U,
-    len: usize,
-    index: usize,
-}
-
-impl<'a, 'b, A, B> ZipSlices<&'a [A], &'b [B]> {
-    /// Create a new `ZipSlices` from slices `a` and `b`.
-    ///
-    /// Act like a double-ended `.zip()` iterator, but more efficiently.
-    ///
-    /// Note that elements past the end of the shortest of the two slices are ignored.
-    #[inline(always)]
-    pub fn new(a: &'a [A], b: &'b [B]) -> Self {
-        let minl = cmp::min(a.len(), b.len());
-        ZipSlices {
-            t: a,
-            u: b,
-            len: minl,
-            index: 0,
-        }
-    }
-}
-
-impl<T, U> ZipSlices<T, U>
-    where T: Slice,
-          U: Slice
-{
-    /// Create a new `ZipSlices` from slices `a` and `b`.
-    ///
-    /// Act like a double-ended `.zip()` iterator, but more efficiently.
-    ///
-    /// Note that elements past the end of the shortest of the two slices are ignored.
-    #[inline(always)]
-    pub fn from_slices(a: T, b: U) -> Self {
-        let minl = cmp::min(a.len(), b.len());
-        ZipSlices {
-            t: a,
-            u: b,
-            len: minl,
-            index: 0,
-        }
-    }
-}
-
-impl<T, U> Iterator for ZipSlices<T, U>
-    where T: Slice,
-          U: Slice
-{
-    type Item = (T::Item, U::Item);
-
-    #[inline(always)]
-    fn next(&mut self) -> Option<Self::Item> {
-        unsafe {
-            if self.index >= self.len {
-                None
-            } else {
-                let i = self.index;
-                self.index += 1;
-                Some((
-                    self.t.get_unchecked(i),
-                    self.u.get_unchecked(i)))
-            }
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let len = self.len - self.index;
-        (len, Some(len))
-    }
-}
-
-impl<T, U> DoubleEndedIterator for ZipSlices<T, U>
-    where T: Slice,
-          U: Slice
-{
-    #[inline(always)]
-    fn next_back(&mut self) -> Option<Self::Item> {
-        unsafe {
-            if self.index >= self.len {
-                None
-            } else {
-                self.len -= 1;
-                let i = self.len;
-                Some((
-                    self.t.get_unchecked(i),
-                    self.u.get_unchecked(i)))
-            }
-        }
-    }
-}
-
-impl<T, U> ExactSizeIterator for ZipSlices<T, U>
-    where T: Slice,
-          U: Slice
-{}
-
-unsafe impl<T, U> Slice for ZipSlices<T, U>
-    where T: Slice,
-          U: Slice
-{
-    type Item = (T::Item, U::Item);
-
-    fn len(&self) -> usize {
-        self.len - self.index
-    }
-
-    unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
-        (self.t.get_unchecked(i),
-         self.u.get_unchecked(i))
-    }
-}
-
-/// A helper trait to let `ZipSlices` accept both `&[T]` and `&mut [T]`.
-///
-/// Unsafe trait because:
-///
-/// - Implementors must guarantee that `get_unchecked` is valid for all indices `0..len()`.
-pub unsafe trait Slice {
-    /// The type of a reference to the slice's elements
-    type Item;
-    #[doc(hidden)]
-    fn len(&self) -> usize;
-    #[doc(hidden)]
-    unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item;
-}
-
-unsafe impl<'a, T> Slice for &'a [T] {
-    type Item = &'a T;
-    #[inline(always)]
-    fn len(&self) -> usize { (**self).len() }
-    #[inline(always)]
-    unsafe fn get_unchecked(&mut self, i: usize) -> &'a T {
-        debug_assert!(i < self.len());
-        (**self).get_unchecked(i)
-    }
-}
-
-unsafe impl<'a, T> Slice for &'a mut [T] {
-    type Item = &'a mut T;
-    #[inline(always)]
-    fn len(&self) -> usize { (**self).len() }
-    #[inline(always)]
-    unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T {
-        debug_assert!(i < self.len());
-        // override the lifetime constraints of &mut &'a mut [T]
-        (*(*self as *mut [T])).get_unchecked_mut(i)
-    }
-}
-
-#[test]
-fn zipslices() {
-
-    let xs = [1, 2, 3, 4, 5, 6];
-    let ys = [1, 2, 3, 7];
-    ::itertools::assert_equal(ZipSlices::new(&xs, &ys), xs.iter().zip(&ys));
-
-    let xs = [1, 2, 3, 4, 5, 6];
-    let mut ys = [0; 6];
-    for (x, y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) {
-        *y = *x;
-    }
-    ::itertools::assert_equal(&xs, &ys);
-}
-
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/benches/tuple_combinations.rs
+++ /dev/null
@@ -1,97 +0,0 @@
-#![feature(test)]
-
-extern crate test;
-extern crate itertools;
-
-use test::{black_box, Bencher};
-use itertools::Itertools;
-
-// aproximate 100_000 iterations for each combination
-const N1: usize = 100_000;
-const N2: usize = 448;
-const N3: usize = 86;
-const N4: usize = 41;
-
-#[bench]
-fn comb_for1(b: &mut Bencher) {
-    b.iter(|| {
-        for i in 0..N1 {
-            black_box(i);
-        }
-    });
-}
-
-#[bench]
-fn comb_for2(b: &mut Bencher) {
-    b.iter(|| {
-        for i in 0..N2 {
-            for j in (i + 1)..N2 {
-                black_box(i + j);
-            }
-        }
-    });
-}
-
-#[bench]
-fn comb_for3(b: &mut Bencher) {
-    b.iter(|| {
-        for i in 0..N3 {
-            for j in (i + 1)..N3 {
-                for k in (j + 1)..N3 {
-                    black_box(i + j + k);
-                }
-            }
-        }
-    });
-}
-
-#[bench]
-fn comb_for4(b: &mut Bencher) {
-    b.iter(|| {
-        for i in 0..N4 {
-            for j in (i + 1)..N4 {
-                for k in (j + 1)..N4 {
-                    for l in (k + 1)..N4 {
-                        black_box(i + j + k + l);
-                    }
-                }
-            }
-        }
-    });
-}
-
-#[bench]
-fn comb_c1(b: &mut Bencher) {
-    b.iter(|| {
-        for (i,) in (0..N1).tuple_combinations() {
-            black_box(i);
-        }
-    });
-}
-
-#[bench]
-fn comb_c2(b: &mut Bencher) {
-    b.iter(|| {
-        for (i, j) in (0..N2).tuple_combinations() {
-            black_box(i + j);
-        }
-    });
-}
-
-#[bench]
-fn comb_c3(b: &mut Bencher) {
-    b.iter(|| {
-        for (i, j, k) in (0..N3).tuple_combinations() {
-            black_box(i + j + k);
-        }
-    });
-}
-
-#[bench]
-fn comb_c4(b: &mut Bencher) {
-    b.iter(|| {
-        for (i, j, k, l) in (0..N4).tuple_combinations() {
-            black_box(i + j + k + l);
-        }
-    });
-}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/benches/tuples.rs
+++ /dev/null
@@ -1,190 +0,0 @@
-#![feature(test)]
-
-extern crate test;
-extern crate itertools;
-
-use test::Bencher;
-use itertools::Itertools;
-
-fn s1(a: u32) -> u32 {
-    a
-}
-
-fn s2(a: u32, b: u32) -> u32 {
-    a + b
-}
-
-fn s3(a: u32, b: u32, c: u32) -> u32 {
-    a + b + c
-}
-
-fn s4(a: u32, b: u32, c: u32, d: u32) -> u32 {
-    a + b + c + d
-}
-
-fn sum_s1(s: &[u32]) -> u32 {
-    s1(s[0])
-}
-
-fn sum_s2(s: &[u32]) -> u32 {
-    s2(s[0], s[1])
-}
-
-fn sum_s3(s: &[u32]) -> u32 {
-    s3(s[0], s[1], s[2])
-}
-
-fn sum_s4(s: &[u32]) -> u32 {
-    s4(s[0], s[1], s[2], s[3])
-}
-
-fn sum_t1(s: &(&u32, )) -> u32 {
-    s1(*s.0)
-}
-
-fn sum_t2(s: &(&u32, &u32)) -> u32 {
-    s2(*s.0, *s.1)
-}
-
-fn sum_t3(s: &(&u32, &u32, &u32)) -> u32 {
-    s3(*s.0, *s.1, *s.2)
-}
-
-fn sum_t4(s: &(&u32, &u32, &u32, &u32)) -> u32 {
-    s4(*s.0, *s.1, *s.2, *s.3)
-}
-
-macro_rules! def_benchs {
-    ($N:expr;
-     $TUPLE_FUN:ident,
-     $TUPLES:ident,
-     $TUPLE_WINDOWS:ident;
-     $SLICE_FUN:ident,
-     $CHUNKS:ident,
-     $WINDOWS:ident;
-     $FOR_CHUNKS:ident,
-     $FOR_WINDOWS:ident
-     ) => (
-        #[bench]
-        fn $FOR_CHUNKS(b: &mut Bencher) {
-            let v: Vec<u32> = (0.. $N * 1_000).collect();
-            let mut s = 0;
-            b.iter(|| {
-                let mut j = 0;
-                for _ in 0..1_000 {
-                    s += $SLICE_FUN(&v[j..(j + $N)]);
-                    j += $N;
-                }
-                s
-            });
-        }
-
-        #[bench]
-        fn $FOR_WINDOWS(b: &mut Bencher) {
-            let v: Vec<u32> = (0..1_000).collect();
-            let mut s = 0;
-            b.iter(|| {
-                for i in 0..(1_000 - $N) {
-                    s += $SLICE_FUN(&v[i..(i + $N)]);
-                }
-                s
-            });
-        }
-
-        #[bench]
-        fn $TUPLES(b: &mut Bencher) {
-            let v: Vec<u32> = (0.. $N * 1_000).collect();
-            let mut s = 0;
-            b.iter(|| {
-                for x in v.iter().tuples() {
-                    s += $TUPLE_FUN(&x);
-                }
-                s
-            });
-        }
-
-        #[bench]
-        fn $CHUNKS(b: &mut Bencher) {
-            let v: Vec<u32> = (0.. $N * 1_000).collect();
-            let mut s = 0;
-            b.iter(|| {
-                for x in v.chunks($N) {
-                    s += $SLICE_FUN(x);
-                }
-                s
-            });
-        }
-
-        #[bench]
-        fn $TUPLE_WINDOWS(b: &mut Bencher) {
-            let v: Vec<u32> = (0..1_000).collect();
-            let mut s = 0;
-            b.iter(|| {
-                for x in v.iter().tuple_windows() {
-                    s += $TUPLE_FUN(&x);
-                }
-                s
-            });
-        }
-
-        #[bench]
-        fn $WINDOWS(b: &mut Bencher) {
-            let v: Vec<u32> = (0..1_000).collect();
-            let mut s = 0;
-            b.iter(|| {
-                for x in v.windows($N) {
-                    s += $SLICE_FUN(x);
-                }
-                s
-            });
-        }
-    )
-}
-
-def_benchs!{
-    1;
-    sum_t1,
-    tuple_chunks_1,
-    tuple_windows_1;
-    sum_s1,
-    slice_chunks_1,
-    slice_windows_1;
-    for_chunks_1,
-    for_windows_1
-}
-
-def_benchs!{
-    2;
-    sum_t2,
-    tuple_chunks_2,
-    tuple_windows_2;
-    sum_s2,
-    slice_chunks_2,
-    slice_windows_2;
-    for_chunks_2,
-    for_windows_2
-}
-
-def_benchs!{
-    3;
-    sum_t3,
-    tuple_chunks_3,
-    tuple_windows_3;
-    sum_s3,
-    slice_chunks_3,
-    slice_windows_3;
-    for_chunks_3,
-    for_windows_3
-}
-
-def_benchs!{
-    4;
-    sum_t4,
-    tuple_chunks_4,
-    tuple_windows_4;
-    sum_s4,
-    slice_chunks_4,
-    slice_windows_4;
-    for_chunks_4,
-    for_windows_4
-}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/custom.css
+++ /dev/null
@@ -1,29 +0,0 @@
-
-.docblock pre.rust { background: #eeeeff; }
-pre.trait, pre.fn, pre.struct, pre.enum, pre.typedef { background: #fcfefc; }
-
-/* Small “example” label for doc examples */
-.docblock pre.rust::before {
-    content: "example";
-    float: right;
-    font-style: italic;
-    font-size: 0.8em;
-    margin-top: -10px;
-    margin-right: -5px;
-}
-
-
-/* Fixup where display in trait listing */
-pre.trait .where::before {
-content: '\a         ';
-}
-
-.docblock code {
-    background-color: inherit;
-    font-weight: bold;
-    padding: 0 0.1em;
-}
-
-a.test-arrow {
-    display: none;
-}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/examples/iris.data
+++ /dev/null
@@ -1,150 +0,0 @@
-5.1,3.5,1.4,0.2,Iris-setosa
-4.9,3.0,1.4,0.2,Iris-setosa
-4.7,3.2,1.3,0.2,Iris-setosa
-4.6,3.1,1.5,0.2,Iris-setosa
-5.0,3.6,1.4,0.2,Iris-setosa
-5.4,3.9,1.7,0.4,Iris-setosa
-4.6,3.4,1.4,0.3,Iris-setosa
-5.0,3.4,1.5,0.2,Iris-setosa
-4.4,2.9,1.4,0.2,Iris-setosa
-4.9,3.1,1.5,0.1,Iris-setosa
-5.4,3.7,1.5,0.2,Iris-setosa
-4.8,3.4,1.6,0.2,Iris-setosa
-4.8,3.0,1.4,0.1,Iris-setosa
-4.3,3.0,1.1,0.1,Iris-setosa
-5.8,4.0,1.2,0.2,Iris-setosa
-5.7,4.4,1.5,0.4,Iris-setosa
-5.4,3.9,1.3,0.4,Iris-setosa
-5.1,3.5,1.4,0.3,Iris-setosa
-5.7,3.8,1.7,0.3,Iris-setosa
-5.1,3.8,1.5,0.3,Iris-setosa
-5.4,3.4,1.7,0.2,Iris-setosa
-5.1,3.7,1.5,0.4,Iris-setosa
-4.6,3.6,1.0,0.2,Iris-setosa
-5.1,3.3,1.7,0.5,Iris-setosa
-4.8,3.4,1.9,0.2,Iris-setosa
-5.0,3.0,1.6,0.2,Iris-setosa
-5.0,3.4,1.6,0.4,Iris-setosa
-5.2,3.5,1.5,0.2,Iris-setosa
-5.2,3.4,1.4,0.2,Iris-setosa
-4.7,3.2,1.6,0.2,Iris-setosa
-4.8,3.1,1.6,0.2,Iris-setosa
-5.4,3.4,1.5,0.4,Iris-setosa
-5.2,4.1,1.5,0.1,Iris-setosa
-5.5,4.2,1.4,0.2,Iris-setosa
-4.9,3.1,1.5,0.1,Iris-setosa
-5.0,3.2,1.2,0.2,Iris-setosa
-5.5,3.5,1.3,0.2,Iris-setosa
-4.9,3.1,1.5,0.1,Iris-setosa
-4.4,3.0,1.3,0.2,Iris-setosa
-5.1,3.4,1.5,0.2,Iris-setosa
-5.0,3.5,1.3,0.3,Iris-setosa
-4.5,2.3,1.3,0.3,Iris-setosa
-4.4,3.2,1.3,0.2,Iris-setosa
-5.0,3.5,1.6,0.6,Iris-setosa
-5.1,3.8,1.9,0.4,Iris-setosa
-4.8,3.0,1.4,0.3,Iris-setosa
-5.1,3.8,1.6,0.2,Iris-setosa
-4.6,3.2,1.4,0.2,Iris-setosa
-5.3,3.7,1.5,0.2,Iris-setosa
-5.0,3.3,1.4,0.2,Iris-setosa
-7.0,3.2,4.7,1.4,Iris-versicolor
-6.4,3.2,4.5,1.5,Iris-versicolor
-6.9,3.1,4.9,1.5,Iris-versicolor
-5.5,2.3,4.0,1.3,Iris-versicolor
-6.5,2.8,4.6,1.5,Iris-versicolor
-5.7,2.8,4.5,1.3,Iris-versicolor
-6.3,3.3,4.7,1.6,Iris-versicolor
-4.9,2.4,3.3,1.0,Iris-versicolor
-6.6,2.9,4.6,1.3,Iris-versicolor
-5.2,2.7,3.9,1.4,Iris-versicolor
-5.0,2.0,3.5,1.0,Iris-versicolor
-5.9,3.0,4.2,1.5,Iris-versicolor
-6.0,2.2,4.0,1.0,Iris-versicolor
-6.1,2.9,4.7,1.4,Iris-versicolor
-5.6,2.9,3.6,1.3,Iris-versicolor
-6.7,3.1,4.4,1.4,Iris-versicolor
-5.6,3.0,4.5,1.5,Iris-versicolor
-5.8,2.7,4.1,1.0,Iris-versicolor
-6.2,2.2,4.5,1.5,Iris-versicolor
-5.6,2.5,3.9,1.1,Iris-versicolor
-5.9,3.2,4.8,1.8,Iris-versicolor
-6.1,2.8,4.0,1.3,Iris-versicolor
-6.3,2.5,4.9,1.5,Iris-versicolor
-6.1,2.8,4.7,1.2,Iris-versicolor
-6.4,2.9,4.3,1.3,Iris-versicolor
-6.6,3.0,4.4,1.4,Iris-versicolor
-6.8,2.8,4.8,1.4,Iris-versicolor
-6.7,3.0,5.0,1.7,Iris-versicolor
-6.0,2.9,4.5,1.5,Iris-versicolor
-5.7,2.6,3.5,1.0,Iris-versicolor
-5.5,2.4,3.8,1.1,Iris-versicolor
-5.5,2.4,3.7,1.0,Iris-versicolor
-5.8,2.7,3.9,1.2,Iris-versicolor
-6.0,2.7,5.1,1.6,Iris-versicolor
-5.4,3.0,4.5,1.5,Iris-versicolor
-6.0,3.4,4.5,1.6,Iris-versicolor
-6.7,3.1,4.7,1.5,Iris-versicolor
-6.3,2.3,4.4,1.3,Iris-versicolor
-5.6,3.0,4.1,1.3,Iris-versicolor
-5.5,2.5,4.0,1.3,Iris-versicolor
-5.5,2.6,4.4,1.2,Iris-versicolor
-6.1,3.0,4.6,1.4,Iris-versicolor
-5.8,2.6,4.0,1.2,Iris-versicolor
-5.0,2.3,3.3,1.0,Iris-versicolor
-5.6,2.7,4.2,1.3,Iris-versicolor
-5.7,3.0,4.2,1.2,Iris-versicolor
-5.7,2.9,4.2,1.3,Iris-versicolor
-6.2,2.9,4.3,1.3,Iris-versicolor
-5.1,2.5,3.0,1.1,Iris-versicolor
-5.7,2.8,4.1,1.3,Iris-versicolor
-6.3,3.3,6.0,2.5,Iris-virginica
-5.8,2.7,5.1,1.9,Iris-virginica
-7.1,3.0,5.9,2.1,Iris-virginica
-6.3,2.9,5.6,1.8,Iris-virginica
-6.5,3.0,5.8,2.2,Iris-virginica
-7.6,3.0,6.6,2.1,Iris-virginica
-4.9,2.5,4.5,1.7,Iris-virginica
-7.3,2.9,6.3,1.8,Iris-virginica
-6.7,2.5,5.8,1.8,Iris-virginica
-7.2,3.6,6.1,2.5,Iris-virginica
-6.5,3.2,5.1,2.0,Iris-virginica
-6.4,2.7,5.3,1.9,Iris-virginica
-6.8,3.0,5.5,2.1,Iris-virginica
-5.7,2.5,5.0,2.0,Iris-virginica
-5.8,2.8,5.1,2.4,Iris-virginica
-6.4,3.2,5.3,2.3,Iris-virginica
-6.5,3.0,5.5,1.8,Iris-virginica
-7.7,3.8,6.7,2.2,Iris-virginica
-7.7,2.6,6.9,2.3,Iris-virginica
-6.0,2.2,5.0,1.5,Iris-virginica
-6.9,3.2,5.7,2.3,Iris-virginica
-5.6,2.8,4.9,2.0,Iris-virginica
-7.7,2.8,6.7,2.0,Iris-virginica
-6.3,2.7,4.9,1.8,Iris-virginica
-6.7,3.3,5.7,2.1,Iris-virginica
-7.2,3.2,6.0,1.8,Iris-virginica
-6.2,2.8,4.8,1.8,Iris-virginica
-6.1,3.0,4.9,1.8,Iris-virginica
-6.4,2.8,5.6,2.1,Iris-virginica
-7.2,3.0,5.8,1.6,Iris-virginica
-7.4,2.8,6.1,1.9,Iris-virginica
-7.9,3.8,6.4,2.0,Iris-virginica
-6.4,2.8,5.6,2.2,Iris-virginica
-6.3,2.8,5.1,1.5,Iris-virginica
-6.1,2.6,5.6,1.4,Iris-virginica
-7.7,3.0,6.1,2.3,Iris-virginica
-6.3,3.4,5.6,2.4,Iris-virginica
-6.4,3.1,5.5,1.8,Iris-virginica
-6.0,3.0,4.8,1.8,Iris-virginica
-6.9,3.1,5.4,2.1,Iris-virginica
-6.7,3.1,5.6,2.4,Iris-virginica
-6.9,3.1,5.1,2.3,Iris-virginica
-5.8,2.7,5.1,1.9,Iris-virginica
-6.8,3.2,5.9,2.3,Iris-virginica
-6.7,3.3,5.7,2.5,Iris-virginica
-6.7,3.0,5.2,2.3,Iris-virginica
-6.3,2.5,5.0,1.9,Iris-virginica
-6.5,3.0,5.2,2.0,Iris-virginica
-6.2,3.4,5.4,2.3,Iris-virginica
-5.9,3.0,5.1,1.8,Iris-virginica
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/examples/iris.rs
+++ /dev/null
@@ -1,141 +0,0 @@
-///
-/// This example parses, sorts and groups the iris dataset
-/// and does some simple manipulations.
-///
-/// Iterators and itertools functionality are used throughout.
-///
-///
-
-extern crate itertools;
-
-use itertools::Itertools;
-use std::collections::HashMap;
-use std::iter::repeat;
-use std::num::ParseFloatError;
-use std::str::FromStr;
-
-static DATA: &'static str = include_str!("iris.data");
-
-#[derive(Clone, Debug)]
-struct Iris {
-    name: String,
-    data: [f32; 4],
-}
-
-#[derive(Clone, Debug)]
-enum ParseError {
-    Numeric(ParseFloatError),
-    Other(&'static str),
-}
-
-impl From<ParseFloatError> for ParseError {
-    fn from(err: ParseFloatError) -> Self {
-        ParseError::Numeric(err)
-    }
-}
-
-/// Parse an Iris from a comma-separated line
-impl FromStr for Iris {
-    type Err = ParseError;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        let mut iris = Iris { name: "".into(), data: [0.; 4] };
-        let mut parts = s.split(",").map(str::trim);
-
-        // using Iterator::by_ref()
-        for (index, part) in parts.by_ref().take(4).enumerate() {
-            iris.data[index] = try!(part.parse::<f32>());
-        }
-        if let Some(name) = parts.next() {
-            iris.name = name.into();
-        } else {
-            return Err(ParseError::Other("Missing name"))
-        }
-        Ok(iris)
-    }
-}
-
-fn main() {
-    // using Itertools::fold_results to create the result of parsing
-    let irises = DATA.lines()
-                     .map(str::parse)
-                     .fold_results(Vec::new(), |mut v, iris: Iris| {
-                         v.push(iris);
-                         v
-                     });
-    let mut irises = match irises {
-        Err(e) => {
-            println!("Error parsing: {:?}", e);
-            std::process::exit(1);
-        }
-        Ok(data) => data,
-    };
-
-    // Sort them and group them
-    irises.sort_by(|a, b| Ord::cmp(&a.name, &b.name));
-
-    // using Iterator::cycle()
-    let mut plot_symbols = "+ox".chars().cycle();
-    let mut symbolmap = HashMap::new();
-
-    // using Itertools::group_by
-    for (species, species_group) in &irises.iter().group_by(|iris| &iris.name) {
-        // assign a plot symbol
-        symbolmap.entry(species).or_insert_with(|| {
-            plot_symbols.next().unwrap()
-        });
-        println!("{} (symbol={})", species, symbolmap[species]);
-
-        for iris in species_group {
-            // using Itertools::format for lazy formatting
-            println!("{:>3.1}", iris.data.iter().format(", "));
-        }
-
-    }
-
-    // Look at all combinations of the four columns
-    //
-    // See https://en.wikipedia.org/wiki/Iris_flower_data_set
-    //
-    let n = 30; // plot size
-    let mut plot = vec![' '; n * n];
-
-    // using Itertools::tuple_combinations
-    for (a, b) in (0..4).tuple_combinations() {
-        println!("Column {} vs {}:", a, b);
-
-        // Clear plot
-        //
-        // using std::iter::repeat;
-        // using Itertools::set_from
-        plot.iter_mut().set_from(repeat(' '));
-
-        // using Itertools::minmax
-        let min_max = |data: &[Iris], col| {
-            data.iter()
-                .map(|iris| iris.data[col])
-                .minmax()
-                .into_option()
-                .expect("Can't find min/max of empty iterator")
-        };
-        let (min_x, max_x) = min_max(&irises, a);
-        let (min_y, max_y) = min_max(&irises, b);
-
-        // Plot the data points
-        let round_to_grid = |x, min, max| ((x - min) / (max - min) * ((n - 1) as f32)) as usize;
-        let flip = |ix| n - 1 - ix; // reverse axis direction
-
-        for iris in &irises {
-            let ix = round_to_grid(iris.data[a], min_x, max_x);
-            let iy = flip(round_to_grid(iris.data[b], min_y, max_y));
-            plot[n * iy + ix] = symbolmap[&iris.name];
-        }
-
-        // render plot
-        //
-        // using Itertools::join
-        for line in plot.chunks(n) {
-            println!("{}", line.iter().join(" "))
-        }
-    }
-}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/adaptors/mod.rs
+++ /dev/null
@@ -1,1505 +0,0 @@
-//! Licensed under the Apache License, Version 2.0
-//! http://www.apache.org/licenses/LICENSE-2.0 or the MIT license
-//! http://opensource.org/licenses/MIT, at your
-//! option. This file may not be copied, modified, or distributed
-//! except according to those terms.
-
-use std::fmt;
-use std::mem::replace;
-use std::ops::Index;
-use std::iter::{Fuse, Peekable};
-use std::collections::HashSet;
-use std::hash::Hash;
-use std::marker::PhantomData;
-use size_hint;
-use fold;
-
-pub mod multipeek;
-pub use self::multipeek::MultiPeek;
-
-macro_rules! clone_fields {
-    ($name:ident, $base:expr, $($field:ident),+) => (
-        $name {
-            $(
-                $field : $base . $field .clone()
-            ),*
-        }
-    );
-}
-
-
-/// An iterator adaptor that alternates elements from two iterators until both
-/// run out.
-///
-/// This iterator is *fused*.
-///
-/// See [`.interleave()`](../trait.Itertools.html#method.interleave) for more information.
-#[derive(Clone, Debug)]
-pub struct Interleave<I, J> {
-    a: Fuse<I>,
-    b: Fuse<J>,
-    flag: bool,
-}
-
-/// Create an iterator that interleaves elements in `i` and `j`.
-///
-/// `IntoIterator` enabled version of `i.interleave(j)`.
-///
-/// ```
-/// use itertools::interleave;
-///
-/// for elt in interleave(&[1, 2, 3], &[2, 3, 4]) {
-///     /* loop body */
-/// }
-/// ```
-pub fn interleave<I, J>(i: I, j: J) -> Interleave<<I as IntoIterator>::IntoIter, <J as IntoIterator>::IntoIter>
-    where I: IntoIterator,
-          J: IntoIterator<Item = I::Item>
-{
-    Interleave {
-        a: i.into_iter().fuse(),
-        b: j.into_iter().fuse(),
-        flag: false,
-    }
-}
-
-impl<I, J> Iterator for Interleave<I, J>
-    where I: Iterator,
-          J: Iterator<Item = I::Item>
-{
-    type Item = I::Item;
-    #[inline]
-    fn next(&mut self) -> Option<I::Item> {
-        self.flag = !self.flag;
-        if self.flag {
-            match self.a.next() {
-                None => self.b.next(),
-                r => r,
-            }
-        } else {
-            match self.b.next() {
-                None => self.a.next(),
-                r => r,
-            }
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        size_hint::add(self.a.size_hint(), self.b.size_hint())
-    }
-}
-
-/// An iterator adaptor that alternates elements from the two iterators until
-/// one of them runs out.
-///
-/// This iterator is *fused*.
-///
-/// See [`.interleave_shortest()`](../trait.Itertools.html#method.interleave_shortest)
-/// for more information.
-#[derive(Clone, Debug)]
-pub struct InterleaveShortest<I, J>
-    where I: Iterator,
-          J: Iterator<Item = I::Item>
-{
-    it0: I,
-    it1: J,
-    phase: bool, // false ==> it0, true ==> it1
-}
-
-/// Create a new `InterleaveShortest` iterator.
-pub fn interleave_shortest<I, J>(a: I, b: J) -> InterleaveShortest<I, J>
-    where I: Iterator,
-          J: Iterator<Item = I::Item>
-{
-    InterleaveShortest {
-        it0: a,
-        it1: b,
-        phase: false,
-    }
-}
-
-impl<I, J> Iterator for InterleaveShortest<I, J>
-    where I: Iterator,
-          J: Iterator<Item = I::Item>
-{
-    type Item = I::Item;
-
-    #[inline]
-    fn next(&mut self) -> Option<I::Item> {
-        match self.phase {
-            false => match self.it0.next() {
-                None => None,
-                e => {
-                    self.phase = true;
-                    e
-                }
-            },
-            true => match self.it1.next() {
-                None => None,
-                e => {
-                    self.phase = false;
-                    e
-                }
-            },
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let (curr_hint, next_hint) = {
-            let it0_hint = self.it0.size_hint();
-            let it1_hint = self.it1.size_hint();
-            if self.phase {
-                (it1_hint, it0_hint)
-            } else {
-                (it0_hint, it1_hint)
-            }
-        };
-        let (curr_lower, curr_upper) = curr_hint;
-        let (next_lower, next_upper) = next_hint;
-        let (combined_lower, combined_upper) =
-            size_hint::mul_scalar(size_hint::min(curr_hint, next_hint), 2);
-        let lower =
-            if curr_lower > next_lower {
-                combined_lower + 1
-            } else {
-                combined_lower
-            };
-        let upper = {
-            let extra_elem = match (curr_upper, next_upper) {
-                (_, None) => false,
-                (None, Some(_)) => true,
-                (Some(curr_max), Some(next_max)) => curr_max > next_max,
-            };
-            if extra_elem {
-                combined_upper.and_then(|x| x.checked_add(1))
-            } else {
-                combined_upper
-            }
-        };
-        (lower, upper)
-    }
-}
-
-#[derive(Clone, Debug)]
-/// An iterator adaptor that allows putting back a single
-/// item to the front of the iterator.
-///
-/// Iterator element type is `I::Item`.
-pub struct PutBack<I>
-    where I: Iterator
-{
-    top: Option<I::Item>,
-    iter: I,
-}
-
-/// Create an iterator where you can put back a single item
-pub fn put_back<I>(iterable: I) -> PutBack<I::IntoIter>
-    where I: IntoIterator
-{
-    PutBack {
-        top: None,
-        iter: iterable.into_iter(),
-    }
-}
-
-impl<I> PutBack<I>
-    where I: Iterator
-{
-    /// put back value `value` (builder method)
-    pub fn with_value(mut self, value: I::Item) -> Self {
-        self.put_back(value);
-        self
-    }
-
-    /// Split the `PutBack` into its parts.
-    #[inline]
-    pub fn into_parts(self) -> (Option<I::Item>, I) {
-        let PutBack{top, iter} = self;
-        (top, iter)
-    }
-
-    /// Put back a single value to the front of the iterator.
-    ///
-    /// If a value is already in the put back slot, it is overwritten.
-    #[inline]
-    pub fn put_back(&mut self, x: I::Item) {
-        self.top = Some(x)
-    }
-}
-
-impl<I> Iterator for PutBack<I>
-    where I: Iterator
-{
-    type Item = I::Item;
-    #[inline]
-    fn next(&mut self) -> Option<I::Item> {
-        match self.top {
-            None => self.iter.next(),
-            ref mut some => some.take(),
-        }
-    }
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        // Not ExactSizeIterator because size may be larger than usize
-        size_hint::add_scalar(self.iter.size_hint(), self.top.is_some() as usize)
-    }
-
-    fn all<G>(&mut self, mut f: G) -> bool
-        where G: FnMut(Self::Item) -> bool
-    {
-        if let Some(elt) = self.top.take() {
-            if !f(elt) {
-                return false;
-            }
-        }
-        self.iter.all(f)
-    }
-
-    fn fold<Acc, G>(mut self, init: Acc, mut f: G) -> Acc
-        where G: FnMut(Acc, Self::Item) -> Acc,
-    {
-        let mut accum = init;
-        if let Some(elt) = self.top.take() {
-            accum = f(accum, elt);
-        }
-        self.iter.fold(accum, f)
-    }
-}
-
-/// An iterator adaptor that allows putting multiple
-/// items in front of the iterator.
-///
-/// Iterator element type is `I::Item`.
-#[derive(Debug, Clone)]
-pub struct PutBackN<I: Iterator> {
-    top: Vec<I::Item>,
-    iter: I,
-}
-
-/// Create an iterator where you can put back multiple values to the front
-/// of the iteration.
-///
-/// Iterator element type is `I::Item`.
-pub fn put_back_n<I>(iterable: I) -> PutBackN<I::IntoIter>
-    where I: IntoIterator
-{
-    PutBackN {
-        top: Vec::new(),
-        iter: iterable.into_iter(),
-    }
-}
-
-impl<I: Iterator> PutBackN<I> {
-    /// Puts x in front of the iterator.
-    /// The values are yielded in order of the most recently put back
-    /// values first.
-    ///
-    /// ```rust
-    /// use itertools::put_back_n;
-    ///
-    /// let mut it = put_back_n(1..5);
-    /// it.next();
-    /// it.put_back(1);
-    /// it.put_back(0);
-    ///
-    /// assert!(itertools::equal(it, 0..5));
-    /// ```
-    #[inline]
-    pub fn put_back(&mut self, x: I::Item) {
-        self.top.push(x);
-    }
-}
-
-impl<I: Iterator> Iterator for PutBackN<I> {
-    type Item = I::Item;
-    #[inline]
-    fn next(&mut self) -> Option<I::Item> {
-        if self.top.is_empty() {
-            self.iter.next()
-        } else {
-            self.top.pop()
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        size_hint::add_scalar(self.iter.size_hint(), self.top.len())
-    }
-}
-
-#[derive(Debug, Clone)]
-/// An iterator adaptor that iterates over the cartesian product of
-/// the element sets of two iterators `I` and `J`.
-///
-/// Iterator element type is `(I::Item, J::Item)`.
-///
-/// See [`.cartesian_product()`](../trait.Itertools.html#method.cartesian_product) for more information.
-pub struct Product<I, J>
-    where I: Iterator
-{
-    a: I,
-    a_cur: Option<I::Item>,
-    b: J,
-    b_orig: J,
-}
-
-/// Create a new cartesian product iterator
-///
-/// Iterator element type is `(I::Item, J::Item)`.
-pub fn cartesian_product<I, J>(mut i: I, j: J) -> Product<I, J>
-    where I: Iterator,
-          J: Clone + Iterator,
-          I::Item: Clone
-{
-    Product {
-        a_cur: i.next(),
-        a: i,
-        b: j.clone(),
-        b_orig: j,
-    }
-}
-
-
-impl<I, J> Iterator for Product<I, J>
-    where I: Iterator,
-          J: Clone + Iterator,
-          I::Item: Clone
-{
-    type Item = (I::Item, J::Item);
-    fn next(&mut self) -> Option<(I::Item, J::Item)> {
-        let elt_b = match self.b.next() {
-            None => {
-                self.b = self.b_orig.clone();
-                match self.b.next() {
-                    None => return None,
-                    Some(x) => {
-                        self.a_cur = self.a.next();
-                        x
-                    }
-                }
-            }
-            Some(x) => x
-        };
-        match self.a_cur {
-            None => None,
-            Some(ref a) => {
-                Some((a.clone(), elt_b))
-            }
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let has_cur = self.a_cur.is_some() as usize;
-        // Not ExactSizeIterator because size may be larger than usize
-        let (b_min, b_max) = self.b.size_hint();
-
-        // Compute a * b_orig + b for both lower and upper bound
-        size_hint::add(
-            size_hint::mul(self.a.size_hint(), self.b_orig.size_hint()),
-            (b_min * has_cur, b_max.map(move |x| x * has_cur)))
-    }
-
-    fn fold<Acc, G>(mut self, mut accum: Acc, mut f: G) -> Acc
-        where G: FnMut(Acc, Self::Item) -> Acc,
-    {
-        // use a split loop to handle the loose a_cur as well as avoiding to
-        // clone b_orig at the end.
-        if let Some(mut a) = self.a_cur.take() {
-            let mut b = self.b;
-            loop {
-                accum = b.fold(accum, |acc, elt| f(acc, (a.clone(), elt)));
-
-                // we can only continue iterating a if we had a first element;
-                if let Some(next_a) = self.a.next() {
-                    b = self.b_orig.clone();
-                    a = next_a;
-                } else {
-                    break;
-                }
-            }
-        }
-        accum
-    }
-}
-
-/// A “meta iterator adaptor”. Its closure recives a reference to the iterator
-/// and may pick off as many elements as it likes, to produce the next iterator element.
-///
-/// Iterator element type is *X*, if the return type of `F` is *Option\<X\>*.
-///
-/// See [`.batching()`](../trait.Itertools.html#method.batching) for more information.
-#[derive(Clone)]
-pub struct Batching<I, F> {
-    f: F,
-    iter: I,
-}
-
-impl<I, F> fmt::Debug for Batching<I, F> where I: fmt::Debug {
-    debug_fmt_fields!(Batching, iter);
-}
-
-/// Create a new Batching iterator.
-pub fn batching<I, F>(iter: I, f: F) -> Batching<I, F> {
-    Batching { f: f, iter: iter }
-}
-
-impl<B, F, I> Iterator for Batching<I, F>
-    where I: Iterator,
-          F: FnMut(&mut I) -> Option<B>
-{
-    type Item = B;
-    #[inline]
-    fn next(&mut self) -> Option<B> {
-        (self.f)(&mut self.iter)
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        // No information about closue behavior
-        (0, None)
-    }
-}
-
-/// An iterator adaptor that steps a number elements in the base iterator
-/// for each iteration.
-///
-/// The iterator steps by yielding the next element from the base iterator,
-/// then skipping forward *n-1* elements.
-///
-/// See [`.step()`](../trait.Itertools.html#method.step) for more information.
-#[derive(Clone, Debug)]
-pub struct Step<I> {
-    iter: Fuse<I>,
-    skip: usize,
-}
-
-/// Create a `Step` iterator.
-///
-/// **Panics** if the step is 0.
-pub fn step<I>(iter: I, step: usize) -> Step<I>
-    where I: Iterator
-{
-    assert!(step != 0);
-    Step {
-        iter: iter.fuse(),
-        skip: step - 1,
-    }
-}
-
-impl<I> Iterator for Step<I>
-    where I: Iterator
-{
-    type Item = I::Item;
-    #[inline]
-    fn next(&mut self) -> Option<I::Item> {
-        let elt = self.iter.next();
-        if self.skip > 0 {
-            self.iter.nth(self.skip - 1);
-        }
-        elt
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let (low, high) = self.iter.size_hint();
-        let div = |x: usize| {
-            if x == 0 {
-                0
-            } else {
-                1 + (x - 1) / (self.skip + 1)
-            }
-        };
-        (div(low), high.map(div))
-    }
-}
-
-// known size
-impl<I> ExactSizeIterator for Step<I>
-    where I: ExactSizeIterator
-{}
-
-
-struct MergeCore<I, J>
-    where I: Iterator,
-          J: Iterator<Item = I::Item>
-{
-    a: Peekable<I>,
-    b: Peekable<J>,
-    fused: Option<bool>,
-}
-
-
-impl<I, J> Clone for MergeCore<I, J>
-    where I: Iterator,
-          J: Iterator<Item = I::Item>,
-          Peekable<I>: Clone,
-          Peekable<J>: Clone
-{
-    fn clone(&self) -> Self {
-        clone_fields!(MergeCore, self, a, b, fused)
-    }
-}
-
-impl<I, J> MergeCore<I, J>
-    where I: Iterator,
-          J: Iterator<Item = I::Item>
-{
-    fn next_with<F>(&mut self, mut less_than: F) -> Option<I::Item>
-        where F: FnMut(&I::Item, &I::Item) -> bool
-    {
-        let less_than = match self.fused {
-            Some(lt) => lt,
-            None => match (self.a.peek(), self.b.peek()) {
-                (Some(a), Some(b)) => less_than(a, b),
-                (Some(_), None) => {
-                    self.fused = Some(true);
-                    true
-                }
-                (None, Some(_)) => {
-                    self.fused = Some(false);
-                    false
-                }
-                (None, None) => return None,
-            }
-        };
-
-        if less_than {
-            self.a.next()
-        } else {
-            self.b.next()
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        // Not ExactSizeIterator because size may be larger than usize
-        size_hint::add(self.a.size_hint(), self.b.size_hint())
-    }
-}
-
-/// An iterator adaptor that merges the two base iterators in ascending order.
-/// If both base iterators are sorted (ascending), the result is sorted.
-///
-/// Iterator element type is `I::Item`.
-///
-/// See [`.merge()`](../trait.Itertools.html#method.merge_by) for more information.
-pub struct Merge<I, J>
-    where I: Iterator,
-          J: Iterator<Item = I::Item>
-{
-    merge: MergeCore<I, J>,
-}
-
-impl<I, J> Clone for Merge<I, J>
-    where I: Iterator,
-          J: Iterator<Item = I::Item>,
-          Peekable<I>: Clone,
-          Peekable<J>: Clone
-{
-    fn clone(&self) -> Self {
-        clone_fields!(Merge, self, merge)
-    }
-}
-
-impl<I, J> fmt::Debug for Merge<I, J>
-    where I: Iterator + fmt::Debug, J: Iterator<Item = I::Item> + fmt::Debug,
-          I::Item: fmt::Debug,
-{
-    debug_fmt_fields!(Merge, merge.a, merge.b);
-}
-
-/// Create an iterator that merges elements in `i` and `j`.
-///
-/// `IntoIterator` enabled version of `i.merge(j)`.
-///
-/// ```
-/// use itertools::merge;
-///
-/// for elt in merge(&[1, 2, 3], &[2, 3, 4]) {
-///     /* loop body */
-/// }
-/// ```
-pub fn merge<I, J>(i: I, j: J) -> Merge<<I as IntoIterator>::IntoIter, <J as IntoIterator>::IntoIter>
-    where I: IntoIterator,
-          J: IntoIterator<Item = I::Item>,
-          I::Item: PartialOrd
-{
-    Merge {
-        merge: MergeCore {
-            a: i.into_iter().peekable(),
-            b: j.into_iter().peekable(),
-            fused: None,
-        },
-    }
-}
-
-impl<I, J> Iterator for Merge<I, J>
-    where I: Iterator,
-          J: Iterator<Item = I::Item>,
-          I::Item: PartialOrd
-{
-    type Item = I::Item;
-
-    fn next(&mut self) -> Option<I::Item> {
-        self.merge.next_with(|a, b| a <= b)
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.merge.size_hint()
-    }
-}
-
-/// An iterator adaptor that merges the two base iterators in ascending order.
-/// If both base iterators are sorted (ascending), the result is sorted.
-///
-/// Iterator element type is `I::Item`.
-///
-/// See [`.merge_by()`](../trait.Itertools.html#method.merge_by) for more information.
-pub struct MergeBy<I, J, F>
-    where I: Iterator,
-          J: Iterator<Item = I::Item>
-{
-    merge: MergeCore<I, J>,
-    cmp: F,
-}
-
-impl<I, J, F> fmt::Debug for MergeBy<I, J, F>
-    where I: Iterator + fmt::Debug, J: Iterator<Item = I::Item> + fmt::Debug,
-          I::Item: fmt::Debug,
-{
-    debug_fmt_fields!(MergeBy, merge.a, merge.b);
-}
-
-/// Create a `MergeBy` iterator.
-pub fn merge_by_new<I, J, F>(a: I, b: J, cmp: F) -> MergeBy<I, J, F>
-    where I: Iterator,
-          J: Iterator<Item = I::Item>
-{
-    MergeBy {
-        merge: MergeCore {
-            a: a.peekable(),
-            b: b.peekable(),
-            fused: None,
-        },
-        cmp: cmp,
-    }
-}
-
-impl<I, J, F> Clone for MergeBy<I, J, F>
-    where I: Iterator,
-          J: Iterator<Item = I::Item>,
-          Peekable<I>: Clone,
-          Peekable<J>: Clone,
-          F: Clone
-{
-    fn clone(&self) -> Self {
-        clone_fields!(MergeBy, self, merge, cmp)
-    }
-}
-
-impl<I, J, F> Iterator for MergeBy<I, J, F>
-    where I: Iterator,
-          J: Iterator<Item = I::Item>,
-          F: FnMut(&I::Item, &I::Item) -> bool
-{
-    type Item = I::Item;
-
-    fn next(&mut self) -> Option<I::Item> {
-        self.merge.next_with(&mut self.cmp)
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.merge.size_hint()
-    }
-}
-
-#[derive(Clone, Debug)]
-pub struct CoalesceCore<I>
-    where I: Iterator
-{
-    iter: I,
-    last: Option<I::Item>,
-}
-
-impl<I> CoalesceCore<I>
-    where I: Iterator
-{
-    fn next_with<F>(&mut self, mut f: F) -> Option<I::Item>
-        where F: FnMut(I::Item, I::Item) -> Result<I::Item, (I::Item, I::Item)>
-    {
-        // this fuses the iterator
-        let mut last = match self.last.take() {
-            None => return None,
-            Some(x) => x,
-        };
-        for next in &mut self.iter {
-            match f(last, next) {
-                Ok(joined) => last = joined,
-                Err((last_, next_)) => {
-                    self.last = Some(next_);
-                    return Some(last_);
-                }
-            }
-        }
-
-        Some(last)
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let (low, hi) = size_hint::add_scalar(self.iter.size_hint(),
-                                              self.last.is_some() as usize);
-        ((low > 0) as usize, hi)
-    }
-}
-
-/// An iterator adaptor that may join together adjacent elements.
-///
-/// See [`.coalesce()`](../trait.Itertools.html#method.coalesce) for more information.
-pub struct Coalesce<I, F>
-    where I: Iterator
-{
-    iter: CoalesceCore<I>,
-    f: F,
-}
-
-impl<I: Clone, F: Clone> Clone for Coalesce<I, F>
-    where I: Iterator,
-          I::Item: Clone
-{
-    fn clone(&self) -> Self {
-        clone_fields!(Coalesce, self, iter, f)
-    }
-}
-
-impl<I, F> fmt::Debug for Coalesce<I, F>
-    where I: Iterator + fmt::Debug,
-          I::Item: fmt::Debug,
-{
-    debug_fmt_fields!(Coalesce, iter);
-}
-
-/// Create a new `Coalesce`.
-pub fn coalesce<I, F>(mut iter: I, f: F) -> Coalesce<I, F>
-    where I: Iterator
-{
-    Coalesce {
-        iter: CoalesceCore {
-            last: iter.next(),
-            iter: iter,
-        },
-        f: f,
-    }
-}
-
-impl<I, F> Iterator for Coalesce<I, F>
-    where I: Iterator,
-          F: FnMut(I::Item, I::Item) -> Result<I::Item, (I::Item, I::Item)>
-{
-    type Item = I::Item;
-
-    fn next(&mut self) -> Option<I::Item> {
-        self.iter.next_with(&mut self.f)
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-}
-
-/// An iterator adaptor that removes repeated duplicates.
-///
-/// See [`.dedup()`](../trait.Itertools.html#method.dedup) for more information.
-pub struct Dedup<I>
-    where I: Iterator
-{
-    iter: CoalesceCore<I>,
-}
-
-impl<I: Clone> Clone for Dedup<I>
-    where I: Iterator,
-          I::Item: Clone
-{
-    fn clone(&self) -> Self {
-        clone_fields!(Dedup, self, iter)
-    }
-}
-
-/// Create a new `Dedup`.
-pub fn dedup<I>(mut iter: I) -> Dedup<I>
-    where I: Iterator
-{
-    Dedup {
-        iter: CoalesceCore {
-            last: iter.next(),
-            iter: iter,
-        },
-    }
-}
-
-impl<I> fmt::Debug for Dedup<I>
-    where I: Iterator + fmt::Debug,
-          I::Item: fmt::Debug,
-{
-    debug_fmt_fields!(Dedup, iter);
-}
-
-impl<I> Iterator for Dedup<I>
-    where I: Iterator,
-          I::Item: PartialEq
-{
-    type Item = I::Item;
-
-    fn next(&mut self) -> Option<I::Item> {
-        self.iter.next_with(|x, y| {
-            if x == y { Ok(x) } else { Err((x, y)) }
-        })
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-
-    fn fold<Acc, G>(self, mut accum: Acc, mut f: G) -> Acc
-        where G: FnMut(Acc, Self::Item) -> Acc,
-    {
-        if let Some(mut last) = self.iter.last {
-            accum = self.iter.iter.fold(accum, |acc, elt| {
-                if elt == last {
-                    acc
-                } else {
-                    f(acc, replace(&mut last, elt))
-                }
-            });
-            f(accum, last)
-        } else {
-            accum
-        }
-    }
-}
-
-/// An iterator adaptor that borrows from a `Clone`-able iterator
-/// to only pick off elements while the predicate returns `true`.
-///
-/// See [`.take_while_ref()`](../trait.Itertools.html#method.take_while_ref) for more information.
-pub struct TakeWhileRef<'a, I: 'a, F> {
-    iter: &'a mut I,
-    f: F,
-}
-
-impl<'a, I, F> fmt::Debug for TakeWhileRef<'a, I, F>
-    where I: Iterator + fmt::Debug,
-{
-    debug_fmt_fields!(TakeWhileRef, iter);
-}
-
-/// Create a new `TakeWhileRef` from a reference to clonable iterator.
-pub fn take_while_ref<I, F>(iter: &mut I, f: F) -> TakeWhileRef<I, F>
-    where I: Iterator + Clone
-{
-    TakeWhileRef { iter: iter, f: f }
-}
-
-impl<'a, I, F> Iterator for TakeWhileRef<'a, I, F>
-    where I: Iterator + Clone,
-          F: FnMut(&I::Item) -> bool
-{
-    type Item = I::Item;
-
-    fn next(&mut self) -> Option<I::Item> {
-        let old = self.iter.clone();
-        match self.iter.next() {
-            None => None,
-            Some(elt) => {
-                if (self.f)(&elt) {
-                    Some(elt)
-                } else {
-                    *self.iter = old;
-                    None
-                }
-            }
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let (_, hi) = self.iter.size_hint();
-        (0, hi)
-    }
-}
-
-/// An iterator adaptor that filters `Option<A>` iterator elements
-/// and produces `A`. Stops on the first `None` encountered.
-///
-/// See [`.while_some()`](../trait.Itertools.html#method.while_some) for more information.
-#[derive(Clone, Debug)]
-pub struct WhileSome<I> {
-    iter: I,
-}
-
-/// Create a new `WhileSome<I>`.
-pub fn while_some<I>(iter: I) -> WhileSome<I> {
-    WhileSome { iter: iter }
-}
-
-impl<I, A> Iterator for WhileSome<I>
-    where I: Iterator<Item = Option<A>>
-{
-    type Item = A;
-
-    fn next(&mut self) -> Option<A> {
-        match self.iter.next() {
-            None | Some(None) => None,
-            Some(elt) => elt,
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let sh = self.iter.size_hint();
-        (0, sh.1)
-    }
-}
-
-/// An iterator to iterate through all combinations in a `Clone`-able iterator that produces tuples
-/// of a specific size.
-///
-/// See [`.tuple_combinations()`](../trait.Itertools.html#method.tuple_combinations) for more
-/// information.
-#[derive(Debug)]
-pub struct TupleCombinations<I, T>
-    where I: Iterator,
-          T: HasCombination<I>
-{
-    iter: T::Combination,
-    _mi: PhantomData<I>,
-    _mt: PhantomData<T>
-}
-
-pub trait HasCombination<I>: Sized {
-    type Combination: From<I> + Iterator<Item = Self>;
-}
-
-/// Create a new `TupleCombinations` from a clonable iterator.
-pub fn tuple_combinations<T, I>(iter: I) -> TupleCombinations<I, T>
-    where I: Iterator + Clone,
-          I::Item: Clone,
-          T: HasCombination<I>,
-{
-    TupleCombinations {
-        iter: T::Combination::from(iter),
-        _mi: PhantomData,
-        _mt: PhantomData,
-    }
-}
-
-impl<I, T> Iterator for TupleCombinations<I, T>
-    where I: Iterator,
-          T: HasCombination<I>,
-{
-    type Item = T;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        self.iter.next()
-    }
-}
-
-#[derive(Debug)]
-pub struct Tuple1Combination<I> {
-    iter: I,
-}
-
-impl<I> From<I> for Tuple1Combination<I> {
-    fn from(iter: I) -> Self {
-        Tuple1Combination { iter: iter }
-    }
-}
-
-impl<I: Iterator> Iterator for Tuple1Combination<I> {
-    type Item = (I::Item,);
-
-    fn next(&mut self) -> Option<Self::Item> {
-        self.iter.next().map(|x| (x,))
-    }
-}
-
-impl<I: Iterator> HasCombination<I> for (I::Item,) {
-    type Combination = Tuple1Combination<I>;
-}
-
-macro_rules! impl_tuple_combination {
-    ($C:ident $P:ident ; $A:ident, $($I:ident),* ; $($X:ident)*) => (
-        #[derive(Debug)]
-        pub struct $C<I: Iterator> {
-            item: Option<I::Item>,
-            iter: I,
-            c: $P<I>,
-        }
-
-        impl<I: Iterator + Clone> From<I> for $C<I> {
-            fn from(mut iter: I) -> Self {
-                $C {
-                    item: iter.next(),
-                    iter: iter.clone(),
-                    c: $P::from(iter),
-                }
-            }
-        }
-
-        impl<I: Iterator + Clone> From<I> for $C<Fuse<I>> {
-            fn from(iter: I) -> Self {
-                let mut iter = iter.fuse();
-                $C {
-                    item: iter.next(),
-                    iter: iter.clone(),
-                    c: $P::from(iter),
-                }
-            }
-        }
-
-        impl<I, $A> Iterator for $C<I>
-            where I: Iterator<Item = $A> + Clone,
-                  I::Item: Clone
-        {
-            type Item = ($($I),*);
-
-            fn next(&mut self) -> Option<Self::Item> {
-                if let Some(($($X),*,)) = self.c.next() {
-                    let z = self.item.clone().unwrap();
-                    Some((z, $($X),*))
-                } else {
-                    self.item = self.iter.next();
-                    self.item.clone().and_then(|z| {
-                        self.c = $P::from(self.iter.clone());
-                        self.c.next().map(|($($X),*,)| (z, $($X),*))
-                    })
-                }
-            }
-        }
-
-        impl<I, $A> HasCombination<I> for ($($I),*)
-            where I: Iterator<Item = $A> + Clone,
-                  I::Item: Clone
-        {
-            type Combination = $C<Fuse<I>>;
-        }
-    )
-}
-
-impl_tuple_combination!(Tuple2Combination Tuple1Combination ; A, A, A ; a);
-impl_tuple_combination!(Tuple3Combination Tuple2Combination ; A, A, A, A ; a b);
-impl_tuple_combination!(Tuple4Combination Tuple3Combination ; A, A, A, A, A; a b c);
-
-#[derive(Debug)]
-struct LazyBuffer<I: Iterator> {
-    it: I,
-    done: bool,
-    buffer: Vec<I::Item>,
-}
-
-impl<I> LazyBuffer<I>
-    where I: Iterator
-{
-    pub fn new(it: I) -> LazyBuffer<I> {
-        let mut it = it;
-        let mut buffer = Vec::new();
-        let done;
-        if let Some(first) = it.next() {
-            buffer.push(first);
-            done = false;
-        } else {
-            done = true;
-        }
-        LazyBuffer {
-            it: it,
-            done: done,
-            buffer: buffer,
-        }
-    }
-
-    pub fn len(&self) -> usize {
-        self.buffer.len()
-    }
-
-    pub fn is_done(&self) -> bool {
-        self.done
-    }
-
-    pub fn get_next(&mut self) -> bool {
-        if self.done {
-            return false;
-        }
-        let next_item = self.it.next();
-        match next_item {
-            Some(x) => {
-                self.buffer.push(x);
-                true
-            }
-            None => {
-                self.done = true;
-                false
-            }
-        }
-    }
-}
-
-impl<I> Index<usize> for LazyBuffer<I>
-    where I: Iterator,
-          I::Item: Sized
-{
-    type Output = I::Item;
-
-    fn index<'b>(&'b self, _index: usize) -> &'b I::Item {
-        self.buffer.index(_index)
-    }
-}
-
-/// An iterator to iterate through all the `n`-length combinations in an iterator.
-///
-/// See [`.combinations()`](../trait.Itertools.html#method.combinations) for more information.
-pub struct Combinations<I: Iterator> {
-    n: usize,
-    indices: Vec<usize>,
-    pool: LazyBuffer<I>,
-    first: bool,
-}
-
-impl<I> fmt::Debug for Combinations<I>
-    where I: Iterator + fmt::Debug,
-          I::Item: fmt::Debug,
-{
-    debug_fmt_fields!(Combinations, n, indices, pool, first);
-}
-
-/// Create a new `Combinations` from a clonable iterator.
-pub fn combinations<I>(iter: I, n: usize) -> Combinations<I>
-    where I: Iterator
-{
-    let mut indices: Vec<usize> = Vec::with_capacity(n);
-    for i in 0..n {
-        indices.push(i);
-    }
-    let mut pool: LazyBuffer<I> = LazyBuffer::new(iter);
-
-    for _ in 0..n {
-        if !pool.get_next() {
-            break;
-        }
-    }
-
-    Combinations {
-        n: n,
-        indices: indices,
-        pool: pool,
-        first: true,
-    }
-}
-
-impl<I> Iterator for Combinations<I>
-    where I: Iterator,
-          I::Item: Clone
-{
-    type Item = Vec<I::Item>;
-    fn next(&mut self) -> Option<Self::Item> {
-        let mut pool_len = self.pool.len();
-        if self.pool.is_done() {
-            if pool_len == 0 || self.n > pool_len {
-                return None;
-            }
-        }
-
-        if self.first {
-            self.first = false;
-        } else if self.n == 0 {
-            return None;
-        } else {
-            // Scan from the end, looking for an index to increment
-            let mut i: usize = self.n - 1;
-
-            // Check if we need to consume more from the iterator
-            if self.indices[i] == pool_len - 1 && !self.pool.is_done() {
-                if self.pool.get_next() {
-                    pool_len += 1;
-                }
-            }
-
-            while self.indices[i] == i + pool_len - self.n {
-                if i > 0 {
-                    i -= 1;
-                } else {
-                    // Reached the last combination
-                    return None;
-                }
-            }
-
-            // Increment index, and reset the ones to its right
-            self.indices[i] += 1;
-            let mut j = i + 1;
-            while j < self.n {
-                self.indices[j] = self.indices[j - 1] + 1;
-                j += 1;
-            }
-        }
-
-        // Create result vector based on the indices
-        let mut result = Vec::with_capacity(self.n);
-        for i in self.indices.iter() {
-            result.push(self.pool[*i].clone());
-        }
-        Some(result)
-    }
-}
-
-/// An iterator adapter to filter out duplicate elements.
-///
-/// See [`.unique_by()`](../trait.Itertools.html#method.unique) for more information.
-#[derive(Clone)]
-pub struct UniqueBy<I: Iterator, V, F> {
-    iter: I,
-    used: HashSet<V>,
-    f: F,
-}
-
-impl<I, V, F> fmt::Debug for UniqueBy<I, V, F>
-    where I: Iterator + fmt::Debug,
-          V: fmt::Debug + Hash + Eq,
-{
-    debug_fmt_fields!(UniqueBy, iter, used);
-}
-
-/// Create a new `UniqueBy` iterator.
-pub fn unique_by<I, V, F>(iter: I, f: F) -> UniqueBy<I, V, F>
-    where V: Eq + Hash,
-          F: FnMut(&I::Item) -> V,
-          I: Iterator,
-{
-    UniqueBy {
-        iter: iter,
-        used: HashSet::new(),
-        f: f,
-    }
-}
-
-impl<I, V, F> Iterator for UniqueBy<I, V, F>
-    where I: Iterator,
-          V: Eq + Hash,
-          F: FnMut(&I::Item) -> V
-{
-    type Item = I::Item;
-
-    fn next(&mut self) -> Option<I::Item> {
-        loop {
-            match self.iter.next() {
-                None => return None,
-                Some(v) => {
-                    let key = (self.f)(&v);
-                    if self.used.insert(key) {
-                        return Some(v);
-                    }
-                }
-            }
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let (low, hi) = self.iter.size_hint();
-        ((low > 0 && self.used.is_empty()) as usize, hi)
-    }
-}
-
-impl<I> Iterator for Unique<I>
-    where I: Iterator,
-          I::Item: Eq + Hash + Clone
-{
-    type Item = I::Item;
-
-    fn next(&mut self) -> Option<I::Item> {
-        loop {
-            match self.iter.iter.next() {
-                None => return None,
-                Some(v) => {
-                    if !self.iter.used.contains(&v) {
-                        // FIXME: Avoid this double lookup when the entry api allows
-                        self.iter.used.insert(v.clone());
-                        return Some(v);
-                    }
-                }
-            }
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let (low, hi) = self.iter.iter.size_hint();
-        ((low > 0 && self.iter.used.is_empty()) as usize, hi)
-    }
-}
-
-/// An iterator adapter to filter out duplicate elements.
-///
-/// See [`.unique()`](../trait.Itertools.html#method.unique) for more information.
-#[derive(Clone)]
-pub struct Unique<I: Iterator> {
-    iter: UniqueBy<I, I::Item, ()>,
-}
-
-impl<I> fmt::Debug for Unique<I>
-    where I: Iterator + fmt::Debug,
-          I::Item: Hash + Eq + fmt::Debug,
-{
-    debug_fmt_fields!(Unique, iter);
-}
-
-pub fn unique<I>(iter: I) -> Unique<I>
-    where I: Iterator,
-          I::Item: Eq + Hash,
-{
-    Unique {
-        iter: UniqueBy {
-            iter: iter,
-            used: HashSet::new(),
-            f: (),
-        }
-    }
-}
-
-/// An iterator adapter to simply flatten a structure.
-///
-/// See [`.flatten()`](../trait.Itertools.html#method.flatten) for more information.
-#[derive(Clone, Debug)]
-pub struct Flatten<I, J> {
-    iter: I,
-    front: Option<J>,
-}
-
-/// Create a new `Flatten` iterator.
-pub fn flatten<I, J>(iter: I) -> Flatten<I, J> {
-    Flatten {
-        iter: iter,
-        front: None,
-    }
-}
-
-impl<I, J> Iterator for Flatten<I, J>
-    where I: Iterator,
-          I::Item: IntoIterator<IntoIter=J, Item=J::Item>,
-          J: Iterator,
-{
-    type Item = J::Item;
-    fn next(&mut self) -> Option<Self::Item> {
-        loop {
-            if let Some(ref mut f) = self.front {
-                match f.next() {
-                    elt @ Some(_) => return elt,
-                    None => { }
-                }
-            }
-            if let Some(next_front) = self.iter.next() {
-                self.front = Some(next_front.into_iter());
-            } else {
-                break;
-            }
-        }
-        None
-    }
-
-    // special case to convert segmented iterator into consecutive loops
-    fn fold<Acc, G>(self, init: Acc, mut f: G) -> Acc
-        where G: FnMut(Acc, Self::Item) -> Acc,
-    {
-        let mut accum = init;
-        if let Some(iter) = self.front {
-            accum = fold(iter, accum, &mut f);
-        }
-        self.iter.fold(accum, move |accum, iter| fold(iter, accum, &mut f))
-    }
-}
-
-/// An iterator adapter to apply a transformation within a nested `Result`.
-///
-/// See [`.map_results()`](../trait.Itertools.html#method.map_results) for more information.
-pub struct MapResults<I, F> {
-    iter: I,
-    f: F
-}
-
-/// Create a new `MapResults` iterator.
-pub fn map_results<I, F, T, U, E>(iter: I, f: F) -> MapResults<I, F>
-    where I: Iterator<Item = Result<T, E>>,
-          F: FnMut(T) -> U,
-{
-    MapResults {
-        iter: iter,
-        f: f,
-    }
-}
-
-impl<I, F, T, U, E> Iterator for MapResults<I, F>
-    where I: Iterator<Item = Result<T, E>>,
-          F: FnMut(T) -> U,
-{
-    type Item = Result<U, E>;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        self.iter.next().map(|v| v.map(&mut self.f))
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-}
-
-/// An iterator adapter to get the positions of each element that matches a predicate.
-///
-/// See [`.positions()`](../trait.Itertools.html#method.positions) for more information.
-pub struct Positions<I, F> {
-    iter: I,
-    f: F,
-    count: usize,
-}
-
-/// Create a new `Positions` iterator.
-pub fn positions<I, F>(iter: I, f: F) -> Positions<I, F>
-    where I: Iterator,
-          F: FnMut(I::Item) -> bool,
-{
-    Positions {
-        iter: iter,
-        f: f,
-        count: 0
-    }
-}
-
-impl<I, F> Iterator for Positions<I, F>
-    where I: Iterator,
-          F: FnMut(I::Item) -> bool,
-{
-    type Item = usize;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        while let Some(v) = self.iter.next() {
-            let i = self.count;
-            self.count = i + 1;
-            if (self.f)(v) {
-                return Some(i);
-            }
-        }
-        None
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        (0, self.iter.size_hint().1)
-    }
-}
-
-impl<I, F> DoubleEndedIterator for Positions<I, F>
-    where I: DoubleEndedIterator + ExactSizeIterator,
-          F: FnMut(I::Item) -> bool,
-{
-    fn next_back(&mut self) -> Option<Self::Item> {
-        while let Some(v) = self.iter.next_back() {
-            if (self.f)(v) {
-                return Some(self.count + self.iter.len())
-            }
-        }
-        None
-    }
-}
-
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/adaptors/multipeek.rs
+++ /dev/null
@@ -1,84 +0,0 @@
-
-
-use std::iter::Fuse;
-use std::collections::VecDeque;
-use size_hint;
-
-/// See [`multipeek()`](../fn.multipeek.html) for more information.
-#[derive(Clone, Debug)]
-pub struct MultiPeek<I>
-    where I: Iterator
-{
-    iter: Fuse<I>,
-    buf: VecDeque<I::Item>,
-    index: usize,
-}
-
-/// An iterator adaptor that allows the user to peek at multiple `.next()`
-/// values without advancing the base iterator.
-pub fn multipeek<I>(iterable: I) -> MultiPeek<I::IntoIter>
-    where I: IntoIterator
-{
-    MultiPeek {
-        iter: iterable.into_iter().fuse(),
-        buf: VecDeque::new(),
-        index: 0,
-    }
-}
-
-impl<I> MultiPeek<I>
-    where I: Iterator
-{
-    /// Reset the peeking “cursor”
-    pub fn reset_peek(&mut self) {
-        self.index = 0;
-    }
-}
-
-impl<I: Iterator> MultiPeek<I> {
-    /// Works exactly like `.next()` with the only difference that it doesn't
-    /// advance itself. `.peek()` can be called multiple times, to peek
-    /// further ahead.
-    pub fn peek(&mut self) -> Option<&I::Item> {
-        let ret = if self.index < self.buf.len() {
-            Some(&self.buf[self.index])
-        } else {
-            match self.iter.next() {
-                Some(x) => {
-                    self.buf.push_back(x);
-                    Some(&self.buf[self.index])
-                }
-                None => return None,
-            }
-        };
-
-        self.index += 1;
-        ret
-    }
-}
-
-impl<I> Iterator for MultiPeek<I>
-    where I: Iterator
-{
-    type Item = I::Item;
-
-    fn next(&mut self) -> Option<I::Item> {
-        self.index = 0;
-        if self.buf.is_empty() {
-            self.iter.next()
-        } else {
-            self.buf.pop_front()
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        size_hint::add_scalar(self.iter.size_hint(), self.buf.len())
-    }
-}
-
-// Same size
-impl<I> ExactSizeIterator for MultiPeek<I>
-    where I: ExactSizeIterator
-{}
-
-
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/concat_impl.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-use Itertools;
-
-/// Combine all an iterator's elements into one element by using `Extend`.
-///
-/// `IntoIterator`-enabled version of `.concat()`
-///
-/// This combinator will extend the first item with each of the rest of the
-/// items of the iterator. If the iterator is empty, the default value of
-/// `I::Item` is returned.
-///
-/// ```rust
-/// use itertools::concat;
-/// 
-/// let input = vec![vec![1], vec![2, 3], vec![4, 5, 6]];
-/// assert_eq!(concat(input), vec![1, 2, 3, 4, 5, 6]);
-/// ```
-pub fn concat<I>(iterable: I) -> I::Item
-    where I: IntoIterator,
-          I::Item: Extend<<<I as IntoIterator>::Item as IntoIterator>::Item> + IntoIterator + Default
-{
-    iterable.into_iter().fold1(|mut a, b| { a.extend(b); a }).unwrap_or_else(|| <_>::default())
-}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/cons_tuples_impl.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-
-macro_rules! impl_cons_iter(
-    ($_A:ident, $_B:ident, ) => (); // stop
-
-    ($A:ident, $($B:ident,)*) => (
-        impl_cons_iter!($($B,)*);
-        #[allow(non_snake_case)]
-        impl<X, Iter, $($B),*> Iterator for ConsTuples<Iter, (($($B,)*), X)>
-            where Iter: Iterator<Item = (($($B,)*), X)>,
-        {
-            type Item = ($($B,)* X, );
-            fn next(&mut self) -> Option<Self::Item> {
-                self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, ))
-            }
-
-            fn size_hint(&self) -> (usize, Option<usize>) {
-                self.iter.size_hint()
-            }
-            fn fold<Acc, Fold>(self, accum: Acc, mut f: Fold) -> Acc
-                where Fold: FnMut(Acc, Self::Item) -> Acc,
-            {
-                self.iter.fold(accum, move |acc, (($($B,)*), x)| f(acc, ($($B,)* x, )))
-            }
-        }
-
-        #[allow(non_snake_case)]
-        impl<X, Iter, $($B),*> DoubleEndedIterator for ConsTuples<Iter, (($($B,)*), X)>
-            where Iter: DoubleEndedIterator<Item = (($($B,)*), X)>,
-        {
-            fn next_back(&mut self) -> Option<Self::Item> {
-                self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, ))
-            }
-        }
-
-    );
-);
-
-impl_cons_iter!(A, B, C, D, E, F, G, H,);
-
-/// An iterator that maps an iterator of tuples like
-/// `((A, B), C)` to an iterator of `(A, B, C)`.
-///
-/// Used by the `iproduct!()` macro.
-pub struct ConsTuples<I, J>
-    where I: Iterator<Item=J>,
-{
-    iter: I,
-}
-
-impl<I, J> Clone for ConsTuples<I, J>
-    where I: Clone + Iterator<Item=J>,
-{
-    fn clone(&self) -> Self {
-        ConsTuples {
-            iter: self.iter.clone(),
-        }
-    }
-}
-
-/// Create an iterator that maps for example iterators of
-/// `((A, B), C)` to `(A, B, C)`.
-pub fn cons_tuples<I, J>(iterable: I) -> ConsTuples<I, J>
-    where I: Iterator<Item=J>
-{
-    ConsTuples { iter: iterable.into_iter() }
-}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/diff.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-//! "Diff"ing iterators for caching elements to sequential collections without requiring the new
-//! elements' iterator to be `Clone`.
-//!
-//! - [**Diff**](./enum.Diff.html) (produced by the [**diff_with**](./fn.diff_with.html) function)
-//! describes the difference between two non-`Clone` iterators `I` and `J` after breaking ASAP from
-//! a lock-step comparison.
-
-use free::put_back;
-use structs::PutBack;
-
-/// A type returned by the [`diff_with`](./fn.diff_with.html) function.
-///
-/// `Diff` represents the way in which the elements yielded by the iterator `I` differ to some
-/// iterator `J`.
-pub enum Diff<I, J>
-    where I: Iterator,
-          J: Iterator
-{
-    /// The index of the first non-matching element along with both iterator's remaining elements
-    /// starting with the first mis-match.
-    FirstMismatch(usize, PutBack<I>, PutBack<J>),
-    /// The total number of elements that were in `J` along with the remaining elements of `I`.
-    Shorter(usize, PutBack<I>),
-    /// The total number of elements that were in `I` along with the remaining elements of `J`.
-    Longer(usize, PutBack<J>),
-}
-
-/// Compares every element yielded by both `i` and `j` with the given function in lock-step and
-/// returns a `Diff` which describes how `j` differs from `i`.
-///
-/// If the number of elements yielded by `j` is less than the number of elements yielded by `i`,
-/// the number of `j` elements yielded will be returned along with `i`'s remaining elements as
-/// `Diff::Shorter`.
-///
-/// If the two elements of a step differ, the index of those elements along with the remaining
-/// elements of both `i` and `j` are returned as `Diff::FirstMismatch`.
-///
-/// If `i` becomes exhausted before `j` becomes exhausted, the number of elements in `i` along with
-/// the remaining `j` elements will be returned as `Diff::Longer`.
-pub fn diff_with<I, J, F>(i: I, j: J, is_equal: F)
-    -> Option<Diff<I::IntoIter, J::IntoIter>>
-    where I: IntoIterator,
-          J: IntoIterator,
-          F: Fn(&I::Item, &J::Item) -> bool
-{
-    let mut i = i.into_iter();
-    let mut j = j.into_iter();
-    let mut idx = 0;
-    while let Some(i_elem) = i.next() {
-        match j.next() {
-            None => return Some(Diff::Shorter(idx, put_back(i).with_value(i_elem))),
-            Some(j_elem) => if !is_equal(&i_elem, &j_elem) {
-                let remaining_i = put_back(i).with_value(i_elem);
-                let remaining_j = put_back(j).with_value(j_elem);
-                return Some(Diff::FirstMismatch(idx, remaining_i, remaining_j));
-            },
-        }
-        idx += 1;
-    }
-    j.next().map(|j_elem| Diff::Longer(idx, put_back(j).with_value(j_elem)))
-}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/format.rs
+++ /dev/null
@@ -1,113 +0,0 @@
-use std::fmt;
-use std::cell::RefCell;
-
-/// Format all iterator elements lazily, separated by `sep`.
-///
-/// The format value can only be formatted once, after that the iterator is
-/// exhausted.
-///
-/// See [`.format_with()`](../trait.Itertools.html#method.format_with) for more information.
-pub struct FormatWith<'a, I, F> {
-    sep: &'a str,
-    /// FormatWith uses interior mutability because Display::fmt takes &self.
-    inner: RefCell<Option<(I, F)>>,
-}
-
-/// Format all iterator elements lazily, separated by `sep`.
-///
-/// The format value can only be formatted once, after that the iterator is
-/// exhausted.
-///
-/// See [`.format()`](../trait.Itertools.html#method.format)
-/// for more information.
-#[derive(Clone)]
-pub struct Format<'a, I> {
-    sep: &'a str,
-    /// Format uses interior mutability because Display::fmt takes &self.
-    inner: RefCell<Option<I>>,
-}
-
-pub fn new_format<'a, I, F>(iter: I, separator: &'a str, f: F) -> FormatWith<'a, I, F>
-    where I: Iterator,
-          F: FnMut(I::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result
-{
-    FormatWith {
-        sep: separator,
-        inner: RefCell::new(Some((iter, f))),
-    }
-}
-
-pub fn new_format_default<'a, I>(iter: I, separator: &'a str) -> Format<'a, I>
-    where I: Iterator,
-{
-    Format {
-        sep: separator,
-        inner: RefCell::new(Some(iter)),
-    }
-}
-
-impl<'a, I, F> fmt::Display for FormatWith<'a, I, F>
-    where I: Iterator,
-          F: FnMut(I::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result
-{
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let (mut iter, mut format) = match self.inner.borrow_mut().take() {
-            Some(t) => t,
-            None => panic!("FormatWith: was already formatted once"),
-        };
-
-        if let Some(fst) = iter.next() {
-            try!(format(fst, &mut |disp: &fmt::Display| disp.fmt(f)));
-            for elt in iter {
-                if self.sep.len() > 0 {
-
-                    try!(f.write_str(self.sep));
-                }
-                try!(format(elt, &mut |disp: &fmt::Display| disp.fmt(f)));
-            }
-        }
-        Ok(())
-    }
-}
-
-impl<'a, I> Format<'a, I>
-    where I: Iterator,
-{
-    fn format<F>(&self, f: &mut fmt::Formatter, mut cb: F) -> fmt::Result
-        where F: FnMut(&I::Item, &mut fmt::Formatter) -> fmt::Result,
-    {
-        let mut iter = match self.inner.borrow_mut().take() {
-            Some(t) => t,
-            None => panic!("Format: was already formatted once"),
-        };
-
-        if let Some(fst) = iter.next() {
-            try!(cb(&fst, f));
-            for elt in iter {
-                if self.sep.len() > 0 {
-                    try!(f.write_str(self.sep));
-                }
-                try!(cb(&elt, f));
-            }
-        }
-        Ok(())
-    }
-}
-
-macro_rules! impl_format {
-    ($($fmt_trait:ident)*) => {
-        $(
-            impl<'a, I> fmt::$fmt_trait for Format<'a, I>
-                where I: Iterator,
-                      I::Item: fmt::$fmt_trait,
-            {
-                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-                    self.format(f, fmt::$fmt_trait::fmt)
-                }
-            }
-        )*
-    }
-}
-
-impl_format!{Display Debug
-             UpperExp LowerExp UpperHex LowerHex Octal Binary Pointer}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/free.rs
+++ /dev/null
@@ -1,222 +0,0 @@
-//! Free functions that create iterator adaptors or call iterator methods.
-//!
-//! The benefit of free functions is that they accept any `IntoIterator` as
-//! argument, so the resulting code may be easier to read.
-
-use std::fmt::Display;
-use std::iter::{self, Zip};
-use Itertools;
-
-pub use adaptors::{
-    interleave,
-    merge,
-    put_back,
-    put_back_n,
-};
-pub use adaptors::multipeek::multipeek;
-pub use kmerge_impl::kmerge;
-pub use zip_eq_impl::zip_eq;
-pub use rciter_impl::rciter;
-
-/// Iterate `iterable` with a running index.
-///
-/// `IntoIterator` enabled version of `.enumerate()`.
-///
-/// ```
-/// use itertools::enumerate;
-///
-/// for (i, elt) in enumerate(&[1, 2, 3]) {
-///     /* loop body */
-/// }
-/// ```
-pub fn enumerate<I>(iterable: I) -> iter::Enumerate<I::IntoIter>
-    where I: IntoIterator
-{
-    iterable.into_iter().enumerate()
-}
-
-/// Iterate `iterable` in reverse.
-///
-/// `IntoIterator` enabled version of `.rev()`.
-///
-/// ```
-/// use itertools::rev;
-///
-/// for elt in rev(&[1, 2, 3]) {
-///     /* loop body */
-/// }
-/// ```
-pub fn rev<I>(iterable: I) -> iter::Rev<I::IntoIter>
-    where I: IntoIterator,
-          I::IntoIter: DoubleEndedIterator
-{
-    iterable.into_iter().rev()
-}
-
-/// Iterate `i` and `j` in lock step.
-///
-/// `IntoIterator` enabled version of `i.zip(j)`.
-///
-/// ```
-/// use itertools::zip;
-///
-/// let data = [1, 2, 3, 4, 5];
-/// for (a, b) in zip(&data, &data[1..]) {
-///     /* loop body */
-/// }
-/// ```
-pub fn zip<I, J>(i: I, j: J) -> Zip<I::IntoIter, J::IntoIter>
-    where I: IntoIterator,
-          J: IntoIterator
-{
-    i.into_iter().zip(j)
-}
-
-/// Create an iterator that first iterates `i` and then `j`.
-///
-/// `IntoIterator` enabled version of `i.chain(j)`.
-///
-/// ```
-/// use itertools::chain;
-///
-/// for elt in chain(&[1, 2, 3], &[4]) {
-///     /* loop body */
-/// }
-/// ```
-pub fn chain<I, J>(i: I, j: J) -> iter::Chain<<I as IntoIterator>::IntoIter, <J as IntoIterator>::IntoIter>
-    where I: IntoIterator,
-          J: IntoIterator<Item = I::Item>
-{
-    i.into_iter().chain(j)
-}
-
-/// Create an iterator that clones each element from &T to T
-///
-/// `IntoIterator` enabled version of `i.cloned()`.
-///
-/// ```
-/// use itertools::cloned;
-///
-/// assert_eq!(cloned(b"abc").next(), Some(b'a'));
-/// ```
-pub fn cloned<'a, I, T: 'a>(iterable: I) -> iter::Cloned<I::IntoIter>
-    where I: IntoIterator<Item=&'a T>,
-          T: Clone,
-{
-    iterable.into_iter().cloned()
-}
-
-/// Perform a fold operation over the iterable.
-///
-/// `IntoIterator` enabled version of `i.fold(init, f)`
-///
-/// ```
-/// use itertools::fold;
-///
-/// assert_eq!(fold(&[1., 2., 3.], 0., |a, &b| f32::max(a, b)), 3.);
-/// ```
-pub fn fold<I, B, F>(iterable: I, init: B, f: F) -> B
-    where I: IntoIterator,
-          F: FnMut(B, I::Item) -> B
-{
-    iterable.into_iter().fold(init, f)
-}
-
-/// Test whether the predicate holds for all elements in the iterable.
-///
-/// `IntoIterator` enabled version of `i.all(f)`
-///
-/// ```
-/// use itertools::all;
-///
-/// assert!(all(&[1, 2, 3], |elt| *elt > 0));
-/// ```
-pub fn all<I, F>(iterable: I, f: F) -> bool
-    where I: IntoIterator,
-          F: FnMut(I::Item) -> bool
-{
-    iterable.into_iter().all(f)
-}
-
-/// Test whether the predicate holds for any elements in the iterable.
-///
-/// `IntoIterator` enabled version of `i.any(f)`
-///
-/// ```
-/// use itertools::any;
-///
-/// assert!(any(&[0, -1, 2], |elt| *elt > 0));
-/// ```
-pub fn any<I, F>(iterable: I, f: F) -> bool
-    where I: IntoIterator,
-          F: FnMut(I::Item) -> bool
-{
-    iterable.into_iter().any(f)
-}
-
-/// Return the maximum value of the iterable.
-///
-/// `IntoIterator` enabled version of `i.max()`.
-///
-/// ```
-/// use itertools::max;
-///
-/// assert_eq!(max(0..10), Some(9));
-/// ```
-pub fn max<I>(iterable: I) -> Option<I::Item>
-    where I: IntoIterator,
-          I::Item: Ord
-{
-    iterable.into_iter().max()
-}
-
-/// Return the minimum value of the iterable.
-///
-/// `IntoIterator` enabled version of `i.min()`.
-///
-/// ```
-/// use itertools::min;
-///
-/// assert_eq!(min(0..10), Some(0));
-/// ```
-pub fn min<I>(iterable: I) -> Option<I::Item>
-    where I: IntoIterator,
-          I::Item: Ord
-{
-    iterable.into_iter().min()
-}
-
-
-/// Combine all iterator elements into one String, seperated by `sep`.
-///
-/// `IntoIterator` enabled version of `iterable.join(sep)`.
-///
-/// ```
-/// use itertools::join;
-///
-/// assert_eq!(join(&[1, 2, 3], ", "), "1, 2, 3");
-/// ```
-pub fn join<I>(iterable: I, sep: &str) -> String
-    where I: IntoIterator,
-          I::Item: Display
-{
-    iterable.into_iter().join(sep)
-}
-
-/// Collect all the iterable's elements into a sorted vector in ascending order.
-///
-/// `IntoIterator` enabled version of `iterable.sorted()`.
-///
-/// ```
-/// use itertools::sorted;
-/// use itertools::assert_equal;
-///
-/// assert_equal(sorted("rust".chars()), "rstu".chars());
-/// ```
-pub fn sorted<I>(iterable: I) -> Vec<I::Item>
-    where I: IntoIterator,
-          I::Item: Ord
-{
-    iterable.into_iter().sorted()
-}
-
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/groupbylazy.rs
+++ /dev/null
@@ -1,566 +0,0 @@
-use std::cell::{Cell, RefCell};
-use std::vec;
-
-/// A trait to unify FnMut for GroupBy with the chunk key in IntoChunks
-trait KeyFunction<A> {
-    type Key;
-    fn call_mut(&mut self, arg: A) -> Self::Key;
-}
-
-impl<'a, A, K, F: ?Sized> KeyFunction<A> for F
-    where F: FnMut(A) -> K
-{
-    type Key = K;
-    #[inline]
-    fn call_mut(&mut self, arg: A) -> Self::Key {
-        (*self)(arg)
-    }
-}
-
-
-/// ChunkIndex acts like the grouping key function for IntoChunks
-struct ChunkIndex {
-    size: usize,
-    index: usize,
-    key: usize,
-}
-
-impl ChunkIndex {
-    #[inline(always)]
-    fn new(size: usize) -> Self {
-        ChunkIndex {
-            size: size,
-            index: 0,
-            key: 0,
-        }
-    }
-}
-
-impl<'a, A> KeyFunction<A> for ChunkIndex {
-    type Key = usize;
-    #[inline(always)]
-    fn call_mut(&mut self, _arg: A) -> Self::Key {
-        if self.index == self.size {
-            self.key += 1;
-            self.index = 0;
-        }
-        self.index += 1;
-        self.key
-    }
-}
-
-
-struct GroupInner<K, I, F>
-    where I: Iterator
-{
-    key: F,
-    iter: I,
-    current_key: Option<K>,
-    current_elt: Option<I::Item>,
-    /// flag set if iterator is exhausted
-    done: bool,
-    /// Index of group we are currently buffering or visiting
-    top_group: usize,
-    /// Least index for which we still have elements buffered
-    oldest_buffered_group: usize,
-    /// Group index for `buffer[0]` -- the slots
-    /// bottom_group..oldest_buffered_group are unused and will be erased when
-    /// that range is large enough.
-    bottom_group: usize,
-    /// Buffered groups, from `bottom_group` (index 0) to `top_group`.
-    buffer: Vec<vec::IntoIter<I::Item>>,
-    /// index of last group iter that was dropped, usize::MAX == none
-    dropped_group: usize,
-}
-
-impl<K, I, F> GroupInner<K, I, F>
-    where I: Iterator,
-          F: for<'a> KeyFunction<&'a I::Item, Key=K>,
-          K: PartialEq,
-{
-    /// `client`: Index of group that requests next element
-    #[inline(always)]
-    fn step(&mut self, client: usize) -> Option<I::Item> {
-        /*
-        println!("client={}, bottom_group={}, oldest_buffered_group={}, top_group={}, buffers=[{}]",
-                 client, self.bottom_group, self.oldest_buffered_group,
-                 self.top_group,
-                 self.buffer.iter().map(|elt| elt.len()).format(", "));
-        */
-        if client < self.oldest_buffered_group {
-            None
-        } else if client < self.top_group ||
-            (client == self.top_group &&
-             self.buffer.len() > self.top_group - self.bottom_group)
-        {
-            self.lookup_buffer(client)
-        } else if self.done {
-            None
-        } else if self.top_group == client {
-            self.step_current()
-        } else {
-            self.step_buffering(client)
-        }
-    }
-
-    #[inline(never)]
-    fn lookup_buffer(&mut self, client: usize) -> Option<I::Item> {
-        // if `bufidx` doesn't exist in self.buffer, it might be empty
-        let bufidx = client - self.bottom_group;
-        if client < self.oldest_buffered_group {
-            return None;
-        }
-        let elt = self.buffer.get_mut(bufidx).and_then(|queue| queue.next());
-        if elt.is_none() && client == self.oldest_buffered_group {
-            // FIXME: VecDeque is unfortunately not zero allocation when empty,
-            // so we do this job manually.
-            // `bottom_group..oldest_buffered_group` is unused, and if it's large enough, erase it.
-            self.oldest_buffered_group += 1;
-            // skip forward further empty queues too
-            while self.buffer.get(self.oldest_buffered_group - self.bottom_group)
-                             .map_or(false, |buf| buf.len() == 0)
-            {
-                self.oldest_buffered_group += 1;
-            }
-
-            let nclear = self.oldest_buffered_group - self.bottom_group;
-            if nclear > 0 && nclear >= self.buffer.len() / 2 {
-                let mut i = 0;
-                self.buffer.retain(|buf| {
-                    i += 1;
-                    debug_assert!(buf.len() == 0 || i > nclear);
-                    i > nclear
-                });
-                self.bottom_group = self.oldest_buffered_group;
-            }
-        }
-        elt
-    }
-
-    /// Take the next element from the iterator, and set the done
-    /// flag if exhausted. Must not be called after done.
-    #[inline(always)]
-    fn next_element(&mut self) -> Option<I::Item> {
-        debug_assert!(!self.done);
-        match self.iter.next() {
-            None => { self.done = true; None }
-            otherwise => otherwise,
-        }
-    }
-
-
-    #[inline(never)]
-    fn step_buffering(&mut self, client: usize) -> Option<I::Item> {
-        // requested a later group -- walk through the current group up to
-        // the requested group index, and buffer the elements (unless
-        // the group is marked as dropped).
-        // Because the `Groups` iterator is always the first to request
-        // each group index, client is the next index efter top_group.
-        debug_assert!(self.top_group + 1 == client);
-        let mut group = Vec::new();
-
-        if let Some(elt) = self.current_elt.take() {
-            if self.top_group != self.dropped_group {
-                group.push(elt);
-            }
-        }
-        let mut first_elt = None; // first element of the next group
-
-        while let Some(elt) = self.next_element() {
-            let key = self.key.call_mut(&elt);
-            match self.current_key.take() {
-                None => {}
-                Some(old_key) => if old_key != key {
-                    self.current_key = Some(key);
-                    first_elt = Some(elt);
-                    break;
-                },
-            }
-            self.current_key = Some(key);
-            if self.top_group != self.dropped_group {
-                group.push(elt);
-            }
-        }
-
-        if self.top_group != self.dropped_group {
-            self.push_next_group(group);
-        }
-        if first_elt.is_some() {
-            self.top_group += 1;
-            debug_assert!(self.top_group == client);
-        }
-        first_elt
-    }
-
-    fn push_next_group(&mut self, group: Vec<I::Item>) {
-        // When we add a new buffered group, fill up slots between oldest_buffered_group and top_group
-        while self.top_group - self.bottom_group > self.buffer.len() {
-            if self.buffer.is_empty() {
-                self.bottom_group += 1;
-                self.oldest_buffered_group += 1;
-            } else {
-                self.buffer.push(Vec::new().into_iter());
-            }
-        }
-        self.buffer.push(group.into_iter());
-        debug_assert!(self.top_group + 1 - self.bottom_group == self.buffer.len());
-    }
-
-    /// This is the immediate case, where we use no buffering
-    #[inline]
-    fn step_current(&mut self) -> Option<I::Item> {
-        debug_assert!(!self.done);
-        if let elt @ Some(..) = self.current_elt.take() {
-            return elt;
-        }
-        match self.next_element() {
-            None => None,
-            Some(elt) => {
-                let key = self.key.call_mut(&elt);
-                match self.current_key.take() {
-                    None => {}
-                    Some(old_key) => if old_key != key {
-                        self.current_key = Some(key);
-                        self.current_elt = Some(elt);
-                        self.top_group += 1;
-                        return None;
-                    },
-                }
-                self.current_key = Some(key);
-                Some(elt)
-            }
-        }
-    }
-
-    /// Request the just started groups' key.
-    ///
-    /// `client`: Index of group
-    ///
-    /// **Panics** if no group key is available.
-    fn group_key(&mut self, client: usize) -> K {
-        // This can only be called after we have just returned the first
-        // element of a group.
-        // Perform this by simply buffering one more element, grabbing the
-        // next key.
-        debug_assert!(!self.done);
-        debug_assert!(client == self.top_group);
-        debug_assert!(self.current_key.is_some());
-        debug_assert!(self.current_elt.is_none());
-        let old_key = self.current_key.take().unwrap();
-        if let Some(elt) = self.next_element() {
-            let key = self.key.call_mut(&elt);
-            if old_key != key {
-                self.top_group += 1;
-            }
-            self.current_key = Some(key);
-            self.current_elt = Some(elt);
-        }
-        old_key
-    }
-}
-
-impl<K, I, F> GroupInner<K, I, F>
-    where I: Iterator,
-{
-    /// Called when a group is dropped
-    fn drop_group(&mut self, client: usize) {
-        // It's only useful to track the maximal index
-        if self.dropped_group == !0 || client > self.dropped_group {
-            self.dropped_group = client;
-        }
-    }
-}
-
-/// `GroupBy` is the storage for the lazy grouping operation.
-///
-/// If the groups are consumed in their original order, or if each
-/// group is dropped without keeping it around, then `GroupBy` uses
-/// no allocations. It needs allocations only if several group iterators
-/// are alive at the same time.
-///
-/// This type implements `IntoIterator` (it is **not** an iterator
-/// itself), because the group iterators need to borrow from this
-/// value. It should be stored in a local variable or temporary and
-/// iterated.
-///
-/// See [`.group_by()`](../trait.Itertools.html#method.group_by) for more information.
-pub struct GroupBy<K, I, F>
-    where I: Iterator,
-{
-    inner: RefCell<GroupInner<K, I, F>>,
-    // the group iterator's current index. Keep this in the main value
-    // so that simultaneous iterators all use the same state.
-    index: Cell<usize>,
-}
-
-/// Create a new
-pub fn new<K, J, F>(iter: J, f: F) -> GroupBy<K, J::IntoIter, F>
-    where J: IntoIterator,
-          F: FnMut(&J::Item) -> K,
-{
-    GroupBy {
-        inner: RefCell::new(GroupInner {
-            key: f,
-            iter: iter.into_iter(),
-            current_key: None,
-            current_elt: None,
-            done: false,
-            top_group: 0,
-            oldest_buffered_group: 0,
-            bottom_group: 0,
-            buffer: Vec::new(),
-            dropped_group: !0,
-        }),
-        index: Cell::new(0),
-    }
-}
-
-impl<K, I, F> GroupBy<K, I, F>
-    where I: Iterator,
-{
-    /// `client`: Index of group that requests next element
-    fn step(&self, client: usize) -> Option<I::Item>
-        where F: FnMut(&I::Item) -> K,
-              K: PartialEq,
-    {
-        self.inner.borrow_mut().step(client)
-    }
-
-    /// `client`: Index of group
-    fn drop_group(&self, client: usize) {
-        self.inner.borrow_mut().drop_group(client)
-    }
-}
-
-impl<'a, K, I, F> IntoIterator for &'a GroupBy<K, I, F>
-    where I: Iterator,
-          I::Item: 'a,
-          F: FnMut(&I::Item) -> K,
-          K: PartialEq
-{
-    type Item = (K, Group<'a, K, I, F>);
-    type IntoIter = Groups<'a, K, I, F>;
-
-    fn into_iter(self) -> Self::IntoIter {
-        Groups { parent: self }
-    }
-}
-
-
-/// An iterator that yields the Group iterators.
-///
-/// Iterator element type is `(K, Group)`:
-/// the group's key `K` and the group's iterator.
-///
-/// See [`.group_by()`](../trait.Itertools.html#method.group_by) for more information.
-pub struct Groups<'a, K: 'a, I: 'a, F: 'a>
-    where I: Iterator,
-          I::Item: 'a
-{
-    parent: &'a GroupBy<K, I, F>,
-}
-
-impl<'a, K, I, F> Iterator for Groups<'a, K, I, F>
-    where I: Iterator,
-          I::Item: 'a,
-          F: FnMut(&I::Item) -> K,
-          K: PartialEq
-{
-    type Item = (K, Group<'a, K, I, F>);
-
-    #[inline]
-    fn next(&mut self) -> Option<Self::Item> {
-        let index = self.parent.index.get();
-        self.parent.index.set(index + 1);
-        let inner = &mut *self.parent.inner.borrow_mut();
-        inner.step(index).map(|elt| {
-            let key = inner.group_key(index);
-            (key, Group {
-                parent: self.parent,
-                index: index,
-                first: Some(elt),
-            })
-        })
-    }
-}
-
-/// An iterator for the elements in a single group.
-///
-/// Iterator element type is `I::Item`.
-pub struct Group<'a, K: 'a, I: 'a, F: 'a>
-    where I: Iterator,
-          I::Item: 'a,
-{
-    parent: &'a GroupBy<K, I, F>,
-    index: usize,
-    first: Option<I::Item>,
-}
-
-impl<'a, K, I, F> Drop for Group<'a, K, I, F>
-    where I: Iterator,
-          I::Item: 'a,
-{
-    fn drop(&mut self) {
-        self.parent.drop_group(self.index);
-    }
-}
-
-impl<'a, K, I, F> Iterator for Group<'a, K, I, F>
-    where I: Iterator,
-          I::Item: 'a,
-          F: FnMut(&I::Item) -> K,
-          K: PartialEq,
-{
-    type Item = I::Item;
-    #[inline]
-    fn next(&mut self) -> Option<Self::Item> {
-        if let elt @ Some(..) = self.first.take() {
-            return elt;
-        }
-        self.parent.step(self.index)
-    }
-}
-
-///// IntoChunks /////
-
-/// Create a new
-pub fn new_chunks<J>(iter: J, size: usize) -> IntoChunks<J::IntoIter>
-    where J: IntoIterator,
-{
-    IntoChunks {
-        inner: RefCell::new(GroupInner {
-            key: ChunkIndex::new(size),
-            iter: iter.into_iter(),
-            current_key: None,
-            current_elt: None,
-            done: false,
-            top_group: 0,
-            oldest_buffered_group: 0,
-            bottom_group: 0,
-            buffer: Vec::new(),
-            dropped_group: !0,
-        }),
-        index: Cell::new(0),
-    }
-}
-
-
-/// `ChunkLazy` is the storage for a lazy chunking operation.
-///
-/// `IntoChunks` behaves just like `GroupBy`: it is iterable, and
-/// it only buffers if several chunk iterators are alive at the same time.
-///
-/// This type implements `IntoIterator` (it is **not** an iterator
-/// itself), because the chunk iterators need to borrow from this
-/// value. It should be stored in a local variable or temporary and
-/// iterated.
-///
-/// Iterator element type is `Chunk`, each chunk's iterator.
-///
-/// See [`.chunks()`](../trait.Itertools.html#method.chunks) for more information.
-pub struct IntoChunks<I>
-    where I: Iterator,
-{
-    inner: RefCell<GroupInner<usize, I, ChunkIndex>>,
-    // the chunk iterator's current index. Keep this in the main value
-    // so that simultaneous iterators all use the same state.
-    index: Cell<usize>,
-}
-
-
-impl<I> IntoChunks<I>
-    where I: Iterator,
-{
-    /// `client`: Index of chunk that requests next element
-    fn step(&self, client: usize) -> Option<I::Item> {
-        self.inner.borrow_mut().step(client)
-    }
-
-    /// `client`: Index of chunk
-    fn drop_group(&self, client: usize) {
-        self.inner.borrow_mut().drop_group(client)
-    }
-}
-
-impl<'a, I> IntoIterator for &'a IntoChunks<I>
-    where I: Iterator,
-          I::Item: 'a,
-{
-    type Item = Chunk<'a, I>;
-    type IntoIter = Chunks<'a, I>;
-
-    fn into_iter(self) -> Self::IntoIter {
-        Chunks {
-            parent: self,
-        }
-    }
-}
-
-
-/// An iterator that yields the Chunk iterators.
-///
-/// Iterator element type is `Chunk`.
-///
-/// See [`.chunks()`](../trait.Itertools.html#method.chunks) for more information.
-pub struct Chunks<'a, I: 'a>
-    where I: Iterator,
-          I::Item: 'a,
-{
-    parent: &'a IntoChunks<I>,
-}
-
-impl<'a, I> Iterator for Chunks<'a, I>
-    where I: Iterator,
-          I::Item: 'a,
-{
-    type Item = Chunk<'a, I>;
-
-    #[inline]
-    fn next(&mut self) -> Option<Self::Item> {
-        let index = self.parent.index.get();
-        self.parent.index.set(index + 1);
-        let inner = &mut *self.parent.inner.borrow_mut();
-        inner.step(index).map(|elt| {
-            Chunk {
-                parent: self.parent,
-                index: index,
-                first: Some(elt),
-            }
-        })
-    }
-}
-
-/// An iterator for the elements in a single chunk.
-///
-/// Iterator element type is `I::Item`.
-pub struct Chunk<'a, I: 'a>
-    where I: Iterator,
-          I::Item: 'a,
-{
-    parent: &'a IntoChunks<I>,
-    index: usize,
-    first: Option<I::Item>,
-}
-
-impl<'a, I> Drop for Chunk<'a, I>
-    where I: Iterator,
-          I::Item: 'a,
-{
-    fn drop(&mut self) {
-        self.parent.drop_group(self.index);
-    }
-}
-
-impl<'a, I> Iterator for Chunk<'a, I>
-    where I: Iterator,
-          I::Item: 'a,
-{
-    type Item = I::Item;
-    #[inline]
-    fn next(&mut self) -> Option<Self::Item> {
-        if let elt @ Some(..) = self.first.take() {
-            return elt;
-        }
-        self.parent.step(self.index)
-    }
-}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/impl_macros.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-//! 
-//! Implementation's internal macros
-
-macro_rules! debug_fmt_fields {
-    ($tyname:ident, $($($field:ident).+),*) => {
-        fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
-            f.debug_struct(stringify!($tyname))
-                $(
-              .field(stringify!($($field).+), &self.$($field).+)
-              )*
-              .finish()
-        }
-    }
-}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/intersperse.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-use std::iter::Fuse;
-use super::size_hint;
-
-#[derive(Clone)]
-/// An iterator adaptor to insert a particular value
-/// between each element of the adapted iterator.
-///
-/// Iterator element type is `I::Item`
-///
-/// This iterator is *fused*.
-///
-/// See [`.intersperse()`](../trait.Itertools.html#method.intersperse) for more information.
-pub struct Intersperse<I>
-    where I: Iterator
-{
-    element: I::Item,
-    iter: Fuse<I>,
-    peek: Option<I::Item>,
-}
-
-/// Create a new Intersperse iterator
-pub fn intersperse<I>(iter: I, elt: I::Item) -> Intersperse<I>
-    where I: Iterator
-{
-    let mut iter = iter.fuse();
-    Intersperse {
-        peek: iter.next(),
-        iter: iter,
-        element: elt,
-    }
-}
-
-impl<I> Iterator for Intersperse<I>
-    where I: Iterator,
-          I::Item: Clone
-{
-    type Item = I::Item;
-    #[inline]
-    fn next(&mut self) -> Option<I::Item> {
-        if self.peek.is_some() {
-            self.peek.take()
-        } else {
-            self.peek = self.iter.next();
-            if self.peek.is_some() {
-                Some(self.element.clone())
-            } else {
-                None
-            }
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        // 2 * SH + { 1 or 0 }
-        let has_peek = self.peek.is_some() as usize;
-        let sh = self.iter.size_hint();
-        size_hint::add_scalar(size_hint::add(sh, sh), has_peek)
-    }
-}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/kmerge_impl.rs
+++ /dev/null
@@ -1,238 +0,0 @@
-
-use size_hint;
-use Itertools;
-
-use std::mem::replace;
-
-macro_rules! clone_fields {
-    ($name:ident, $base:expr, $($field:ident),+) => (
-        $name {
-            $(
-                $field : $base . $field .clone()
-            ),*
-        }
-    );
-}
-
-/// Head element and Tail iterator pair
-///
-/// `PartialEq`, `Eq`, `PartialOrd` and `Ord` are implemented by comparing sequences based on
-/// first items (which are guaranteed to exist).
-///
-/// The meanings of `PartialOrd` and `Ord` are reversed so as to turn the heap used in
-/// `KMerge` into a min-heap.
-struct HeadTail<I>
-    where I: Iterator
-{
-    head: I::Item,
-    tail: I,
-}
-
-impl<I> HeadTail<I>
-    where I: Iterator
-{
-    /// Constructs a `HeadTail` from an `Iterator`. Returns `None` if the `Iterator` is empty.
-    fn new(mut it: I) -> Option<HeadTail<I>> {
-        let head = it.next();
-        head.map(|h| {
-            HeadTail {
-                head: h,
-                tail: it,
-            }
-        })
-    }
-
-    /// Get the next element and update `head`, returning the old head in `Some`.
-    ///
-    /// Returns `None` when the tail is exhausted (only `head` then remains).
-    fn next(&mut self) -> Option<I::Item> {
-        if let Some(next) = self.tail.next() {
-            Some(replace(&mut self.head, next))
-        } else {
-            None
-        }
-    }
-
-    /// Hints at the size of the sequence, same as the `Iterator` method.
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        size_hint::add_scalar(self.tail.size_hint(), 1)
-    }
-}
-
-impl<I> Clone for HeadTail<I>
-    where I: Iterator + Clone,
-          I::Item: Clone
-{
-    fn clone(&self) -> Self {
-        clone_fields!(HeadTail, self, head, tail)
-    }
-}
-
-/// Make `data` a heap (min-heap w.r.t the sorting).
-fn heapify<T, S>(data: &mut [T], mut less_than: S)
-    where S: FnMut(&T, &T) -> bool
-{
-    for i in (0..data.len() / 2).rev() {
-        sift_down(data, i, &mut less_than);
-    }
-}
-
-/// Sift down element at `index` (`heap` is a min-heap wrt the ordering)
-fn sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S)
-    where S: FnMut(&T, &T) -> bool
-{
-    debug_assert!(index <= heap.len());
-    let mut pos = index;
-    let mut child = 2 * pos + 1;
-    // the `pos` conditional is to avoid a bounds check
-    while pos < heap.len() && child < heap.len() {
-        let right = child + 1;
-
-        // pick the smaller of the two children
-        if right < heap.len() && less_than(&heap[right], &heap[child]) {
-            child = right;
-        }
-
-        // sift down is done if we are already in order
-        if !less_than(&heap[child], &heap[pos]) {
-            return;
-        }
-        heap.swap(pos, child);
-        pos = child;
-        child = 2 * pos + 1;
-    }
-}
-
-/// An iterator adaptor that merges an abitrary number of base iterators in ascending order.
-/// If all base iterators are sorted (ascending), the result is sorted.
-///
-/// Iterator element type is `I::Item`.
-///
-/// See [`.kmerge()`](../trait.Itertools.html#method.kmerge) for more information.
-pub struct KMerge<I>
-    where I: Iterator
-{
-    heap: Vec<HeadTail<I>>,
-}
-
-/// Create an iterator that merges elements of the contained iterators using
-/// the ordering function.
-///
-/// Equivalent to `iterable.into_iter().kmerge()`.
-///
-/// ```
-/// use itertools::kmerge;
-///
-/// for elt in kmerge(vec![vec![0, 2, 4], vec![1, 3, 5], vec![6, 7]]) {
-///     /* loop body */
-/// }
-/// ```
-pub fn kmerge<I>(iterable: I) -> KMerge<<I::Item as IntoIterator>::IntoIter>
-    where I: IntoIterator,
-          I::Item: IntoIterator,
-          <<I as IntoIterator>::Item as IntoIterator>::Item: PartialOrd
-{
-    let iter = iterable.into_iter();
-    let (lower, _) = iter.size_hint();
-    let mut heap = Vec::with_capacity(lower);
-    heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
-    heapify(&mut heap, |a, b| a.head < b.head);
-    KMerge { heap: heap }
-}
-
-impl<I> Clone for KMerge<I>
-    where I: Iterator + Clone,
-          I::Item: Clone
-{
-    fn clone(&self) -> KMerge<I> {
-        clone_fields!(KMerge, self, heap)
-    }
-}
-
-impl<I> Iterator for KMerge<I>
-    where I: Iterator,
-          I::Item: PartialOrd
-{
-    type Item = I::Item;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        if self.heap.is_empty() {
-            return None;
-        }
-        let result = if let Some(next) = self.heap[0].next() {
-            next
-        } else {
-            self.heap.swap_remove(0).head
-        };
-        sift_down(&mut self.heap, 0, |a, b| a.head < b.head);
-        Some(result)
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.heap.iter()
-                 .map(|i| i.size_hint())
-                 .fold1(size_hint::add)
-                 .unwrap_or((0, Some(0)))
-    }
-}
-
-/// An iterator adaptor that merges an abitrary number of base iterators
-/// according to an ordering function.
-///
-/// Iterator element type is `I::Item`.
-///
-/// See [`.kmerge_by()`](../trait.Itertools.html#method.kmerge_by) for more
-/// information.
-pub struct KMergeBy<I, F>
-    where I: Iterator,
-{
-    heap: Vec<HeadTail<I>>,
-    less_than: F,
-}
-
-/// Create an iterator that merges elements of the contained iterators.
-///
-/// Equivalent to `iterable.into_iter().kmerge_by(less_than)`.
-pub fn kmerge_by<I, F>(iterable: I, mut less_than: F)
-    -> KMergeBy<<I::Item as IntoIterator>::IntoIter, F>
-    where I: IntoIterator,
-          I::Item: IntoIterator,
-          F: FnMut(&<<I as IntoIterator>::Item as IntoIterator>::Item,
-                   &<<I as IntoIterator>::Item as IntoIterator>::Item) -> bool
-{
-    let iter = iterable.into_iter();
-    let (lower, _) = iter.size_hint();
-    let mut heap: Vec<_> = Vec::with_capacity(lower);
-    heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
-    heapify(&mut heap, |a, b| less_than(&a.head, &b.head));
-    KMergeBy { heap: heap, less_than: less_than }
-}
-
-
-impl<I, F> Iterator for KMergeBy<I, F>
-    where I: Iterator,
-          F: FnMut(&I::Item, &I::Item) -> bool
-{
-    type Item = I::Item;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        if self.heap.is_empty() {
-            return None;
-        }
-        let result = if let Some(next) = self.heap[0].next() {
-            next
-        } else {
-            self.heap.swap_remove(0).head
-        };
-        let less_than = &mut self.less_than;
-        sift_down(&mut self.heap, 0, |a, b| less_than(&a.head, &b.head));
-        Some(result)
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.heap.iter()
-                 .map(|i| i.size_hint())
-                 .fold1(size_hint::add)
-                 .unwrap_or((0, Some(0)))
-    }
-}
deleted file mode 100755
--- a/third_party/rust/itertools-0.6.5/src/lib.rs
+++ /dev/null
@@ -1,1738 +0,0 @@
-#![warn(missing_docs)]
-#![crate_name="itertools"]
-
-//! Itertools — extra iterator adaptors, functions and macros.
-//!
-//! To use the iterator methods in this crate, import the [`Itertools` trait](./trait.Itertools.html):
-//!
-//! ```ignore
-//! use itertools::Itertools;
-//! ```
-//!
-//! ## Rust Version
-//!
-//! This version of itertools requires Rust 1.12 or later.
-//!
-#![doc(html_root_url="https://docs.rs/itertools/")]
-
-extern crate either;
-
-pub use either::Either;
-
-use std::iter::{IntoIterator};
-use std::fmt::Write;
-use std::cmp::Ordering;
-use std::fmt;
-use std::hash::Hash;
-
-#[macro_use]
-mod impl_macros;
-
-/// The concrete iterator types.
-pub mod structs {
-    pub use adaptors::{
-        Dedup,
-        Interleave,
-        InterleaveShortest,
-        Product,
-        PutBack,
-        PutBackN,
-        Batching,
-        Step,
-        MapResults,
-        Merge,
-        MergeBy,
-        MultiPeek,
-        TakeWhileRef,
-        WhileSome,
-        Coalesce,
-        TupleCombinations,
-        Combinations,
-        Unique,
-        UniqueBy,
-        Flatten,
-        Positions,
-    };
-    pub use cons_tuples_impl::ConsTuples;
-    pub use format::{Format, FormatWith};
-    pub use groupbylazy::{IntoChunks, Chunk, Chunks, GroupBy, Group, Groups};
-    pub use intersperse::Intersperse;
-    pub use kmerge_impl::{KMerge, KMergeBy};
-    pub use pad_tail::PadUsing;
-    pub use peeking_take_while::PeekingTakeWhile;
-    pub use process_results_impl::ProcessResults;
-    pub use rciter_impl::RcIter;
-    pub use repeatn::RepeatN;
-    pub use sources::{RepeatCall, Unfold, Iterate};
-    pub use tee::Tee;
-    pub use tuple_impl::{TupleBuffer, TupleWindows, Tuples};
-    pub use with_position::WithPosition;
-    pub use zip_eq_impl::ZipEq;
-    pub use zip_longest::ZipLongest;
-    pub use ziptuple::Zip;
-}
-pub use structs::*;
-pub use concat_impl::concat;
-pub use cons_tuples_impl::cons_tuples;
-pub use diff::diff_with;
-pub use diff::Diff;
-pub use kmerge_impl::{kmerge_by};
-pub use minmax::MinMaxResult;
-pub use peeking_take_while::PeekingNext;
-pub use process_results_impl::process_results;
-pub use repeatn::repeat_n;
-pub use sources::{repeat_call, unfold, iterate};
-pub use with_position::Position;
-pub use zip_longest::EitherOrBoth;
-pub use ziptuple::multizip;
-mod adaptors;
-#[doc(hidden)]
-pub mod free;
-#[doc(inline)]
-pub use free::*;
-mod concat_impl;
-mod cons_tuples_impl;
-mod diff;
-mod format;
-mod groupbylazy;
-mod intersperse;
-mod kmerge_impl;
-mod minmax;
-mod pad_tail;
-mod peeking_take_while;
-mod process_results_impl;
-mod rciter_impl;
-mod repeatn;
-mod size_hint;
-mod sources;
-mod tee;
-mod tuple_impl;
-mod with_position;
-mod zip_eq_impl;
-mod zip_longest;
-mod ziptuple;
-
-#[macro_export]
-/// Create an iterator over the “cartesian product” of iterators.
-///
-/// Iterator element type is like `(A, B, ..., E)` if formed
-/// from iterators `(I, J, ..., M)` with element types `I::Item = A`, `J::Item = B`, etc.
-///
-/// ```
-/// #[macro_use] extern crate itertools;
-/// # fn main() {
-/// // Iterate over the coordinates of a 4 x 4 x 4 grid
-/// // from (0, 0, 0), (0, 0, 1), .., (0, 1, 0), (0, 1, 1), .. etc until (3, 3, 3)
-/// for (i, j, k) in iproduct!(0..4, 0..4, 0..4) {
-///    // ..
-/// }
-/// # }
-/// ```
-///
-/// Note: To enable the macros in this crate, use the `#[macro_use]` attribute
-/// when importing the crate.
-///
-/// ```ignore
-/// #[macro_use] extern crate itertools;
-/// ```
-macro_rules! iproduct {
-    (@flatten $I:expr,) => (
-        $I
-    );
-    (@flatten $I:expr, $J:expr, $($K:expr,)*) => (
-        iproduct!(@flatten $crate::cons_tuples(iproduct!($I, $J)), $($K,)*)
-    );
-    ($I:expr) => (
-        ::std::iter::IntoIterator::into_iter($I)
-    );
-    ($I:expr, $J:expr) => (
-        $crate::Itertools::cartesian_product(iproduct!($I), iproduct!($J))
-    );
-    ($I:expr, $J:expr, $($K:expr),+) => (
-        iproduct!(@flatten iproduct!($I, $J), $($K,)+)
-    );
-}
-
-#[macro_export]
-/// Create an iterator running multiple iterators in lockstep.
-///
-/// The izip! iterator yields elements until any subiterator
-/// returns `None`.
-///
-/// Iterator element type is like `(A, B, ..., E)` if formed
-/// from iterators `(I, J, ..., M)` implementing `I: Iterator<A>`,
-/// `J: Iterator<B>`, ..., `M: Iterator<E>`
-///
-/// ```
-/// #[macro_use] extern crate itertools;
-/// # fn main() {
-///
-/// // Iterate over three sequences side-by-side
-/// let mut xs = [0, 0, 0];
-/// let ys = [69, 107, 101];
-///
-/// for (i, a, b) in izip!(0..100, &mut xs, &ys) {
-///    *a = i ^ *b;
-/// }
-///
-/// assert_eq!(xs, [69, 106, 103]);
-/// # }
-/// ```
-///
-/// Note: To enable the macros in this crate, use the `#[macro_use]` attribute
-/// when importing the crate.
-///
-/// ```ignore
-/// #[macro_use] extern crate itertools;
-/// ```
-macro_rules! izip {
-    ($I:expr) => (
-        ::std::iter::IntoIterator::into_iter($I)
-    );
-    ($($I:expr),*) => (
-        {
-            $crate::multizip(($(izip!($I)),*))
-        }
-    );
-}
-
-/// The trait `Itertools`: extra iterator adaptors and methods for iterators.
-///
-/// This trait defines a number of methods. They are divided into two groups:
-///
-/// * *Adaptors* take an iterator and parameter as input, and return
-/// a new iterator value. These are listed first in the trait. An example
-/// of an adaptor is [`.interleave()`](#method.interleave)
-///
-/// * *Regular methods* are those that don't return iterators and instead
-/// return a regular value of some other kind.
-/// [`.next_tuple()`](#method.next_tuple) is an example and the first regular
-/// method in the list.
-pub trait Itertools : Iterator {
-    // adaptors
-
-    /// Alternate elements from two iterators until both have run out.
-    ///
-    /// Iterator element type is `Self::Item`.
-    ///
-    /// This iterator is *fused*.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let it = (1..7).interleave(vec![-1, -2]);
-    /// itertools::assert_equal(it, vec![1, -1, 2, -2, 3, 4, 5, 6]);
-    /// ```
-    fn interleave<J>(self, other: J) -> Interleave<Self, J::IntoIter>
-        where J: IntoIterator<Item = Self::Item>,
-              Self: Sized
-    {
-        interleave(self, other)
-    }
-
-    /// Alternate elements from two iterators until at least one of them has run
-    /// out.
-    ///
-    /// Iterator element type is `Self::Item`.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let it = (1..7).interleave_shortest(vec![-1, -2]);
-    /// itertools::assert_equal(it, vec![1, -1, 2, -2, 3]);
-    /// ```
-    fn interleave_shortest<J>(self, other: J) -> InterleaveShortest<Self, J::IntoIter>
-        where J: IntoIterator<Item = Self::Item>,
-              Self: Sized
-    {
-        adaptors::interleave_shortest(self, other.into_iter())
-    }
-
-    /// An iterator adaptor to insert a particular value
-    /// between each element of the adapted iterator.
-    ///
-    /// Iterator element type is `Self::Item`.
-    ///
-    /// This iterator is *fused*.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// itertools::assert_equal((0..3).intersperse(8), vec![0, 8, 1, 8, 2]);
-    /// ```
-    fn intersperse(self, element: Self::Item) -> Intersperse<Self>
-        where Self: Sized,
-              Self::Item: Clone
-    {
-        intersperse::intersperse(self, element)
-    }
-
-    /// Create an iterator which iterates over both this and the specified
-    /// iterator simultaneously, yielding pairs of two optional elements.
-    ///
-    /// This iterator is *fused*.
-    ///
-    /// When both iterators return `None`, all further invocations of `.next()`
-    /// will return `None`.
-    ///
-    /// Iterator element type is
-    /// [`EitherOrBoth<Self::Item, J::Item>`](enum.EitherOrBoth.html).
-    ///
-    /// ```rust
-    /// use itertools::EitherOrBoth::{Both, Right};
-    /// use itertools::Itertools;
-    /// let it = (0..1).zip_longest(1..3);
-    /// itertools::assert_equal(it, vec![Both(0, 1), Right(2)]);
-    /// ```
-    #[inline]
-    fn zip_longest<J>(self, other: J) -> ZipLongest<Self, J::IntoIter>
-        where J: IntoIterator,
-              Self: Sized
-    {
-        zip_longest::zip_longest(self, other.into_iter())
-    }
-
-    /// Create an iterator which iterates over both this and the specified
-    /// iterator simultaneously, yielding pairs of elements.
-    ///
-    /// **Panics** if the iterators reach an end and they are not of equal
-    /// lengths.
-    #[inline]
-    fn zip_eq<J>(self, other: J) -> ZipEq<Self, J::IntoIter>
-        where J: IntoIterator,
-              Self: Sized
-    {
-        zip_eq(self, other)
-    }
-
-    /// A “meta iterator adaptor”. Its closure recives a reference to the
-    /// iterator and may pick off as many elements as it likes, to produce the
-    /// next iterator element.
-    ///
-    /// Iterator element type is `B`.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// // An adaptor that gathers elements in pairs
-    /// let pit = (0..4).batching(|it| {
-    ///            match it.next() {
-    ///                None => None,
-    ///                Some(x) => match it.next() {
-    ///                    None => None,
-    ///                    Some(y) => Some((x, y)),
-    ///                }
-    ///            }
-    ///        });
-    ///
-    /// itertools::assert_equal(pit, vec![(0, 1), (2, 3)]);
-    /// ```
-    ///
-    fn batching<B, F>(self, f: F) -> Batching<Self, F>
-        where F: FnMut(&mut Self) -> Option<B>,
-              Self: Sized
-    {
-        adaptors::batching(self, f)
-    }
-
-    /// Return an *iterable* that can group iterator elements.
-    /// Consecutive elements that map to the same key (“runs”), are assigned
-    /// to the same group.
-    ///
-    /// `GroupBy` is the storage for the lazy grouping operation.
-    ///
-    /// If the groups are consumed in order, or if each group's iterator is
-    /// dropped without keeping it around, then `GroupBy` uses no
-    /// allocations.  It needs allocations only if several group iterators
-    /// are alive at the same time.
-    ///
-    /// This type implements `IntoIterator` (it is **not** an iterator
-    /// itself), because the group iterators need to borrow from this
-    /// value. It should be stored in a local variable or temporary and
-    /// iterated.
-    ///
-    /// Iterator element type is `(K, Group)`: the group's key and the
-    /// group iterator.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// // group data into runs of larger than zero or not.
-    /// let data = vec![1, 3, -2, -2, 1, 0, 1, 2];
-    /// // groups:     |---->|------>|--------->|
-    ///
-    /// // Note: The `&` is significant here, `GroupBy` is iterable
-    /// // only by reference. You can also call `.into_iter()` explicitly.
-    /// for (key, group) in &data.into_iter().group_by(|elt| *elt >= 0) {
-    ///     // Check that the sum of each group is +/- 4.
-    ///     assert_eq!(4, group.sum::<i32>().abs());
-    /// }
-    /// ```
-    fn group_by<K, F>(self, key: F) -> GroupBy<K, Self, F>
-        where Self: Sized,
-              F: FnMut(&Self::Item) -> K,
-    {
-        groupbylazy::new(self, key)
-    }
-
-    /// Return an *iterable* that can chunk the iterator.
-    ///
-    /// Yield subiterators (chunks) that each yield a fixed number elements,
-    /// determined by `size`. The last chunk will be shorter if there aren't
-    /// enough elements.
-    ///
-    /// `IntoChunks` is based on `GroupBy`: it is iterable (implements
-    /// `IntoIterator`, **not** `Iterator`), and it only buffers if several
-    /// chunk iterators are alive at the same time.
-    ///
-    /// Iterator element type is `Chunk`, each chunk's iterator.
-    ///
-    /// **Panics** if `size` is 0.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let data = vec![1, 1, 2, -2, 6, 0, 3, 1];
-    /// //chunk size=3 |------->|-------->|--->|
-    ///
-    /// // Note: The `&` is significant here, `IntoChunks` is iterable
-    /// // only by reference. You can also call `.into_iter()` explicitly.
-    /// for chunk in &data.into_iter().chunks(3) {
-    ///     // Check that the sum of each chunk is 4.
-    ///     assert_eq!(4, chunk.sum());
-    /// }
-    /// ```
-    fn chunks(self, size: usize) -> IntoChunks<Self>
-        where Self: Sized,
-    {
-        assert!(size != 0);
-        groupbylazy::new_chunks(self, size)
-    }
-
-    /// Return an iterator over all contiguous windows producing tuples of
-    /// a specific size (up to 4).
-    ///
-    /// `tuple_windows` clones the iterator elements so that they can be
-    /// part of successive windows, this makes it most suited for iterators
-    /// of references and other values that are cheap to copy.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    /// let mut v = Vec::new();
-    /// for (a, b) in (1..5).tuple_windows() {
-    ///     v.push((a, b));
-    /// }
-    /// assert_eq!(v, vec![(1, 2), (2, 3), (3, 4)]);
-    ///
-    /// let mut it = (1..5).tuple_windows();
-    /// assert_eq!(Some((1, 2, 3)), it.next());
-    /// assert_eq!(Some((2, 3, 4)), it.next());
-    /// assert_eq!(None, it.next());
-    ///
-    /// // this requires a type hint
-    /// let it = (1..5).tuple_windows::<(_, _, _)>();
-    /// itertools::assert_equal(it, vec![(1, 2, 3), (2, 3, 4)]);
-    ///
-    /// // you can also specify the complete type
-    /// use itertools::TupleWindows;
-    /// use std::ops::Range;
-    ///
-    /// let it: TupleWindows<Range<u32>, (u32, u32, u32)> = (1..5).tuple_windows();
-    /// itertools::assert_equal(it, vec![(1, 2, 3), (2, 3, 4)]);
-    /// ```
-    fn tuple_windows<T>(self) -> TupleWindows<Self, T>
-        where Self: Sized + Iterator<Item = T::Item>,
-              T: tuple_impl::TupleCollect,
-              T::Item: Clone
-    {
-        tuple_impl::tuple_windows(self)
-    }
-
-    /// Return an iterator that groups the items in tuples of a specific size
-    /// (up to 4).
-    ///
-    /// See also the method [`.next_tuple()`](#method.next_tuple).
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    /// let mut v = Vec::new();
-    /// for (a, b) in (1..5).tuples() {
-    ///     v.push((a, b));
-    /// }
-    /// assert_eq!(v, vec![(1, 2), (3, 4)]);
-    ///
-    /// let mut it = (1..7).tuples();
-    /// assert_eq!(Some((1, 2, 3)), it.next());
-    /// assert_eq!(Some((4, 5, 6)), it.next());
-    /// assert_eq!(None, it.next());
-    ///
-    /// // this requires a type hint
-    /// let it = (1..7).tuples::<(_, _, _)>();
-    /// itertools::assert_equal(it, vec![(1, 2, 3), (4, 5, 6)]);
-    ///
-    /// // you can also specify the complete type
-    /// use itertools::Tuples;
-    /// use std::ops::Range;
-    ///
-    /// let it: Tuples<Range<u32>, (u32, u32, u32)> = (1..7).tuples();
-    /// itertools::assert_equal(it, vec![(1, 2, 3), (4, 5, 6)]);
-    /// ```
-    ///
-    /// See also [`Tuples::into_buffer`](structs/struct.Tuples.html#method.into_buffer).
-    fn tuples<T>(self) -> Tuples<Self, T>
-        where Self: Sized + Iterator<Item = T::Item>,
-              T: tuple_impl::TupleCollect
-    {
-        tuple_impl::tuples(self)
-    }
-
-    /// Split into an iterator pair that both yield all elements from
-    /// the original iterator.
-    ///
-    /// **Note:** If the iterator is clonable, prefer using that instead
-    /// of using this method. It is likely to be more efficient.
-    ///
-    /// Iterator element type is `Self::Item`.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    /// let xs = vec![0, 1, 2, 3];
-    ///
-    /// let (mut t1, t2) = xs.into_iter().tee();
-    /// itertools::assert_equal(t1.next(), Some(0));
-    /// itertools::assert_equal(t2, 0..4);
-    /// itertools::assert_equal(t1, 1..4);
-    /// ```
-    fn tee(self) -> (Tee<Self>, Tee<Self>)
-        where Self: Sized,
-              Self::Item: Clone
-    {
-        tee::new(self)
-    }
-
-    /// Return an iterator adaptor that steps `n` elements in the base iterator
-    /// for each iteration.
-    ///
-    /// The iterator steps by yielding the next element from the base iterator,
-    /// then skipping forward `n - 1` elements.
-    ///
-    /// Iterator element type is `Self::Item`.
-    ///
-    /// **Panics** if the step is 0.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let it = (0..8).step(3);
-    /// itertools::assert_equal(it, vec![0, 3, 6]);
-    /// ```
-    fn step(self, n: usize) -> Step<Self>
-        where Self: Sized
-    {
-        adaptors::step(self, n)
-    }
-
-    /// Return an iterator adaptor that applies the provided closure
-    /// to every `Result::Ok` value. `Result::Err` values are
-    /// unchanged.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let input = vec![Ok(41), Err(false), Ok(11)];
-    /// let it = input.into_iter().map_results(|i| i + 1);
-    /// itertools::assert_equal(it, vec![Ok(42), Err(false), Ok(12)]);
-    /// ```
-    fn map_results<F, T, U, E>(self, f: F) -> MapResults<Self, F>
-        where Self: Iterator<Item = Result<T, E>> + Sized,
-              F: FnMut(T) -> U,
-    {
-        adaptors::map_results(self, f)
-    }
-
-    /// Return an iterator adaptor that merges the two base iterators in
-    /// ascending order.  If both base iterators are sorted (ascending), the
-    /// result is sorted.
-    ///
-    /// Iterator element type is `Self::Item`.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let a = (0..11).step(3);
-    /// let b = (0..11).step(5);
-    /// let it = a.merge(b);
-    /// itertools::assert_equal(it, vec![0, 0, 3, 5, 6, 9, 10]);
-    /// ```
-    fn merge<J>(self, other: J) -> Merge<Self, J::IntoIter>
-        where Self: Sized,
-              Self::Item: PartialOrd,
-              J: IntoIterator<Item = Self::Item>
-    {
-        merge(self, other)
-    }
-
-    /// Return an iterator adaptor that merges the two base iterators in order.
-    /// This is much like `.merge()` but allows for a custom ordering.
-    ///
-    /// This can be especially useful for sequences of tuples.
-    ///
-    /// Iterator element type is `Self::Item`.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let a = (0..).zip("bc".chars());
-    /// let b = (0..).zip("ad".chars());
-    /// let it = a.merge_by(b, |x, y| x.1 <= y.1);
-    /// itertools::assert_equal(it, vec![(0, 'a'), (0, 'b'), (1, 'c'), (1, 'd')]);
-    /// ```
-
-    fn merge_by<J, F>(self, other: J, is_first: F) -> MergeBy<Self, J::IntoIter, F>
-        where Self: Sized,
-              J: IntoIterator<Item = Self::Item>,
-              F: FnMut(&Self::Item, &Self::Item) -> bool
-    {
-        adaptors::merge_by_new(self, other.into_iter(), is_first)
-    }
-
-    /// Return an iterator adaptor that flattens an iterator of iterators by
-    /// merging them in ascending order.
-    ///
-    /// If all base iterators are sorted (ascending), the result is sorted.
-    ///
-    /// Iterator element type is `Self::Item`.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let a = (0..6).step(3);
-    /// let b = (1..6).step(3);
-    /// let c = (2..6).step(3);
-    /// let it = vec![a, b, c].into_iter().kmerge();
-    /// itertools::assert_equal(it, vec![0, 1, 2, 3, 4, 5]);
-    /// ```
-    fn kmerge(self) -> KMerge<<Self::Item as IntoIterator>::IntoIter>
-        where Self: Sized,
-              Self::Item: IntoIterator,
-              <Self::Item as IntoIterator>::Item: PartialOrd,
-    {
-        kmerge(self)
-    }
-
-    /// Return an iterator adaptor that flattens an iterator of iterators by
-    /// merging them according to the given closure.
-    ///
-    /// The closure `first` is called with two elements *a*, *b* and should
-    /// return `true` if *a* is ordered before *b*.
-    ///
-    /// If all base iterators are sorted according to `first`, the result is
-    /// sorted.
-    ///
-    /// Iterator element type is `Self::Item`.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let a = vec![-1f64, 2., 3., -5., 6., -7.];
-    /// let b = vec![0., 2., -4.];
-    /// let mut it = vec![a, b].into_iter().kmerge_by(|a, b| a.abs() < b.abs());
-    /// assert_eq!(it.next(), Some(0.));
-    /// assert_eq!(it.last(), Some(-7.));
-    /// ```
-    fn kmerge_by<F>(self, first: F)
-        -> KMergeBy<<Self::Item as IntoIterator>::IntoIter, F>
-        where Self: Sized,
-              Self::Item: IntoIterator,
-              F: FnMut(&<Self::Item as IntoIterator>::Item,
-                       &<Self::Item as IntoIterator>::Item) -> bool
-    {
-        kmerge_by(self, first)
-    }
-
-    /// Return an iterator adaptor that iterates over the cartesian product of
-    /// the element sets of two iterators `self` and `J`.
-    ///
-    /// Iterator element type is `(Self::Item, J::Item)`.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let it = (0..2).cartesian_product("αβ".chars());
-    /// itertools::assert_equal(it, vec![(0, 'α'), (0, 'β'), (1, 'α'), (1, 'β')]);
-    /// ```
-    fn cartesian_product<J>(self, other: J) -> Product<Self, J::IntoIter>
-        where Self: Sized,
-              Self::Item: Clone,
-              J: IntoIterator,
-              J::IntoIter: Clone
-    {
-        adaptors::cartesian_product(self, other.into_iter())
-    }
-
-    /// Return an iterator adaptor that uses the passed-in closure to
-    /// optionally merge together consecutive elements.
-    ///
-    /// The closure `f` is passed two elements, `previous` and `current` and may
-    /// return either (1) `Ok(combined)` to merge the two values or
-    /// (2) `Err((previous', current'))` to indicate they can't be merged.
-    /// In (2), the value `previous'` is emitted by the iterator.
-    /// Either (1) `combined` or (2) `current'` becomes the previous value
-    /// when coalesce continues with the next pair of elements to merge. The
-    /// value that remains at the end is also emitted by the iterator.
-    ///
-    /// Iterator element type is `Self::Item`.
-    ///
-    /// This iterator is *fused*.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// // sum same-sign runs together
-    /// let data = vec![-1., -2., -3., 3., 1., 0., -1.];
-    /// itertools::assert_equal(data.into_iter().coalesce(|x, y|
-    ///         if (x >= 0.) == (y >= 0.) {
-    ///             Ok(x + y)
-    ///         } else {
-    ///             Err((x, y))
-    ///         }),
-    ///         vec![-6., 4., -1.]);
-    /// ```
-    fn coalesce<F>(self, f: F) -> Coalesce<Self, F>
-        where Self: Sized,
-              F: FnMut(Self::Item, Self::Item)
-                       -> Result<Self::Item, (Self::Item, Self::Item)>
-    {
-        adaptors::coalesce(self, f)
-    }
-
-    /// Remove duplicates from sections of consecutive identical elements.
-    /// If the iterator is sorted, all elements will be unique.
-    ///
-    /// Iterator element type is `Self::Item`.
-    ///
-    /// This iterator is *fused*.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let data = vec![1., 1., 2., 3., 3., 2., 2.];
-    /// itertools::assert_equal(data.into_iter().dedup(),
-    ///                         vec![1., 2., 3., 2.]);
-    /// ```
-    fn dedup(self) -> Dedup<Self>
-        where Self: Sized,
-              Self::Item: PartialEq,
-    {
-        adaptors::dedup(self)
-    }
-
-    /// Return an iterator adaptor that filters out elements that have
-    /// already been produced once during the iteration. Duplicates
-    /// are detected using hash and equality.
-    ///
-    /// Clones of visited elements are stored in a hash set in the
-    /// iterator.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let data = vec![10, 20, 30, 20, 40, 10, 50];
-    /// itertools::assert_equal(data.into_iter().unique(),
-    ///                         vec![10, 20, 30, 40, 50]);
-    /// ```
-    fn unique(self) -> Unique<Self>
-        where Self: Sized,
-              Self::Item: Clone + Eq + Hash
-    {
-        adaptors::unique(self)
-    }
-
-    /// Return an iterator adaptor that filters out elements that have
-    /// already been produced once during the iteration.
-    ///
-    /// Duplicates are detected by comparing the key they map to
-    /// with the keying function `f` by hash and equality.
-    /// The keys are stored in a hash set in the iterator.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let data = vec!["a", "bb", "aa", "c", "ccc"];
-    /// itertools::assert_equal(data.into_iter().unique_by(|s| s.len()),
-    ///                         vec!["a", "bb", "ccc"]);
-    /// ```
-    fn unique_by<V, F>(self, f: F) -> UniqueBy<Self, V, F>
-        where Self: Sized,
-              V: Eq + Hash,
-              F: FnMut(&Self::Item) -> V
-    {
-        adaptors::unique_by(self, f)
-    }
-
-    /// Return an iterator adaptor that borrows from this iterator and
-    /// takes items while the closure `accept` returns `true`.
-    ///
-    /// This adaptor can only be used on iterators that implement `PeekingNext`
-    /// like `.peekable()`, `put_back` and a few other collection iterators.
-    ///
-    /// The last and rejected element (first `false`) is still available when
-    /// `peeking_take_while` is done.
-    ///
-    ///
-    /// See also [`.take_while_ref()`](#method.take_while_ref)
-    /// which is a similar adaptor.
-    fn peeking_take_while<F>(&mut self, accept: F) -> PeekingTakeWhile<Self, F>
-        where Self: Sized + PeekingNext,
-              F: FnMut(&Self::Item) -> bool,
-    {
-        peeking_take_while::peeking_take_while(self, accept)
-    }
-
-    /// Return an iterator adaptor that borrows from a `Clone`-able iterator
-    /// to only pick off elements while the predicate `accept` returns `true`.
-    ///
-    /// It uses the `Clone` trait to restore the original iterator so that the
-    /// last and rejected element (first `false`) is still available when
-    /// `take_while_ref` is done.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let mut hexadecimals = "0123456789abcdef".chars();
-    ///
-    /// let decimals = hexadecimals.take_while_ref(|c| c.is_numeric())
-    ///                            .collect::<String>();
-    /// assert_eq!(decimals, "0123456789");
-    /// assert_eq!(hexadecimals.next(), Some('a'));
-    ///
-    /// ```
-    fn take_while_ref<F>(&mut self, accept: F) -> TakeWhileRef<Self, F>
-        where Self: Clone,
-              F: FnMut(&Self::Item) -> bool
-    {
-        adaptors::take_while_ref(self, accept)
-    }
-
-    /// Return an iterator adaptor that filters `Option<A>` iterator elements
-    /// and produces `A`. Stops on the first `None` encountered.
-    ///
-    /// Iterator element type is `A`, the unwrapped element.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// // List all hexadecimal digits
-    /// itertools::assert_equal(
-    ///     (0..).map(|i| std::char::from_digit(i, 16)).while_some(),
-    ///     "0123456789abcdef".chars());
-    ///
-    /// ```
-    fn while_some<A>(self) -> WhileSome<Self>
-        where Self: Sized + Iterator<Item = Option<A>>
-    {
-        adaptors::while_some(self)
-    }
-
-    /// Return an iterator adaptor that iterates over the combinations of the
-    /// elements from an iterator.
-    ///
-    /// Iterator element can be any homogeneous tuple of type `Self::Item` with
-    /// size up to 4.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let mut v = Vec::new();
-    /// for (a, b) in (1..5).tuple_combinations() {
-    ///     v.push((a, b));
-    /// }
-    /// assert_eq!(v, vec![(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]);
-    ///
-    /// let mut it = (1..5).tuple_combinations();
-    /// assert_eq!(Some((1, 2, 3)), it.next());
-    /// assert_eq!(Some((1, 2, 4)), it.next());
-    /// assert_eq!(Some((1, 3, 4)), it.next());
-    /// assert_eq!(Some((2, 3, 4)), it.next());
-    /// assert_eq!(None, it.next());
-    ///
-    /// // this requires a type hint
-    /// let it = (1..5).tuple_combinations::<(_, _, _)>();
-    /// itertools::assert_equal(it, vec![(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]);
-    ///
-    /// // you can also specify the complete type
-    /// use itertools::TupleCombinations;
-    /// use std::ops::Range;
-    ///
-    /// let it: TupleCombinations<Range<u32>, (u32, u32, u32)> = (1..5).tuple_combinations();
-    /// itertools::assert_equal(it, vec![(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]);
-    /// ```
-    fn tuple_combinations<T>(self) -> TupleCombinations<Self, T>
-        where Self: Sized + Clone,
-              Self::Item: Clone,
-              T: adaptors::HasCombination<Self>,
-    {
-        adaptors::tuple_combinations(self)
-    }
-
-    /// Return an iterator adaptor that iterates over the `n`-length combinations of
-    /// the elements from an iterator.
-    ///
-    /// Iterator element type is `Vec<Self::Item>`. The iterator produces a new Vec per iteration,
-    /// and clones the iterator elements.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let it = (1..5).combinations(3);
-    /// itertools::assert_equal(it, vec![
-    ///     vec![1, 2, 3],
-    ///     vec![1, 2, 4],
-    ///     vec![1, 3, 4],
-    ///     vec![2, 3, 4],
-    ///     ]);
-    /// ```
-    fn combinations(self, n: usize) -> Combinations<Self>
-        where Self: Sized,
-              Self::Item: Clone
-    {
-        adaptors::combinations(self, n)
-    }
-
-    /// Return an iterator adaptor that pads the sequence to a minimum length of
-    /// `min` by filling missing elements using a closure `f`.
-    ///
-    /// Iterator element type is `Self::Item`.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let it = (0..5).pad_using(10, |i| 2*i);
-    /// itertools::assert_equal(it, vec![0, 1, 2, 3, 4, 10, 12, 14, 16, 18]);
-    ///
-    /// let it = (0..10).pad_using(5, |i| 2*i);
-    /// itertools::assert_equal(it, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
-    ///
-    /// let it = (0..5).pad_using(10, |i| 2*i).rev();
-    /// itertools::assert_equal(it, vec![18, 16, 14, 12, 10, 4, 3, 2, 1, 0]);
-    /// ```
-    fn pad_using<F>(self, min: usize, f: F) -> PadUsing<Self, F>
-        where Self: Sized,
-              F: FnMut(usize) -> Self::Item
-    {
-        pad_tail::pad_using(self, min, f)
-    }
-
-    /// Unravel a nested iterator.
-    ///
-    /// This is more or less equivalent to `.flat_map` with an identity
-    /// function.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let data = vec![vec![1, 2, 3], vec![4, 5, 6]];
-    /// let flattened = data.iter().flatten();
-    ///
-    /// itertools::assert_equal(flattened, &[1, 2, 3, 4, 5, 6]);
-    /// ```
-    fn flatten(self) -> Flatten<Self, <Self::Item as IntoIterator>::IntoIter>
-        where Self: Sized,
-              Self::Item: IntoIterator
-    {
-        adaptors::flatten(self)
-    }
-
-    /// Return an iterator adaptor that wraps each element in a `Position` to
-    /// ease special-case handling of the first or last elements.
-    ///
-    /// Iterator element type is
-    /// [`Position<Self::Item>`](enum.Position.html)
-    ///
-    /// ```
-    /// use itertools::{Itertools, Position};
-    ///
-    /// let it = (0..4).with_position();
-    /// itertools::assert_equal(it,
-    ///                         vec![Position::First(0),
-    ///                              Position::Middle(1),
-    ///                              Position::Middle(2),
-    ///                              Position::Last(3)]);
-    ///
-    /// let it = (0..1).with_position();
-    /// itertools::assert_equal(it, vec![Position::Only(0)]);
-    /// ```
-    fn with_position(self) -> WithPosition<Self>
-        where Self: Sized,
-    {
-        with_position::with_position(self)
-    }
-
-    /// Return an iterator adaptor that yields the indices of all elements
-    /// satisfying a predicate, counted from the start of the iterator.
-    ///
-    /// Equivalent to `iter.enumerate().filter(|(_, v)| predicate(v)).map(|(i, _)| i)`.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let data = vec![1, 2, 3, 3, 4, 6, 7, 9];
-    /// itertools::assert_equal(data.iter().positions(|v| v % 2 == 0), vec![1, 4, 5]);
-    ///
-    /// itertools::assert_equal(data.iter().positions(|v| v % 2 == 1).rev(), vec![7, 6, 3, 2, 0]);
-    /// ```
-    fn positions<P>(self, predicate: P) -> Positions<Self, P>
-        where Self: Sized,
-              P: FnMut(Self::Item) -> bool,
-    {
-        adaptors::positions(self, predicate)
-    }
-
-    // non-adaptor methods
-    /// Advances the iterator and returns the next items grouped in a tuple of
-    /// a specific size (up to 4).
-    ///
-    /// If there are enough elements to be grouped in a tuple, then the tuple is
-    /// returned inside `Some`, otherwise `None` is returned.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let mut iter = 1..5;
-    ///
-    /// assert_eq!(Some((1, 2)), iter.next_tuple());
-    /// ```
-    fn next_tuple<T>(&mut self) -> Option<T>
-        where Self: Sized + Iterator<Item = T::Item>,
-              T: tuple_impl::TupleCollect
-    {
-        T::collect_from_iter_no_buf(self)
-    }
-
-
-    /// Find the position and value of the first element satisfying a predicate.
-    ///
-    /// The iterator is not advanced past the first element found.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let text = "Hα";
-    /// assert_eq!(text.chars().find_position(|ch| ch.is_lowercase()), Some((1, 'α')));
-    /// ```
-    fn find_position<P>(&mut self, mut pred: P) -> Option<(usize, Self::Item)>
-        where P: FnMut(&Self::Item) -> bool
-    {
-        let mut index = 0usize;
-        for elt in self {
-            if pred(&elt) {
-                return Some((index, elt));
-            }
-            index += 1;
-        }
-        None
-    }
-
-    /// Check whether all elements compare equal.
-    ///
-    /// Empty iterators are considered to have equal elements:
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let data = vec![1, 1, 1, 2, 2, 3, 3, 3, 4, 5, 5];
-    /// assert!(!data.iter().all_equal());
-    /// assert!(data[0..3].iter().all_equal());
-    /// assert!(data[3..5].iter().all_equal());
-    /// assert!(data[5..8].iter().all_equal());
-    ///
-    /// let data : Option<usize> = None;
-    /// assert!(data.into_iter().all_equal());
-    /// ```
-    fn all_equal(&mut self) -> bool
-        where Self::Item: PartialEq,
-    {
-        self.dedup().nth(1).is_none()
-    }
-
-    /// Consume the first `n` elements from the iterator eagerly,
-    /// and return the same iterator again.
-    ///
-    /// It works similarly to *.skip(* `n` *)* except it is eager and
-    /// preserves the iterator type.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let mut iter = "αβγ".chars().dropping(2);
-    /// itertools::assert_equal(iter, "γ".chars());
-    /// ```
-    ///
-    /// *Fusing notes: if the iterator is exhausted by dropping,
-    /// the result of calling `.next()` again depends on the iterator implementation.*
-    fn dropping(mut self, n: usize) -> Self
-        where Self: Sized
-    {
-        if n > 0 {
-            self.nth(n - 1);
-        }
-        self
-    }
-
-    /// Consume the last `n` elements from the iterator eagerly,
-    /// and return the same iterator again.
-    ///
-    /// This is only possible on double ended iterators. `n` may be
-    /// larger than the number of elements.
-    ///
-    /// Note: This method is eager, dropping the back elements immediately and
-    /// preserves the iterator type.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let init = vec![0, 3, 6, 9].into_iter().dropping_back(1);
-    /// itertools::assert_equal(init, vec![0, 3, 6]);
-    /// ```
-    fn dropping_back(mut self, n: usize) -> Self
-        where Self: Sized,
-              Self: DoubleEndedIterator
-    {
-        if n > 0 {
-            (&mut self).rev().nth(n - 1);
-        }
-        self
-    }
-
-    /// Run the closure `f` eagerly on each element of the iterator.
-    ///
-    /// Consumes the iterator until its end.
-    ///
-    /// ```
-    /// use std::sync::mpsc::channel;
-    /// use itertools::Itertools;
-    ///
-    /// let (tx, rx) = channel();
-    ///
-    /// // use .foreach() to apply a function to each value -- sending it
-    /// (0..5).map(|x| x * 2 + 1).foreach(|x| { tx.send(x).unwrap(); } );
-    ///
-    /// drop(tx);
-    ///
-    /// itertools::assert_equal(rx.iter(), vec![1, 3, 5, 7, 9]);
-    /// ```
-    fn foreach<F>(self, mut f: F)
-        where F: FnMut(Self::Item),
-              Self: Sized,
-    {
-        self.fold((), move |(), element| f(element))
-    }
-
-    /// Combine all an iterator's elements into one element by using `Extend`.
-    ///
-    /// This combinator will extend the first item with each of the rest of the
-    /// items of the iterator. If the iterator is empty, the default value of
-    /// `I::Item` is returned.
-    ///
-    /// ```rust
-    /// use itertools::Itertools;
-    ///
-    /// let input = vec![vec![1], vec![2, 3], vec![4, 5, 6]];
-    /// assert_eq!(input.into_iter().concat(),
-    ///            vec![1, 2, 3, 4, 5, 6]);
-    /// ```
-    fn concat(self) -> Self::Item
-        where Self: Sized,
-              Self::Item: Extend<<<Self as Iterator>::Item as IntoIterator>::Item> + IntoIterator + Default
-    {
-        concat(self)
-    }
-
-    /// `.collect_vec()` is simply a type specialization of `.collect()`,
-    /// for convenience.
-    fn collect_vec(self) -> Vec<Self::Item>
-        where Self: Sized
-    {
-        self.collect()
-    }
-
-    /// Assign to each reference in `self` from the `from` iterator,
-    /// stopping at the shortest of the two iterators.
-    ///
-    /// The `from` iterator is queried for its next element before the `self`
-    /// iterator, and if either is exhausted the method is done.
-    ///
-    /// Return the number of elements written.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let mut xs = [0; 4];
-    /// xs.iter_mut().set_from(1..);
-    /// assert_eq!(xs, [1, 2, 3, 4]);
-    /// ```
-    #[inline]
-    fn set_from<'a, A: 'a, J>(&mut self, from: J) -> usize
-        where Self: Iterator<Item = &'a mut A>,
-              J: IntoIterator<Item = A>
-    {
-        let mut count = 0;
-        for elt in from {
-            match self.next() {
-                None => break,
-                Some(ptr) => *ptr = elt,
-            }
-            count += 1;
-        }
-        count
-    }
-
-    /// Combine all iterator elements into one String, seperated by `sep`.
-    ///
-    /// Use the `Display` implementation of each element.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// assert_eq!(["a", "b", "c"].iter().join(", "), "a, b, c");
-    /// assert_eq!([1, 2, 3].iter().join(", "), "1, 2, 3");
-    /// ```
-    fn join(&mut self, sep: &str) -> String
-        where Self::Item: std::fmt::Display
-    {
-        match self.next() {
-            None => String::new(),
-            Some(first_elt) => {
-                // estimate lower bound of capacity needed
-                let (lower, _) = self.size_hint();
-                let mut result = String::with_capacity(sep.len() * lower);
-                write!(&mut result, "{}", first_elt).unwrap();
-                for elt in self {
-                    result.push_str(sep);
-                    write!(&mut result, "{}", elt).unwrap();
-                }
-                result
-            }
-        }
-    }
-
-    /// Format all iterator elements, separated by `sep`.
-    ///
-    /// All elements are formatted (any formatting trait)
-    /// with `sep` inserted between each element.
-    ///
-    /// **Panics** if the formatter helper is formatted more than once.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let data = [1.1, 2.71828, -3.];
-    /// assert_eq!(
-    ///     format!("{:.2}", data.iter().format(", ")),
-    ///            "1.10, 2.72, -3.00");
-    /// ```
-    fn format(self, sep: &str) -> Format<Self>
-        where Self: Sized,
-    {
-        format::new_format_default(self, sep)
-    }
-
-    /// Format all iterator elements, separated by `sep`.
-    ///
-    /// This is a customizable version of `.format()`.
-    ///
-    /// The supplied closure `format` is called once per iterator element,
-    /// with two arguments: the element and a callback that takes a
-    /// `&Display` value, i.e. any reference to type that implements `Display`.
-    ///
-    /// Using `&format_args!(...)` is the most versatile way to apply custom
-    /// element formatting. The callback can be called multiple times if needed.
-    ///
-    /// **Panics** if the formatter helper is formatted more than once.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// let data = [1.1, 2.71828, -3.];
-    /// let data_formatter = data.iter().format_with(", ", |elt, f| f(&format_args!("{:.2}", elt)));
-    /// assert_eq!(format!("{}", data_formatter),
-    ///            "1.10, 2.72, -3.00");
-    ///
-    /// // .format_with() is recursively composable
-    /// let matrix = [[1., 2., 3.],
-    ///               [4., 5., 6.]];
-    /// let matrix_formatter = matrix.iter().format_with("\n", |row, f| {
-    ///                                 f(&row.iter().format_with(", ", |elt, g| g(&elt)))
-    ///                              });
-    /// assert_eq!(format!("{}", matrix_formatter),
-    ///            "1, 2, 3\n4, 5, 6");
-    ///
-    ///
-    /// ```
-    fn format_with<F>(self, sep: &str, format: F) -> FormatWith<Self, F>
-        where Self: Sized,
-              F: FnMut(Self::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result,
-    {
-        format::new_format(self, sep, format)
-    }
-
-    /// Fold `Result` values from an iterator.
-    ///
-    /// Only `Ok` values are folded. If no error is encountered, the folded
-    /// value is returned inside `Ok`. Otherwise, the operation terminates
-    /// and returns the first `Err` value it encounters. No iterator elements are
-    /// consumed after the first error.
-    ///
-    /// The first accumulator value is the `start` parameter.
-    /// Each iteration passes the accumulator value and the next value inside `Ok`
-    /// to the fold function `f` and its return value becomes the new accumulator value.
-    ///
-    /// For example the sequence *Ok(1), Ok(2), Ok(3)* will result in a
-    /// computation like this:
-    ///
-    /// ```ignore
-    /// let mut accum = start;
-    /// accum = f(accum, 1);
-    /// accum = f(accum, 2);
-    /// accum = f(accum, 3);
-    /// ```
-    ///
-    /// With a `start` value of 0 and an addition as folding function,
-    /// this effetively results in *((0 + 1) + 2) + 3*
-    ///
-    /// ```
-    /// use std::ops::Add;
-    /// use itertools::Itertools;
-    ///
-    /// let values = [1, 2, -2, -1, 2, 1];
-    /// assert_eq!(
-    ///     values.iter()
-    ///           .map(Ok::<_, ()>)
-    ///           .fold_results(0, Add::add),
-    ///     Ok(3)
-    /// );
-    /// assert!(
-    ///     values.iter()
-    ///           .map(|&x| if x >= 0 { Ok(x) } else { Err("Negative number") })
-    ///           .fold_results(0, Add::add)
-    ///           .is_err()
-    /// );
-    /// ```
-    fn fold_results<A, E, B, F>(&mut self, mut start: B, mut f: F) -> Result<B, E>
-        where Self: Iterator<Item = Result<A, E>>,
-              F: FnMut(B, A) -> B
-    {
-        for elt in self {
-            match elt {
-                Ok(v) => start = f(start, v),
-                Err(u) => return Err(u),
-            }
-        }
-        Ok(start)
-    }
-
-    /// Fold `Option` values from an iterator.
-    ///
-    /// Only `Some` values are folded. If no `None` is encountered, the folded
-    /// value is returned inside `Some`. Otherwise, the operation terminates
-    /// and returns `None`. No iterator elements are consumed after the `None`.
-    ///
-    /// This is the `Option` equivalent to `fold_results`.
-    ///
-    /// ```
-    /// use std::ops::Add;
-    /// use itertools::Itertools;
-    ///
-    /// let mut values = vec![Some(1), Some(2), Some(-2)].into_iter();
-    /// assert_eq!(values.fold_options(5, Add::add), Some(5 + 1 + 2 - 2));
-    ///
-    /// let mut more_values = vec![Some(2), None, Some(0)].into_iter();
-    /// assert!(more_values.fold_options(0, Add::add).is_none());
-    /// assert_eq!(more_values.next().unwrap(), Some(0));
-    /// ```
-    fn fold_options<A, B, F>(&mut self, mut start: B, mut f: F) -> Option<B>
-        where Self: Iterator<Item = Option<A>>,
-              F: FnMut(B, A) -> B
-    {
-        for elt in self {
-            match elt {
-                Some(v) => start = f(start, v),
-                None => return None,
-            }
-        }
-        Some(start)
-    }
-
-    /// Accumulator of the elements in the iterator.
-    ///
-    /// Like `.fold()`, without a base case. If the iterator is
-    /// empty, return `None`. With just one element, return it.
-    /// Otherwise elements are accumulated in sequence using the closure `f`.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// assert_eq!((0..10).fold1(|x, y| x + y).unwrap_or(0), 45);
-    /// assert_eq!((0..0).fold1(|x, y| x * y), None);
-    /// ```
-    fn fold1<F>(mut self, f: F) -> Option<Self::Item>
-        where F: FnMut(Self::Item, Self::Item) -> Self::Item,
-              Self: Sized,
-    {
-        self.next().map(move |x| self.fold(x, f))
-    }
-
-    /// An iterator method that applies a function, producing a single, final value.
-    ///
-    /// `fold_while()` is basically equivalent to `fold()` but with additional support for
-    /// early exit via short-circuiting.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    /// use itertools::FoldWhile::{Continue, Done};
-    ///
-    /// let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-    ///
-    /// let mut result = 0;
-    ///
-    /// // for loop:
-    /// for i in &numbers {
-    ///     if *i > 5 {
-    ///         break;
-    ///     }
-    ///     result = result + i;
-    /// }
-    ///
-    /// // fold:
-    /// let result2 = numbers.iter().fold(0, |acc, x| {
-    ///     if *x > 5 { acc } else { acc + x }
-    /// });
-    ///
-    /// // fold_while:
-    /// let result3 = numbers.iter().fold_while(0, |acc, x| {
-    ///     if *x > 5 { Done(acc) } else { Continue(acc + x) }
-    /// }).into_inner();
-    ///
-    /// // they're the same
-    /// assert_eq!(result, result2);
-    /// assert_eq!(result2, result3);
-    /// ```
-    ///
-    /// The big difference between the computations of `result2` and `result3` is that while
-    /// `fold()` called the provided closure for every item of the callee iterator,
-    /// `fold_while()` actually stopped iterating as soon as it encountered `Fold::Done(_)`.
-    fn fold_while<B, F>(&mut self, init: B, mut f: F) -> FoldWhile<B>
-        where Self: Sized,
-              F: FnMut(B, Self::Item) -> FoldWhile<B>
-    {
-        let mut acc = init;
-        while let Some(item) = self.next() {
-            match f(acc, item) {
-                FoldWhile::Continue(res) => acc = res,
-                res @ FoldWhile::Done(_) => return res,
-            }
-        }
-        FoldWhile::Continue(acc)
-    }
-
-    /// Collect all iterator elements into a sorted vector in ascending order.
-    ///
-    /// **Note:** This consumes the entire iterator, uses the
-    /// `slice::sort_by()` method and returns the sorted vector.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// // sort the letters of the text in ascending order
-    /// let text = "bdacfe";
-    /// itertools::assert_equal(text.chars().sorted(),
-    ///                         "abcdef".chars());
-    /// ```
-    fn sorted(self) -> Vec<Self::Item>
-        where Self: Sized,
-              Self::Item: Ord
-    {
-        self.sorted_by(Ord::cmp)
-    }
-
-    /// Collect all iterator elements into a sorted vector.
-    ///
-    /// **Note:** This consumes the entire iterator, uses the
-    /// `slice::sort_by()` method and returns the sorted vector.
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    ///
-    /// // sort people in descending order by age
-    /// let people = vec![("Jane", 20), ("John", 18), ("Jill", 30), ("Jack", 27)];
-    ///
-    /// let oldest_people_first = people
-    ///     .into_iter()
-    ///     .sorted_by(|a, b| Ord::cmp(&b.1, &a.1))
-    ///     .into_iter()
-    ///     .map(|(person, _age)| person);
-    ///
-    /// itertools::assert_equal(oldest_people_first,
-    ///                         vec!["Jill", "Jack", "Jane", "John"]);
-    /// ```
-    fn sorted_by<F>(self, cmp: F) -> Vec<Self::Item>
-        where Self: Sized,
-              F: FnMut(&Self::Item, &Self::Item) -> Ordering,
-    {
-        let mut v: Vec<Self::Item> = self.collect();
-
-        v.sort_by(cmp);
-        v
-    }
-
-    /// Collect all iterator elements into one of two
-    /// partitions. Unlike `Iterator::partition`, each partition may
-    /// have a distinct type.
-    ///
-    /// ```
-    /// use itertools::{Itertools, Either};
-    ///
-    /// let successes_and_failures = vec![Ok(1), Err(false), Err(true), Ok(2)];
-    ///
-    /// let (successes, failures): (Vec<_>, Vec<_>) = successes_and_failures
-    ///     .into_iter()
-    ///     .partition_map(|r| {
-    ///         match r {
-    ///             Ok(v) => Either::Left(v),
-    ///             Err(v) => Either::Right(v),
-    ///         }
-    ///     });
-    ///
-    /// assert_eq!(successes, [1, 2]);
-    /// assert_eq!(failures, [false, true]);
-    /// ```
-    fn partition_map<A, B, F, L, R>(self, predicate: F) -> (A, B)
-        where Self: Sized,
-              F: Fn(Self::Item) -> Either<L, R>,
-              A: Default + Extend<L>,
-              B: Default + Extend<R>,
-    {
-        let mut left = A::default();
-        let mut right = B::default();
-
-        for val in self {
-            match predicate(val) {
-                Either::Left(v) => left.extend(Some(v)),
-                Either::Right(v) => right.extend(Some(v)),
-            }
-        }
-
-        (left, right)
-    }
-
-    /// Return the minimum and maximum elements in the iterator.
-    ///
-    /// The return type `MinMaxResult` is an enum of three variants:
-    ///
-    /// - `NoElements` if the iterator is empty.
-    /// - `OneElement(x)` if the iterator has exactly one element.
-    /// - `MinMax(x, y)` is returned otherwise, where `x <= y`. Two
-    ///    values are equal if and only if there is more than one
-    ///    element in the iterator and all elements are equal.
-    ///
-    /// On an iterator of length `n`, `minmax` does `1.5 * n` comparisons,
-    /// and so is faster than calling `min` and `max` separately which does
-    /// `2 * n` comparisons.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use itertools::Itertools;
-    /// use itertools::MinMaxResult::{NoElements, OneElement, MinMax};
-    ///
-    /// let a: [i32; 0] = [];
-    /// assert_eq!(a.iter().minmax(), NoElements);
-    ///
-    /// let a = [1];
-    /// assert_eq!(a.iter().minmax(), OneElement(&1));
-    ///
-    /// let a = [1, 2, 3, 4, 5];
-    /// assert_eq!(a.iter().minmax(), MinMax(&1, &5));
-    ///
-    /// let a = [1, 1, 1, 1];
-    /// assert_eq!(a.iter().minmax(), MinMax(&1, &1));
-    /// ```
-    ///
-    /// The elements can be floats but no particular result is guaranteed
-    /// if an element is NaN.
-    fn minmax(self) -> MinMaxResult<Self::Item>
-        where Self: Sized, Self::Item: PartialOrd
-    {
-        minmax::minmax_impl(self, |_| (), |x, y, _, _| x < y)
-    }
-
-    /// Return the minimum and maximum element of an iterator, as determined by
-    /// the specified function.
-    ///
-    /// The return value is a variant of `MinMaxResult` like for `minmax()`.
-    ///
-    /// For the minimum, the first minimal element is returned.  For the maximum,
-    /// the last maximal element wins.  This matches the behavior of the standard
-    /// `Iterator::min()` and `Iterator::max()` methods.
-    ///
-    /// The keys can be floats but no particular result is guaranteed
-    /// if a key is NaN.
-    fn minmax_by_key<K, F>(self, key: F) -> MinMaxResult<Self::Item>
-        where Self: Sized, K: PartialOrd, F: FnMut(&Self::Item) -> K
-    {
-        minmax::minmax_impl(self, key, |_, _, xk, yk| xk < yk)
-    }
-
-    /// Return the minimum and maximum element of an iterator, as determined by
-    /// the specified comparison function.
-    ///
-    /// The return value is a variant of `MinMaxResult` like for `minmax()`.
-    ///
-    /// For the minimum, the first minimal element is returned.  For the maximum,
-    /// the last maximal element wins.  This matches the behavior of the standard
-    /// `Iterator::min()` and `Iterator::max()` methods.
-    fn minmax_by<F>(self, mut compare: F) -> MinMaxResult<Self::Item>
-        where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering
-    {
-        minmax::minmax_impl(
-            self,
-            |_| (),
-            |x, y, _, _| Ordering::Less == compare(x, y)
-        )
-    }
-}
-
-impl<T: ?Sized> Itertools for T where T: Iterator { }
-
-/// Return `true` if both iterators produce equal sequences
-/// (elements pairwise equal and sequences of the same length),
-/// `false` otherwise.
-///
-/// **Note:** the standard library method `Iterator::eq` now provides
-/// the same functionality.
-///
-/// ```
-/// assert!(itertools::equal(vec![1, 2, 3], 1..4));
-/// assert!(!itertools::equal(&[0, 0], &[0, 0, 0]));
-/// ```
-pub fn equal<I, J>(a: I, b: J) -> bool
-    where I: IntoIterator,
-          J: IntoIterator,
-          I::Item: PartialEq<J::Item>
-{
-    let mut ia = a.into_iter();
-    let mut ib = b.into_iter();
-    loop {
-        match ia.next() {
-            Some(ref x) => match ib.next() {
-                Some(ref y) => if x != y { return false; },
-                None => return false,
-            },
-            None => return ib.next().is_none()
-        }
-    }
-}
-
-/// Assert that two iterators produce equal sequences, with the same
-/// semantics as *equal(a, b)*.
-///
-/// **Panics** on assertion failure with a message that shows the
-/// two iteration elements.
-///
-/// ```ignore
-/// assert_equal("exceed".split('c'), "excess".split('c'));
-/// // ^PANIC: panicked at 'Failed assertion Some("eed") == Some("ess") for iteration 1',
-/// ```
-pub fn assert_equal<I, J>(a: I, b: J)
-    where I: IntoIterator,
-          J: IntoIterator,
-          I::Item: fmt::Debug + PartialEq<J::Item>,
-          J::Item: fmt::Debug,
-{
-    let mut ia = a.into_iter();
-    let mut ib = b.into_iter();
-    let mut i = 0;
-    loop {
-        match (ia.next(), ib.next()) {
-            (None, None) => return,
-            (a, b) => {
-                let equal = match (&a, &b) {
-                    (&Some(ref a), &Some(ref b)) => a == b,
-                    _ => false,
-                };
-                assert!(equal, "Failed assertion {a:?} == {b:?} for iteration {i}",
-                        i=i, a=a, b=b);
-                i += 1;
-            }
-        }
-    }
-}
-
-/// Partition a sequence using predicate `pred` so that elements
-/// that map to `true` are placed before elements which map to `false`.
-///
-/// The order within the partitions is arbitrary.
-///
-/// Return the index of the split point.
-///
-/// ```
-/// use itertools::partition;
-///
-/// # // use repeated numbers to not promise any ordering
-/// let mut data = [7, 1, 1, 7, 1, 1, 7];
-/// let split_index = partition(&mut data, |elt| *elt >= 3);
-///
-/// assert_eq!(data, [7, 7, 7, 1, 1, 1, 1]);
-/// assert_eq!(split_index, 3);
-/// ```
-pub fn partition<'a, A: 'a, I, F>(iter: I, mut pred: F) -> usize
-    where I: IntoIterator<Item = &'a mut A>,
-          I::IntoIter: DoubleEndedIterator,
-          F: FnMut(&A) -> bool
-{
-    let mut split_index = 0;
-    let mut iter = iter.into_iter();
-    'main: while let Some(front) = iter.next() {
-        if !pred(front) {
-            loop {
-                match iter.next_back() {
-                    Some(back) => if pred(back) {
-                        std::mem::swap(front, back);
-                        break;
-                    },
-                    None => break 'main,
-                }
-            }
-        }
-        split_index += 1;
-    }
-    split_index
-}
-
-/// An enum used for controlling the execution of `.fold_while()`.
-///
-/// See [`.fold_while()`](trait.Itertools.html#method.fold_while) for more information.
-#[derive(Copy, Clone, Debug)]
-pub enum FoldWhile<T> {
-    /// Continue folding with this value
-    Continue(T),
-    /// Fold is complete and will return this value
-    Done(T),
-}
-
-impl<T> FoldWhile<T> {
-    /// Return the value in the continue or done.
-    pub fn into_inner(self) -> T {
-        match self {
-            FoldWhile::Continue(x) | FoldWhile::Done(x) => x,
-        }
-    }
-
-    /// Return true if `self` is `Done`, false if it is `Continue`.
-    pub fn is_done(&self) -> bool {
-        match *self {
-            FoldWhile::Continue(_) => false,
-            FoldWhile::Done(_) => true,
-        }
-    }
-}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/minmax.rs
+++ /dev/null
@@ -1,114 +0,0 @@
-
-/// `MinMaxResult` is an enum returned by `minmax`. See `Itertools::minmax()` for
-/// more detail.
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum MinMaxResult<T> {
-    /// Empty iterator
-    NoElements,
-
-    /// Iterator with one element, so the minimum and maximum are the same
-    OneElement(T),
-
-    /// More than one element in the iterator, the first element is not larger
-    /// than the second
-    MinMax(T, T)
-}
-
-impl<T: Clone> MinMaxResult<T> {
-    /// `into_option` creates an `Option` of type `(T, T)`. The returned `Option`
-    /// has variant `None` if and only if the `MinMaxResult` has variant
-    /// `NoElements`. Otherwise `Some((x, y))` is returned where `x <= y`.
-    /// If the `MinMaxResult` has variant `OneElement(x)`, performing this
-    /// operation will make one clone of `x`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use itertools::MinMaxResult::{self, NoElements, OneElement, MinMax};
-    ///
-    /// let r: MinMaxResult<i32> = NoElements;
-    /// assert_eq!(r.into_option(), None);
-    ///
-    /// let r = OneElement(1);
-    /// assert_eq!(r.into_option(), Some((1, 1)));
-    ///
-    /// let r = MinMax(1, 2);
-    /// assert_eq!(r.into_option(), Some((1, 2)));
-    /// ```
-    pub fn into_option(self) -> Option<(T,T)> {
-        match self {
-            MinMaxResult::NoElements => None,
-            MinMaxResult::OneElement(x) => Some((x.clone(), x)),
-            MinMaxResult::MinMax(x, y) => Some((x, y))
-        }
-    }
-}
-
-/// Implementation guts for `minmax` and `minmax_by_key`.
-pub fn minmax_impl<I, K, F, L>(mut it: I, mut key_for: F,
-                               mut lt: L) -> MinMaxResult<I::Item>
-    where I: Iterator,
-          F: FnMut(&I::Item) -> K,
-          L: FnMut(&I::Item, &I::Item, &K, &K) -> bool,
-{
-    let (mut min, mut max, mut min_key, mut max_key) = match it.next() {
-        None => return MinMaxResult::NoElements,
-        Some(x) => {
-            match it.next() {
-                None => return MinMaxResult::OneElement(x),
-                Some(y) => {
-                    let xk = key_for(&x);
-                    let yk = key_for(&y);
-                    if !lt(&y, &x, &yk, &xk) {(x, y, xk, yk)} else {(y, x, yk, xk)}
-                }
-            }
-        }
-    };
-
-    loop {
-        // `first` and `second` are the two next elements we want to look
-        // at.  We first compare `first` and `second` (#1). The smaller one
-        // is then compared to current minimum (#2). The larger one is
-        // compared to current maximum (#3). This way we do 3 comparisons
-        // for 2 elements.
-        let first = match it.next() {
-            None => break,
-            Some(x) => x
-        };
-        let second = match it.next() {
-            None => {
-                let first_key = key_for(&first);
-                if lt(&first, &min, &first_key, &min_key) {
-                    min = first;
-                } else if !lt(&first, &max, &first_key, &max_key) {
-                    max = first;
-                }
-                break;
-            }
-            Some(x) => x
-        };
-        let first_key = key_for(&first);
-        let second_key = key_for(&second);
-        if !lt(&second, &first, &second_key, &first_key) {
-            if lt(&first, &min, &first_key, &min_key) {
-                min = first;
-                min_key = first_key;
-            }
-            if !lt(&second, &max, &second_key, &max_key) {
-                max = second;
-                max_key = second_key;
-            }
-        } else {
-            if lt(&second, &min, &second_key, &min_key) {
-                min = second;
-                min_key = second_key;
-            }
-            if !lt(&first, &max, &first_key, &max_key) {
-                max = first;
-                max_key = first_key;
-            }
-        }
-    }
-
-    MinMaxResult::MinMax(min, max)
-}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/pad_tail.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-use std::iter::Fuse;
-use size_hint;
-
-/// An iterator adaptor that pads a sequence to a minimum length by filling
-/// missing elements using a closure.
-///
-/// Iterator element type is `I::Item`.
-///
-/// See [`.pad_using()`](../trait.Itertools.html#method.pad_using) for more information.
-#[derive(Clone)]
-pub struct PadUsing<I, F> {
-    iter: Fuse<I>,
-    min: usize,
-    pos: usize,
-    filler: F,
-}
-
-/// Create a new **PadUsing** iterator.
-pub fn pad_using<I, F>(iter: I, min: usize, filler: F) -> PadUsing<I, F>
-    where I: Iterator,
-          F: FnMut(usize) -> I::Item
-{
-    PadUsing {
-        iter: iter.fuse(),
-        min: min,
-        pos: 0,
-        filler: filler,
-    }
-}
-
-impl<I, F> Iterator for PadUsing<I, F>
-    where I: Iterator,
-          F: FnMut(usize) -> I::Item
-{
-    type Item = I::Item;
-
-    #[inline]
-    fn next(&mut self) -> Option<I::Item> {
-        match self.iter.next() {
-            None => {
-                if self.pos < self.min {
-                    let e = Some((self.filler)(self.pos));
-                    self.pos += 1;
-                    e
-                } else {
-                    None
-                }
-            },
-            e => {
-                self.pos += 1;
-                e
-            }
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let tail = self.min.saturating_sub(self.pos);
-        size_hint::max(self.iter.size_hint(), (tail, Some(tail)))
-    }
-}
-
-impl<I, F> DoubleEndedIterator for PadUsing<I, F>
-    where I: DoubleEndedIterator + ExactSizeIterator,
-          F: FnMut(usize) -> I::Item
-{
-    fn next_back(&mut self) -> Option<I::Item> {
-        if self.min == 0 {
-            self.iter.next_back()
-        } else if self.iter.len() >= self.min {
-            self.min -= 1;
-            self.iter.next_back()
-        } else {
-            self.min -= 1;
-            Some((self.filler)(self.min))
-        }
-    }
-}
-
-impl<I, F> ExactSizeIterator for PadUsing<I, F>
-    where I: ExactSizeIterator,
-          F: FnMut(usize) -> I::Item
-{}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/peeking_take_while.rs
+++ /dev/null
@@ -1,144 +0,0 @@
-
-use std::iter::Peekable;
-use PutBack;
-use PutBackN;
-
-/// An iterator that allows peeking at an element before deciding to accept it.
-///
-/// See [`.peeking_take_while()`](trait.Itertools.html#method.peeking_take_while)
-/// for more information.
-///
-/// This is implemented by peeking adaptors like peekable and put back,
-/// but also by a few iterators that can be peeked natively, like the slice’s
-/// by reference iterator (`std::slice::Iter`).
-pub trait PeekingNext : Iterator {
-    /// Pass a reference to the next iterator element to the closure `accept`;
-    /// if `accept` returns true, return it as the next element,
-    /// else None.
-    fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
-        where F: FnOnce(&Self::Item) -> bool;
-}
-
-impl<I> PeekingNext for Peekable<I>
-    where I: Iterator,
-{
-    fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
-        where F: FnOnce(&Self::Item) -> bool
-    {
-        if let Some(r) = self.peek() {
-            if !accept(r) {
-                return None;
-            }
-        }
-        self.next()
-    }
-}
-
-impl<I> PeekingNext for PutBack<I>
-    where I: Iterator,
-{
-    fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
-        where F: FnOnce(&Self::Item) -> bool
-    {
-        if let Some(r) = self.next() {
-            if !accept(&r) {
-                self.put_back(r);
-                return None;
-            }
-            Some(r)
-        } else {
-            None
-        }
-    }
-}
-
-impl<I> PeekingNext for PutBackN<I>
-    where I: Iterator,
-{
-    fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
-        where F: FnOnce(&Self::Item) -> bool
-    {
-        if let Some(r) = self.next() {
-            if !accept(&r) {
-                self.put_back(r);
-                return None;
-            }
-            Some(r)
-        } else {
-            None
-        }
-    }
-}
-
-/// An iterator adaptor that takes items while a closure returns `true`.
-///
-/// See [`.peeking_take_while()`](../trait.Itertools.html#method.peeking_take_while)
-/// for more information.
-pub struct PeekingTakeWhile<'a, I: 'a, F>
-    where I: Iterator,
-{
-    iter: &'a mut I,
-    f: F,
-}
-
-/// Create a PeekingTakeWhile
-pub fn peeking_take_while<I, F>(iter: &mut I, f: F) -> PeekingTakeWhile<I, F>
-    where I: Iterator,
-{
-    PeekingTakeWhile {
-        iter: iter,
-        f: f,
-    }
-}
-
-impl<'a, I, F> Iterator for PeekingTakeWhile<'a, I, F>
-    where I: PeekingNext,
-          F: FnMut(&I::Item) -> bool,
-
-{
-    type Item = I::Item;
-    fn next(&mut self) -> Option<Self::Item> {
-        self.iter.peeking_next(&mut self.f)
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let (_, hi) = self.iter.size_hint();
-        (0, hi)
-    }
-}
-
-// Some iterators are so lightweight we can simply clone them to save their
-// state and use that for peeking.
-macro_rules! peeking_next_by_clone {
-    ([$($typarm:tt)*] $type_:ty) => {
-        impl<$($typarm)*> PeekingNext for $type_ {
-            fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
-                where F: FnOnce(&Self::Item) -> bool
-            {
-                let saved_state = self.clone();
-                if let Some(r) = self.next() {
-                    if !accept(&r) {
-                        *self = saved_state;
-                    } else {
-                        return Some(r)
-                    }
-                }
-                None
-            }
-        }
-    }
-}
-
-peeking_next_by_clone! { ['a, T] ::std::slice::Iter<'a, T> }
-peeking_next_by_clone! { ['a] ::std::str::Chars<'a> }
-peeking_next_by_clone! { ['a] ::std::str::CharIndices<'a> }
-peeking_next_by_clone! { ['a] ::std::str::Bytes<'a> }
-peeking_next_by_clone! { ['a, T] ::std::option::Iter<'a, T> }
-peeking_next_by_clone! { ['a, T] ::std::result::Iter<'a, T> }
-peeking_next_by_clone! { [T] ::std::iter::Empty<T> }
-peeking_next_by_clone! { ['a, T] ::std::collections::linked_list::Iter<'a, T> }
-peeking_next_by_clone! { ['a, T] ::std::collections::vec_deque::Iter<'a, T> }
-
-// cloning a Rev has no extra overhead; peekable and put backs are never DEI.
-peeking_next_by_clone! { [I: Clone + PeekingNext + DoubleEndedIterator]
-                         ::std::iter::Rev<I> }
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/process_results_impl.rs
+++ /dev/null
@@ -1,79 +0,0 @@
-
-/// An iterator that produces only the `T` values as long as the
-/// inner iterator produces `Ok(T)`.
-///
-/// Used by [`process_results`](../fn.process_results.html), see its docs
-/// for more information.
-pub struct ProcessResults<'a, I, E: 'a> {
-    error: &'a mut Result<(), E>,
-    iter: I,
-}
-
-impl<'a, I, T, E> Iterator for ProcessResults<'a, I, E>
-    where I: Iterator<Item = Result<T, E>>
-{
-    type Item = T;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        match self.iter.next() {
-            Some(Ok(x)) => Some(x),
-            Some(Err(e)) => {
-                *self.error = Err(e);
-                None
-            }
-            None => None,
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let (_, hi) = self.iter.size_hint();
-        (0, hi)
-    }
-}
-
-/// “Lift” a function of the values of an iterator so that it can process
-/// an iterator of `Result` values instead.
-///
-/// `iterable` is an iterator or iterable with `Result<T, E>` elements, where
-/// `T` is the value type and `E` the error type.
-///
-/// `processor` is a closure that receives an adapted version of the iterable
-/// as the only argument — the adapted iterator produces elements of type `T`,
-/// as long as the original iterator produces `Ok` values.
-///
-/// If the original iterable produces an error at any point, the adapted
-/// iterator ends and the `process_results` function will return the
-/// error iself.
-///
-/// Otherwise, the return value from the closure is returned wrapped
-/// inside `Ok`.
-///
-/// # Example
-///
-/// ```
-/// use itertools::process_results;
-///
-/// type R = Result<i32, &'static str>;
-///
-/// let first_values: Vec<R> = vec![Ok(1), Ok(0), Ok(3)];
-/// let second_values: Vec<R> = vec![Ok(2), Ok(1), Err("overflow")];
-///
-/// // “Lift” the iterator .max() method to work on the values in Results using process_results
-///
-/// let first_max = process_results(first_values, |iter| iter.max().unwrap_or(0));
-/// let second_max = process_results(second_values, |iter| iter.max().unwrap_or(0));
-///
-/// assert_eq!(first_max, Ok(3));
-/// assert!(second_max.is_err());
-/// ```
-pub fn process_results<I, F, T, E, R>(iterable: I, processor: F) -> Result<R, E>
-    where I: IntoIterator<Item = Result<T, E>>,
-          F: FnOnce(ProcessResults<I::IntoIter, E>) -> R
-{
-    let iter = iterable.into_iter();
-    let mut error = Ok(());
-
-    let result = processor(ProcessResults { error: &mut error, iter: iter });
-
-    error.map(|_| result)
-}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/rciter_impl.rs
+++ /dev/null
@@ -1,97 +0,0 @@
-
-use std::iter::IntoIterator;
-use std::rc::Rc;
-use std::cell::RefCell;
-
-/// A wrapper for `Rc<RefCell<I>>`, that implements the `Iterator` trait.
-pub struct RcIter<I> {
-    /// The boxed iterator.
-    pub rciter: Rc<RefCell<I>>,
-}
-
-/// Return an iterator inside a `Rc<RefCell<_>>` wrapper.
-///
-/// The returned `RcIter` can be cloned, and each clone will refer back to the
-/// same original iterator.
-///
-/// `RcIter` allows doing interesting things like using `.zip()` on an iterator with
-/// itself, at the cost of runtime borrow checking which may have a performance
-/// penalty.
-///
-/// Iterator element type is `Self::Item`.
-///
-/// ```
-/// use itertools::rciter;
-/// use itertools::zip;
-///
-/// // In this example a range iterator is created and we iterate it using
-/// // three separate handles (two of them given to zip).
-/// // We also use the IntoIterator implementation for `&RcIter`.
-///
-/// let mut iter = rciter(0..9);
-/// let mut z = zip(&iter, &iter);
-///
-/// assert_eq!(z.next(), Some((0, 1)));
-/// assert_eq!(z.next(), Some((2, 3)));
-/// assert_eq!(z.next(), Some((4, 5)));
-/// assert_eq!(iter.next(), Some(6));
-/// assert_eq!(z.next(), Some((7, 8)));
-/// assert_eq!(z.next(), None);
-/// ```
-///
-/// **Panics** in iterator methods if a borrow error is encountered in the
-/// iterator methods. It can only happen if the `RcIter` is reentered in
-/// `.next()`, i.e. if it somehow participates in an “iterator knot”
-/// where it is an adaptor of itself.
-pub fn rciter<I>(iterable: I) -> RcIter<I::IntoIter>
-    where I: IntoIterator
-{
-    RcIter { rciter: Rc::new(RefCell::new(iterable.into_iter())) }
-}
-
-impl<I> Clone for RcIter<I> {
-    #[inline]
-    fn clone(&self) -> RcIter<I> {
-        RcIter { rciter: self.rciter.clone() }
-    }
-}
-
-impl<A, I> Iterator for RcIter<I>
-    where I: Iterator<Item = A>
-{
-    type Item = A;
-    #[inline]
-    fn next(&mut self) -> Option<A> {
-        self.rciter.borrow_mut().next()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        // To work sanely with other API that assume they own an iterator,
-        // so it can't change in other places, we can't guarantee as much
-        // in our size_hint. Other clones may drain values under our feet.
-        let (_, hi) = self.rciter.borrow().size_hint();
-        (0, hi)
-    }
-}
-
-impl<I> DoubleEndedIterator for RcIter<I>
-    where I: DoubleEndedIterator
-{
-    #[inline]
-    fn next_back(&mut self) -> Option<I::Item> {
-        self.rciter.borrow_mut().next_back()
-    }
-}
-
-/// Return an iterator from `&RcIter<I>` (by simply cloning it).
-impl<'a, I> IntoIterator for &'a RcIter<I>
-    where I: Iterator
-{
-    type Item = I::Item;
-    type IntoIter = RcIter<I>;
-
-    fn into_iter(self) -> RcIter<I> {
-        self.clone()
-    }
-}
deleted file mode 100644
--- a/third_party/rust/itertools-0.6.5/src/repeatn.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-
-/// An iterator that produces *n* repetitions of an element.
-///
-/// See [`repeat_n()`](../fn.repeat_n.html) for more information.
-pub struct RepeatN<A> {
-    elt: Option<A>,
-    n: usize,
-}
-
-/// Create an iterator that produces `n` repetitions of `element`.
-pub fn repeat_n<A>(element: A, n: usize) -> RepeatN<A>
-    where A: Clone,
-{
-    if n == 0 {
-        RepeatN { elt: None, n: n, }
-    } else {
-        RepeatN { elt: Some(element), n: n, }
-    }