Upgrade base64 to 0.21.7 am: 86d8e5b747 am: 81ef64c5ce

Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/base64/+/2939820

Change-Id: I094842c9b7ff27dc08a29689a319618c559f2b99
Signed-off-by: Automerger Merge Worker <[email protected]>
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index c34d445..d61e543 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "7f81bafe0e76bcdb84f3069d81d56d77a7a24280"
+    "sha1": "9652c787730e58515ce7b44fcafd2430ab424628"
   },
   "path_in_vcs": ""
 }
\ No newline at end of file
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 70eb080..ac0fae1 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -51,6 +51,12 @@
           name: Log rustc version
           command: rustc --version
       - run:
+          name: Build main target
+          # update first to select dependencies appropriate for this toolchain
+          command: |
+            cargo update
+            cargo build
+      - run:
           name: Check formatting
           command: |
             rustup component add rustfmt
@@ -65,9 +71,6 @@
               cargo clippy --all-targets
             fi
       - run:
-          name: Build main target
-          command: cargo build
-      - run:
           name: Build all targets
           command: |
             if [[ '<< parameters.toolchain_override >>' != '__msrv__' ]]
diff --git a/Android.bp b/Android.bp
index 51c475d..22a37c0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,7 +42,7 @@
     host_supported: true,
     crate_name: "base64",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.21.5",
+    cargo_pkg_version: "0.21.7",
     srcs: ["src/lib.rs"],
     edition: "2018",
     features: [
diff --git a/Cargo.toml b/Cargo.toml
index 2de75ab..e508297 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
 edition = "2018"
 rust-version = "1.48.0"
 name = "base64"
-version = "0.21.5"
+version = "0.21.7"
 authors = [
     "Alice Maz <[email protected]>",
     "Marshall Pierce <[email protected]>",
@@ -58,24 +58,29 @@
 harness = false
 required-features = ["std"]
 
+[dev-dependencies.clap]
+version = "3.2.25"
+features = ["derive"]
+
 [dev-dependencies.criterion]
 version = "0.4.0"
 
-[dev-dependencies.lazy_static]
-version = "1.4.0"
+[dev-dependencies.once_cell]
+version = "1"
 
 [dev-dependencies.rand]
 version = "0.8.5"
 features = ["small_rng"]
 
 [dev-dependencies.rstest]
-version = "0.12.0"
+version = "0.13.0"
 
 [dev-dependencies.rstest_reuse]
-version = "0.3.0"
+version = "0.6.0"
 
-[dev-dependencies.structopt]
-version = "0.3.26"
+[dev-dependencies.strum]
+version = "0.25"
+features = ["derive"]
 
 [features]
 alloc = []
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index dc9437b..4db5d26 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "base64"
-version = "0.21.5"
+version = "0.21.7"
 authors = ["Alice Maz <[email protected]>", "Marshall Pierce <[email protected]>"]
 description = "encodes and decodes base64 as bytes or utf8"
 repository = "https://github.com/marshallpierce/rust-base64"
@@ -37,11 +37,14 @@
 [dev-dependencies]
 criterion = "0.4.0"
 rand = { version = "0.8.5", features = ["small_rng"] }
-structopt = "0.3.26"
+# Latest is 4.4.13 but specifies MSRV in Cargo.toml which means we can't depend
+# on it (even though we won't compile it in MSRV CI).
+clap = { version = "3.2.25", features = ["derive"] }
+strum = { version = "0.25", features = ["derive"] }
 # test fixtures for engine tests
-rstest = "0.12.0"
-rstest_reuse = "0.3.0"
-lazy_static = "1.4.0"
+rstest = "0.13.0"
+rstest_reuse = "0.6.0"
+once_cell = "1"
 
 [features]
 default = ["std"]
diff --git a/METADATA b/METADATA
index bfc6933..b4a6927 100644
--- a/METADATA
+++ b/METADATA
@@ -1,5 +1,5 @@
 # This project was upgraded with external_updater.
-# Usage: tools/external_updater/updater.sh update rust/crates/base64
+# Usage: tools/external_updater/updater.sh update external/rust/crates/base64
 # For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
 
 name: "base64"
@@ -7,14 +7,14 @@
 third_party {
   license_type: NOTICE
   last_upgrade_date {
-    year: 2023
-    month: 11
-    day: 24
+    year: 2024
+    month: 1
+    day: 31
   }
   homepage: "https://crates.io/crates/base64"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/base64/base64-0.21.5.crate"
-    version: "0.21.5"
+    value: "https://static.crates.io/crates/base64/base64-0.21.7.crate"
+    version: "0.21.7"
   }
 }
diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index d6d94c5..0031215 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -1,3 +1,11 @@
+# 0.21.7
+
+- Support getting an alphabet's contents as a str via `Alphabet::as_str()`
+
+# 0.21.6
+
+- Improved introductory documentation and example
+
 # 0.21.5
 
 - Add `Debug` and `Clone` impls for the general purpose Engine
diff --git a/examples/base64.rs b/examples/base64.rs
index 0a214d2..0c8aa3f 100644
--- a/examples/base64.rs
+++ b/examples/base64.rs
@@ -2,51 +2,40 @@
 use std::io::{self, Read};
 use std::path::PathBuf;
 use std::process;
-use std::str::FromStr;
 
 use base64::{alphabet, engine, read, write};
-use structopt::StructOpt;
+use clap::Parser;
 
-#[derive(Debug, StructOpt)]
+#[derive(Clone, Debug, Parser, strum::EnumString, Default)]
+#[strum(serialize_all = "kebab-case")]
 enum Alphabet {
+    #[default]
     Standard,
     UrlSafe,
 }
 
-impl Default for Alphabet {
-    fn default() -> Self {
-        Self::Standard
-    }
-}
-
-impl FromStr for Alphabet {
-    type Err = String;
-    fn from_str(s: &str) -> Result<Self, String> {
-        match s {
-            "standard" => Ok(Self::Standard),
-            "urlsafe" => Ok(Self::UrlSafe),
-            _ => Err(format!("alphabet '{}' unrecognized", s)),
-        }
-    }
-}
-
 /// Base64 encode or decode FILE (or standard input), to standard output.
-#[derive(Debug, StructOpt)]
+#[derive(Debug, Parser)]
 struct Opt {
-    /// decode data
-    #[structopt(short = "d", long = "decode")]
+    /// Decode the base64-encoded input (default: encode the input as base64).
+    #[structopt(short = 'd', long = "decode")]
     decode: bool,
-    /// The alphabet to choose. Defaults to the standard base64 alphabet.
-    /// Supported alphabets include "standard" and "urlsafe".
+
+    /// The encoding alphabet: "standard" (default) or "url-safe".
     #[structopt(long = "alphabet")]
     alphabet: Option<Alphabet>,
-    /// The file to encode/decode.
-    #[structopt(parse(from_os_str))]
+
+    /// Omit padding characters while encoding, and reject them while decoding.
+    #[structopt(short = 'p', long = "no-padding")]
+    no_padding: bool,
+
+    /// The file to encode or decode.
+    #[structopt(name = "FILE", parse(from_os_str))]
     file: Option<PathBuf>,
 }
 
 fn main() {
-    let opt = Opt::from_args();
+    let opt = Opt::parse();
     let stdin;
     let mut input: Box<dyn Read> = match opt.file {
         None => {
@@ -66,7 +55,10 @@
             Alphabet::Standard => alphabet::STANDARD,
             Alphabet::UrlSafe => alphabet::URL_SAFE,
         },
-        engine::general_purpose::PAD,
+        match opt.no_padding {
+            true => engine::general_purpose::NO_PAD,
+            false => engine::general_purpose::PAD,
+        },
     );
 
     let stdout = io::stdout();
diff --git a/src/alphabet.rs b/src/alphabet.rs
index f7cd819..7895914 100644
--- a/src/alphabet.rs
+++ b/src/alphabet.rs
@@ -38,17 +38,18 @@
 /// };
 /// ```
 ///
-/// Building a lazy_static:
+/// Building lazily:
 ///
 /// ```
 /// use base64::{
 ///     alphabet::Alphabet,
 ///     engine::{general_purpose::GeneralPurpose, GeneralPurposeConfig},
 /// };
+/// use once_cell::sync::Lazy;
 ///
-/// lazy_static::lazy_static! {
-///     static ref CUSTOM: Alphabet = Alphabet::new("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/").unwrap();
-/// }
+/// static CUSTOM: Lazy<Alphabet> = Lazy::new(||
+///     Alphabet::new("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/").unwrap()
+/// );
 /// ```
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct Alphabet {
@@ -122,6 +123,11 @@
 
         Ok(Self::from_str_unchecked(alphabet))
     }
+
+    /// Create a `&str` from the symbols in the `Alphabet`
+    pub fn as_str(&self) -> &str {
+        core::str::from_utf8(&self.symbols).unwrap()
+    }
 }
 
 impl convert::TryFrom<&str> for Alphabet {
@@ -159,21 +165,21 @@
 #[cfg(any(feature = "std", test))]
 impl error::Error for ParseAlphabetError {}
 
-/// The standard alphabet (uses `+` and `/`).
+/// The standard alphabet (with `+` and `/`) specified in [RFC 4648][].
 ///
-/// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3).
+/// [RFC 4648]: https://datatracker.ietf.org/doc/html/rfc4648#section-4
 pub const STANDARD: Alphabet = Alphabet::from_str_unchecked(
     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
 );
 
-/// The URL safe alphabet (uses `-` and `_`).
+/// The URL-safe alphabet (with `-` and `_`) specified in [RFC 4648][].
 ///
-/// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-4).
+/// [RFC 4648]: https://datatracker.ietf.org/doc/html/rfc4648#section-5
 pub const URL_SAFE: Alphabet = Alphabet::from_str_unchecked(
     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
 );
 
-/// The `crypt(3)` alphabet (uses `.` and `/` as the first two values).
+/// The `crypt(3)` alphabet (with `.` and `/` as the _first_ two characters).
 ///
 /// Not standardized, but folk wisdom on the net asserts that this alphabet is what crypt uses.
 pub const CRYPT: Alphabet = Alphabet::from_str_unchecked(
@@ -185,7 +191,7 @@
     "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
 );
 
-/// The alphabet used in IMAP-modified UTF-7 (uses `+` and `,`).
+/// The alphabet used in IMAP-modified UTF-7 (with `+` and `,`).
 ///
 /// See [RFC 3501](https://tools.ietf.org/html/rfc3501#section-5.1.3)
 pub const IMAP_MUTF7: Alphabet = Alphabet::from_str_unchecked(
@@ -269,4 +275,11 @@
                 .unwrap()
         );
     }
+
+    #[test]
+    fn str_same_as_input() {
+        let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+        let a = Alphabet::try_from(alphabet).unwrap();
+        assert_eq!(alphabet, a.as_str())
+    }
 }
diff --git a/src/encode.rs b/src/encode.rs
index 88e6499..ae6d790 100644
--- a/src/encode.rs
+++ b/src/encode.rs
@@ -98,7 +98,8 @@
     let rem = bytes_len % 3;
 
     let complete_input_chunks = bytes_len / 3;
-    // `let Some(_) = _ else` requires 1.65.0, whereas this messier one works on 1.48
+    // `?` is disallowed in const, and `let Some(_) = _ else` requires 1.65.0, whereas this
+    // messier syntax works on 1.48
     let complete_chunk_output =
         if let Some(complete_chunk_output) = complete_input_chunks.checked_mul(4) {
             complete_chunk_output
diff --git a/src/lib.rs b/src/lib.rs
index 6b11fa6..6ec3c12 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,100 +1,124 @@
-//! # Getting started
+//! Correct, fast, and configurable [base64][] decoding and encoding. Base64
+//! transports binary data efficiently in contexts where only plain text is
+//! allowed.
 //!
-//! 1. Perhaps one of the preconfigured engines in [engine::general_purpose] will suit, e.g.
-//! [engine::general_purpose::STANDARD_NO_PAD].
-//!     - These are re-exported in [prelude] with a `BASE64_` prefix for those who prefer to
-//!       `use base64::prelude::*` or equivalent, e.g. [prelude::BASE64_STANDARD_NO_PAD]
-//! 1. If not, choose which alphabet you want. Most usage will want [alphabet::STANDARD] or [alphabet::URL_SAFE].
-//! 1. Choose which [Engine] implementation you want. For the moment there is only one: [engine::GeneralPurpose].
-//! 1. Configure the engine appropriately using the engine's `Config` type.
-//!     - This is where you'll select whether to add padding (when encoding) or expect it (when
-//!     decoding). If given the choice, prefer no padding.
-//! 1. Build the engine using the selected alphabet and config.
+//! [base64]: https://developer.mozilla.org/en-US/docs/Glossary/Base64
 //!
-//! For more detail, see below.
+//! # Usage
 //!
-//! ## Alphabets
+//! Use an [`Engine`] to decode or encode base64, configured with the base64
+//! alphabet and padding behavior best suited to your application.
 //!
-//! An [alphabet::Alphabet] defines what ASCII symbols are used to encode to or decode from.
+//! ## Engine setup
 //!
-//! Constants in [alphabet] like [alphabet::STANDARD] or [alphabet::URL_SAFE] provide commonly used
-//! alphabets, but you can also build your own custom [alphabet::Alphabet] if needed.
+//! There is more than one way to encode a stream of bytes as “base64”.
+//! Different applications use different encoding
+//! [alphabets][alphabet::Alphabet] and
+//! [padding behaviors][engine::general_purpose::GeneralPurposeConfig].
 //!
-//! ## Engines
+//! ### Encoding alphabet
 //!
-//! Once you have an `Alphabet`, you can pick which `Engine` you want. A few parts of the public
-//! API provide a default, but otherwise the user must provide an `Engine` to use.
+//! Almost all base64 [alphabets][alphabet::Alphabet] use `A-Z`, `a-z`, and
+//! `0-9`, which gives nearly 64 characters (26 + 26 + 10 = 62), but they differ
+//! in their choice of their final 2.
 //!
-//! See [Engine] for more.
-//!
-//! ## Config
-//!
-//! In addition to an `Alphabet`, constructing an `Engine` also requires an [engine::Config]. Each
-//! `Engine` has a corresponding `Config` implementation since different `Engine`s may offer different
-//! levels of configurability.
-//!
-//! # Encoding
-//!
-//! Several different encoding methods on [Engine] are available to you depending on your desire for
-//! convenience vs performance.
-//!
-//! | Method                   | Output                       | Allocates                      |
-//! | ------------------------ | ---------------------------- | ------------------------------ |
-//! | [Engine::encode]         | Returns a new `String`       | Always                         |
-//! | [Engine::encode_string]  | Appends to provided `String` | Only if `String` needs to grow |
-//! | [Engine::encode_slice]   | Writes to provided `&[u8]`   | Never - fastest                |
-//!
-//! All of the encoding methods will pad as per the engine's config.
-//!
-//! # Decoding
-//!
-//! Just as for encoding, there are different decoding methods available.
-//!
-//! | Method                   | Output                        | Allocates                      |
-//! | ------------------------ | ----------------------------- | ------------------------------ |
-//! | [Engine::decode]         | Returns a new `Vec<u8>`       | Always                         |
-//! | [Engine::decode_vec]     | Appends to provided `Vec<u8>` | Only if `Vec` needs to grow    |
-//! | [Engine::decode_slice]   | Writes to provided `&[u8]`    | Never - fastest                |
-//!
-//! Unlike encoding, where all possible input is valid, decoding can fail (see [DecodeError]).
-//!
-//! Input can be invalid because it has invalid characters or invalid padding. The nature of how
-//! padding is checked depends on the engine's config.
-//! Whitespace in the input is invalid, just like any other non-base64 byte.
-//!
-//! # `Read` and `Write`
-//!
-//! To decode a [std::io::Read] of b64 bytes, wrap a reader (file, network socket, etc) with
-//! [read::DecoderReader].
-//!
-//! To write raw bytes and have them b64 encoded on the fly, wrap a [std::io::Write] with
-//! [write::EncoderWriter].
-//!
-//! There is some performance overhead (15% or so) because of the necessary buffer shuffling --
-//! still fast enough that almost nobody cares. Also, these implementations do not heap allocate.
-//!
-//! # `Display`
-//!
-//! See [display] for how to transparently base64 data via a `Display` implementation.
-//!
-//! # Examples
-//!
-//! ## Using predefined engines
+//! Most applications use the [standard][alphabet::STANDARD] alphabet specified
+//! in [RFC 4648][rfc-alphabet].  If that’s all you need, you can get started
+//! quickly by using the pre-configured
+//! [`STANDARD`][engine::general_purpose::STANDARD] engine, which is also available
+//! in the [`prelude`] module as shown here, if you prefer a minimal `use`
+//! footprint.
 //!
 #![cfg_attr(feature = "alloc", doc = "```")]
 #![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
-//! use base64::{Engine as _, engine::general_purpose};
+//! use base64::prelude::*;
 //!
-//! let orig = b"data";
-//! let encoded: String = general_purpose::STANDARD_NO_PAD.encode(orig);
-//! assert_eq!("ZGF0YQ", encoded);
-//! assert_eq!(orig.as_slice(), &general_purpose::STANDARD_NO_PAD.decode(encoded).unwrap());
-//!
-//! // or, URL-safe
-//! let encoded_url = general_purpose::URL_SAFE_NO_PAD.encode(orig);
+//! # fn main() -> Result<(), base64::DecodeError> {
+//! assert_eq!(BASE64_STANDARD.decode(b"+uwgVQA=")?, b"\xFA\xEC\x20\x55\0");
+//! assert_eq!(BASE64_STANDARD.encode(b"\xFF\xEC\x20\x55\0"), "/+wgVQA=");
+//! # Ok(())
+//! # }
 //! ```
 //!
-//! ## Custom alphabet, config, and engine
+//! [rfc-alphabet]: https://datatracker.ietf.org/doc/html/rfc4648#section-4
+//!
+//! Other common alphabets are available in the [`alphabet`] module.
+//!
+//! #### URL-safe alphabet
+//!
+//! The standard alphabet uses `+` and `/` as its two non-alphanumeric tokens,
+//! which cannot be safely used in URL’s without encoding them as `%2B` and
+//! `%2F`.
+//!
+//! To avoid that, some applications use a [“URL-safe” alphabet][alphabet::URL_SAFE],
+//! which uses `-` and `_` instead. To use that alternative alphabet, use the
+//! [`URL_SAFE`][engine::general_purpose::URL_SAFE] engine. This example doesn't
+//! use [`prelude`] to show what a more explicit `use` would look like.
+//!
+#![cfg_attr(feature = "alloc", doc = "```")]
+#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
+//! use base64::{engine::general_purpose::URL_SAFE, Engine as _};
+//!
+//! # fn main() -> Result<(), base64::DecodeError> {
+//! assert_eq!(URL_SAFE.decode(b"-uwgVQA=")?, b"\xFA\xEC\x20\x55\0");
+//! assert_eq!(URL_SAFE.encode(b"\xFF\xEC\x20\x55\0"), "_-wgVQA=");
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! ### Padding characters
+//!
+//! Each base64 character represents 6 bits (2⁶ = 64) of the original binary
+//! data, and every 3 bytes of input binary data will encode to 4 base64
+//! characters (8 bits × 3 = 6 bits × 4 = 24 bits).
+//!
+//! When the input is not an even multiple of 3 bytes in length, [canonical][]
+//! base64 encoders insert padding characters at the end, so that the output
+//! length is always a multiple of 4:
+//!
+//! [canonical]: https://datatracker.ietf.org/doc/html/rfc4648#section-3.5
+//!
+#![cfg_attr(feature = "alloc", doc = "```")]
+#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
+//! use base64::{engine::general_purpose::STANDARD, Engine as _};
+//!
+//! assert_eq!(STANDARD.encode(b""),    "");
+//! assert_eq!(STANDARD.encode(b"f"),   "Zg==");
+//! assert_eq!(STANDARD.encode(b"fo"),  "Zm8=");
+//! assert_eq!(STANDARD.encode(b"foo"), "Zm9v");
+//! ```
+//!
+//! Canonical encoding ensures that base64 encodings will be exactly the same,
+//! byte-for-byte, regardless of input length. But the `=` padding characters
+//! aren’t necessary for decoding, and they may be omitted by using a
+//! [`NO_PAD`][engine::general_purpose::NO_PAD] configuration:
+//!
+#![cfg_attr(feature = "alloc", doc = "```")]
+#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
+//! use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _};
+//!
+//! assert_eq!(STANDARD_NO_PAD.encode(b""),    "");
+//! assert_eq!(STANDARD_NO_PAD.encode(b"f"),   "Zg");
+//! assert_eq!(STANDARD_NO_PAD.encode(b"fo"),  "Zm8");
+//! assert_eq!(STANDARD_NO_PAD.encode(b"foo"), "Zm9v");
+//! ```
+//!
+//! The pre-configured `NO_PAD` engines will reject inputs containing padding
+//! `=` characters. To encode without padding and still accept padding while
+//! decoding, create an [engine][engine::general_purpose::GeneralPurpose] with
+//! that [padding mode][engine::DecodePaddingMode].
+//!
+#![cfg_attr(feature = "alloc", doc = "```")]
+#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
+//! # use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _};
+//! assert_eq!(STANDARD_NO_PAD.decode(b"Zm8="), Err(base64::DecodeError::InvalidPadding));
+//! ```
+//!
+//! ### Further customization
+//!
+//! Decoding and encoding behavior can be customized by creating an
+//! [engine][engine::GeneralPurpose] with an [alphabet][alphabet::Alphabet] and
+//! [padding configuration][engine::GeneralPurposeConfig]:
 //!
 #![cfg_attr(feature = "alloc", doc = "```")]
 #![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
@@ -117,6 +141,81 @@
 //!
 //! ```
 //!
+//! ## Memory allocation
+//!
+//! The [decode][Engine::decode()] and [encode][Engine::encode()] engine methods
+//! allocate memory for their results – `decode` returns a `Vec<u8>` and
+//! `encode` returns a `String`. To instead decode or encode into a buffer that
+//! you allocated, use one of the alternative methods:
+//!
+//! #### Decoding
+//!
+//! | Method                     | Output                        | Allocates memory              |
+//! | -------------------------- | ----------------------------- | ----------------------------- |
+//! | [`Engine::decode`]         | returns a new `Vec<u8>`       | always                        |
+//! | [`Engine::decode_vec`]     | appends to provided `Vec<u8>` | if `Vec` lacks capacity       |
+//! | [`Engine::decode_slice`]   | writes to provided `&[u8]`    | never
+//!
+//! #### Encoding
+//!
+//! | Method                     | Output                       | Allocates memory               |
+//! | -------------------------- | ---------------------------- | ------------------------------ |
+//! | [`Engine::encode`]         | returns a new `String`       | always                         |
+//! | [`Engine::encode_string`]  | appends to provided `String` | if `String` lacks capacity     |
+//! | [`Engine::encode_slice`]   | writes to provided `&[u8]`   | never                          |
+//!
+//! ## Input and output
+//!
+//! The `base64` crate can [decode][Engine::decode()] and
+//! [encode][Engine::encode()] values in memory, or
+//! [`DecoderReader`][read::DecoderReader] and
+//! [`EncoderWriter`][write::EncoderWriter] provide streaming decoding and
+//! encoding for any [readable][std::io::Read] or [writable][std::io::Write]
+//! byte stream.
+//!
+//! #### Decoding
+//!
+#![cfg_attr(feature = "std", doc = "```")]
+#![cfg_attr(not(feature = "std"), doc = "```ignore")]
+//! # use std::io;
+//! use base64::{engine::general_purpose::STANDARD, read::DecoderReader};
+//!
+//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
+//! let mut input = io::stdin();
+//! let mut decoder = DecoderReader::new(&mut input, &STANDARD);
+//! io::copy(&mut decoder, &mut io::stdout())?;
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! #### Encoding
+//!
+#![cfg_attr(feature = "std", doc = "```")]
+#![cfg_attr(not(feature = "std"), doc = "```ignore")]
+//! # use std::io;
+//! use base64::{engine::general_purpose::STANDARD, write::EncoderWriter};
+//!
+//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
+//! let mut output = io::stdout();
+//! let mut encoder = EncoderWriter::new(&mut output, &STANDARD);
+//! io::copy(&mut io::stdin(), &mut encoder)?;
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! #### Display
+//!
+//! If you only need a base64 representation for implementing the
+//! [`Display`][std::fmt::Display] trait, use
+//! [`Base64Display`][display::Base64Display]:
+//!
+//! ```
+//! use base64::{display::Base64Display, engine::general_purpose::STANDARD};
+//!
+//! let value = Base64Display::new(b"\0\x01\x02\x03", &STANDARD);
+//! assert_eq!("base64: AAECAw==", format!("base64: {}", value));
+//! ```
+//!
 //! # Panics
 //!
 //! If length calculations result in overflowing `usize`, a panic will result.