use std::string::FromUtf8Error;
trait Pam {
fn to_pam(&self) -> Vec<u8>;
fn from_pam(pam: Vec<u8>) -> Result<String, FromUtf8Error>;
}
impl Pam for String {
fn to_pam(&self) -> Vec<u8> {
let bytes = self.as_bytes();
let mut result_vec: Vec<u8> = Vec::with_capacity(bytes.len() * 4);
for byte in bytes {
println!("0x{:08b}", byte);
for i in 0..=3 {
let downshifted = byte >> (3 - i) * 2;
let masked = downshifted & 0b00000011;
result_vec.push(masked);
}
}
println!("vec: {:?}", result_vec);
return result_vec;
}
fn from_pam(pam: Vec<u8>) -> Result<String, FromUtf8Error> {
let len = pam.len() / 4;
let mut bytes: Vec<u8> = Vec::with_capacity(len);
for i in 0..len {
let mut byte: u8 = 0b00000000;
for j in 0..=3 {
byte |= pam[i * 4 + j] << 2 * (3 - j);
}
bytes.push(byte);
}
return String::from_utf8(bytes);
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_utf_8_size() {
let s: String = "hello €".to_string();
assert_eq!(s.len(), 9);
}
#[test]
fn string_to_pam() {
let s: String = "not a planet".to_string();
let pam = s.to_pam();
let correct_pam = [
1, 2, 3, 2, 1, 2, 3, 3, 1, 3, 1, 0, 0, 2, 0, 0, 1, 2, 0, 1, 0, 2, 0, 0, 1, 3, 0, 0, 1,
2, 3, 0, 1, 2, 0, 1, 1, 2, 3, 2, 1, 2, 1, 1, 1, 3, 1, 0,
];
assert_eq!(pam, correct_pam);
}
#[test]
fn pam_to_string() {
let pam = vec![
1, 2, 3, 3, 1, 3, 0, 2, 0, 2, 0, 0, 1, 2, 2, 1, 1, 3, 0, 3, 0, 2, 0, 0, 1, 2, 2, 1, 1,
3, 1, 0, 0, 3, 3, 3,
];
let s = String::from_pam(pam);
let correct_s = "or is it?".to_string();
assert_eq!(s.unwrap(), correct_s);
}
#[test]
fn str_to_pam_to_str() {
let s = "The quick brown fox jumps over the lazy dog 0123456789!@#$%^&*()€\n\r".to_string();
let p = s.to_pam();
let reconst = String::from_pam(p).unwrap();
assert_eq!(s, reconst);
}
}