1pub const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~_";
2
3#[inline]
4#[must_use]
5pub fn sized_encode<const S: usize>(input: &[u8]) -> [u8; S] {
6 let mut output = [b'='; S];
7 let mut index = 0;
8
9 let mut push = |byte: u8| {
10 if index < S {
11 output[index] = byte;
12 index += 1;
13 }
14 };
15
16 for chunk in input.chunks_exact(3) {
17 push(ALPHABET[(chunk[0] >> 2) as usize]);
18 push(ALPHABET[(((chunk[0] & 0x3) << 4) | (chunk[1] >> 4)) as usize]);
19 push(ALPHABET[(((chunk[1] & 0xf) << 2) | (chunk[2] >> 6)) as usize]);
20 push(ALPHABET[(chunk[2] & 0x3f) as usize]);
21 }
22
23 let remainder = input.len() % 3;
24
25 if remainder == 1 {
26 let index: usize = input.len() - 1;
27
28 push(ALPHABET[(input[index] >> 2) as usize]);
29 push(ALPHABET[((input[index] & 3) << 4) as usize]);
30 } else if remainder == 2 {
31 let index: usize = input.len() - 2;
32
33 push(ALPHABET[(input[index] >> 2) as usize]);
34 push(ALPHABET[(((input[index] & 0x3) << 4) | (input[index + 1] >> 4)) as usize]);
35 push(ALPHABET[((input[index + 1] & 0xf) << 2) as usize]);
36 }
37
38 output
39}
40
41#[must_use]
42pub fn encode(input: &[u8]) -> String {
43 let mut output = Vec::with_capacity(input.len() * 4 / 3 + 1);
44
45 for chunk in input.chunks_exact(3) {
46 output.push(ALPHABET[(chunk[0] >> 2) as usize]);
47 output.push(ALPHABET[(((chunk[0] & 0x3) << 4) | (chunk[1] >> 4)) as usize]);
48 output.push(ALPHABET[(((chunk[1] & 0xf) << 2) | (chunk[2] >> 6)) as usize]);
49 output.push(ALPHABET[(chunk[2] & 0x3f) as usize]);
50 }
51
52 let remainder = input.len() % 3;
53
54 if remainder == 1 {
55 let index: usize = input.len() - 1;
56
57 output.push(ALPHABET[(input[index] >> 2) as usize]);
58 output.push(ALPHABET[((input[index] & 3) << 4) as usize]);
59 } else if remainder == 2 {
60 let index: usize = input.len() - 2;
61
62 output.push(ALPHABET[(input[index] >> 2) as usize]);
63 output.push(ALPHABET[(((input[index] & 0x3) << 4) | (input[index + 1] >> 4)) as usize]);
64 output.push(ALPHABET[((input[index + 1] & 0xf) << 2) as usize]);
65 }
66
67 unsafe { String::from_utf8_unchecked(output) }
69}