• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! # Getting started
2 //!
3 //! 1. Perhaps one of the preconfigured engines in [engine::general_purpose] will suit, e.g.
4 //! [engine::general_purpose::STANDARD_NO_PAD].
5 //!     - These are re-exported in [prelude] with a `BASE64_` prefix for those who prefer to
6 //!       `use base64::prelude::*` or equivalent, e.g. [prelude::BASE64_STANDARD_NO_PAD]
7 //! 1. If not, choose which alphabet you want. Most usage will want [alphabet::STANDARD] or [alphabet::URL_SAFE].
8 //! 1. Choose which [Engine] implementation you want. For the moment there is only one: [engine::GeneralPurpose].
9 //! 1. Configure the engine appropriately using the engine's `Config` type.
10 //!     - This is where you'll select whether to add padding (when encoding) or expect it (when
11 //!     decoding). If given the choice, prefer no padding.
12 //! 1. Build the engine using the selected alphabet and config.
13 //!
14 //! For more detail, see below.
15 //!
16 //! ## Alphabets
17 //!
18 //! An [alphabet::Alphabet] defines what ASCII symbols are used to encode to or decode from.
19 //!
20 //! Constants in [alphabet] like [alphabet::STANDARD] or [alphabet::URL_SAFE] provide commonly used
21 //! alphabets, but you can also build your own custom [alphabet::Alphabet] if needed.
22 //!
23 //! ## Engines
24 //!
25 //! Once you have an `Alphabet`, you can pick which `Engine` you want. A few parts of the public
26 //! API provide a default, but otherwise the user must provide an `Engine` to use.
27 //!
28 //! See [Engine] for more.
29 //!
30 //! ## Config
31 //!
32 //! In addition to an `Alphabet`, constructing an `Engine` also requires an [engine::Config]. Each
33 //! `Engine` has a corresponding `Config` implementation since different `Engine`s may offer different
34 //! levels of configurability.
35 //!
36 //! # Encoding
37 //!
38 //! Several different encoding methods on [Engine] are available to you depending on your desire for
39 //! convenience vs performance.
40 //!
41 //! | Method                   | Output                       | Allocates                      |
42 //! | ------------------------ | ---------------------------- | ------------------------------ |
43 //! | [Engine::encode]         | Returns a new `String`       | Always                         |
44 //! | [Engine::encode_string]  | Appends to provided `String` | Only if `String` needs to grow |
45 //! | [Engine::encode_slice]   | Writes to provided `&[u8]`   | Never - fastest                |
46 //!
47 //! All of the encoding methods will pad as per the engine's config.
48 //!
49 //! # Decoding
50 //!
51 //! Just as for encoding, there are different decoding methods available.
52 //!
53 //! | Method                   | Output                        | Allocates                      |
54 //! | ------------------------ | ----------------------------- | ------------------------------ |
55 //! | [Engine::decode]         | Returns a new `Vec<u8>`       | Always                         |
56 //! | [Engine::decode_vec]     | Appends to provided `Vec<u8>` | Only if `Vec` needs to grow    |
57 //! | [Engine::decode_slice]   | Writes to provided `&[u8]`    | Never - fastest                |
58 //!
59 //! Unlike encoding, where all possible input is valid, decoding can fail (see [DecodeError]).
60 //!
61 //! Input can be invalid because it has invalid characters or invalid padding. The nature of how
62 //! padding is checked depends on the engine's config.
63 //! Whitespace in the input is invalid, just like any other non-base64 byte.
64 //!
65 //! # `Read` and `Write`
66 //!
67 //! To decode a [std::io::Read] of b64 bytes, wrap a reader (file, network socket, etc) with
68 //! [read::DecoderReader].
69 //!
70 //! To write raw bytes and have them b64 encoded on the fly, wrap a [std::io::Write] with
71 //! [write::EncoderWriter].
72 //!
73 //! There is some performance overhead (15% or so) because of the necessary buffer shuffling --
74 //! still fast enough that almost nobody cares. Also, these implementations do not heap allocate.
75 //!
76 //! # `Display`
77 //!
78 //! See [display] for how to transparently base64 data via a `Display` implementation.
79 //!
80 //! # Examples
81 //!
82 //! ## Using predefined engines
83 //!
84 //! ```
85 //! use base64::{Engine as _, engine::general_purpose};
86 //!
87 //! let orig = b"data";
88 //! let encoded: String = general_purpose::STANDARD_NO_PAD.encode(orig);
89 //! assert_eq!("ZGF0YQ", encoded);
90 //! assert_eq!(orig.as_slice(), &general_purpose::STANDARD_NO_PAD.decode(encoded).unwrap());
91 //!
92 //! // or, URL-safe
93 //! let encoded_url = general_purpose::URL_SAFE_NO_PAD.encode(orig);
94 //! ```
95 //!
96 //! ## Custom alphabet, config, and engine
97 //!
98 //! ```
99 //! use base64::{engine, alphabet, Engine as _};
100 //!
101 //! // bizarro-world base64: +/ as the first symbols instead of the last
102 //! let alphabet =
103 //!     alphabet::Alphabet::new("+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
104 //!     .unwrap();
105 //!
106 //! // a very weird config that encodes with padding but requires no padding when decoding...?
107 //! let crazy_config = engine::GeneralPurposeConfig::new()
108 //!     .with_decode_allow_trailing_bits(true)
109 //!     .with_encode_padding(true)
110 //!     .with_decode_padding_mode(engine::DecodePaddingMode::RequireNone);
111 //!
112 //! let crazy_engine = engine::GeneralPurpose::new(&alphabet, crazy_config);
113 //!
114 //! let encoded = crazy_engine.encode(b"abc 123");
115 //!
116 //! ```
117 //!
118 //! # Panics
119 //!
120 //! If length calculations result in overflowing `usize`, a panic will result.
121 
122 #![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))]
123 #![deny(
124     missing_docs,
125     trivial_casts,
126     trivial_numeric_casts,
127     unused_extern_crates,
128     unused_import_braces,
129     unused_results,
130     variant_size_differences,
131     warnings
132 )]
133 #![forbid(unsafe_code)]
134 // Allow globally until https://github.com/rust-lang/rust-clippy/issues/8768 is resolved.
135 // The desired state is to allow it only for the rstest_reuse import.
136 #![allow(clippy::single_component_path_imports)]
137 #![cfg_attr(not(any(feature = "std", test)), no_std)]
138 
139 #[cfg(all(feature = "alloc", not(any(feature = "std", test))))]
140 extern crate alloc;
141 #[cfg(any(feature = "std", test))]
142 extern crate std as alloc;
143 
144 // has to be included at top level because of the way rstest_reuse defines its macros
145 #[cfg(test)]
146 use rstest_reuse;
147 
148 mod chunked_encoder;
149 pub mod display;
150 #[cfg(any(feature = "std", test))]
151 pub mod read;
152 #[cfg(any(feature = "std", test))]
153 pub mod write;
154 
155 pub mod engine;
156 pub use engine::Engine;
157 
158 pub mod alphabet;
159 
160 mod encode;
161 #[allow(deprecated)]
162 #[cfg(any(feature = "alloc", feature = "std", test))]
163 pub use crate::encode::{encode, encode_engine, encode_engine_string};
164 #[allow(deprecated)]
165 pub use crate::encode::{encode_engine_slice, encoded_len, EncodeSliceError};
166 
167 mod decode;
168 #[allow(deprecated)]
169 #[cfg(any(feature = "alloc", feature = "std", test))]
170 pub use crate::decode::{decode, decode_engine, decode_engine_vec};
171 #[allow(deprecated)]
172 pub use crate::decode::{decode_engine_slice, decoded_len_estimate, DecodeError, DecodeSliceError};
173 
174 pub mod prelude;
175 
176 #[cfg(test)]
177 mod tests;
178 
179 const PAD_BYTE: u8 = b'=';
180