Skip to main content

base64/
lib.rs

1//! Correct, fast, and configurable [base64][] decoding and encoding. Base64
2//! transports binary data efficiently in contexts where only plain text is
3//! allowed.
4//!
5//! [base64]: https://developer.mozilla.org/en-US/docs/Glossary/Base64
6//!
7//! # Usage
8//!
9//! Use an [`Engine`] to decode or encode base64, configured with the base64
10//! alphabet and padding behavior best suited to your application.
11//!
12//! ## Engine setup
13//!
14//! There is more than one way to encode a stream of bytes as “base64”.
15//! Different applications use different encoding
16//! [alphabets][alphabet::Alphabet] and
17//! [padding behaviors][engine::general_purpose::GeneralPurposeConfig].
18//!
19//! ### Encoding alphabet
20//!
21//! Almost all base64 [alphabets][alphabet::Alphabet] use `A-Z`, `a-z`, and
22//! `0-9`, which gives nearly 64 characters (26 + 26 + 10 = 62), but they differ
23//! in their choice of their final 2.
24//!
25//! Most applications use the [standard][alphabet::STANDARD] alphabet specified
26//! in [RFC 4648][rfc-alphabet].  If that’s all you need, you can get started
27//! quickly by using the pre-configured
28//! [`STANDARD`][engine::general_purpose::STANDARD] engine, which is also available
29//! in the [`prelude`] module as shown here, if you prefer a minimal `use`
30//! footprint.
31//!
32#![cfg_attr(feature = "alloc", doc = "```")]
33#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
34//! use base64::prelude::*;
35//!
36//! # fn main() -> Result<(), base64::DecodeError> {
37//! assert_eq!(BASE64_STANDARD.decode(b"+uwgVQA=")?, b"\xFA\xEC\x20\x55\0");
38//! assert_eq!(BASE64_STANDARD.encode(b"\xFF\xEC\x20\x55\0"), "/+wgVQA=");
39//! # Ok(())
40//! # }
41//! ```
42//!
43//! [rfc-alphabet]: https://datatracker.ietf.org/doc/html/rfc4648#section-4
44//!
45//! Other common alphabets are available in the [`alphabet`] module.
46//!
47//! #### URL-safe alphabet
48//!
49//! The standard alphabet uses `+` and `/` as its two non-alphanumeric symbols,
50//! which cannot be safely used in URL’s without encoding them as `%2B` and
51//! `%2F`.
52//!
53//! To avoid that, some applications use a [“URL-safe” alphabet][alphabet::URL_SAFE],
54//! which uses `-` and `_` instead. To use that alternative alphabet, use the
55//! [`URL_SAFE`][engine::general_purpose::URL_SAFE] engine. This example doesn't
56//! use [`prelude`] to show what a more explicit `use` would look like.
57//!
58#![cfg_attr(feature = "alloc", doc = "```")]
59#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
60//! use base64::{engine::general_purpose::URL_SAFE, Engine as _};
61//!
62//! # fn main() -> Result<(), base64::DecodeError> {
63//! assert_eq!(URL_SAFE.decode(b"-uwgVQA=")?, b"\xFA\xEC\x20\x55\0");
64//! assert_eq!(URL_SAFE.encode(b"\xFF\xEC\x20\x55\0"), "_-wgVQA=");
65//! # Ok(())
66//! # }
67//! ```
68//!
69//! ### Padding characters
70//!
71//! Each base64 character represents 6 bits (2⁶ = 64) of the original binary
72//! data, and every 3 bytes of input binary data will encode to 4 base64
73//! characters (8 bits × 3 = 6 bits × 4 = 24 bits).
74//!
75//! When the input is not an even multiple of 3 bytes in length, [canonical][]
76//! base64 encoders insert padding characters at the end, so that the output
77//! length is always a multiple of 4:
78//!
79//! [canonical]: https://datatracker.ietf.org/doc/html/rfc4648#section-3.5
80//!
81#![cfg_attr(feature = "alloc", doc = "```")]
82#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
83//! use base64::{engine::general_purpose::STANDARD, Engine as _};
84//!
85//! assert_eq!(STANDARD.encode(b""),    "");
86//! assert_eq!(STANDARD.encode(b"f"),   "Zg==");
87//! assert_eq!(STANDARD.encode(b"fo"),  "Zm8=");
88//! assert_eq!(STANDARD.encode(b"foo"), "Zm9v");
89//! ```
90//!
91//! Canonical encoding ensures that base64 encodings will be exactly the same,
92//! byte-for-byte, regardless of input length. But the `=` padding characters
93//! aren’t necessary for decoding, and they may be omitted by using a
94//! [`NO_PAD`][engine::general_purpose::NO_PAD] configuration:
95//!
96#![cfg_attr(feature = "alloc", doc = "```")]
97#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
98//! use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _};
99//!
100//! assert_eq!(STANDARD_NO_PAD.encode(b""),    "");
101//! assert_eq!(STANDARD_NO_PAD.encode(b"f"),   "Zg");
102//! assert_eq!(STANDARD_NO_PAD.encode(b"fo"),  "Zm8");
103//! assert_eq!(STANDARD_NO_PAD.encode(b"foo"), "Zm9v");
104//! ```
105//!
106//! The pre-configured `NO_PAD` engines will reject inputs containing padding
107//! `=` characters. To encode without padding and still accept padding while
108//! decoding, create an [engine][engine::general_purpose::GeneralPurpose] with
109//! that [padding mode][engine::DecodePaddingMode].
110//!
111#![cfg_attr(feature = "alloc", doc = "```")]
112#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
113//! # use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _};
114//! assert_eq!(STANDARD_NO_PAD.decode(b"Zm8="), Err(base64::DecodeError::InvalidPadding));
115//! ```
116//!
117//! Padding serves no practical purpose, so where possible, encode without padding.
118//!
119//! ### Further customization
120//!
121//! Decoding and encoding behavior can be customized by creating an
122//! [engine][engine::GeneralPurpose] with an [alphabet][alphabet::Alphabet] and
123//! [padding configuration][engine::GeneralPurposeConfig]:
124//!
125#![cfg_attr(feature = "alloc", doc = "```")]
126#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
127//! use base64::{engine, alphabet, Engine as _};
128//!
129//! // bizarro-world base64: +/ as the first symbols instead of the last
130//! let alphabet =
131//!     alphabet::Alphabet::new("+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
132//!     .unwrap();
133//!
134//! // a very weird config that encodes with padding but requires no padding when decoding...?
135//! let crazy_config = engine::GeneralPurposeConfig::new()
136//!     .with_decode_allow_trailing_bits(true)
137//!     .with_encode_padding(true)
138//!     .with_decode_padding_mode(engine::DecodePaddingMode::RequireNone);
139//!
140//! let crazy_engine = engine::GeneralPurpose::new(&alphabet, crazy_config);
141//!
142//! let encoded = crazy_engine.encode(b"abc 123");
143//!
144//! ```
145//!
146//! ## Memory allocation
147//!
148//! The [decode][Engine::decode()] and [encode][Engine::encode()] engine methods
149//! allocate memory for their results – `decode` returns a `Vec<u8>` and
150//! `encode` returns a `String`. To instead decode or encode into a buffer that
151//! you allocated, use one of the alternative methods:
152//!
153//! #### Decoding
154//!
155//! | Method                     | Output                        | Allocates memory              |
156//! | -------------------------- | ----------------------------- | ----------------------------- |
157//! | [`Engine::decode`]         | returns a new `Vec<u8>`       | always                        |
158//! | [`Engine::decode_vec`]     | appends to provided `Vec<u8>` | if `Vec` lacks capacity       |
159//! | [`Engine::decode_slice`]   | writes to provided `&[u8]`    | never
160//!
161//! #### Encoding
162//!
163//! | Method                     | Output                       | Allocates memory               |
164//! | -------------------------- | ---------------------------- | ------------------------------ |
165//! | [`Engine::encode`]         | returns a new `String`       | always                         |
166//! | [`Engine::encode_string`]  | appends to provided `String` | if `String` lacks capacity     |
167//! | [`Engine::encode_slice`]   | writes to provided `&[u8]`   | never                          |
168//!
169//! ## Input and output
170//!
171//! The `base64` crate can [decode][Engine::decode()] and
172//! [encode][Engine::encode()] values in memory, or
173//! [`DecoderReader`][read::DecoderReader] and
174//! [`EncoderWriter`][write::EncoderWriter] provide streaming decoding and
175//! encoding for any [readable][std::io::Read] or [writable][std::io::Write]
176//! byte stream.
177//!
178//! #### Decoding
179//!
180#![cfg_attr(feature = "std", doc = "```")]
181#![cfg_attr(not(feature = "std"), doc = "```ignore")]
182//! # use std::io;
183//! use base64::{engine::general_purpose::STANDARD, read::DecoderReader};
184//!
185//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
186//! let mut input = io::stdin();
187//! let mut decoder = DecoderReader::new(&mut input, &STANDARD);
188//! io::copy(&mut decoder, &mut io::stdout())?;
189//! # Ok(())
190//! # }
191//! ```
192//!
193//! This also allows for constant-space validity checking of encoded data, using a
194//! statically allocated buffer:
195//!
196#![cfg_attr(feature = "std", doc = "```")]
197#![cfg_attr(not(feature = "std"), doc = "```ignore")]
198//! # use std::io::{self, Read};
199//! use base64::{engine::general_purpose::STANDARD, read::DecoderReader};
200//!
201//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
202//! let mut invalid_input = "dt==";
203//! let mut decoder = DecoderReader::new(io::Cursor::new(&mut invalid_input), &STANDARD);
204//!
205//! let mut buf = [0u8; 128];
206//!
207//! let is_valid = loop {
208//!     match decoder.read(&mut buf) {
209//!         Ok(0) => break true, // Read to end w/o error
210//!         Ok(_) => continue,
211//!         Err(_) => break false,
212//!     }
213//! };
214//!
215//! assert!(!is_valid);
216//! # Ok(())
217//! # }
218//! ```
219//!
220//! #### Encoding
221//!
222#![cfg_attr(feature = "std", doc = "```")]
223#![cfg_attr(not(feature = "std"), doc = "```ignore")]
224//! # use std::io;
225//! use base64::{engine::general_purpose::STANDARD, write::EncoderWriter};
226//!
227//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
228//! let mut output = io::stdout();
229//! let mut encoder = EncoderWriter::new(&mut output, &STANDARD);
230//! io::copy(&mut io::stdin(), &mut encoder)?;
231//! # Ok(())
232//! # }
233//! ```
234//!
235//! #### Display
236//!
237//! If you only need a base64 representation for implementing the
238//! [`Display`][std::fmt::Display] trait, use
239//! [`Base64Display`][display::Base64Display]:
240//!
241//! ```
242//! use base64::{display::Base64Display, engine::general_purpose::STANDARD};
243//!
244//! let value = Base64Display::new(b"\0\x01\x02\x03", &STANDARD);
245//! assert_eq!("base64: AAECAw==", format!("base64: {}", value));
246//! ```
247//!
248//! # Crate features
249//!
250//! - `std` (default): enables `std::io` integration, [`std::error::Error`] impls, and heap
251//!   allocation. Implies `alloc`.
252//! - `alloc`: enables the allocating APIs (e.g. [`Engine::encode`], [`Engine::decode`]) in a
253//!   `no_std` build.
254//! - `simd-unsafe`: enables the SIMD-accelerated engines. It is on by default and is the only
255//!   feature that introduces `unsafe` code; with it disabled the crate is
256//!   `#![forbid(unsafe_code)]`.
257//!
258//! ## SIMD acceleration
259//!
260//! With the `simd-unsafe` feature, the [`engine`] module provides SIMD engines for the standard and
261//! URL-safe alphabets that are several times faster than [`GeneralPurpose`][engine::GeneralPurpose]:
262//!
263//! - `Simd` picks the best available instruction set (AVX2 on `x86_64`, NEON on `aarch64`) at
264//!   runtime and falls back to the scalar engine. It needs `std` for the CPU-feature detection.
265//! - `Avx2` and `Neon` target one instruction set without runtime detection, so they can be used in
266//!   `no_std` builds when the target is known to support the instructions.
267//!
268//! # Panics
269//!
270//! If length calculations result in overflowing `usize`, a panic will result.
271
272#![deny(
273    missing_docs,
274    trivial_casts,
275    trivial_numeric_casts,
276    unused_extern_crates,
277    unused_import_braces,
278    unused_results,
279    variant_size_differences
280)]
281// The `simd-unsafe` feature (on by default) is the only source of `unsafe`; without it the crate
282// is `#![forbid(unsafe_code)]`. When it is enabled, `unsafe` is confined to the SIMD engine module,
283// which opts back in with a localized `allow`.
284#![cfg_attr(not(feature = "simd-unsafe"), forbid(unsafe_code))]
285#![cfg_attr(feature = "simd-unsafe", deny(unsafe_code))]
286#![cfg_attr(not(any(feature = "std", test)), no_std)]
287
288#[cfg(any(feature = "alloc", test))]
289extern crate alloc;
290
291mod chunked_encoder;
292pub mod display;
293#[cfg(any(feature = "std", test))]
294pub mod read;
295#[cfg(any(feature = "std", test))]
296pub mod write;
297
298pub mod engine;
299pub use engine::Engine;
300
301pub mod alphabet;
302
303mod encode;
304#[allow(deprecated)]
305#[cfg(any(feature = "alloc", test))]
306pub use crate::encode::{encode, encode_engine, encode_engine_string};
307#[allow(deprecated)]
308pub use crate::encode::{encode_engine_slice, encoded_len, EncodeSliceError};
309
310mod decode;
311#[allow(deprecated)]
312#[cfg(any(feature = "alloc", test))]
313pub use crate::decode::{decode, decode_engine, decode_engine_vec};
314#[allow(deprecated)]
315pub use crate::decode::{decode_engine_slice, decoded_len_estimate, DecodeError, DecodeSliceError};
316
317pub mod prelude;
318
319#[cfg(test)]
320mod tests;