diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-02-06 20:49:38 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-02-06 20:49:38 +0000 |
commit | e28df0fd612235b5d070f76c2f9086e055ba46f4 (patch) | |
tree | 090d8fd7c304c662f43d4d8cfd0d77a08a2a8138 | |
parent | 51314055696511647d11cb511623a87a5022e862 (diff) | |
parent | 16917241ce89485898ef502a72956c6d2c32a3e8 (diff) | |
download | data-encoding-e28df0fd612235b5d070f76c2f9086e055ba46f4.tar.gz |
Snap for 11413053 from 16917241ce89485898ef502a72956c6d2c32a3e8 to build-tools-release
Change-Id: I6840f97dd1ff0f9529763be68c74967a72043324
-rw-r--r-- | .cargo_vcs_info.json | 6 | ||||
-rw-r--r-- | Android.bp | 2 | ||||
-rw-r--r-- | Cargo.toml | 7 | ||||
-rw-r--r-- | Cargo.toml.orig | 8 | ||||
-rw-r--r-- | METADATA | 25 | ||||
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | src/lib.rs | 240 |
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 @@ -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: [ @@ -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 = [] @@ -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" } } @@ -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 @@ -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: |