1use std::io::Error;
2
3const B64_URL_ENCODE: [u8; 64] = [
4 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
5 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
6 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
7 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2d, 0x5f,
8];
9
10const B64_URL_PAD: u8 = 0x3d;
11
12pub struct B64Url<T>(T);
13
14pub trait B64UrlEncode<I, O, E> {
15 fn encode(input: I) -> Result<O, E>;
16}
17
18impl B64UrlEncode<&[u8], Vec<u8>, Error> for B64Url<Vec<u8>> {
19 fn encode(input: &[u8]) -> Result<Vec<u8>, Error> {
20 let bytes = input;
21 let length = input.len();
22 let mut vector = Vec::<u8>::with_capacity(length * 4 / 3);
23 let mut index = 0;
24
25 while index + 3 <= length {
26 let value = (bytes[index] as u32) << 16
27 | (bytes[index + 1] as u32) << 8
28 | (bytes[index + 2] as u32);
29 vector.push(B64_URL_ENCODE[((value >> 18) & 0b11_1111) as usize]);
30 vector.push(B64_URL_ENCODE[((value >> 12) & 0b11_1111) as usize]);
31 vector.push(B64_URL_ENCODE[((value >> 6) & 0b11_1111) as usize]);
32 vector.push(B64_URL_ENCODE[(value & 0b11_1111) as usize]);
33 index += 3;
34 }
35
36 match length - index {
37 2 => {
38 let value = (bytes[index] as u32) << 16 | (bytes[index + 1] as u32) << 8;
39 vector.push(B64_URL_ENCODE[((value >> 18) & 0b11_1111) as usize]);
40 vector.push(B64_URL_ENCODE[((value >> 12) & 0b11_1111) as usize]);
41 vector.push(B64_URL_ENCODE[((value >> 6) & 0b11_1111) as usize]);
42 vector.push(B64_URL_PAD);
43 }
44 1 => {
45 let value = (bytes[index] as u32) << 16;
46 vector.push(B64_URL_ENCODE[((value >> 18) & 0b11_1111) as usize]);
47 vector.push(B64_URL_ENCODE[((value >> 12) & 0b11_1111) as usize]);
48 vector.push(B64_URL_PAD);
49 vector.push(B64_URL_PAD);
50 }
51 _ => {}
52 };
53
54 Ok(vector)
55 }
56}
57
58#[cfg(test)]
59mod b64_url_encode {
60 use super::*;
61
62 #[test]
63 fn t1() {
64 let result = B64Url::<Vec<u8>>::encode(b"").unwrap();
65 assert_eq!(result, b"");
66 }
67
68 #[test]
69 fn t2() {
70 let result = B64Url::<Vec<u8>>::encode(b"f").unwrap();
71 assert_eq!(result, b"Zg==");
72 }
73
74 #[test]
75 fn t3() {
76 let result = B64Url::<Vec<u8>>::encode(b"fo").unwrap();
77 assert_eq!(result, b"Zm8=");
78 }
79
80 #[test]
81 fn t4() {
82 let result = B64Url::<Vec<u8>>::encode(b"foo").unwrap();
83 assert_eq!(result, b"Zm9v");
84 }
85
86 #[test]
87 fn t5() {
88 let result = B64Url::<Vec<u8>>::encode(b"foob").unwrap();
89 assert_eq!(result, b"Zm9vYg==");
90 }
91
92 #[test]
93 fn t6() {
94 let result = B64Url::<Vec<u8>>::encode(b"fooba").unwrap();
95 assert_eq!(result, b"Zm9vYmE=");
96 }
97
98 #[test]
99 fn t7() {
100 let result = B64Url::<Vec<u8>>::encode(b"foobar").unwrap();
101 assert_eq!(result, b"Zm9vYmFy");
102 }
103}