big_int/
base64.rs

1//! base64 encoding & decoding, baked into the library :)
2
3use crate::prelude::*;
4/// Base64 alphabet; used for encoding & decoding numbers to and from base64.
5pub const BASE64_ALPHABET: &str =
6    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7
8/// Encode an array of bytes into base64 data.
9///
10/// Note: probably slower than using a standalone
11/// library to perform this conversion. However, it's very neat :3
12///
13/// ```
14/// use big_int::base64::*;
15///
16/// assert_eq!(encode(b"Hello world!"), "SGVsbG8gd29ybGQh");
17/// ```
18pub fn encode(bytes: &[u8]) -> String {
19    let mut digits = vec![255, 255, 255]
20        .into_iter()
21        .chain(bytes.into_iter().copied().map(Digit::from))
22        .collect::<Vec<_>>();
23    let padding = 3 - ((digits.len() - 1) % 3) - 1;
24    digits.extend(vec![0; padding]);
25    let data_as_int: Loose<256> = digits.iter().copied().collect();
26    let base64_data: Loose<64> = unsafe { data_as_int.convert::<64, Loose<64>>().unsafe_into() };
27    let base64_string = base64_data.display(BASE64_ALPHABET).unwrap();
28    base64_string[4..base64_string.len() - padding].to_string()
29}
30
31/// Decode a base64 string into an array of bytes.
32///
33/// Note: probably slower than using a standalone
34/// library to perform this conversion. However, again, it's very neat c:
35///
36/// ```
37/// use big_int::base64::*;
38///
39/// assert_eq!(decode("SGVsbG8gd29ybGQh").unwrap(), b"Hello world!");
40/// ```
41pub fn decode(b64_string: impl Into<String>) -> Result<Vec<u8>, BigIntError> {
42    let mut b64_string = b64_string.into();
43    b64_string = format!("////{b64_string}");
44    let padding = 4 - ((b64_string.len() - 1) % 4) - 1;
45    b64_string.extend(vec!['A'; padding]);
46    let string_as_int: Loose<64> = unsafe {
47        Loose::<64>::parse(&b64_string, BASE64_ALPHABET)
48            .map_err(BigIntError::ParseFailed)?
49            .unsafe_into()
50    };
51    let bytes_int: Loose<256> = unsafe { string_as_int.convert::<256, Loose<256>>().unsafe_into() };
52    let bytes = bytes_int
53        .iter()
54        .map(u8::try_from)
55        .collect::<Result<Vec<_>, _>>()
56        .unwrap();
57    let bytes = bytes[3..bytes.len() - padding].to_vec();
58    Ok(bytes)
59}