Upgrade data-encoding to 2.5.0

This project was upgraded with external_updater.
Usage: tools/external_updater/updater.sh update external/rust/crates/data-encoding
For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md

Test: TreeHugger
Change-Id: I9f0cdbbab02ba778a045aca2003bf1e566dacbe0
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..17a6993
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "14391e0d2d845100b1feea0d59907ff542d86da5"
+  },
+  "path_in_vcs": "lib"
+}
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index e040c18..c0743f8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -6,7 +6,7 @@
     host_supported: true,
     crate_name: "data_encoding",
     cargo_env_compat: true,
-    cargo_pkg_version: "2.4.0",
+    cargo_pkg_version: "2.5.0",
     srcs: ["src/lib.rs"],
     edition: "2018",
     features: [
diff --git a/Cargo.toml b/Cargo.toml
index e4879f7..2f83776 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,9 +11,9 @@
 
 [package]
 edition = "2018"
-rust-version = "1.47"
+rust-version = "1.48"
 name = "data-encoding"
-version = "2.4.0"
+version = "2.5.0"
 authors = ["Julien Cretin <git@ia0.eu>"]
 include = [
     "Cargo.toml",
@@ -37,6 +37,9 @@
 license = "MIT"
 repository = "https://github.com/ia0/data-encoding"
 
+[package.metadata.docs.rs]
+rustdoc-args = ["--cfg=docsrs"]
+
 [features]
 alloc = []
 default = ["std"]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index d60c6e3..19ca78b 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,10 +1,10 @@
 [package]
 name = "data-encoding"
-version = "2.4.0"
+version = "2.5.0"
 authors = ["Julien Cretin <git@ia0.eu>"]
 license = "MIT"
 edition = "2018"
-rust-version = "1.47"
+rust-version = "1.48"
 keywords = ["no_std", "base64", "base32", "hex"]
 categories = ["encoding", "no-std"]
 readme = "README.md"
@@ -13,6 +13,10 @@
 description = "Efficient and customizable data-encoding functions like base64, base32, and hex"
 include = ["Cargo.toml", "LICENSE", "README.md", "src/lib.rs"]
 
+# TODO: Remove this once doc_auto_cfg is in the MSRV.
+[package.metadata.docs.rs]
+rustdoc-args = ["--cfg=docsrs"]
+
 [features]
 default = ["std"]
 alloc = []
diff --git a/METADATA b/METADATA
index c72af71..9fa161f 100644
--- a/METADATA
+++ b/METADATA
@@ -1,19 +1,20 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update external/rust/crates/data-encoding
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
+
 name: "data-encoding"
 description: "Efficient and customizable data-encoding functions like base64, base32, and hex"
 third_party {
-  url {
-    type: HOMEPAGE
-    value: "https://crates.io/crates/data-encoding"
-  }
-  url {
-    type: ARCHIVE
-    value: "https://static.crates.io/crates/data-encoding/data-encoding-2.4.0.crate"
-  }
-  version: "2.4.0"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2023
-    month: 6
-    day: 7
+    year: 2024
+    month: 2
+    day: 1
+  }
+  homepage: "https://crates.io/crates/data-encoding"
+  identifier {
+    type: "Archive"
+    value: "https://static.crates.io/crates/data-encoding/data-encoding-2.5.0.crate"
+    version: "2.5.0"
   }
 }
diff --git a/README.md b/README.md
index 64d2dec..41e5d86 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,6 @@
 
 [ci]: https://github.com/ia0/data-encoding/actions/workflows/ci.yml
 [ci_badge]: https://github.com/ia0/data-encoding/actions/workflows/ci.yml/badge.svg
-[coveralls]: https://coveralls.io/github/ia0/data-encoding?branch=master
-[coveralls_badge]: https://coveralls.io/repos/github/ia0/data-encoding/badge.svg?branch=master
+[coveralls]: https://coveralls.io/github/ia0/data-encoding?branch=main
+[coveralls_badge]: https://coveralls.io/repos/github/ia0/data-encoding/badge.svg?branch=main
 [documentation]: https://docs.rs/data-encoding
diff --git a/src/lib.rs b/src/lib.rs
index 14438ed..f393690 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -77,8 +77,8 @@
 //! - They are deterministic: their output only depends on their input
 //! - They have no side-effects: they do not modify any hidden mutable state
 //! - They are correct: encoding followed by decoding gives the initial data
-//! - They are canonical (unless [`is_canonical`] returns false): decoding followed by encoding gives the
-//!   initial data
+//! - They are canonical (unless [`is_canonical`] returns false): decoding followed by encoding
+//!   gives the initial data
 //!
 //! This last property is usually not satisfied by base64 implementations. This is a matter of
 //! choice and this crate has made the choice to let the user choose. Support for canonical encoding
@@ -144,7 +144,20 @@
 //! [wrapping]: struct.Specification.html#structfield.wrap
 
 #![no_std]
-#![warn(unused_results, missing_docs)]
+#![cfg_attr(docsrs, feature(doc_auto_cfg))]
+// TODO: This list up to warn(clippy::pedantic) should ideally use a lint group.
+#![warn(elided_lifetimes_in_paths)]
+// TODO(msrv): #![warn(let_underscore_drop)]
+#![warn(missing_debug_implementations)]
+#![warn(missing_docs)]
+#![warn(unreachable_pub)]
+// TODO(msrv): #![warn(unsafe_op_in_unsafe_fn)]
+#![warn(unused_results)]
+#![allow(unused_unsafe)] // TODO(msrv)
+#![warn(clippy::pedantic)]
+#![allow(clippy::enum_glob_use)]
+#![allow(clippy::similar_names)]
+#![allow(clippy::uninlined_format_args)] // TODO(msrv)
 
 #[cfg(feature = "alloc")]
 extern crate alloc;
@@ -242,14 +255,12 @@
 
 unsafe fn chunk_unchecked(x: &[u8], n: usize, i: usize) -> &[u8] {
     debug_assert!((i + 1) * n <= x.len());
-    let ptr = x.as_ptr().add(n * i);
-    core::slice::from_raw_parts(ptr, n)
+    unsafe { core::slice::from_raw_parts(x.as_ptr().add(n * i), n) }
 }
 
 unsafe fn chunk_mut_unchecked(x: &mut [u8], n: usize, i: usize) -> &mut [u8] {
     debug_assert!((i + 1) * n <= x.len());
-    let ptr = x.as_mut_ptr().add(n * i);
-    core::slice::from_raw_parts_mut(ptr, n)
+    unsafe { core::slice::from_raw_parts_mut(x.as_mut_ptr().add(n * i), n) }
 }
 
 fn div_ceil(x: usize, m: usize) -> usize {
@@ -288,7 +299,7 @@
 }
 
 impl core::fmt::Display for DecodeKind {
-    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         let description = match self {
             DecodeKind::Length => "invalid length",
             DecodeKind::Symbol => "invalid symbol",
@@ -315,7 +326,7 @@
 impl std::error::Error for DecodeError {}
 
 impl core::fmt::Display for DecodeError {
-    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         write!(f, "{} at {}", self.kind, self.position)
     }
 }
@@ -379,7 +390,7 @@
     }
     for (i, output) in output.iter_mut().enumerate() {
         let y = x >> (bit * order(msb, dec(bit), i));
-        *output = symbols[y as usize % 256];
+        *output = symbols[(y & 0xff) as usize];
     }
 }
 
@@ -419,7 +430,7 @@
         x |= u64::from(y) << (bit * order(msb, dec(bit), j));
     }
     for (j, output) in output.iter_mut().enumerate() {
-        *output = (x >> (8 * order(msb, enc(bit), j))) as u8;
+        *output = (x >> (8 * order(msb, enc(bit), j)) & 0xff) as u8;
     }
     Ok(())
 }
@@ -805,10 +816,6 @@
 /// assert_eq!(msb.encode(&[0b01010011]), "01010011");
 /// assert_eq!(lsb.encode(&[0b01010011]), "11001010");
 /// ```
-///
-/// # Features
-///
-/// Requires the `alloc` feature.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 #[cfg(feature = "alloc")]
 pub enum BitOrder {
@@ -871,7 +878,7 @@
 // - width % dec(bit) == 0
 // - for all x in separator values[x] is IGNORE
 #[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Encoding(pub InternalEncoding);
+pub struct Encoding(#[doc(hidden)] pub InternalEncoding);
 
 /// How to translate characters when decoding
 ///
@@ -879,10 +886,6 @@
 /// of the `to` field. The second to the second. Etc.
 ///
 /// See [Specification](struct.Specification.html) for more information.
-///
-/// # Features
-///
-/// Requires the `alloc` feature.
 #[derive(Debug, Clone)]
 #[cfg(feature = "alloc")]
 pub struct Translate {
@@ -896,10 +899,6 @@
 /// How to wrap the output when encoding
 ///
 /// See [Specification](struct.Specification.html) for more information.
-///
-/// # Features
-///
-/// Requires the `alloc` feature.
 #[derive(Debug, Clone)]
 #[cfg(feature = "alloc")]
 pub struct Wrap {
@@ -1154,10 +1153,6 @@
 /// assert_eq!(base.decode(b"BOIl"), base.decode(b"b011"));
 /// ```
 ///
-/// # Features
-///
-/// Requires the `alloc` feature.
-///
 /// [base-conversion]: https://en.wikipedia.org/wiki/Positional_notation#Base_conversion
 /// [canonical]: https://tools.ietf.org/html/rfc4648#section-3.5
 #[derive(Debug, Clone)]
@@ -1243,6 +1238,15 @@
         (self.0[513] & 0x7) as usize
     }
 
+    /// Minimum number of input and output blocks when encoding
+    fn block_len(&self) -> (usize, usize) {
+        let bit = self.bit();
+        match self.wrap() {
+            Some((col, end)) => (col / dec(bit) * enc(bit), col + end.len()),
+            None => (enc(bit), dec(bit)),
+        }
+    }
+
     fn wrap(&self) -> Option<(usize, &[u8])> {
         if self.0.len() <= 515 {
             return None;
@@ -1259,6 +1263,7 @@
     /// See [`encode_mut`] for when to use it.
     ///
     /// [`encode_mut`]: struct.Encoding.html#method.encode_mut
+    #[must_use]
     pub fn encode_len(&self, len: usize) -> usize {
         dispatch! {
             let bit: usize = self.bit();
@@ -1311,10 +1316,6 @@
     /// BASE64.encode_append(input, &mut output);
     /// assert_eq!(output, "Result: SGVsbG8gd29ybGQ=");
     /// ```
-    ///
-    /// # Features
-    ///
-    /// Requires the `alloc` feature.
     #[cfg(feature = "alloc")]
     pub fn encode_append(&self, input: &[u8], output: &mut String) {
         let output = unsafe { output.as_mut_vec() };
@@ -1323,6 +1324,50 @@
         self.encode_mut(input, &mut output[output_len ..]);
     }
 
+    /// Returns an object to encode a fragmented input and append it to `output`
+    ///
+    /// See the documentation of [`Encoder`] for more details and examples.
+    #[cfg(feature = "alloc")]
+    pub fn new_encoder<'a>(&'a self, output: &'a mut String) -> Encoder<'a> {
+        Encoder::new(self, output)
+    }
+
+    /// Writes the encoding of `input` to `output`
+    ///
+    /// This allocates a buffer of 1024 bytes on the stack. If you want to control the buffer size
+    /// and location, use [`Encoding::encode_write_buffer()`] instead.
+    ///
+    /// # Errors
+    ///
+    /// Returns an error when writing to the output fails.
+    pub fn encode_write(
+        &self, input: &[u8], output: &mut impl core::fmt::Write,
+    ) -> core::fmt::Result {
+        self.encode_write_buffer(input, output, &mut [0; 1024])
+    }
+
+    /// Writes the encoding of `input` to `output` using a temporary `buffer`
+    ///
+    /// # Panics
+    ///
+    /// Panics if the buffer is shorter than 510 bytes.
+    ///
+    /// # Errors
+    ///
+    /// Returns an error when writing to the output fails.
+    pub fn encode_write_buffer(
+        &self, input: &[u8], output: &mut impl core::fmt::Write, buffer: &mut [u8],
+    ) -> core::fmt::Result {
+        assert!(510 <= buffer.len());
+        let (enc, dec) = self.block_len();
+        for input in input.chunks(buffer.len() / dec * enc) {
+            let buffer = &mut buffer[.. self.encode_len(input.len())];
+            self.encode_mut(input, buffer);
+            output.write_str(unsafe { core::str::from_utf8_unchecked(buffer) })?;
+        }
+        Ok(())
+    }
+
     /// Returns encoded `input`
     ///
     /// # Examples
@@ -1331,11 +1376,8 @@
     /// use data_encoding::BASE64;
     /// assert_eq!(BASE64.encode(b"Hello world"), "SGVsbG8gd29ybGQ=");
     /// ```
-    ///
-    /// # Features
-    ///
-    /// Requires the `alloc` feature.
     #[cfg(feature = "alloc")]
+    #[must_use]
     pub fn encode(&self, input: &[u8]) -> String {
         let mut output = vec![0u8; self.encode_len(input.len())];
         self.encode_mut(input, &mut output);
@@ -1441,10 +1483,6 @@
     /// assert_eq!(BASE64.decode(b"SGVsbA==byB3b3JsZA==").unwrap(), b"Hello world");
     /// ```
     ///
-    /// # Features
-    ///
-    /// Requires the `alloc` feature.
-    ///
     /// [`Length`]: enum.DecodeKind.html#variant.Length
     /// [`Symbol`]: enum.DecodeKind.html#variant.Symbol
     /// [`Trailing`]: enum.DecodeKind.html#variant.Trailing
@@ -1459,6 +1497,7 @@
     }
 
     /// Returns the bit-width
+    #[must_use]
     pub fn bit_width(&self) -> usize {
         self.bit()
     }
@@ -1471,6 +1510,7 @@
     /// - padding is used
     /// - characters are ignored
     /// - characters are translated
+    #[must_use]
     pub fn is_canonical(&self) -> bool {
         if !self.ctb() {
             return false;
@@ -1485,7 +1525,7 @@
             if val[i] >= 1 << bit {
                 return false;
             }
-            if sym[val[i] as usize] != i as u8 {
+            if sym[val[i] as usize] as usize != i {
                 return false;
             }
         }
@@ -1493,11 +1533,9 @@
     }
 
     /// Returns the encoding specification
-    ///
-    /// # Features
-    ///
-    /// Requires the `alloc` feature.
+    #[allow(clippy::missing_panics_doc)] // no panic
     #[cfg(feature = "alloc")]
+    #[must_use]
     pub fn specification(&self) -> Specification {
         let mut specification = Specification::new();
         specification
@@ -1537,6 +1575,7 @@
     }
 
     #[doc(hidden)]
+    #[must_use]
     pub const fn internal_new(implementation: &'static [u8]) -> Encoding {
         #[cfg(feature = "alloc")]
         let encoding = Encoding(Cow::Borrowed(implementation));
@@ -1546,11 +1585,89 @@
     }
 
     #[doc(hidden)]
+    #[must_use]
     pub fn internal_implementation(&self) -> &[u8] {
         &self.0
     }
 }
 
+/// Encodes fragmented input to an output
+///
+/// It is equivalent to use an [`Encoder`] with multiple calls to [`Encoder::append()`] than to
+/// first concatenate all the input and then use [`Encoding::encode_append()`]. In particular, this
+/// function will not introduce padding or wrapping between inputs.
+///
+/// # Examples
+///
+/// ```rust
+/// // This is a bit inconvenient but we can't take a long-term reference to data_encoding::BASE64
+/// // because it's a constant. We need to use a static which has an address instead. This will be
+/// // fixed in version 3 of the library.
+/// static BASE64: data_encoding::Encoding = data_encoding::BASE64;
+/// let mut output = String::new();
+/// let mut encoder = BASE64.new_encoder(&mut output);
+/// encoder.append(b"hello");
+/// encoder.append(b"world");
+/// encoder.finalize();
+/// assert_eq!(output, BASE64.encode(b"helloworld"));
+/// ```
+#[derive(Debug)]
+#[cfg(feature = "alloc")]
+pub struct Encoder<'a> {
+    encoding: &'a Encoding,
+    output: &'a mut String,
+    buffer: [u8; 255],
+    length: u8,
+}
+
+#[cfg(feature = "alloc")]
+impl<'a> Drop for Encoder<'a> {
+    fn drop(&mut self) {
+        self.encoding.encode_append(&self.buffer[.. self.length as usize], self.output);
+    }
+}
+
+#[cfg(feature = "alloc")]
+impl<'a> Encoder<'a> {
+    fn new(encoding: &'a Encoding, output: &'a mut String) -> Self {
+        Encoder { encoding, output, buffer: [0; 255], length: 0 }
+    }
+
+    /// Encodes the provided input fragment and appends the result to the output
+    pub fn append(&mut self, mut input: &[u8]) {
+        #[allow(clippy::cast_possible_truncation)] // no truncation
+        let max = self.encoding.block_len().0 as u8;
+        if self.length != 0 {
+            let len = self.length;
+            #[allow(clippy::cast_possible_truncation)] // no truncation
+            let add = core::cmp::min((max - len) as usize, input.len()) as u8;
+            self.buffer[len as usize ..][.. add as usize].copy_from_slice(&input[.. add as usize]);
+            self.length += add;
+            input = &input[add as usize ..];
+            if self.length != max {
+                debug_assert!(self.length < max);
+                debug_assert!(input.is_empty());
+                return;
+            }
+            self.encoding.encode_append(&self.buffer[.. max as usize], self.output);
+            self.length = 0;
+        }
+        let len = floor(input.len(), max as usize);
+        self.encoding.encode_append(&input[.. len], self.output);
+        input = &input[len ..];
+        #[allow(clippy::cast_possible_truncation)] // no truncation
+        let len = input.len() as u8;
+        self.buffer[.. len as usize].copy_from_slice(input);
+        self.length = len;
+    }
+
+    /// Makes sure all inputs have been encoded and appended to the output
+    ///
+    /// This is equivalent to dropping the encoder and required for correctness, otherwise some
+    /// encoded data may be missing at the end.
+    pub fn finalize(self) {}
+}
+
 #[derive(Debug, Copy, Clone)]
 #[cfg(feature = "alloc")]
 enum SpecificationErrorImpl {
@@ -1567,17 +1684,13 @@
 use crate::SpecificationErrorImpl::*;
 
 /// Specification error
-///
-/// # Features
-///
-/// Requires the `alloc` feature.
 #[derive(Debug, Copy, Clone)]
 #[cfg(feature = "alloc")]
 pub struct SpecificationError(SpecificationErrorImpl);
 
 #[cfg(feature = "alloc")]
 impl core::fmt::Display for SpecificationError {
-    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         match self.0 {
             BadSize => write!(f, "invalid number of symbols"),
             NotAscii => write!(f, "non-ascii character"),
@@ -1610,6 +1723,7 @@
 #[cfg(feature = "alloc")]
 impl Specification {
     /// Returns a default specification
+    #[must_use]
     pub fn new() -> Specification {
         Specification {
             symbols: String::new(),
@@ -1629,7 +1743,7 @@
     /// Returns an error if the specification is invalid.
     pub fn encoding(&self) -> Result<Encoding, SpecificationError> {
         let symbols = self.symbols.as_bytes();
-        let bit: usize = match symbols.len() {
+        let bit: u8 = match symbols.len() {
             2 => 1,
             4 => 2,
             8 => 3,
@@ -1649,6 +1763,7 @@
             Ok(())
         };
         for (v, symbols) in symbols.iter().enumerate() {
+            #[allow(clippy::cast_possible_truncation)] // no truncation
             set(&mut values, *symbols, v as u8)?;
         }
         let msb = self.bit_order == MostSignificantFirst;
@@ -1668,15 +1783,19 @@
         let wrap = if self.wrap.separator.is_empty() || self.wrap.width == 0 {
             None
         } else {
-            Some((self.wrap.width, self.wrap.separator.as_bytes()))
-        };
-        if let Some((col, end)) = wrap {
+            let col = self.wrap.width;
+            let end = self.wrap.separator.as_bytes();
             check!(SpecificationError(WrapLength), col < 256 && end.len() < 256);
-            check!(SpecificationError(WrapWidth(dec(bit) as u8)), col % dec(bit) == 0);
-            for i in end.iter() {
-                set(&mut values, *i, IGNORE)?;
+            #[allow(clippy::cast_possible_truncation)] // no truncation
+            let col = col as u8;
+            #[allow(clippy::cast_possible_truncation)] // no truncation
+            let dec = dec(bit as usize) as u8;
+            check!(SpecificationError(WrapWidth(dec)), col % dec == 0);
+            for &i in end {
+                set(&mut values, i, IGNORE)?;
             }
-        }
+            Some((col, end))
+        };
         let from = self.translate.from.as_bytes();
         let to = self.translate.to.as_bytes();
         check!(SpecificationError(FromTo), from.len() == to.len());
@@ -1696,7 +1815,7 @@
             None => encoding.push(INVALID),
             Some(pad) => encoding.push(pad),
         }
-        encoding.push(bit as u8);
+        encoding.push(bit);
         if msb {
             encoding[513] |= 0x08;
         }
@@ -1704,7 +1823,7 @@
             encoding[513] |= 0x10;
         }
         if let Some((col, end)) = wrap {
-            encoding.push(col as u8);
+            encoding.push(col);
             encoding.extend_from_slice(end);
         } else if values.contains(&IGNORE) {
             encoding.push(0);
@@ -2130,6 +2249,7 @@
     128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 29,
 ];
 
+#[allow(clippy::doc_markdown)]
 /// DNSCurve base32 encoding
 ///
 /// This encoding is a static version of: