1use crate::alphabet::Alphabet;
2use num_traits::Zero;
3
4#[derive(Debug, PartialEq, Eq)]
6pub enum DecodeError {
7 InvalidCharacter(char),
9 EmptyInput,
11 InvalidPadding,
13}
14
15impl std::fmt::Display for DecodeError {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 match self {
18 DecodeError::InvalidCharacter(c) => write!(f, "Invalid character in input: {}", c),
19 DecodeError::EmptyInput => write!(f, "Cannot decode empty input"),
20 DecodeError::InvalidPadding => write!(f, "Invalid padding"),
21 }
22 }
23}
24
25impl std::error::Error for DecodeError {}
26
27pub fn encode(data: &[u8], alphabet: &Alphabet) -> String {
28 if data.is_empty() {
29 return String::new();
30 }
31
32 let leading_zeros = data.iter().take_while(|&&b| b == 0).count();
34
35 if leading_zeros == data.len() {
37 return alphabet.encode_digit(0).unwrap().to_string().repeat(data.len());
38 }
39
40 let base = alphabet.base();
41 let mut num = num_bigint::BigUint::from_bytes_be(&data[leading_zeros..]);
42 let mut result = Vec::new();
43 let base_big = num_bigint::BigUint::from(base);
44
45 while !num.is_zero() {
46 let remainder = &num % &base_big;
47 let digit = remainder.to_u64_digits();
48 let digit_val = if digit.is_empty() { 0 } else { digit[0] as usize };
49 result.push(alphabet.encode_digit(digit_val).unwrap());
50 num /= &base_big;
51 }
52
53 for _ in 0..leading_zeros {
55 result.push(alphabet.encode_digit(0).unwrap());
56 }
57
58 result.reverse();
59 result.into_iter().collect()
60}
61
62pub fn decode(encoded: &str, alphabet: &Alphabet) -> Result<Vec<u8>, DecodeError> {
63 if encoded.is_empty() {
64 return Err(DecodeError::EmptyInput);
65 }
66
67 let base = alphabet.base();
68 let mut num = num_bigint::BigUint::from(0u8);
69 let base_big = num_bigint::BigUint::from(base);
70
71 let chars: Vec<char> = encoded.chars().collect();
72 let mut leading_zeros = 0;
73
74 for &c in &chars {
75 let digit = alphabet.decode_char(c)
76 .ok_or(DecodeError::InvalidCharacter(c))?;
77
78 if num.is_zero() && digit == 0 {
79 leading_zeros += 1;
80 } else {
81 num = num * &base_big + num_bigint::BigUint::from(digit);
82 }
83 }
84
85 let bytes = num.to_bytes_be();
86
87 if num.is_zero() && leading_zeros > 0 {
88 return Ok(vec![0u8; leading_zeros]);
89 }
90
91 let mut result = vec![0u8; leading_zeros];
93 result.extend_from_slice(&bytes);
94
95 Ok(result)
96}