aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-02-02 23:52:37 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-02-02 23:52:37 +0000
commit9a1245d3ec655c9873d957deb776c5f39f6a76cd (patch)
tree090d8fd7c304c662f43d4d8cfd0d77a08a2a8138
parent733aad58e01977d2a9830b8c9bbe1d4ae778af12 (diff)
parent16917241ce89485898ef502a72956c6d2c32a3e8 (diff)
downloaddata-encoding-simpleperf-release.tar.gz
Snap for 11400057 from 16917241ce89485898ef502a72956c6d2c32a3e8 to simpleperf-releasesimpleperf-release
Change-Id: I2229bd1b9ea79c0ef3200aebb1a9ea356bc685b6
-rw-r--r--.cargo_vcs_info.json6
-rw-r--r--Android.bp2
-rw-r--r--Cargo.toml7
-rw-r--r--Cargo.toml.orig8
-rw-r--r--METADATA25
-rw-r--r--README.md4
-rw-r--r--src/lib.rs240
7 files changed, 213 insertions, 79 deletions
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 @@ rust_library {
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 @@ categories = [
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 @@ documentation = "https://docs.rs/data-encoding"
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 @@ See the [documentation] for more details.
[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 @@ macro_rules! dispatch {
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 @@ pub enum DecodeKind {
}
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 @@ pub struct DecodeError {
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 @@ fn encode_block<B: Static<usize>, M: Static<bool>>(
}
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 @@ fn decode_block<B: Static<usize>, M: Static<bool>>(
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 @@ fn decode_wrap_mut<B: Static<usize>, M: Static<bool>, P: Static<bool>, I: Static
/// 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 @@ pub type InternalEncoding = &'static [u8];
// - 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 @@ pub struct Encoding(pub InternalEncoding);
/// 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 @@ pub struct Translate {
/// 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 @@ pub struct Wrap {
/// 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 @@ impl Encoding {
(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 @@ impl Encoding {
/// 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 @@ impl Encoding {
/// 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 @@ impl Encoding {
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 @@ impl Encoding {
/// 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 @@ impl Encoding {
/// 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 @@ impl Encoding {
}
/// Returns the bit-width
+ #[must_use]
pub fn bit_width(&self) -> usize {
self.bit()
}
@@ -1471,6 +1510,7 @@ impl Encoding {
/// - 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 @@ impl Encoding {
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 @@ impl Encoding {
}
/// 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 @@ impl Encoding {
}
#[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 @@ impl Encoding {
}
#[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 @@ enum SpecificationErrorImpl {
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 @@ impl std::error::Error for SpecificationError {
#[cfg(feature = "alloc")]
impl Specification {
/// Returns a default specification
+ #[must_use]
pub fn new() -> Specification {
Specification {
symbols: String::new(),
@@ -1629,7 +1743,7 @@ impl Specification {
/// 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 @@ impl Specification {
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 @@ impl Specification {
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 @@ impl Specification {
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 @@ impl Specification {
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 @@ const BASE32_DNSSEC_IMPL: &[u8] = &[
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: