base64-const 0.0.6

Base64 encode/decode with const-friendly decode and URL-safe macros
Documentation
#[macro_export]
macro_rules! base64_decode {
    ($base64:expr) => {{
        const INPUT: &str = $base64;
        const BYTES: &[u8] = INPUT.as_bytes();
        const LEN: usize = {
            let mut index = 0;
            let mut start_bit: u8 = 0;
            let mut result_idx = 0;

            while index < BYTES.len() {
                let ascii = BYTES[index];
                if ascii == b'=' {
                    break;
                }

                if start_bit >= 2 {
                    result_idx += 1;
                }
                start_bit = (start_bit + 6) % 8;
                index += 1;
            }
            result_idx
        };
        const DECODED: [u8; LEN] = {
            let mut result = [0u8; LEN];
            let mut index = 0;
            let mut start_bit: u8 = 0;
            let mut byte: u8 = 0;
            let mut result_idx = 0;

            while index < BYTES.len() && result_idx < LEN {
                let ascii = BYTES[index];
                if ascii == b'=' {
                    break;
                }

                let b64 = if ascii >= b'a' {
                    26 + ascii - b'a'
                } else if ascii >= b'A' {
                    ascii - b'A'
                } else if ascii >= b'0' {
                    52 + ascii - b'0'
                } else if ascii == b'+' {
                    62
                } else if ascii == b'/' {
                    63
                } else {
                    0xff
                };

                if start_bit <= 2 {
                    byte |= b64 << (2 - start_bit);
                    if start_bit == 2 {
                        if result_idx < LEN {
                            result[result_idx] = byte;
                            result_idx += 1;
                        }
                        byte = 0;
                    }
                } else {
                    byte |= b64 >> (start_bit - 2);
                    if result_idx < LEN {
                        result[result_idx] = byte;
                        result_idx += 1;
                    }
                    byte = b64 << (8 - start_bit + 2);
                }
                start_bit = (start_bit + 6) % 8;
                index += 1;
            }
            result
        };
        DECODED
    }};
}

#[macro_export]
macro_rules! base64_url_unsafe {
    ($base64:expr) => {{
        const INPUT:&[u8] = $base64.as_bytes();
        const SUFFIX_LEN:usize = 4 - (INPUT.len() % 4);
        const LEN:usize = SUFFIX_LEN + INPUT.len();
        const DECODED: [u8; LEN] = {
            let mut index = 0;
            let mut result = [0u8; LEN];
            while index < INPUT.len() {
                result[index] = match INPUT[index] {
                    b'-' => b'+',
                    b'_' => b'/',
                    c => c
                };
                index += 1;
            }
            let mut index = index;
            while index < LEN {
                result[index] = b'=';
                index += 1;
            }
            result
        };
        std::str::from_utf8(&DECODED).unwrap()
    }};
}

#[macro_export]
macro_rules! base64_url_safe {
    ($base64:expr) => {{
        const INPUT:&[u8] = $base64.as_bytes();

        const SUFFIX_LEN:usize = {
            let mut suffix_len:usize = 0;
            if INPUT.len() > 0 {
                let mut index = INPUT.len() - 1;
                while INPUT[index] == b'=' {
                    suffix_len += 1;
                    if index == 0 {break}
                    index -= 1;
                }
            }
            suffix_len
        };
        const LEN:usize = INPUT.len() - SUFFIX_LEN;
        const DECODED: [u8; LEN] = {
            let mut index = 0;
            let mut result = [0u8; LEN];
            while index < LEN {
                result[index] = match INPUT[index] {
                    b'+' => b'-',
                    b'/' => b'_',
                    c => c
                };
                index += 1;
            }
            result
        };
        std::str::from_utf8(&DECODED).unwrap()
    }};
}