diff options
Diffstat (limited to 'vendor/array_tool/src')
-rw-r--r-- | vendor/array_tool/src/iter.rs | 166 | ||||
-rw-r--r-- | vendor/array_tool/src/lib.rs | 58 | ||||
-rw-r--r-- | vendor/array_tool/src/string.rs | 303 | ||||
-rw-r--r-- | vendor/array_tool/src/vec.rs | 318 |
4 files changed, 845 insertions, 0 deletions
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() + } +} |