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