base_encodings/
lib.rs

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}