1use std::string::FromUtf8Error;
5
6trait Pam {
8 fn to_pam(&self) -> Vec<u8>;
9 fn from_pam(pam: Vec<u8>) -> Result<String, FromUtf8Error>;
10}
11
12impl Pam for String {
13 fn to_pam(&self) -> Vec<u8> {
16 let bytes = self.as_bytes();
17 let mut result_vec: Vec<u8> = Vec::with_capacity(bytes.len() * 4);
18
19 for byte in bytes {
20 println!("0x{:08b}", byte);
21 for i in 0..=3 {
22 let downshifted = byte >> (3 - i) * 2;
23 let masked = downshifted & 0b00000011;
24 result_vec.push(masked);
25 }
26 }
27
28 println!("vec: {:?}", result_vec);
29 return result_vec;
30 }
31
32 fn from_pam(pam: Vec<u8>) -> Result<String, FromUtf8Error> {
33 let len = pam.len() / 4;
35 let mut bytes: Vec<u8> = Vec::with_capacity(len);
37
38 for i in 0..len {
39 let mut byte: u8 = 0b00000000;
41 for j in 0..=3 {
42 byte |= pam[i * 4 + j] << 2 * (3 - j);
43 }
44 bytes.push(byte);
45 }
46 return String::from_utf8(bytes);
47 }
48}
49
50#[cfg(test)]
51mod test {
52 use super::*;
53
54 #[test]
55 fn test_utf_8_size() {
56 let s: String = "hello €".to_string();
58 assert_eq!(s.len(), 9);
59 }
60
61 #[test]
62 fn string_to_pam() {
63 let s: String = "not a planet".to_string();
64 let pam = s.to_pam();
65
66 let correct_pam = [
67 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,
68 2, 3, 0, 1, 2, 0, 1, 1, 2, 3, 2, 1, 2, 1, 1, 1, 3, 1, 0,
69 ];
70 assert_eq!(pam, correct_pam);
71 }
72
73 #[test]
74 fn pam_to_string() {
75 let pam = vec![
76 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,
77 3, 1, 0, 0, 3, 3, 3,
78 ];
79 let s = String::from_pam(pam);
80 let correct_s = "or is it?".to_string();
81 assert_eq!(s.unwrap(), correct_s);
82 }
83
84 #[test]
85 fn str_to_pam_to_str() {
86 let s = "The quick brown fox jumps over the lazy dog 0123456789!@#$%^&*()€\n\r".to_string();
89 let p = s.to_pam();
90
91 let reconst = String::from_pam(p).unwrap();
92 assert_eq!(s, reconst);
93 }
94}