summaryrefslogtreecommitdiffstats
path: root/vendor/array_tool
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /vendor/array_tool
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/array_tool')
-rw-r--r--vendor/array_tool/.cargo-checksum.json1
-rw-r--r--vendor/array_tool/Cargo.toml32
-rw-r--r--vendor/array_tool/MIT-LICENSE20
-rw-r--r--vendor/array_tool/README.md170
-rw-r--r--vendor/array_tool/alternates.txt37
-rw-r--r--vendor/array_tool/appveyor.yml57
-rw-r--r--vendor/array_tool/benches/bench.rs44
-rw-r--r--vendor/array_tool/src/iter.rs166
-rw-r--r--vendor/array_tool/src/lib.rs58
-rw-r--r--vendor/array_tool/src/string.rs303
-rw-r--r--vendor/array_tool/src/vec.rs318
-rw-r--r--vendor/array_tool/tests/lib.rs10
-rw-r--r--vendor/array_tool/tests/string.rs130
-rw-r--r--vendor/array_tool/tests/vec.rs111
14 files changed, 1457 insertions, 0 deletions
diff --git a/vendor/array_tool/.cargo-checksum.json b/vendor/array_tool/.cargo-checksum.json
new file mode 100644
index 000000000..9979c6e0b
--- /dev/null
+++ b/vendor/array_tool/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"19b1c324cdaaa082a2d925646e0a01eb5cde8b37c1711cece6f34606d9a0cf70","MIT-LICENSE":"31624f0f4ff485de373f8a9ee06645254f0c25d50800e85b870932ab17a1ac29","README.md":"e2a1437a88968dd291ed58e404313961a226af9df8a2b3e707ad78bb234cfcb5","alternates.txt":"897ffd9e1a619a1e3dec49a02f1ff8f4f78931b192e8bbea26b058d3b741d44f","appveyor.yml":"5fec5c11fbba591a027649e45a0fa0884af28a4dc6906e0ffce4f255e034a132","benches/bench.rs":"c58134312b18dc5285cd4d78f64ad98a5b862039ac457e4fd29d61ad2144404b","src/iter.rs":"5ec4abf7b3b45d287e4ab2f3eea1380bfa7ee12f0a3e5e682dd12d8d2e84fbad","src/lib.rs":"f782a75d8f6f45be8c9f9c3084913b0c245916beb49d0240813857baf86dc1f0","src/string.rs":"ea3d70ef71c812deb292df0eb6b9e6d59f92f51c9016304af751e964111d99e4","src/vec.rs":"66a841124153aef905160f289813f21ce50af415ebfa6e0aa769d1119c858c33","tests/lib.rs":"0636bb6172db7c885b9f132037d0de37ab63fef6f283a524948c2295649ad232","tests/string.rs":"79449681f1df29e480d360876216447bae20b21d2c8b36251e60180f06ae8db8","tests/vec.rs":"f3610fa3797311271e9c6f3cb7903312ea123deff858541943d3f1ea459c6113"},"package":"8f8cb5d814eb646a863c4f24978cff2880c4be96ad8cde2c0f0678732902e271"} \ No newline at end of file
diff --git a/vendor/array_tool/Cargo.toml b/vendor/array_tool/Cargo.toml
new file mode 100644
index 000000000..76a287a4f
--- /dev/null
+++ b/vendor/array_tool/Cargo.toml
@@ -0,0 +1,32 @@
+# 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 = "array_tool"
+version = "1.0.3"
+authors = ["Daniel P. Clark <6ftdan@gmail.com>"]
+description = "Helper methods for processing collections"
+homepage = "https://github.com/danielpclark/array_tool"
+documentation = "http://danielpclark.github.io/array_tool/index.html"
+readme = "README.md"
+keywords = ["vector", "string", "grapheme", "unique", "substitution"]
+categories = ["text-processing", "data-structures", "value-formatting"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/danielpclark/array_tool"
+[badges.appveyor]
+branch = "master"
+repository = "danielpclark/array_tool"
+service = "github"
+
+[badges.travis-ci]
+branch = "master"
+repository = "danielpclark/array_tool"
diff --git a/vendor/array_tool/MIT-LICENSE b/vendor/array_tool/MIT-LICENSE
new file mode 100644
index 000000000..4b0cb7084
--- /dev/null
+++ b/vendor/array_tool/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright 2015-2018 Daniel P. Clark
+
+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.
diff --git a/vendor/array_tool/README.md b/vendor/array_tool/README.md
new file mode 100644
index 000000000..452a3b2ab
--- /dev/null
+++ b/vendor/array_tool/README.md
@@ -0,0 +1,170 @@
+# array_tool
+[![Build Status](https://travis-ci.org/danielpclark/array_tool.svg?branch=master)](https://travis-ci.org/danielpclark/array_tool)
+[![Build Status](https://ci.appveyor.com/api/projects/status/dffq3dwb8w220q4f/branch/master?svg=true)](https://ci.appveyor.com/project/danielpclark/array-tool/branch/master)
+[![Documentation](https://img.shields.io/badge/docs-100%25-brightgreen.svg)](http://danielpclark.github.io/array_tool/index.html)
+[![crates.io version](https://img.shields.io/crates/v/array_tool.svg)](https://crates.io/crates/array_tool)
+[![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)]()
+
+Array helpers for Rust. Some of the most common methods you would
+use on Arrays made available on Vectors. Polymorphic implementations
+for handling most of your use cases.
+
+
+### Installation
+
+Add the following to your Cargo.toml file
+```toml
+[dependencies]
+array_tool = "1.0.0"
+```
+
+And in your rust files where you plan to use it put this at the top
+```rust
+extern crate array_tool;
+```
+
+And if you plan to use all of the Vector helper methods available you may do
+```rust
+use array_tool::vec::*;
+```
+
+This crate has helpful methods for strings as well.
+
+## Iterator Usage
+
+```rust
+use array_tool::iter::ZipOpt;
+fn zip_option<U: Iterator>(self, other: U) -> ZipOption<Self, U>
+ where Self: Sized, U: IntoIterator;
+ // let a = vec![1];
+ // let b = vec![];
+ // a.zip_option(b).next() // input
+ // Some((Some(1), None)) // return value
+```
+
+## Vector Usage
+
+```rust
+pub fn uniques<T: PartialEq + Clone>(a: Vec<T>, b: Vec<T>) -> Vec<Vec<T>>
+ // array_tool::uniques(vec![1,2,3,4,5], vec![2,5,6,7,8]) // input
+ // vec![vec![1,3,4], vec![6,7,8]] // return value
+
+use array_tool::vec::Uniq;
+fn uniq(&self, other: Vec<T>) -> Vec<T>;
+ // vec![1,2,3,4,5,6].uniq( vec![1,2,5,7,9] ) // input
+ // vec![3,4,6] // return value
+fn uniq_via<F: Fn(&T, &T) -> bool>(&self, other: Self, f: F) -> Self;
+ // vec![1,2,3,4,5,6].uniq_via( vec![1,2,5,7,9], |&l, r| l == r + 2 ) // input
+ // vec![1,2,4,6] // return value
+fn unique(&self) -> Vec<T>;
+ // vec![1,2,1,3,2,3,4,5,6].unique() // input
+ // vec![1,2,3,4,5,6] // return value
+fn unique_via<F: Fn(&T, &T) -> bool>(&self, f: F) -> Self;
+ // vec![1.0,2.0,1.4,3.3,2.1,3.5,4.6,5.2,6.2].
+ // unique_via( |l: &f64, r: &f64| l.floor() == r.floor() ) // input
+ // vec![1.0,2.0,3.3,4.6,5.2,6.2] // return value
+fn is_unique(&self) -> bool;
+ // vec![1,2,1,3,4,3,4,5,6].is_unique() // input
+ // false // return value
+ // vec![1,2,3,4,5,6].is_unique() // input
+ // true // return value
+
+use array_tool::vec::Shift;
+fn unshift(&mut self, other: T); // no return value, modifies &mut self directly
+ // let mut x = vec![1,2,3];
+ // x.unshift(0);
+ // assert_eq!(x, vec![0,1,2,3]);
+fn shift(&mut self) -> Option<T>;
+ // let mut x = vec![0,1,2,3];
+ // assert_eq!(x.shift(), Some(0));
+ // assert_eq!(x, vec![1,2,3]);
+
+use array_tool::vec::Intersect;
+fn intersect(&self, other: Vec<T>) -> Vec<T>;
+ // vec![1,1,3,5].intersect(vec![1,2,3]) // input
+ // vec![1,3] // return value
+fn intersect_if<F: Fn(&T, &T) -> bool>(&self, other: Vec<T>, validator: F) -> Vec<T>;
+ // vec!['a','a','c','e'].intersect_if(vec!['A','B','C'], |l, r| l.eq_ignore_ascii_case(r)) // input
+ // vec!['a','c'] // return value
+
+use array_tool::vec::Join;
+fn join(&self, joiner: &'static str) -> String;
+ // vec![1,2,3].join(",") // input
+ // "1,2,3" // return value
+
+use array_tool::vec::Times;
+fn times(&self, qty: i32) -> Vec<T>;
+ // vec![1,2,3].times(3) // input
+ // vec![1,2,3,1,2,3,1,2,3] // return value
+
+use array_tool::vec::Union;
+fn union(&self, other: Vec<T>) -> Vec<T>;
+ // vec!["a","b","c"].union(vec!["c","d","a"]) // input
+ // vec![ "a", "b", "c", "d" ] // return value
+```
+
+## String Usage
+
+```rust
+use array_tool::string::ToGraphemeBytesIter;
+fn grapheme_bytes_iter(&'a self) -> GraphemeBytesIter<'a>;
+ // let string = "a s—d féZ";
+ // let mut graphemes = string.grapheme_bytes_iter()
+ // graphemes.skip(3).next(); // input
+ // [226, 128, 148] // return value for emdash `—`
+
+use array_tool::string::Squeeze;
+fn squeeze(&self, targets: &'static str) -> String;
+ // "yellow moon".squeeze("") // input
+ // "yelow mon" // return value
+ // " now is the".squeeze(" ") // input
+ // " now is the" // return value
+
+use array_tool::string::Justify;
+fn justify_line(&self, width: usize) -> String;
+ // "asd as df asd".justify_line(16) // input
+ // "asd as df asd" // return value
+ // "asd as df asd".justify_line(18) // input
+ // "asd as df asd" // return value
+
+use array_tool::string::SubstMarks;
+fn subst_marks(&self, marks: Vec<usize>, chr: &'static str) -> String;
+ // "asdf asdf asdf".subst_marks(vec![0,5,8], "Z") // input
+ // "Zsdf ZsdZ asdf" // return value
+
+use array_tool::string::WordWrap;
+fn word_wrap(&self, width: usize) -> String;
+ // "01234 67 9 BC EFG IJ".word_wrap(6) // input
+ // "01234\n67 9\nBC\nEFG IJ" // return value
+
+use array_tool::string::AfterWhitespace;
+fn seek_end_of_whitespace(&self, offset: usize) -> Option<usize>;
+ // "asdf asdf asdf".seek_end_of_whitespace(6) // input
+ // Some(9) // return value
+ // "asdf".seek_end_of_whitespace(3) // input
+ // Some(0) // return value
+ // "asdf ".seek_end_of_whitespace(6) // input
+ // None // return_value
+
+```
+
+## Future plans
+
+Expect methods to become more polymorphic over time (same method implemented
+for similar & compatible types). I plan to implement many of the methods
+available for Arrays in higher languages; such as Ruby. Expect regular updates.
+
+## License
+
+Licensed under either of
+
+ * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
+ * MIT license ([MIT-LICENSE](MIT-LICENSE) or http://opensource.org/licenses/MIT)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
+additional terms or conditions.
diff --git a/vendor/array_tool/alternates.txt b/vendor/array_tool/alternates.txt
new file mode 100644
index 000000000..3e13f17cf
--- /dev/null
+++ b/vendor/array_tool/alternates.txt
@@ -0,0 +1,37 @@
+43% SLOWER implementation
+
+pub fn experimental_uniques<T: std::cmp::PartialEq<T> + std::clone::Clone>(a: Vec<T>, b: Vec<T>) -> Vec<Vec<T>> {
+ let mut first_uniq = a.clone();
+ let mut second_uniq = b.clone();
+
+ let mut x = first_uniq.len();
+
+ 'outer: loop {
+ x -= 1;
+ let mut y = second_uniq.len();
+ let mut removed = false;
+ 'inner: loop {
+ y -= 1;
+ if first_uniq[x] == second_uniq[y] {
+ first_uniq.remove(x);
+ second_uniq.remove(y);
+ removed = true
+ }
+ if x == 0{
+ if y == 0{
+ break 'outer
+ }
+ }
+ else {
+ if y == 0{
+ break
+ }
+ if removed {
+ continue 'outer
+ }
+ }
+ }
+ }
+
+ vec![first_uniq, second_uniq]
+}
diff --git a/vendor/array_tool/appveyor.yml b/vendor/array_tool/appveyor.yml
new file mode 100644
index 000000000..c2e1298af
--- /dev/null
+++ b/vendor/array_tool/appveyor.yml
@@ -0,0 +1,57 @@
+# Based on the "trust" template v0.1.1
+# https://github.com/japaric/trust/tree/v0.1.1
+
+environment:
+ global:
+ RUST_VERSION: stable
+
+ CRATE_NAME: array_tool
+
+ matrix:
+ # MinGW
+ - TARGET: i686-pc-windows-gnu
+ - TARGET: x86_64-pc-windows-gnu
+
+ # MSVC
+ - TARGET: i686-pc-windows-msvc
+ - TARGET: x86_64-pc-windows-msvc
+
+ # Testing other channels
+ - TARGET: x86_64-pc-windows-gnu
+ RUST_VERSION: nightly
+ - TARGET: x86_64-pc-windows-msvc
+ RUST_VERSION: nightly
+
+install:
+ - ps: >-
+ If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') {
+ $Env:PATH += ';C:\msys64\mingw64\bin'
+ } ElseIf ($Env:TARGET -eq 'i686-pc-windows-gnu') {
+ $Env:PATH += ';C:\msys64\mingw32\bin'
+ }
+ - curl -sSf -o rustup-init.exe https://win.rustup.rs/
+ - rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_VERSION%
+ - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
+ - rustc -Vv
+ - cargo -V
+
+test_script:
+ - if [%APPVEYOR_REPO_TAG%]==[false] (
+ cargo build --target %TARGET% &&
+ cargo build --target %TARGET% --release &&
+ cargo test --target %TARGET% &&
+ cargo test --target %TARGET% --release
+ )
+
+cache:
+ - C:\Users\appveyor\.cargo\registry
+ - target
+
+branches:
+ only:
+ # Release tags
+ - /^v\d+\.\d+\.\d+.*$/
+ - master
+
+# Building is done in the test phase, so we disable Appveyor's build phase.
+build: false
diff --git a/vendor/array_tool/benches/bench.rs b/vendor/array_tool/benches/bench.rs
new file mode 100644
index 000000000..81e84de94
--- /dev/null
+++ b/vendor/array_tool/benches/bench.rs
@@ -0,0 +1,44 @@
+#![feature(test)]
+
+// NOTES
+//
+// string slices are faster than character iteration with method nth.
+
+extern crate test;
+use test::Bencher;
+extern crate array_tool;
+use array_tool::*;
+
+#[bench]
+fn uniques1(b: &mut Bencher){
+ b.iter(|| {
+ let a: Vec<i32> = vec![1,43,6,26,62,7,27,2,3,62,246,2346,6,7,2,35,62,6,325,56,63,25,4,8,8727,7,74,452];
+ let d: Vec<i32> = vec![36,63,74,872,2,772,7,2,54,265,3245,45,754,235,4567,67,23,2,542,352];
+ uniques(a, d)
+ })
+}
+
+#[bench]
+fn times(b: &mut Bencher){
+ b.iter(|| {
+ use array_tool::vec::Times;
+ vec![1,2,3,4,5,6].times(150);
+ });
+}
+
+#[bench]
+fn subst_marks(b: &mut Bencher){
+ b.iter(|| {
+ use array_tool::string::SubstMarks;
+ "dfgklerfgseawrfgawergq35g4w6uw4372472q4762q47yq35uw4567u32qy7q3yuq3".subst_marks(
+ vec![0,3,6,9,12,24,34,40], "Z");
+ });
+}
+
+#[bench]
+fn word_wrap(b: &mut Bencher){
+ b.iter(|| {
+ use array_tool::string::WordWrap;
+ "asdf sdf s df d sd\n sf sfg sg g\n sfdgsg\n gfdga a\n ".word_wrap(3);
+ });
+}
diff --git a/vendor/array_tool/src/iter.rs b/vendor/array_tool/src/iter.rs
new file mode 100644
index 000000000..a176d5c79
--- /dev/null
+++ b/vendor/array_tool/src/iter.rs
@@ -0,0 +1,166 @@
+use std::cmp;
+use std::iter::IntoIterator;
+
+#[doc(hidden)]
+#[derive(Clone, Debug)]
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+pub struct ZipOption<A, B> {
+ a: A,
+ b: B,
+ // index and len are only used by the specialized version of zip
+ index: usize,
+ len: usize,
+}
+
+/// Zips to iterators together to the longest length
+/// via Option<(Option<A>, Option<B>)>
+pub trait ZipOpt {
+ /// Zip to iterators to longest length via Option<(Option<A>, Option<B>)> results.
+ /// # Example
+ /// ```
+ /// use array_tool::iter::ZipOpt;
+ ///
+ /// let a = vec!["a","b","c", "d"];
+ /// let b = vec!["c","d"];
+ /// let mut x = a.iter().zip_option(b.iter());
+ ///
+ /// assert_eq!(x.next(), Some((Some(&"a"), Some(&"c"))));
+ /// assert_eq!(x.next(), Some((Some(&"b"), Some(&"d"))));
+ /// assert_eq!(x.next(), Some((Some(&"c"), None)));
+ /// assert_eq!(x.next(), Some((Some(&"d"), None)));
+ /// assert_eq!(x.next(), None);
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// vec![ "a", "b", "c", "d" ]
+ /// ```
+ fn zip_option<U>(self, other: U) -> ZipOption<Self, U::IntoIter>
+ where Self: Sized, U: IntoIterator;
+}
+
+impl<I: Iterator> ZipOpt for I {
+ #[inline]
+ fn zip_option<U>(self, other: U) -> ZipOption<Self, U::IntoIter>
+ where Self: Sized, U: IntoIterator {
+
+ ZipOption::new(self, other.into_iter())
+ }
+}
+
+impl<A, B> Iterator for ZipOption<A, B> where A: Iterator, B: Iterator {
+ type Item = (Option<A::Item>, Option<B::Item>);
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ ZipImpl::next(self)
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ ZipImpl::size_hint(self)
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ ZipImpl::nth(self, n)
+ }
+}
+
+#[doc(hidden)]
+impl<A, B> DoubleEndedIterator for ZipOption<A, B> where
+A: DoubleEndedIterator + ExactSizeIterator,
+B: DoubleEndedIterator + ExactSizeIterator,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<(Option<A::Item>, Option<B::Item>)> {
+ ZipImpl::next_back(self)
+ }
+}
+
+#[doc(hidden)]
+trait ZipImpl<A, B> {
+ type Item;
+ fn new(a: A, b: B) -> Self;
+ fn next(&mut self) -> Option<Self::Item>;
+ fn size_hint(&self) -> (usize, Option<usize>);
+ fn nth(&mut self, n: usize) -> Option<Self::Item>;
+ fn super_nth(&mut self, mut n: usize) -> Option<Self::Item> {
+ while let Some(x) = self.next() {
+ if n == 0 { return Some(x) }
+ n -= 1;
+ }
+ None
+ }
+ fn next_back(&mut self) -> Option<Self::Item>
+ where A: DoubleEndedIterator + ExactSizeIterator,
+ B: DoubleEndedIterator + ExactSizeIterator;
+}
+
+#[doc(hidden)]
+impl<A, B> ZipImpl<A, B> for ZipOption<A, B>
+ where A: Iterator, B: Iterator {
+ type Item = (Option<A::Item>, Option<B::Item>);
+ fn new(a: A, b: B) -> Self {
+ ZipOption {
+ a,
+ b,
+ index: 0, // unused
+ len: 0, // unused
+ }
+ }
+
+ #[inline]
+ fn next(&mut self) -> Option<(Option<A::Item>, Option<B::Item>)> {
+ let first = self.a.next();
+ let second = self.b.next();
+
+ if first.is_some() || second.is_some() {
+ Some((first, second))
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ self.super_nth(n)
+ }
+
+ #[inline]
+ fn next_back(&mut self) -> Option<(Option<A::Item>, Option<B::Item>)>
+ where A: DoubleEndedIterator + ExactSizeIterator,
+ B: DoubleEndedIterator + ExactSizeIterator {
+ let a_sz = self.a.len();
+ let b_sz = self.b.len();
+ if a_sz != b_sz {
+ // Adjust a, b to equal length
+ if a_sz > b_sz {
+ for _ in 0..a_sz - b_sz { self.a.next_back(); }
+ } else {
+ for _ in 0..b_sz - a_sz { self.b.next_back(); }
+ }
+ }
+ match (self.a.next_back(), self.b.next_back()) {
+ (None, None) => None,
+ (f,s) => Some((f, s)),
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (a_lower, a_upper) = self.a.size_hint();
+ let (b_lower, b_upper) = self.b.size_hint();
+
+ let lower = cmp::min(a_lower, b_lower);
+
+ let upper = match (a_upper, b_upper) {
+ (Some(x), Some(y)) => Some(cmp::max(x,y)),
+ (Some(x), None) => Some(x),
+ (None, Some(y)) => Some(y),
+ (None, None) => None
+ };
+
+ (lower, upper)
+ }
+}
diff --git a/vendor/array_tool/src/lib.rs b/vendor/array_tool/src/lib.rs
new file mode 100644
index 000000000..5a7787f67
--- /dev/null
+++ b/vendor/array_tool/src/lib.rs
@@ -0,0 +1,58 @@
+#![deny(missing_docs,trivial_casts,trivial_numeric_casts,
+ missing_debug_implementations, missing_copy_implementations,
+ unsafe_code,unused_import_braces,unused_qualifications)
+]
+// Copyright 2015-2017 Daniel P. Clark & array_tool Developers
+//
+// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
+// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
+// http://opensource.org/licenses/MIT>, at your option. This file may not be
+// copied, modified, or distributed except according to those terms.
+
+//! # Array Tool
+//!
+//! is a collection of powerful methods for working with collections.
+//! Some of the most common methods you would use on Arrays made available
+//! on Vectors. Polymorphic implementations for handling most of your use cases.
+//!
+//! In your rust files where you plan to use it put this at the top
+//!
+//! ```
+//! extern crate array_tool;
+//! ```
+//!
+//! And if you plan to use all of the Vector helper methods available:
+//!
+//! ```
+//! use array_tool::vec::*;
+//! ```
+//!
+//! This crate is not limited to just Vector methods and has some helpful
+//! string methods as well.
+
+
+/// Array Tool provides useful methods for iterators
+pub mod iter;
+/// Array Tool provides many useful methods for vectors
+pub mod vec;
+/// A string is a collection so we should have more methods for handling strings.
+pub mod string;
+
+/// Get `uniques` from two vectors
+///
+/// # Example
+/// ```
+/// use array_tool::uniques;
+///
+/// uniques(vec![1,2,3,4,5], vec![2,5,6,7,8]);
+/// ```
+///
+/// # Output
+/// ```text
+/// vec![vec![1,3,4], vec![6,7,8]]
+/// ```
+pub fn uniques<T: PartialEq + Clone>(a: Vec<T>, b: Vec<T>) -> Vec<Vec<T>> {
+ use self::vec::Uniq;
+ vec![a.uniq(b.clone()), b.uniq(a)]
+}
+
diff --git a/vendor/array_tool/src/string.rs b/vendor/array_tool/src/string.rs
new file mode 100644
index 000000000..dc0e317ef
--- /dev/null
+++ b/vendor/array_tool/src/string.rs
@@ -0,0 +1,303 @@
+// Copyright 2015-2017 Daniel P. Clark & array_tool Developers
+//
+// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
+// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
+// http://opensource.org/licenses/MIT>, at your option. This file may not be
+// copied, modified, or distributed except according to those terms.
+
+/// A grapheme iterator that produces the bytes for each grapheme.
+#[derive(Debug)]
+pub struct GraphemeBytesIter<'a> {
+ source: &'a str,
+ offset: usize,
+ grapheme_count: usize,
+}
+impl<'a> GraphemeBytesIter<'a> {
+ /// Creates a new grapheme iterator from a string source.
+ pub fn new(source: &'a str) -> GraphemeBytesIter<'a> {
+ GraphemeBytesIter {
+ source: source,
+ offset: 0,
+ grapheme_count: 0,
+ }
+ }
+}
+impl<'a> Iterator for GraphemeBytesIter<'a> {
+ type Item = &'a [u8];
+
+ fn next(&mut self) -> Option<&'a [u8]> {
+ let mut result: Option<&[u8]> = None;
+ let mut idx = self.offset;
+ for _ in self.offset..self.source.len() {
+ idx += 1;
+ if self.offset < self.source.len() {
+ if self.source.is_char_boundary(idx) {
+ let slice: &[u8] = self.source[self.offset..idx].as_bytes();
+
+ self.grapheme_count += 1;
+ self.offset = idx;
+
+ result = Some(slice);
+ break
+ }
+ }
+ }
+ result
+ }
+}
+impl<'a> ExactSizeIterator for GraphemeBytesIter<'a> {
+ fn len(&self) -> usize {
+ self.source.chars().count()
+ }
+}
+/// ToGraphemeBytesIter - create an iterator to return bytes for each grapheme in a string.
+pub trait ToGraphemeBytesIter<'a> {
+ /// Returns a GraphemeBytesIter which you may iterate over.
+ ///
+ /// # Example
+ /// ```
+ /// use array_tool::string::ToGraphemeBytesIter;
+ ///
+ /// let string = "a s—d féZ";
+ /// let mut graphemes = string.grapheme_bytes_iter();
+ /// graphemes.skip(3).next();
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// [226, 128, 148]
+ /// ```
+ fn grapheme_bytes_iter(&'a self) -> GraphemeBytesIter<'a>;
+}
+impl<'a> ToGraphemeBytesIter<'a> for str {
+ fn grapheme_bytes_iter(&'a self) -> GraphemeBytesIter<'a> {
+ GraphemeBytesIter::new(&self)
+ }
+}
+
+/// Squeeze - squeezes duplicate characters down to one each
+pub trait Squeeze {
+ /// # Example
+ /// ```
+ /// use array_tool::string::Squeeze;
+ ///
+ /// "yellow moon".squeeze("");
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// "yelow mon"
+ /// ```
+ fn squeeze(&self, targets: &'static str) -> String;
+}
+impl Squeeze for str {
+ fn squeeze(&self, targets: &'static str) -> String {
+ let mut output = Vec::<u8>::with_capacity(self.len());
+ let everything: bool = targets.is_empty();
+ let chars = targets.grapheme_bytes_iter().collect::<Vec<&[u8]>>();
+ let mut last: &[u8] = &[0];
+ for character in self.grapheme_bytes_iter() {
+ if last != character {
+ output.extend_from_slice(character);
+ } else if !(everything || chars.contains(&character)) {
+ output.extend_from_slice(character);
+ }
+ last = character;
+ }
+ String::from_utf8(output).expect("squeeze failed to render String!")
+ }
+}
+
+/// Justify - expand line to given width.
+pub trait Justify {
+ /// # Example
+ /// ```
+ /// use array_tool::string::Justify;
+ ///
+ /// "asd asdf asd".justify_line(14);
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// "asd asdf asd"
+ /// ```
+ fn justify_line(&self, width: usize) -> String;
+}
+
+impl Justify for str {
+ fn justify_line(&self, width: usize) -> String {
+ if self.is_empty() { return format!("{}", self) };
+ let trimmed = self.trim() ;
+ let len = trimmed.chars().count();
+ if len >= width { return self.to_string(); };
+ let difference = width - len;
+ let iter = trimmed.split_whitespace();
+ let spaces = iter.count() - 1;
+ let mut iter = trimmed.split_whitespace().peekable();
+ if spaces == 0 { return self.to_string(); }
+ let mut obj = String::with_capacity(trimmed.len() + spaces);
+
+ let div = difference / spaces;
+ let mut remainder = difference % spaces;
+
+ while let Some(x) = iter.next() {
+ obj.push_str( x );
+ let val = if remainder > 0 {
+ remainder = remainder - 1;
+ div + 1
+ } else { div };
+ for _ in 0..val+1 {
+ if let Some(_) = iter.peek() { // Don't add spaces if last word
+ obj.push_str( " " );
+ }
+ }
+ }
+ obj
+ }
+}
+
+/// Substitute string character for each index given.
+pub trait SubstMarks {
+ /// # Example
+ /// ```
+ /// use array_tool::string::SubstMarks;
+ ///
+ /// "asdf asdf asdf".subst_marks(vec![0,5,8], "Z");
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// "Zsdf ZsdZ asdf"
+ /// ```
+ fn subst_marks(&self, marks: Vec<usize>, chr: &'static str) -> String;
+}
+impl SubstMarks for str {
+ fn subst_marks(&self, marks: Vec<usize>, chr: &'static str) -> String {
+ let mut output = Vec::<u8>::with_capacity(self.len());
+ let mut count = 0;
+ let mut last = 0;
+ for i in 0..self.len() {
+ let idx = i + 1;
+ if self.is_char_boundary(idx) {
+ if marks.contains(&count) {
+ count += 1;
+ last = idx;
+ output.extend_from_slice(chr.as_bytes());
+ continue
+ }
+
+ let slice: &[u8] = self[last..idx].as_bytes();
+ output.extend_from_slice(slice);
+
+ count += 1;
+ last = idx
+ }
+ }
+ String::from_utf8(output).expect("subst_marks failed to render String!")
+ }
+}
+
+/// After whitespace
+pub trait AfterWhitespace {
+ /// Given offset method will seek from there to end of string to find the first
+ /// non white space. Resulting value is counted from offset.
+ ///
+ /// # Example
+ /// ```
+ /// use array_tool::string::AfterWhitespace;
+ ///
+ /// assert_eq!(
+ /// "asdf asdf asdf".seek_end_of_whitespace(6),
+ /// Some(9)
+ /// );
+ /// ```
+ fn seek_end_of_whitespace(&self, offset: usize) -> Option<usize>;
+}
+impl AfterWhitespace for str {
+ fn seek_end_of_whitespace(&self, offset: usize) -> Option<usize> {
+ if self.len() < offset { return None; };
+ let mut seeker = self[offset..self.len()].chars();
+ let mut val = None;
+ let mut indx = 0;
+ while let Some(x) = seeker.next() {
+ if x.ne(&" ".chars().next().unwrap()) {
+ val = Some(indx);
+ break;
+ }
+ indx += 1;
+ }
+ val
+ }
+}
+
+/// Word wrapping
+pub trait WordWrap {
+ /// White space is treated as valid content and new lines will only be swapped in for
+ /// the last white space character at the end of the given width. White space may reach beyond
+ /// the width you've provided. You will need to trim end of lines in your own output (e.g.
+ /// splitting string at each new line and printing the line with trim_right). Or just trust
+ /// that lines that are beyond the width are just white space and only print the width -
+ /// ignoring tailing white space.
+ ///
+ /// # Example
+ /// ```
+ /// use array_tool::string::WordWrap;
+ ///
+ /// "asd asdf asd".word_wrap(8);
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// "asd asdf\nasd"
+ /// ```
+ fn word_wrap(&self, width: usize) -> String;
+}
+// No need to worry about character encoding since we're only checking for the
+// space and new line characters.
+impl WordWrap for &'static str {
+ fn word_wrap(&self, width: usize) -> String {
+ let mut markers = vec![];
+ fn wordwrap(t: &'static str, chunk: usize, offset: usize, mrkrs: &mut Vec<usize>) -> String {
+ match t[offset..*vec![offset+chunk,t.len()].iter().min().unwrap()].rfind("\n") {
+ None => {
+ match t[offset..*vec![offset+chunk,t.len()].iter().min().unwrap()].rfind(" ") {
+ Some(x) => {
+ let mut eows = x; // end of white space
+ if offset+chunk < t.len() { // check if white space continues
+ match t.seek_end_of_whitespace(offset+x) {
+ Some(a) => {
+ if a.ne(&0) {
+ eows = x+a-1;
+ }
+ },
+ None => {},
+ }
+ }
+ if offset+chunk < t.len() { // safe to seek ahead by 1 or not end of string
+ if !["\n".chars().next().unwrap(), " ".chars().next().unwrap()].contains(
+ &t[offset+eows+1..offset+eows+2].chars().next().unwrap()
+ ) {
+ mrkrs.push(offset+eows)
+ }
+ };
+ wordwrap(t, chunk, offset+eows+1, mrkrs)
+ },
+ None => {
+ if offset+chunk < t.len() { // String may continue
+ wordwrap(t, chunk, offset+1, mrkrs) // Recurse + 1 until next space
+ } else {
+ use string::SubstMarks;
+
+ return t.subst_marks(mrkrs.to_vec(), "\n")
+ }
+ },
+ }
+ },
+ Some(x) => {
+ wordwrap(t, chunk, offset+x+1, mrkrs)
+ },
+ }
+ };
+ wordwrap(self, width+1, 0, &mut markers)
+ }
+}
diff --git a/vendor/array_tool/src/vec.rs b/vendor/array_tool/src/vec.rs
new file mode 100644
index 000000000..14c32c049
--- /dev/null
+++ b/vendor/array_tool/src/vec.rs
@@ -0,0 +1,318 @@
+// Copyright 2015-2017 Daniel P. Clark & array_tool Developers
+//
+// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
+// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
+// http://opensource.org/licenses/MIT>, at your option. This file may not be
+// copied, modified, or distributed except according to those terms.
+
+/// Several different methods for getting, or evaluating, uniqueness.
+pub trait Uniq<T> {
+ /// `uniq` returns a vector of unique values within itself as compared to
+ /// the other vector which is provided as an input parameter.
+ ///
+ /// # Example
+ /// ```
+ /// use array_tool::vec::Uniq;
+ ///
+ /// vec![1,2,3,4,5,6].uniq( vec![1,2,5,7,9] );
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// vec![3,4,6]
+ /// ```
+ fn uniq(&self, other: Self) -> Self;
+
+ /// `unique` removes duplicates from within the vector and returns Self.
+ ///
+ /// # Example
+ /// ```
+ /// use array_tool::vec::Uniq;
+ ///
+ /// vec![1,2,1,3,2,3,4,5,6].unique();
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// vec![1,2,3,4,5,6]
+ /// ```
+ fn unique(&self) -> Self;
+
+ /// `is_unique` returns boolean value on whether all values within
+ /// Self are unique.
+ ///
+ /// # Example
+ /// ```
+ /// use array_tool::vec::Uniq;
+ ///
+ /// vec![1,2,1,3,4,3,4,5,6].is_unique();
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// false
+ /// ```
+ fn is_unique(&self) -> bool;
+
+ /// `uniq_via` returns a vector of unique values within itself as compared to
+ /// the other vector which is provided as an input parameter, as defined by a
+ /// provided custom comparator.
+ ///
+ /// # Example
+ /// ```
+ /// use array_tool::vec::Uniq;
+ ///
+ /// vec![1,2,3,4,5,6].uniq_via( vec![1,2,5,7,9], |&l, r| l == r + 2 );
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// vec![1,2,4,6]
+ /// ```
+ fn uniq_via<F: Fn(&T, &T) -> bool>(&self, other: Self, f: F) -> Self;
+
+ /// `unique_via` removes duplicates, as defined by a provided custom comparator,
+ /// from within the vector and returns Self.
+ ///
+ /// # Example
+ /// ```
+ /// use array_tool::vec::Uniq;
+ ///
+ /// vec![1.0,2.0,1.4,3.3,2.1,3.5,4.6,5.2,6.2].unique_via( |l: &f64, r: &f64| l.floor() == r.floor() );
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// vec![1.0,2.0,3.3,4.6,5.2,6.2]
+ /// ```
+ fn unique_via<F: Fn(&T, &T) -> bool>(&self, f: F) -> Self;
+
+ /// `is_unique_via` returns boolean value on whether all values within
+ /// Self are unique, as defined by a provided custom comparator.
+ ///
+ /// # Example
+ /// ```
+ /// use array_tool::vec::Uniq;
+ ///
+ /// vec![1.0,2.0,1.4,3.3,2.1,3.5,4.6,5.2,6.2].is_unique_via( |l: &f64, r: &f64| l.floor() == r.floor() );
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// false
+ /// ```
+ fn is_unique_via<F: Fn(&T, &T) -> bool>(&self, f: F) -> bool;
+}
+
+impl<T: Clone + PartialEq> Uniq<T> for Vec<T> {
+ fn uniq(&self, other: Vec<T>) -> Vec<T> {
+ self.uniq_via(other, |lhs, rhs| lhs == rhs)
+ }
+ fn unique(&self) -> Vec<T> {
+ self.unique_via(|lhs, rhs| lhs == rhs)
+ }
+ fn is_unique(&self) -> bool {
+ self.is_unique_via(|lhs, rhs| lhs == rhs)
+ }
+
+ fn uniq_via<F: Fn(&T, &T) -> bool>(&self, other: Vec<T>, f: F) -> Vec<T> {
+ let mut out = self.unique();
+ for x in other.unique() {
+ for y in (0..out.len()).rev() {
+ if f(&x, &out[y]) {
+ out.remove(y);
+ }
+ }
+ }
+ out
+ }
+ fn unique_via<F: Fn(&T, &T) -> bool>(&self, f: F) -> Vec<T> {
+ let mut a = self.clone();
+ for x in (0..a.len()).rev() {
+ for y in (x+1..a.len()).rev() {
+ if f(&a[x], &a[y]) {
+ a.remove(y);
+ }
+ }
+ }
+ a
+ }
+ fn is_unique_via<F: Fn(&T, &T) -> bool>(&self, f: F) -> bool {
+ let mut a = true;
+ for x in 0..self.len() {
+ for y in x+1..self.len() {
+ if f(&self[x], &self[y]) {
+ a = false;
+ break;
+ }
+ }
+ }
+ a
+ }
+}
+
+/// Removes, or Adds, the first element of self.
+pub trait Shift<T> {
+ /// Removes and returns the first item from the vector
+ ///
+ /// # Example
+ /// ```
+ /// use array_tool::vec::Shift;
+ ///
+ /// let mut x = vec![0,1,2,3];
+ /// assert_eq!(x.shift(), Some(0));
+ /// assert_eq!(x, vec![1,2,3]);
+ /// ```
+ fn shift(&mut self) -> Option<T>;
+ /// Insert item at the beginning of the vector. No return value.
+ ///
+ /// # Example
+ /// ```
+ /// use array_tool::vec::Shift;
+ ///
+ /// let mut x = vec![1,2,3];
+ /// x.unshift(0);
+ /// assert_eq!(x, vec![0,1,2,3]);
+ /// ```
+ fn unshift(&mut self, other: T);
+}
+impl<T: PartialEq> Shift<T> for Vec<T> {
+ fn shift(&mut self) -> Option<T> {
+ if self.len() == 0 { return None; }
+ Some(self.remove(0))
+ }
+ fn unshift(&mut self, other: T) {
+ &self.insert(0, other);
+ }
+}
+
+/// Set Intersection — Returns a new array containing elements common to the two arrays,
+/// excluding any duplicates. The order is preserved from the original array.
+pub trait Intersect<T> {
+ /// # Example
+ /// ```
+ /// use array_tool::vec::Intersect;
+ ///
+ /// vec![1,1,3,5].intersect(vec![1,2,3]);
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// vec![1,3]
+ /// ```
+ fn intersect(&self, Self) -> Self;
+ /// # Example
+ /// ```
+ /// # use std::ascii::AsciiExt;
+ /// use array_tool::vec::Intersect;
+ ///
+ /// vec!['a','a','c','e'].intersect_if(vec!['A','B','C'], |l, r| l.eq_ignore_ascii_case(r));
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// vec!['a','c']
+ /// ```
+ fn intersect_if<F: Fn(&T, &T) -> bool>(&self, Self, validator: F) -> Self;
+}
+impl<T: PartialEq + Clone> Intersect<T> for Vec<T> {
+ fn intersect(&self, other: Vec<T>) -> Vec<T> {
+ self.intersect_if(other, |l, r| l == r)
+ }
+ fn intersect_if<F: Fn(&T, &T) -> bool>(&self, other: Self, validator: F) -> Self {
+ let mut out = vec![];
+ let a = self.unique();
+ let length = other.len();
+ for x in a {
+ for y in 0..length {
+ if validator(&x, &other[y]) {
+ out.push(x);
+ break;
+ }
+ }
+ }
+ out
+ }
+}
+
+/// Join vector of ToString capable things to a String with given delimiter.
+pub trait Join {
+ /// # Example
+ /// ```
+ /// use array_tool::vec::Join;
+ ///
+ /// vec![1,2,3].join(",");
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// "1,2,3"
+ /// ```
+ fn join(&self, joiner: &'static str) -> String;
+}
+impl<T: ToString> Join for Vec<T> {
+ fn join(&self, joiner: &'static str) -> String {
+ let mut out = String::from("");
+ for x in 0..self.len() {
+ out.push_str(&self[x].to_string());
+ if x < self.len()-1 {
+ out.push_str(&joiner)
+ }
+ }
+ out
+ }
+}
+
+/// Expand and duplicate the vectors content `times` the integer given
+pub trait Times {
+ /// # Example
+ /// ```
+ /// use array_tool::vec::Times;
+ ///
+ /// vec![1,2,3].times(3);
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// vec![1,2,3,1,2,3,1,2,3]
+ /// ```
+ fn times(&self, qty: i32) -> Self;
+}
+impl<T: Clone> Times for Vec<T> {
+ fn times(&self, qty: i32) -> Vec<T> {
+ if self.is_empty() { return vec![] };
+ let mut out = vec![self[0].clone();self.len()*(qty as usize)];
+ let mut cycle = self.iter().cycle();
+ for x in 0..self.len()*(qty as usize) {
+ out[x] = cycle.next().unwrap().clone();
+ }
+ out
+ }
+}
+
+/// Create a `union` between two vectors.
+/// Returns a new vector by joining with other, excluding any duplicates and preserving
+/// the order from the original vector.
+pub trait Union {
+ /// # Example
+ /// ```
+ /// use array_tool::vec::Union;
+ ///
+ /// vec!["a","b","c"].union(vec!["c","d","a"]);
+ /// ```
+ ///
+ /// # Output
+ /// ```text
+ /// vec![ "a", "b", "c", "d" ]
+ /// ```
+ fn union(&self, other: Self) -> Self;
+}
+impl<T: PartialEq + Clone> Union for Vec<T> {
+ fn union(&self, other: Vec<T>) -> Vec<T> {
+ let mut stack = self.clone();
+ for x in other { // don't use append method as it's destructive
+ stack.push(x)
+ }
+ stack.unique()
+ }
+}
diff --git a/vendor/array_tool/tests/lib.rs b/vendor/array_tool/tests/lib.rs
new file mode 100644
index 000000000..1c37d9703
--- /dev/null
+++ b/vendor/array_tool/tests/lib.rs
@@ -0,0 +1,10 @@
+extern crate array_tool;
+
+#[test]
+fn it_implements_uniques() {
+ assert_eq!(array_tool::uniques(vec![1,2,3,4,5,6],vec![1,2]), vec![vec![3,4,5,6],vec![]]);
+ assert_eq!(array_tool::uniques(vec![1,2,3,4,5,6],vec![1,2,3,4]), vec![vec![5,6], vec![]]);
+ assert_eq!(array_tool::uniques(vec![1,2,3],vec![1,2,3,4,5]), vec![vec![], vec![4,5]]);
+ assert_eq!(array_tool::uniques(vec![1,2,9],vec![1,2,3,4,5]), vec![vec![9], vec![3,4,5]]);
+}
+
diff --git a/vendor/array_tool/tests/string.rs b/vendor/array_tool/tests/string.rs
new file mode 100644
index 000000000..ec73bbb74
--- /dev/null
+++ b/vendor/array_tool/tests/string.rs
@@ -0,0 +1,130 @@
+extern crate array_tool;
+
+#[test]
+fn it_squeezes_characters() {
+ use array_tool::string::Squeeze;
+
+ assert_eq!("yellow moon".squeeze(""), "yelow mon");
+ assert_eq!(" now is the".squeeze(" "), " now is the");
+ assert_eq!("ééé".squeeze(""), "é");
+ assert_eq!(" /// aa".squeeze("/"), " / aa");
+
+ let string: String = format!("yellow moon");
+ assert_eq!(string.squeeze(""), "yelow mon");
+
+ assert_eq!("".squeeze(""), "");
+}
+
+#[test]
+fn it_iterates_over_every_grapheme_character() {
+ use array_tool::string::ToGraphemeBytesIter;
+
+ let temp = "a s—d féZ";
+ let mut giter = temp.grapheme_bytes_iter();
+
+ assert_eq!(giter.next().unwrap(), "a".as_bytes());
+ assert_eq!(giter.next().unwrap(), " ".as_bytes());
+ assert_eq!(giter.next().unwrap(), "s".as_bytes());
+ assert_eq!(giter.next().unwrap(), "—".as_bytes());
+ assert_eq!(giter.next().unwrap(), "d".as_bytes());
+ assert_eq!(giter.next().unwrap(), " ".as_bytes());
+ assert_eq!(giter.next().unwrap(), "f".as_bytes());
+ assert_eq!(giter.next().unwrap(), "é".as_bytes());
+ assert_eq!(giter.next().unwrap(), "Z".as_bytes());
+ assert_eq!(giter.next(), None);
+
+ let somestring2 = format!("{}", "a s—d féZ");
+ let mut giter2 = somestring2.grapheme_bytes_iter();
+
+ assert_eq!(giter2.next().unwrap(), "a".as_bytes());
+ assert_eq!(giter2.next().unwrap(), " ".as_bytes());
+ assert_eq!(giter2.next().unwrap(), "s".as_bytes());
+ assert_eq!(giter2.next().unwrap(), "—".as_bytes());
+ assert_eq!(giter2.next().unwrap(), "d".as_bytes());
+ assert_eq!(giter2.next().unwrap(), " ".as_bytes());
+ assert_eq!(giter2.next().unwrap(), "f".as_bytes());
+ assert_eq!(giter2.next().unwrap(), "é".as_bytes());
+ assert_eq!(giter2.next().unwrap(), "Z".as_bytes());
+ assert_eq!(giter2.next(), None);
+
+ assert_eq!("".grapheme_bytes_iter().next(), None);
+}
+
+#[test]
+fn it_justifies_one_line_in_for_string() {
+ use array_tool::string::Justify;
+
+ assert_eq!("asd asdf asd".justify_line(14), "asd asdf asd");
+ assert_eq!("asd asdf asd".justify_line(16), "asd asdf asd");
+ assert_eq!("asd as df asd".justify_line(16), "asd as df asd");
+ assert_eq!("asd as df asd".justify_line(18), "asd as df asd");
+ assert_eq!(" asd as df asd ".justify_line(16), "asd as df asd");
+ assert_eq!("asdasdfasd".justify_line(16), "asdasdfasd");
+ assert_eq!("asdasdfasd".justify_line(6), "asdasdfasd");
+ assert_eq!("é é".justify_line(5), "é é");
+ assert_eq!("a s—d féZ".justify_line(12), "a s—d féZ");
+
+ assert_eq!("".justify_line(14), "");
+}
+
+#[test]
+fn it_substitutes_character_at_each_indexed_point() {
+ use array_tool::string::SubstMarks;
+
+ assert_eq!("asdf asdf asdf".subst_marks(vec![0,5,8], "Z"), "Zsdf ZsdZ asdf");
+ assert_eq!("asdf asdf asdf".subst_marks(vec![8,5,0], "Z"), "Zsdf ZsdZ asdf");
+ assert_eq!("asdf asdf asdf".subst_marks(vec![0,5,8], "\n"), "\nsdf \nsd\n asdf");
+ assert_eq!("ééé".subst_marks(vec![1], "Z"), "éZé");
+ assert_eq!("ééé".subst_marks(vec![1,2], "Z"), "éZZ");
+ assert_eq!("ZZZ".subst_marks(vec![0,2], "é" ), "éZé");
+ assert_eq!("ééé".subst_marks(vec![0], "Z"), "Zéé");
+
+ assert_eq!("".subst_marks(vec![0], "Z"), "");
+}
+
+#[test]
+fn it_seeks_end_of_whitespace_after_offset() {
+ use array_tool::string::AfterWhitespace;
+
+ assert_eq!("asdf asdf asdf".seek_end_of_whitespace(6), Some(9));
+ assert_eq!("asdf".seek_end_of_whitespace(3), Some(0));
+ assert_eq!("asdf ".seek_end_of_whitespace(6), None);
+ assert_eq!("asdf".seek_end_of_whitespace(6), None);
+
+ assert_eq!("".seek_end_of_whitespace(6), None);
+}
+
+#[test]
+fn it_word_wraps_for_string() {
+ use array_tool::string::WordWrap;
+
+ assert_eq!(
+ "01234 67 9 BC EFG IJ".word_wrap(6),
+ "01234\n67 9\nBC EFG\nIJ"
+ );
+
+ assert_eq!(
+ "0123456789ABC EFG IJ".word_wrap(6),
+ "0123456789ABC\nEFG IJ"
+ );
+ assert_eq!(
+ "1234\n 1234 6789 1234".word_wrap(10),
+ "1234\n 1234 6789\n1234"
+ );
+ assert_eq!(
+ "1234\n 1234 67 90 1234".word_wrap(10),
+ "1234\n 1234 67\n90 1234"
+ );
+ assert_eq!(
+ "1234\n 1234 67 90A 1234".word_wrap(10),
+ "1234\n 1234 67\n90A 1234"
+ );
+ assert_eq!("1 \n34 ".word_wrap(3), "1 \n34 ");
+ assert_eq!("1 34".word_wrap(3), "1 \n34");
+ assert_eq!("\n \n \n \n".word_wrap(1), "\n \n \n \n" );
+
+ // White space to new line shouldn't add new lines. Use seek ahead.
+ assert_eq!("\nAA\nA \nA \n".word_wrap(1), "\nAA\nA \nA \n" );
+ assert_eq!("\n \n \n \n ".word_wrap(1), "\n \n \n \n " );
+}
+
diff --git a/vendor/array_tool/tests/vec.rs b/vendor/array_tool/tests/vec.rs
new file mode 100644
index 000000000..8d21ceb23
--- /dev/null
+++ b/vendor/array_tool/tests/vec.rs
@@ -0,0 +1,111 @@
+extern crate array_tool;
+
+#[test]
+fn it_implements_individual_uniq_on_vec() {
+ use array_tool::vec::Uniq;
+ assert_eq!(vec![1,2,3,4,5,6].uniq(vec![1,2,5,7,9]),vec![3,4,6]);
+ assert_eq!(vec![1,2,3,1,3,2,1,3,1,2,3,1,2,3,3,1,2,3,3,1,2,3,1,2,3,3,4,1,5,4,6].uniq(vec![3,5]),
+ vec![1,2,4,6]
+ );
+}
+
+#[test]
+fn it_can_return_its_own_unique() {
+ use array_tool::vec::Uniq;
+ assert_eq!(vec![1,2,1,3,4,3,4,5,6].unique(),vec![1,2,3,4,5,6]);
+ assert_eq!(vec![1,2,3,1,3,2,1,3,1,2,3,1,2,3,3,1,2,3,3,1,2,3,1,2,3,3,4,1,5,4,6].unique(),
+ vec![1,2,3,4,5,6]
+ );
+}
+
+#[test]
+fn it_answers_about_uniqueness() {
+ use array_tool::vec::Uniq;
+ assert_eq!(vec![1,2,1,3,4,3,4,5,6].is_unique(), false);
+ assert_eq!(vec![1,2,3,4,5,6].is_unique(), true);
+}
+
+#[test]
+fn it_implements_individual_uniq_on_vec_via() {
+ use array_tool::vec::Uniq;
+ assert_eq!(vec![1.1,2.6,3.7,4.7,5.4,6.6].uniq_via(vec![1.5,2.7,5.0,7.1,9.4], |l: &f64, r: &f64| l.floor() == r.floor()),vec![3.7,4.7,6.6]);
+ assert_eq!(vec![1.2,2.5,3.4,1.2,3.8,2.9,1.0,3.2,1.2,2.5,3.7,1.7,2.9,3.1,3.5,1.6,2.7,3.9,3.1,1.5,2.6,3.8,1.2,2.6,3.7,3.8,4.9,1.0,5.1,4.4,6.6]
+ .uniq_via(vec![3.5,5.1], |l: &f64, r: &f64| l.floor() == r.floor()),
+ vec![1.2,2.5,2.9,1.0,1.7,1.6,2.7,1.5,2.6,4.9,4.4, 6.6]
+ );
+}
+
+#[test]
+fn it_can_return_its_own_unique_via() {
+ use array_tool::vec::Uniq;
+ assert_eq!(vec![1.2,2.5,1.4,3.2,4.8,3.9,4.0,5.2,6.2].unique_via(|l: &f64, r: &f64| l.floor() == r.floor()),vec![1.2,2.5,3.2,4.8,5.2,6.2]);
+ assert_eq!(vec![1.2,2.5,3.4,1.2,3.8,2.9,1.0,3.2,1.2,2.5,3.7,1.7,2.9,3.1,3.5,1.6,2.7,3.9,3.1,1.5,2.6,3.8,1.2,2.6,3.7,3.8,4.9,1.0,5.1,4.4,6.6]
+ .unique_via(|l: &f64, r: &f64| l.floor() == r.floor()),
+ vec![1.2,2.5,3.4,4.9,5.1,6.6]
+ );
+}
+
+#[test]
+fn it_answers_about_uniqueness_via() {
+ use array_tool::vec::Uniq;
+ assert_eq!(vec![1.2,2.4,1.5,3.6,4.1,3.5,4.7,5.9,6.5].is_unique_via(|l: &f64, r: &f64| l.floor() == r.floor()), false);
+ assert_eq!(vec![1.2,2.4,3.5,4.6,5.1,6.5].is_unique_via(|l: &f64, r: &f64| l.floor() == r.floor()), true);
+}
+
+#[test]
+fn it_shifts() {
+ use array_tool::vec::Shift;
+ let mut x = vec![1,2,3];
+ x.unshift(0);
+ assert_eq!(x, vec![0,1,2,3]);
+ assert_eq!(x.shift(), Some(0));
+ assert_eq!(x, vec![1,2,3]);
+}
+
+#[test]
+fn it_handles_empty_shift() {
+ use array_tool::vec::Shift;
+ let mut x: Vec<u8> = vec![];
+ assert_eq!(x.shift(), None);
+}
+
+#[test]
+fn it_intersects() {
+ use array_tool::vec::Intersect;
+ assert_eq!(vec![1,1,3,5].intersect(vec![1,2,3]), vec![1,3])
+}
+
+#[allow(unused_imports)]
+#[test]
+fn it_intersects_if() {
+ use array_tool::vec::Intersect;
+ use std::ascii::AsciiExt;
+ assert_eq!(vec!['a','a','c','e'].intersect_if(vec!['A','B','C'], |l, r| l.eq_ignore_ascii_case(r)), vec!['a','c']);
+}
+
+#[test]
+fn it_multiplies(){
+ use array_tool::vec::Times;
+ assert_eq!(vec![1,2,3].times(3), vec![1,2,3,1,2,3,1,2,3]);
+
+ // Empty collection
+ let vec1: Vec<i32> = Vec::new();
+ let vec2: Vec<i32> = Vec::new();
+ assert_eq!(vec1.times(4), vec2)
+}
+
+#[test]
+fn it_joins(){
+ use array_tool::vec::Join;
+ assert_eq!(vec![1,2,3].join(","), "1,2,3")
+}
+
+#[test]
+fn it_creates_union() {
+ use array_tool::vec::Union;
+ assert_eq!(vec!["a","b","c"].union(vec!["c","d","a"]), vec![ "a", "b", "c", "d" ]);
+ assert_eq!(vec![1,2,3,1,3,2,1,3,1,2,3,1,2,3,3,1,2,3,3,1,2,3,1,2,3,3,4,1,4,6].union(vec![3,5,7,8,0]),
+ vec![1,2,3,4,6,5,7,8,0]
+ );
+}
+