From fcf882991c2de0b456e58f20259d88f1c71ec048 Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Thu, 24 Mar 2022 23:16:17 -0400 Subject: [PATCH] Complete set 1 challenge 1. --- src/main.rs | 18 ++++++++++++--- src/set1.rs | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index a70d659..2017116 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,20 @@ mod set1; -use crate::set1::convert_hex_to_base64; +use crate::set1::{base64_to_string, bytes_to_base64, to_bytes}; + +fn test_set1() { + let input = to_bytes("49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d"); + let expected = String::from("SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t"); + match input { + Ok(bytes) => { + let output = base64_to_string(bytes_to_base64(bytes)); + assert_eq!(output, expected); + println!("{:?}", output); + } + Err(e) => println!("Error: {:?}", e), + }; +} fn main() { - println!("Hello, world! Does it work?"); - convert_hex_to_base64(); + test_set1(); } diff --git a/src/set1.rs b/src/set1.rs index 9e63ab5..1112a96 100644 --- a/src/set1.rs +++ b/src/set1.rs @@ -1,3 +1,65 @@ -pub fn convert_hex_to_base64() { - println!("We are here too."); +use std::num::ParseIntError; +use std::str; + +pub fn to_bytes(s: &str) -> Result, String> { + if s.len() % 2 != 0 { + return Err(String::from("Input string has uneven number of characters")); + } + + let bytes_result: Result, ParseIntError> = (0..s.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&s[i..i + 2], 16)) + .collect(); + + match bytes_result { + Ok(b) => Ok(b), + Err(_) => Err(String::from("Could not convert all digit pairs to hex.")), + } +} + +fn chunk_to_base64(c: &[u8]) -> Vec { + let (value, iterations) = match c.len() { + 0 => return vec![], + 1 => ((c[0] as u32) << 16, 2), + 2 => ((c[0] as u32) << 16 | (c[1] as u32) << 8, 3), + 3 => ((c[0] as u32) << 16 | (c[1] as u32) << 8 | (c[2] as u32), 4), + _ => panic!("Unexpected number of chunks {}.", c.len()), + }; + (0..iterations) + .map(|i| (value.rotate_right((3 - i) * 6) & 0b111111) as u8) + .collect() +} + +pub fn bytes_to_base64(bytes: Vec) -> Vec { + bytes + .chunks(3) + .map(|c| chunk_to_base64(c)) + .flatten() + .collect() +} + +pub fn base64_to_string(digits: Vec) -> String { + let mut r: Vec = digits + .iter() + .map(|d| match d { + 0..=25 => *d + ('A' as u8), + 26..=51 => *d - 26 + ('a' as u8), + 52..=61 => *d - 52 + ('0' as u8), + 62 => '+' as u8, + 63 => '/' as u8, + _ => panic!("Unexpected base64 digit '{}'", d), + }) + .collect(); + // Handle padding + let pad = '=' as u8; + match r.len() % 4 { + 0 => (), + 2 => { + r.push(pad); + r.push(pad); + } + 3 => r.push(pad), + _ => (), + } + str::from_utf8(r.as_slice()).unwrap().to_string() }