Use HexBytes traits for base64

This commit is contained in:
Eryn Wells 2018-03-25 18:50:45 -04:00
parent 2621f30830
commit af8c16dcc4
2 changed files with 106 additions and 29 deletions

View file

@ -1,13 +1,16 @@
use hex::{AsHexBytes, HexResult};
static B64: &'static str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+\\";
pub fn base64(hex: &str) -> Result<String, String> {
let mut out = String::from("");
let mut num_bits = 0;
let mut acc: u32 = 0;
for (idx, c) in hex.char_indices() {
if let Some(c_digit) = c.to_digit(16) {
for (idx, c) in hex.hex_bytes().enumerate() {
match c {
HexResult::Byte(c) => {
// Accumulate bytes until we have 6 chunks of 4.
acc = (acc << 4) + c_digit;
acc = (acc << 4) + (c as u32);
num_bits += 4;
if idx % 6 != 5 {
continue;
@ -25,8 +28,10 @@ pub fn base64(hex: &str) -> Result<String, String> {
}
acc = 0;
num_bits = 0;
} else {
},
HexResult::Invalid(c) => {
return Err(format!("Invalid input: {}", c));
},
}
}

View file

@ -1,3 +1,4 @@
use std::char;
use std::iter;
use std::str::Chars;
@ -6,17 +7,21 @@ pub enum HexResult {
Invalid(char),
}
pub struct HexDecoder<'a> {
pub struct HexBytes<'a> {
input: Chars<'a>,
}
impl<'a> HexDecoder<'a> {
fn new(input: &'a str) -> HexDecoder {
HexDecoder { input: input.chars() }
impl<'a> HexBytes<'a> {
fn new(input: &'a str) -> HexBytes {
HexBytes { input: input.chars() }
}
pub fn valid(self) -> ValidHexBytes<'a> {
ValidHexBytes::new(self)
}
}
impl<'a> iter::Iterator for HexDecoder<'a> {
impl<'a> iter::Iterator for HexBytes<'a> {
type Item = HexResult;
fn next(&mut self) -> Option<Self::Item> {
@ -32,14 +37,81 @@ impl<'a> iter::Iterator for HexDecoder<'a> {
}
}
/*
* ValidHexBytes --
*/
pub struct ValidHexBytes<'a> {
input: HexBytes<'a>,
}
impl<'a> ValidHexBytes<'a> {
fn new(input: HexBytes) -> ValidHexBytes {
ValidHexBytes { input: input }
}
}
impl<'a> iter::Iterator for ValidHexBytes<'a> {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.input.next() {
Some(hex_c) => match hex_c {
HexResult::Byte(c) => return Some(c),
_ => continue,
},
None => return None,
}
}
}
}
/*
* HexDigest --
*/
pub trait HexDigest {
fn hex_digest(self) -> String;
}
impl<'a> HexDigest for HexBytes<'a> {
fn hex_digest(self) -> String {
self.valid().hex_digest()
}
}
impl<'a> HexDigest for ValidHexBytes<'a> {
fn hex_digest(self) -> String {
self.map(|x| char::from_digit(x as u32, 16).unwrap()).collect()
}
}
impl HexDigest for Vec<u8> {
fn hex_digest(self) -> String {
self.into_iter().map(|x| char::from_digit(x as u32, 16).unwrap()).collect()
}
}
/*
* AsHexbytes --
*/
pub trait AsHexBytes<'a> {
fn hex_bytes(&self) -> HexBytes<'a>;
}
impl<'a> AsHexBytes<'a> for &'a str {
fn hex_bytes(&self) -> HexBytes<'a> { HexBytes::new(self) }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn simple() {
let decoder = HexDecoder::new("123");
let collected: Vec<u8> = decoder.map(|c| match c {
let collected: Vec<u8> = "123".hex_bytes().map(|c| match c {
HexResult::Byte(c) => c,
_ => panic!(),
}).collect();