glassy 0.0.3

An easy and fast library for encoding and decoding binary data.
Documentation
//! Base64 encoding and decoding.
//!
//! This module implements RFC 4648 sections 4 and 5.  The basic idea is to
//! convert every six bits of binary data into a printable character.  This
//! results in a 3:4 size ratio, an overhead of 33%.
//!
//! The basic algorithm for Base64-encoding data is:
//! 1. Interpret the sequence of bytes as a sequence of bits (within each byte,
//!    bits are ordered from most to least significant).
//! 2. Append zero bits until the number of bits is divisible by 6.
//! 3. Interpret the sequence of bits as a sequence of 6-bit indices (the bits
//!    in the sequence are ordered from most to least significant).
//! 4. Replace each 6-bit index with a 1-byte character from the table below.
//! 5. Optionally, append padding characters until the number of characters is
//!    divisible by 4.
//!
//! The basic algorithm for Base64-decoding data is:
//! 1. Append padding bytes until the number of characters is divisible by 4.
//! 2. Form groups of 4 consecutive characters in the sequence.
//! 3. Determine the number of output bytes in each 4-character group, based on
//!    the number of padding characters at the end of the group, based on the
//!    table below.
//! 4. Replace each character with a 6-bit index from the table below (padding
//!    bytes are interpreted as indices with value 0).
//! 5. Interpret the sequence of groups of 4 6-bit indices as a sequence of
//!    24-bit strings (the bits in each index are ordered from most to least
//!    significant).
//! 6. Interpret the sequence of 24-bit strings as a sequence of groups of 3
//!    8-bit bytes (the bits in the sequence are ordered from most to least
//!    significant).
//! 7. Truncate each group of 3 bytes to the number of actual output bytes,
//!    based on the value computed at step 3.
//! 8. Interpret the sequence of groups of bytes as a sequence of bytes.
//!
//! The following table relates, within the encoding of up to 3 bytes of binary
//! data or the decoding of 4 characters, the number of padding bytes at the end
//! of the encoded data to the number of bytes in the decoded data:
//!
//! ```text
//! Amount of Padding | 0 1 2 3 4
//! Non-Padding Bytes | 4 3 2 1 0
//!        Input Size | 3 2 1   0
//! ```
//!
//! All blank entries represent invalid combinations.
//!
//! The following table relates 6-bit indices to printable characters, for the
//! RFC 6468 section 4 encoding `base64`:
//!
//! ```text
//! Bin    Dec Hex  | Hex ASCII  | Bin    Dec Hex  | Hex ASCII
//! 000000   0   0  |  41 A      | 100000  32  20  |  67 g
//! 000001   1   1  |  42 B      | 100001  33  21  |  68 h
//! 000010   2   2  |  43 C      | 100010  34  22  |  69 i
//! 000011   3   3  |  44 D      | 100011  35  23  |  6A j
//! 000100   4   4  |  45 E      | 100100  36  24  |  6B k
//! 000101   5   5  |  46 F      | 100101  37  25  |  6C l
//! 000110   6   6  |  47 G      | 100110  38  26  |  6D m
//! 000111   7   7  |  48 H      | 100111  39  27  |  6E n
//! 001000   8   8  |  49 I      | 101000  40  28  |  6F o
//! 001001   9   9  |  4A J      | 101001  41  29  |  70 p
//! 001010  10   A  |  4B K      | 101010  42  2A  |  71 q
//! 001011  11   B  |  4C L      | 101011  43  2B  |  72 r
//! 001100  12   C  |  4D M      | 101100  44  2C  |  73 s
//! 001101  13   D  |  4E N      | 101101  45  2D  |  74 t
//! 001110  14   E  |  4F O      | 101110  46  2E  |  75 u
//! 001111  15   F  |  50 P      | 101111  47  2F  |  76 v
//! 010000  16  10  |  51 Q      | 110000  48  30  |  77 w
//! 010001  17  11  |  52 R      | 110001  49  31  |  78 x
//! 010010  18  12  |  53 S      | 110010  50  32  |  79 y
//! 010011  19  13  |  54 T      | 110011  51  33  |  7A z
//! 010100  20  14  |  55 U      | 110100  52  34  |  30 0
//! 010101  21  15  |  56 V      | 110101  53  35  |  31 1
//! 010110  22  16  |  57 W      | 110110  54  36  |  32 2
//! 010111  23  17  |  58 X      | 110111  55  37  |  33 3
//! 011000  24  18  |  59 Y      | 111000  56  38  |  34 4
//! 011001  25  19  |  5A Z      | 111001  57  39  |  35 5
//! 011010  26  1A  |  61 a      | 111010  58  3A  |  36 6
//! 011011  27  1B  |  62 b      | 111011  59  3B  |  37 7
//! 011100  28  1C  |  63 c      | 111100  60  3C  |  38 8
//! 011101  29  1D  |  64 d      | 111101  61  3D  |  39 9
//! 011110  30  1E  |  65 e      | 111110  62  3E  |  2B +
//! 011111  31  1F  |  66 f      | 111111  63  3F  |  2F /
//! ```
//!
//! The character `=` (hex `3D`) is used for padding.
//!
//! The following table relates 6-bit indices to printable characters, for the
//! RFC 6468 section 5 encoding `base64url`:
//!
//! ```text
//! Bin    Dec Hex  | Hex ASCII  | Bin    Dec Hex  | Hex ASCII
//! 000000   0   0  |  41 A      | 100000  32  20  |  67 g
//! 000001   1   1  |  42 B      | 100001  33  21  |  68 h
//! 000010   2   2  |  43 C      | 100010  34  22  |  69 i
//! 000011   3   3  |  44 D      | 100011  35  23  |  6A j
//! 000100   4   4  |  45 E      | 100100  36  24  |  6B k
//! 000101   5   5  |  46 F      | 100101  37  25  |  6C l
//! 000110   6   6  |  47 G      | 100110  38  26  |  6D m
//! 000111   7   7  |  48 H      | 100111  39  27  |  6E n
//! 001000   8   8  |  49 I      | 101000  40  28  |  6F o
//! 001001   9   9  |  4A J      | 101001  41  29  |  70 p
//! 001010  10   A  |  4B K      | 101010  42  2A  |  71 q
//! 001011  11   B  |  4C L      | 101011  43  2B  |  72 r
//! 001100  12   C  |  4D M      | 101100  44  2C  |  73 s
//! 001101  13   D  |  4E N      | 101101  45  2D  |  74 t
//! 001110  14   E  |  4F O      | 101110  46  2E  |  75 u
//! 001111  15   F  |  50 P      | 101111  47  2F  |  76 v
//! 010000  16  10  |  51 Q      | 110000  48  30  |  77 w
//! 010001  17  11  |  52 R      | 110001  49  31  |  78 x
//! 010010  18  12  |  53 S      | 110010  50  32  |  79 y
//! 010011  19  13  |  54 T      | 110011  51  33  |  7A z
//! 010100  20  14  |  55 U      | 110100  52  34  |  30 0
//! 010101  21  15  |  56 V      | 110101  53  35  |  31 1
//! 010110  22  16  |  57 W      | 110110  54  36  |  32 2
//! 010111  23  17  |  58 X      | 110111  55  37  |  33 3
//! 011000  24  18  |  59 Y      | 111000  56  38  |  34 4
//! 011001  25  19  |  5A Z      | 111001  57  39  |  35 5
//! 011010  26  1A  |  61 a      | 111010  58  3A  |  36 6
//! 011011  27  1B  |  62 b      | 111011  59  3B  |  37 7
//! 011100  28  1C  |  63 c      | 111100  60  3C  |  38 8
//! 011101  29  1D  |  64 d      | 111101  61  3D  |  39 9
//! 011110  30  1E  |  65 e      | 111110  62  3E  |  2D -
//! 011111  31  1F  |  66 f      | 111111  63  3F  |  5F _
//! ```
//!
//! The character `=` (hex `3D`) is used for padding.

use core::fmt;

pub mod generic;

/// The specific Base64 format to use.
#[derive(Clone, Debug)]
pub enum Format {
    /// The `base64` format defined by RFC 4648 section 4.
    Base64 {
        /// Whether the encoder should output padding bytes.
        encode_padding: bool,

        /// Whether the decoder accepts padding bytes.
        decode_padding: bool,

        /// Whether the decoder ignores garbage characters.
        decode_garbage: bool,
    },

    /// The `base64url` format defined by RFC 4648 section 5.
    Base64URL {
        /// Whether the encoder should output padding bytes.
        encode_padding: bool,

        /// Whether the decoder accepts padding bytes.
        decode_padding: bool,

        /// Whether the decoder ignores garbage characters.
        decode_garbage: bool,
    },
}

impl Format {
    /// Whether to encode padding or not.
    ///
    /// If this returns [`true`], then padding bytes will be inserted at the end
    /// of the encoding process so that the complete encoded string's byte size
    /// is a multiple of 4.
    pub fn encode_padding(&self) -> bool {
        match self {
            Self::Base64 { encode_padding, .. }
          | Self::Base64URL { encode_padding, .. }
            => *encode_padding,
        }
    }

    /// Whether to decode padding or not.
    ///
    /// If this returns [`true`], then padding bytes in the input will be parsed
    /// correctly.
    pub fn decode_padding(&self) -> bool {
        match self {
            Self::Base64 { decode_padding, .. }
          | Self::Base64URL { decode_padding, .. }
            => *decode_padding,
        }
    }

    /// Whether to decode garbage or not.
    ///
    /// If this returns [`true`], then 'garbage' bytes in the input (those that
    /// could not have been produced by the encoder) will be ignored rather than
    /// causing errors.
    pub fn decode_garbage(&self) -> bool {
        match self {
            Self::Base64 { decode_garbage, .. }
          | Self::Base64URL { decode_garbage, .. }
            => *decode_garbage,
        }
    }
}

/// A decoding error.
#[derive(Clone, Debug)]
pub struct DecodeError;

impl fmt::Display for DecodeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("A malformed input was received")
    }
}