use crate::binarytext::{BinaryText, build_decoding_lut};
use crate::error::BinTxtError;
#[derive(Clone, Debug)]
pub struct IntEncoder {
name: String,
lut_enc: Vec<u8>,
lut_dec: [u8; 128],
}
impl IntEncoder {
pub fn base36() -> Self {
let name = "Base36".to_string();
let lut_enc = vec![
b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D',
b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R',
b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z',
];
let lut_dec = build_decoding_lut(&lut_enc);
Self {
name,
lut_enc,
lut_dec,
}
}
pub fn base56() -> Self {
let name = "Base56".to_string();
let lut_enc = vec![
b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E', b'F',
b'G', b'H', b'J', b'K', b'L', b'M', b'N', b'P', b'Q', b'R', b'S', b'T', b'U', b'V',
b'W', b'X', b'Y', b'Z', b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j',
b'k', b'm', b'n', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z',
];
let lut_dec = build_decoding_lut(&lut_enc);
Self {
name,
lut_enc,
lut_dec,
}
}
pub fn base58() -> Self {
let name = "Base58".to_string();
let lut_enc = vec![
b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E',
b'F', b'G', b'H', b'J', b'K', b'L', b'M', b'N', b'P', b'Q', b'R', b'S', b'T', b'U',
b'V', b'W', b'X', b'Y', b'Z', b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i',
b'j', b'k', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x',
b'y', b'z',
];
let lut_dec = build_decoding_lut(&lut_enc);
Self {
name,
lut_enc,
lut_dec,
}
}
pub fn base62() -> Self {
let name = "Base62".to_string();
let lut_enc = vec![
b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D',
b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R',
b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'a', b'b', b'c', b'd', b'e', b'f',
b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't',
b'u', b'v', b'w', b'x', b'y', b'z',
];
let lut_dec = build_decoding_lut(&lut_enc);
Self {
name,
lut_enc,
lut_dec,
}
}
}
impl BinaryText for IntEncoder {
fn base(&self) -> usize {
self.lut_enc.len()
}
fn name(&self) -> &str {
self.name.as_str()
}
fn n_bytes_encode(&self) -> usize {
1
}
fn n_bytes_decode(&self) -> usize {
1
}
fn encode_byte(&self, byte: u8) -> Result<u8, BinTxtError> {
let max = self.base() as u8;
if byte >= max {
let msg = format!("Byte {byte} exceeds maximum {}", 62);
return Err(BinTxtError::EncodingErr(msg));
}
Ok(self.lut_enc[byte as usize])
}
fn encode_into_vec(&self, input: &[u8], res: &mut Vec<u8>) -> Result<(), BinTxtError> {
if input.len() > 16 {
let msg = "Unable to encode more than 16 bytes with IntEncoder".to_string();
return Err(BinTxtError::EncodingErr(msg));
}
let mut int = 0u128;
for (ind, &byte) in input.iter().rev().enumerate() {
int += (byte as u128) << (ind * 8);
}
let enc = self.encode_u128(int)?;
res.clear();
for b in enc.bytes() {
res.push(b);
}
Ok(())
}
fn decode_byte(&self, byte: u8) -> Result<u8, BinTxtError> {
let b = if byte < 128 {
self.lut_dec[byte as usize]
} else {
255
};
if b < 255 {
Ok(b)
} else {
let errmsg = format!("Invalid byte \"{}\" in {} string", byte, self.name());
Err(BinTxtError::DecodingErr(errmsg))
}
}
fn decode_into_vec(&self, input: &[u8], res: &mut Vec<u8>) -> Result<(), BinTxtError> {
res.clear();
let int = self.decode_u128(input)?;
let mut start = false;
for ind_byte in (0..16).rev() {
let tmp = (int >> (ind_byte * 8)) as u8;
if tmp > 0 {
start = true;
}
if start {
res.push(tmp);
}
}
Ok(())
}
fn is_decodable(&self, input: &str) -> bool {
for &byte in input.as_bytes() {
match self.decode_byte(byte) {
Ok(_) => {}
Err(_) => {
return false;
}
}
}
true
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_alphabet() {
let base56 = IntEncoder::base56();
for &e in base56.lut_enc.iter() {
let pos = e as usize;
assert!(base56.lut_dec[pos] != 255);
}
let base58 = IntEncoder::base58();
for &e in base58.lut_enc.iter() {
let pos = e as usize;
assert!(base58.lut_dec[pos] != 255);
}
let base62 = IntEncoder::base62();
for &e in base62.lut_enc.iter() {
let pos = e as usize;
assert!(base62.lut_dec[pos] != 255);
}
}
}