base64/
lib.rs

1//! # Configs
2//!
3//! There isn't just one type of Base64; that would be too simple. You need to choose a character
4//! set (standard, URL-safe, etc) and padding suffix (yes/no).
5//! The `Config` struct encapsulates this info. There are some common configs included: `STANDARD`,
6//! `URL_SAFE`, etc. You can also make your own `Config` if needed.
7//!
8//! The functions that don't have `config` in the name (e.g. `encode()` and `decode()`) use the
9//! `STANDARD` config .
10//!
11//! The functions that write to a slice (the ones that end in `_slice`) are generally the fastest
12//! because they don't need to resize anything. If it fits in your workflow and you care about
13//! performance, keep using the same buffer (growing as need be) and use the `_slice` methods for
14//! the best performance.
15//!
16//! # Encoding
17//!
18//! Several different encoding functions are available to you depending on your desire for
19//! convenience vs performance.
20//!
21//! | Function                | Output                       | Allocates                      |
22//! | ----------------------- | ---------------------------- | ------------------------------ |
23//! | `encode`                | Returns a new `String`       | Always                         |
24//! | `encode_config`         | Returns a new `String`       | Always                         |
25//! | `encode_config_buf`     | Appends to provided `String` | Only if `String` needs to grow |
26//! | `encode_config_slice`   | Writes to provided `&[u8]`   | Never                          |
27//!
28//! All of the encoding functions that take a `Config` will pad as per the config.
29//!
30//! # Decoding
31//!
32//! Just as for encoding, there are different decoding functions available.
33//!
34//! | Function                | Output                        | Allocates                      |
35//! | ----------------------- | ----------------------------- | ------------------------------ |
36//! | `decode`                | Returns a new `Vec<u8>`       | Always                         |
37//! | `decode_config`         | Returns a new `Vec<u8>`       | Always                         |
38//! | `decode_config_buf`     | Appends to provided `Vec<u8>` | Only if `Vec` needs to grow    |
39//! | `decode_config_slice`   | Writes to provided `&[u8]`    | Never                          |
40//!
41//! Unlike encoding, where all possible input is valid, decoding can fail (see `DecodeError`).
42//!
43//! Input can be invalid because it has invalid characters or invalid padding. (No padding at all is
44//! valid, but excess padding is not.) Whitespace in the input is invalid.
45//!
46//! # Panics
47//!
48//! If length calculations result in overflowing `usize`, a panic will result.
49//!
50//! The `_slice` flavors of encode or decode will panic if the provided output slice is too small,
51
52#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))]
53#![deny(
54    missing_docs,
55    trivial_casts,
56    trivial_numeric_casts,
57    unused_extern_crates,
58    unused_import_braces,
59    unused_results,
60    variant_size_differences,
61    warnings,
62    unsafe_code
63)]
64#![allow(unknown_lints, bare_trait_objects)]
65
66extern crate byteorder;
67
68#[cfg(test)] extern crate rand;
69#[cfg(test)] #[macro_use] extern crate doc_comment;
70
71#[cfg(bench)] extern crate criterion;
72
73#[cfg(test)]
74doctest!("../README.md");
75
76mod chunked_encoder;
77pub mod display;
78mod tables;
79pub mod write;
80
81mod encode;
82pub use encode::{encode, encode_config, encode_config_buf, encode_config_slice};
83
84mod decode;
85pub use decode::{
86    decode, decode_config, decode_config_buf, decode_config_slice, DecodeError,
87};
88
89#[cfg(test)]
90mod tests;
91
92/// Available encoding character sets
93#[derive(Clone, Copy, Debug)]
94pub enum CharacterSet {
95    /// The standard character set (uses `+` and `/`).
96    ///
97    /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3).
98    Standard,
99    /// The URL safe character set (uses `-` and `_`).
100    ///
101    /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-4).
102    UrlSafe,
103    /// The `crypt(3)` character set (uses `./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`).
104    ///
105    /// Not standardized, but folk wisdom on the net asserts that this alphabet is what crypt uses.
106    Crypt,
107}
108
109impl CharacterSet {
110    fn encode_table(self) -> &'static [u8; 64] {
111        match self {
112            CharacterSet::Standard => tables::STANDARD_ENCODE,
113            CharacterSet::UrlSafe => tables::URL_SAFE_ENCODE,
114            CharacterSet::Crypt => tables::CRYPT_ENCODE,
115        }
116    }
117
118    fn decode_table(self) -> &'static [u8; 256] {
119        match self {
120            CharacterSet::Standard => tables::STANDARD_DECODE,
121            CharacterSet::UrlSafe => tables::URL_SAFE_DECODE,
122            CharacterSet::Crypt => tables::CRYPT_DECODE,
123        }
124    }
125}
126
127/// Contains configuration parameters for base64 encoding
128#[derive(Clone, Copy, Debug)]
129pub struct Config {
130    /// Character set to use
131    char_set: CharacterSet,
132    /// True to pad output with `=` characters
133    pad: bool,
134    /// True to ignore excess nonzero bits in the last few symbols, otherwise an error is returned.
135    decode_allow_trailing_bits: bool,
136}
137
138impl Config {
139    /// Create a new `Config`.
140    pub fn new(char_set: CharacterSet, pad: bool) -> Config {
141        Config {
142            char_set,
143            pad,
144            decode_allow_trailing_bits: false,
145        }
146    }
147
148    /// Sets whether to pad output with `=` characters.
149    pub fn pad(self, pad: bool) -> Config {
150        Config { pad, ..self }
151    }
152
153    /// Sets whether to emit errors for nonzero trailing bits.
154    ///
155    /// This is useful when implementing
156    /// [forgiving-base64 decode](https://infra.spec.whatwg.org/#forgiving-base64-decode).
157    pub fn decode_allow_trailing_bits(self, allow: bool) -> Config {
158        Config {
159            decode_allow_trailing_bits: allow,
160            ..self
161        }
162    }
163}
164
165/// Standard character set with padding.
166pub const STANDARD: Config = Config {
167    char_set: CharacterSet::Standard,
168    pad: true,
169    decode_allow_trailing_bits: false,
170};
171
172/// Standard character set without padding.
173pub const STANDARD_NO_PAD: Config = Config {
174    char_set: CharacterSet::Standard,
175    pad: false,
176    decode_allow_trailing_bits: false,
177};
178
179/// URL-safe character set with padding
180pub const URL_SAFE: Config = Config {
181    char_set: CharacterSet::UrlSafe,
182    pad: true,
183    decode_allow_trailing_bits: false,
184};
185
186/// URL-safe character set without padding
187pub const URL_SAFE_NO_PAD: Config = Config {
188    char_set: CharacterSet::UrlSafe,
189    pad: false,
190    decode_allow_trailing_bits: false,
191};
192
193/// As per `crypt(3)` requirements
194pub const CRYPT: Config = Config {
195    char_set: CharacterSet::Crypt,
196    pad: false,
197    decode_allow_trailing_bits: false,
198};