pub fn ascii_bytes(input: &[u8]) -> ByteIterator {
ByteIterator {
input: input.to_vec(),
pos: 0,
bit: 0,
max: 7,
}
}
pub fn ascii_str(input: &str) -> StringIterator {
StringIterator(ascii_bytes(input.as_bytes()))
}
pub fn bytes(input: &[u8]) -> ByteIterator {
ByteIterator {
input: input.to_vec(),
pos: 0,
bit: 0,
max: 8,
}
}
pub fn utf8(input: &str) -> StringIterator {
StringIterator(bytes(input.as_bytes()))
}
#[derive(Clone, Debug)]
pub struct ByteIterator {
input: Vec<u8>,
pos: usize,
bit: usize,
max: usize,
}
impl Iterator for ByteIterator {
type Item = Vec<u8>;
fn next(&mut self) -> Option<Self::Item> {
if self.pos >= self.input.len() {
None
} else {
let mut output = self.input.clone();
output[self.pos] ^= 1 << self.bit;
self.bit += 1;
if self.bit >= self.max {
self.pos += 1;
self.bit = 0;
}
Some(output)
}
}
}
#[derive(Clone, Debug)]
pub struct StringIterator(ByteIterator);
impl Iterator for StringIterator {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
for next in self.0.by_ref() {
if let Ok(s) = String::from_utf8(next) {
return Some(s);
}
}
None
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeSet;
macro_rules! test_bytes {
($fn:ident, $input:expr, $expected:expr,) => {
let results: BTreeSet<Vec<u8>> = $fn($input).collect();
let expected: BTreeSet<Vec<u8>> =
$expected.into_iter().map(|bstr| bstr.to_vec()).collect();
assert_eq!(results, expected);
};
($fn:ident, $input:expr, $expected:expr) => {
test_bytes!($fn, $input, $expected,)
};
}
macro_rules! test_string {
($fn:ident, $input:expr, $expected:expr,) => {
let results: BTreeSet<String> = $fn($input).collect();
let expected: BTreeSet<String> = $expected.into_iter().map(String::from).collect();
assert_eq!(results, expected);
};
($fn:ident, $input:expr, $expected:expr) => {
test_string!($fn, $input, $expected,)
};
}
#[test]
fn test_ascii_bytes() {
test_bytes!(
ascii_bytes,
b"abc",
[
b"!bc", b"Abc", b"qbc", b"ibc", b"ebc", b"cbc", b"`bc", b"a\"c", b"aBc", b"arc",
b"ajc", b"afc", b"a`c", b"acc", b"ab#", b"abC", b"abs", b"abk", b"abg", b"aba",
b"abb",
],
);
}
#[test]
fn test_bytes() {
test_bytes!(
bytes,
b"abc",
[
b"!bc", b"Abc", b"qbc", b"ibc", b"ebc", b"cbc", b"`bc", b"a\"c", b"aBc", b"arc",
b"ajc", b"afc", b"a`c", b"acc", b"ab#", b"abC", b"abs", b"abk", b"abg", b"aba",
b"abb", b"\xe1bc", b"a\xe2c", b"ab\xe3",
]
);
}
#[test]
fn test_ascii_str() {
test_string!(
ascii_str,
"abc",
[
"!bc", "Abc", "qbc", "ibc", "ebc", "cbc", "`bc", "a\"c", "aBc", "arc", "ajc",
"afc", "a`c", "acc", "ab#", "abC", "abs", "abk", "abg", "aba", "abb",
]
);
}
#[test]
fn test_utf8() {
test_string!(
utf8,
"abc",
[
"!bc", "Abc", "qbc", "ibc", "ebc", "cbc", "`bc", "a\"c", "aBc", "arc", "ajc",
"afc", "a`c", "acc", "ab#", "abC", "abs", "abk", "abg", "aba", "abb",
]
);
}
}