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 | |