use base64::prelude::*;
use super::error::Error;
pub fn from_text_to_bytes(text: &str) -> Result<Vec<u8>, Error> {
let lead_size = (4 - (text.len() % 4)) % 4;
let full_derivative = [&"A".repeat(lead_size), text].concat();
Ok(BASE64_URL_SAFE.decode(full_derivative)?.to_vec())
}
pub fn from_bytes_to_text(bytes: &[u8]) -> String {
let lead_size = (3 - (bytes.len() % 3)) % 3;
let full_derivative: Vec<_> = std::iter::repeat_n(0, lead_size)
.chain(bytes.iter().copied())
.collect();
BASE64_URL_SAFE.encode(full_derivative)
}
pub fn b64_to_num(b64: &str) -> Result<u16, Error> {
let slice = from_text_to_bytes(b64)?;
let len = slice.len();
Ok(u16::from_be_bytes(match len {
0 => [0u8; 2],
1 => [0, slice[0]],
_ => [slice[len - 2], slice[len - 1]],
}))
}
pub fn num_to_b64(num: u16) -> String {
let b64 = from_bytes_to_text(num.to_be_bytes().as_ref());
if num < 64 {
b64[3..].to_string()
} else if num < 4096 {
b64[2..].to_string()
} else {
todo!()
}
}
pub fn adjust_with_num(sn: u16, expected_length: usize) -> String {
if expected_length > 0 {
let i = num_to_b64(sn);
if i.len() < expected_length {
let missing_part = "A".repeat(expected_length - i.len());
[missing_part, i].join("")
} else {
[i].join("")
}
} else {
"".to_string()
}
}
pub fn check_first_three_bits(byte: &u8) -> u8 {
(byte >> 5) & 0b111 }
#[test]
fn num_to_b64_test() {
assert_eq!("A", num_to_b64(0));
assert_eq!("B", num_to_b64(1));
assert_eq!("C", num_to_b64(2));
assert_eq!("D", num_to_b64(3));
assert_eq!("b", num_to_b64(27));
assert_eq!("BQ", num_to_b64(80));
assert_eq!("__", num_to_b64(4095));
}
#[test]
fn b64_to_num_test() {
assert_eq!(b64_to_num("AAAA").unwrap(), 0);
assert_eq!(b64_to_num("A").unwrap(), 0);
assert_eq!(b64_to_num("B").unwrap(), 1);
assert_eq!(b64_to_num("C").unwrap(), 2);
assert_eq!(b64_to_num("D").unwrap(), 3);
assert_eq!(b64_to_num("b").unwrap(), 27);
assert_eq!(b64_to_num("BQ").unwrap(), 80);
assert_eq!(b64_to_num("__").unwrap(), 4095);
}
#[test]
fn test_from_text_to_bytes() {
assert_eq!(hex::encode(from_text_to_bytes("MP__").unwrap()), "30ffff");
assert_eq!(hex::encode(from_text_to_bytes("MAAA").unwrap()), "300000");
assert_eq!(hex::encode(from_text_to_bytes("MAAB").unwrap()), "300001");
}
#[test]
fn test_from_bytes_to_text() {
let b_bytes = from_text_to_bytes("B").unwrap();
assert_eq!("AAAB", from_bytes_to_text(&b_bytes));
assert_eq!(
from_bytes_to_text(&hex::decode("300000").unwrap()),
"MAAA".to_string()
);
assert_eq!(
from_bytes_to_text(&hex::decode("300001").unwrap()),
"MAAB".to_string()
);
assert_eq!(
from_bytes_to_text(&hex::decode("30ffff").unwrap()),
"MP__".to_string()
);
}
#[test]
fn test_adjust_with_num() {
assert_eq!(adjust_with_num(2, 4), "AAAC");
assert_eq!(adjust_with_num(27, 6), "AAAAAb");
}