use crate::error::BinTxtError;
pub trait BinaryText {
fn base(&self) -> usize;
fn name(&self) -> &str;
fn n_bytes_encode(&self) -> usize;
fn n_bytes_decode(&self) -> usize;
fn encode_byte(&self, byte: u8) -> Result<u8, BinTxtError>;
fn encode_into_vec(&self, input: &[u8], res: &mut Vec<u8>) -> Result<(), BinTxtError>;
fn encode_and_return(&self, input: &[u8]) -> Result<Vec<u8>, BinTxtError> {
let len_enc = input.len() * self.n_bytes_decode() / self.n_bytes_encode();
let mut ret = Vec::<u8>::with_capacity(len_enc);
self.encode_into_vec(input, &mut ret)?;
Ok(ret)
}
fn decode_byte(&self, byte: u8) -> Result<u8, BinTxtError>;
fn decode_into_vec(&self, input: &[u8], res: &mut Vec<u8>) -> Result<(), BinTxtError>;
fn decode_and_return(&self, input: &[u8]) -> Result<Vec<u8>, BinTxtError> {
let len_dec = input.len() * self.n_bytes_encode() / self.n_bytes_decode();
let mut ret = Vec::<u8>::with_capacity(len_dec);
self.decode_into_vec(input, &mut ret)?;
Ok(ret)
}
fn is_decodable(&self, input: &str) -> bool;
fn encode_from_str(&self, input: &str) -> Result<String, BinTxtError> {
let bytes = self.encode_and_return(input.as_bytes())?;
match String::from_utf8(bytes) {
Ok(s) => Ok(s),
Err(_) => Err(BinTxtError::EncodingErr(
"Error converting to UTF-8 string".to_string(),
)),
}
}
fn decode_from_str(&self, input: &str) -> Result<String, BinTxtError> {
let bytes = self.decode_and_return(input.as_bytes())?;
match String::from_utf8(bytes) {
Ok(s) => Ok(s),
Err(_) => Err(BinTxtError::DecodingErr(
"Error converting to UTF-8 string".to_string(),
)),
}
}
fn encode_u128(&self, int: u128) -> Result<String, BinTxtError> {
let base = self.base() as u128;
let mut test = int;
let mut n = 0usize;
while test > 0 {
test /= base;
n += 1;
}
test = int;
let mut div = 1;
for _i in 1..n {
div *= base;
}
let mut ret = vec!['0'; n];
for r in ret.iter_mut() {
let byte = test / div;
let enc = self.encode_byte(byte as u8)?;
*r = enc as char;
test -= byte * div;
div /= base;
}
Ok(String::from_iter(ret))
}
fn encode_u64(&self, int: u64) -> Result<String, BinTxtError> {
self.encode_u128(int as u128)
}
fn decode_u128(&self, input: &[u8]) -> Result<u128, BinTxtError> {
let base = self.base() as u128;
let mut ret = 0;
let mut mul = 1;
for &b in input.iter().skip(1).rev() {
let dec = self.decode_byte(b)? as u128;
ret += dec * mul;
mul *= base;
}
if !input.is_empty() {
let dec = self.decode_byte(input[0])? as u128;
ret += dec * mul;
}
Ok(ret)
}
fn decode_u64(&self, input: &[u8]) -> Result<u64, BinTxtError> {
let res = self.decode_u128(input)?;
if res > u64::MAX as u128 {
return Err(BinTxtError::DecodingErr(
"Error decoding into u64".to_string(),
));
}
Ok(res as u64)
}
}
impl BinaryText for Box<dyn BinaryText> {
fn base(&self) -> usize {
(**self).base()
}
fn name(&self) -> &str {
(**self).name()
}
fn n_bytes_encode(&self) -> usize {
(**self).n_bytes_encode()
}
fn n_bytes_decode(&self) -> usize {
(**self).n_bytes_decode()
}
fn encode_byte(&self, byte: u8) -> Result<u8, BinTxtError> {
(**self).encode_byte(byte)
}
fn encode_into_vec(&self, input: &[u8], res: &mut Vec<u8>) -> Result<(), BinTxtError> {
(**self).encode_into_vec(input, res)
}
fn decode_byte(&self, byte: u8) -> Result<u8, BinTxtError> {
(**self).decode_byte(byte)
}
fn decode_into_vec(&self, input: &[u8], res: &mut Vec<u8>) -> Result<(), BinTxtError> {
(**self).decode_into_vec(input, res)
}
fn is_decodable(&self, input: &str) -> bool {
(**self).is_decodable(input)
}
}
pub(crate) fn build_decoding_lut(lut_enc: &[u8]) -> [u8; 128] {
let mut ret = [255u8; 128];
for (ind, &b) in lut_enc.iter().enumerate() {
ret[b as usize] = ind as u8;
}
ret
}