1use crate::arena::ArenaString;
7
8const CHARSET: [u8; 64] = *b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
9
10#[inline]
13pub fn encode_len(src_len: usize) -> usize {
14 src_len.div_ceil(3) * 4
15}
16
17pub fn encode(dst: &mut ArenaString, src: &[u8]) {
19 unsafe {
20 let mut inp = src.as_ptr();
21 let mut remaining = src.len();
22 let dst = dst.as_mut_vec();
23
24 let out_len = encode_len(src.len());
25 dst.reserve(out_len);
27
28 let mut out = dst.as_mut_ptr().add(dst.len());
31
32 if remaining != 0 {
33 while remaining > 3 {
35 let val = u32::from_be((inp as *const u32).read_unaligned());
39 inp = inp.add(3);
40 remaining -= 3;
41
42 *out = CHARSET[(val >> 26) as usize];
43 out = out.add(1);
44 *out = CHARSET[(val >> 20) as usize & 0x3f];
45 out = out.add(1);
46 *out = CHARSET[(val >> 14) as usize & 0x3f];
47 out = out.add(1);
48 *out = CHARSET[(val >> 8) as usize & 0x3f];
49 out = out.add(1);
50 }
51
52 let mut in1 = 0;
54 let mut in2 = 0;
55
56 *out.add(3) = b'=';
59 *out.add(2) = b'=';
60
61 if remaining >= 3 {
62 in2 = inp.add(2).read() as usize;
63 *out.add(3) = CHARSET[in2 & 0x3f];
64 }
65
66 if remaining >= 2 {
67 in1 = inp.add(1).read() as usize;
68 *out.add(2) = CHARSET[(in1 << 2 | in2 >> 6) & 0x3f];
69 }
70
71 let in0 = inp.add(0).read() as usize;
72 *out.add(1) = CHARSET[(in0 << 4 | in1 >> 4) & 0x3f];
73 *out.add(0) = CHARSET[in0 >> 2];
74 }
75
76 dst.set_len(dst.len() + out_len);
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::encode;
83 use crate::arena::{Arena, ArenaString};
84
85 #[test]
86 fn test_basic() {
87 let arena = Arena::new(4 * 1024).unwrap();
88 let enc = |s: &[u8]| {
89 let mut dst = ArenaString::new_in(&arena);
90 encode(&mut dst, s);
91 dst
92 };
93 assert_eq!(enc(b""), "");
94 assert_eq!(enc(b"a"), "YQ==");
95 assert_eq!(enc(b"ab"), "YWI=");
96 assert_eq!(enc(b"abc"), "YWJj");
97 assert_eq!(enc(b"abcd"), "YWJjZA==");
98 assert_eq!(enc(b"abcde"), "YWJjZGU=");
99 assert_eq!(enc(b"abcdef"), "YWJjZGVm");
100 assert_eq!(enc(b"abcdefg"), "YWJjZGVmZw==");
101 assert_eq!(enc(b"abcdefgh"), "YWJjZGVmZ2g=");
102 assert_eq!(enc(b"abcdefghi"), "YWJjZGVmZ2hp");
103 assert_eq!(enc(b"abcdefghij"), "YWJjZGVmZ2hpag==");
104 assert_eq!(enc(b"abcdefghijk"), "YWJjZGVmZ2hpams=");
105 assert_eq!(enc(b"abcdefghijkl"), "YWJjZGVmZ2hpamts");
106 assert_eq!(enc(b"abcdefghijklm"), "YWJjZGVmZ2hpamtsbQ==");
107 assert_eq!(enc(b"abcdefghijklmN"), "YWJjZGVmZ2hpamtsbU4=");
108 assert_eq!(enc(b"abcdefghijklmNO"), "YWJjZGVmZ2hpamtsbU5P");
109 assert_eq!(enc(b"abcdefghijklmNOP"), "YWJjZGVmZ2hpamtsbU5PUA==");
110 assert_eq!(enc(b"abcdefghijklmNOPQ"), "YWJjZGVmZ2hpamtsbU5PUFE=");
111 assert_eq!(enc(b"abcdefghijklmNOPQR"), "YWJjZGVmZ2hpamtsbU5PUFFS");
112 assert_eq!(enc(b"abcdefghijklmNOPQRS"), "YWJjZGVmZ2hpamtsbU5PUFFSUw==");
113 assert_eq!(enc(b"abcdefghijklmNOPQRST"), "YWJjZGVmZ2hpamtsbU5PUFFSU1Q=");
114 assert_eq!(enc(b"abcdefghijklmNOPQRSTU"), "YWJjZGVmZ2hpamtsbU5PUFFSU1RV");
115 assert_eq!(enc(b"abcdefghijklmNOPQRSTUV"), "YWJjZGVmZ2hpamtsbU5PUFFSU1RVVg==");
116 assert_eq!(enc(b"abcdefghijklmNOPQRSTUVW"), "YWJjZGVmZ2hpamtsbU5PUFFSU1RVVlc=");
117 assert_eq!(enc(b"abcdefghijklmNOPQRSTUVWX"), "YWJjZGVmZ2hpamtsbU5PUFFSU1RVVldY");
118 assert_eq!(enc(b"abcdefghijklmNOPQRSTUVWXY"), "YWJjZGVmZ2hpamtsbU5PUFFSU1RVVldYWQ==");
119 assert_eq!(enc(b"abcdefghijklmNOPQRSTUVWXYZ"), "YWJjZGVmZ2hpamtsbU5PUFFSU1RVVldYWVo=");
120 }
121}