summaryrefslogtreecommitdiffstats
path: root/third_party/rust/base16/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/base16/src/lib.rs')
-rw-r--r--third_party/rust/base16/src/lib.rs639
1 files changed, 639 insertions, 0 deletions
diff --git a/third_party/rust/base16/src/lib.rs b/third_party/rust/base16/src/lib.rs
new file mode 100644
index 0000000000..4f8c384216
--- /dev/null
+++ b/third_party/rust/base16/src/lib.rs
@@ -0,0 +1,639 @@
+//! This is a base16 (e.g. hexadecimal) encoding and decoding library with an
+//! emphasis on performance. The API is very similar and inspired by the base64
+//! crate's API, however it's less complex (base16 is much more simple than
+//! base64).
+//!
+//! # Encoding
+//!
+//! The config options at the moment are limited to the output case (upper vs
+//! lower).
+//!
+//! | Function | Output | Allocates | Requires `alloc` feature |
+//! | ---------------------------------- | ---------------------------- | ----------------------- | ------------------------ |
+//! | [`encode_upper`], [`encode_lower`] | Returns a new `String` | Always | Yes |
+//! | [`encode_config`] | Returns a new `String` | Always | Yes |
+//! | [`encode_config_buf`] | Appends to provided `String` | If buffer needs to grow | Yes |
+//! | [`encode_config_slice`] | Writes to provided `&[u8]` | Never | No |
+//!
+//! # Decoding
+//!
+//! Note that there are no config options (In the future one might be added to
+//! restrict the input character set, but it's not clear to me that this is
+//! useful).
+//!
+//! | Function | Output | Allocates | Requires `alloc` feature |
+//! | ----------------- | ----------------------------- | ----------------------- | ------------------------ |
+//! | [`decode`] | Returns a new `Vec<u8>` | Always | Yes |
+//! | [`decode_slice`] | Writes to provided `&[u8]` | Never | No |
+//! | [`decode_buf`] | Appends to provided `Vec<u8>` | If buffer needs to grow | Yes |
+//!
+//! # Features
+//!
+//! This crate has two features, both are enabled by default and exist to allow
+//! users in `no_std` environments to disable various portions of .
+//!
+//! - The `"alloc"` feature, which is on by default, adds a number of helpful
+//! functions that require use of the [`alloc`][alloc_crate] crate, but not the
+//! rest of `std`.
+//! - This is `no_std` compatible.
+//! - Each function should list whether or not it requires this feature
+//! under the `Availability` of its documentation.
+//!
+//! - The `"std"` feature, which is on by default, enables the `"alloc"`
+//! feature, and additionally makes [`DecodeError`] implement the
+//! `std::error::Error` trait.
+//!
+//! - Frustratingly, this trait is in `std` (and not in `core` or `alloc`),
+//! but not implementing it would be quite annoying for some users, so
+//! it's kept, even though it's what prevents us from being `no_std`
+//! compatible in all configurations.
+//!
+//! [alloc_crate]: https://doc.rust-lang.org/alloc/index.html
+
+#![cfg_attr(not(feature = "std"), no_std)]
+#![deny(missing_docs)]
+
+#[cfg(feature = "alloc")]
+extern crate alloc;
+
+#[cfg(feature = "alloc")]
+use alloc::{vec::Vec, string::String};
+
+/// Configuration options for encoding. Just specifies whether or not output
+/// should be uppercase or lowercase.
+#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub enum EncConfig {
+ /// Encode using lower case characters for hex values >= 10
+ EncodeLower,
+ /// Encode using upper case characters for hex values >= 10
+ EncodeUpper,
+}
+
+pub use EncConfig::*;
+
+#[inline]
+fn encoded_size(source_len: usize) -> usize {
+ const USIZE_TOP_BIT: usize = 1usize << (core::mem::size_of::<usize>() * 8 - 1);
+ if (source_len & USIZE_TOP_BIT) != 0 {
+ usize_overflow(source_len)
+ }
+ source_len << 1
+}
+
+#[inline]
+fn encode_slice_raw(src: &[u8], cfg: EncConfig, dst: &mut [u8]) {
+ let lut = if cfg == EncodeLower { HEX_LOWER } else { HEX_UPPER };
+ debug_assert!(dst.len() == encoded_size(src.len()));
+ dst.chunks_exact_mut(2).zip(src.iter().copied()).for_each(|(d, sb)| {
+ d[0] = lut[(sb >> 4) as usize];
+ d[1] = lut[(sb & 0xf) as usize];
+ })
+}
+
+#[cfg(feature = "alloc")]
+#[inline]
+fn encode_to_string(bytes: &[u8], cfg: EncConfig) -> String {
+ let size = encoded_size(bytes.len());
+ let mut buf: Vec<u8> = Vec::with_capacity(size);
+ unsafe { buf.set_len(size); }
+ encode_slice_raw(bytes, cfg, &mut buf);
+ debug_assert!(core::str::from_utf8(&buf).is_ok());
+ unsafe { String::from_utf8_unchecked(buf) }
+}
+
+#[cfg(feature = "alloc")]
+#[inline]
+unsafe fn grow_vec_uninitialized(v: &mut Vec<u8>, grow_by: usize) -> usize {
+ v.reserve(grow_by);
+ let initial_len = v.len();
+ let new_len = initial_len + grow_by;
+ debug_assert!(new_len <= v.capacity());
+ v.set_len(new_len);
+ initial_len
+}
+
+/// Encode bytes as base16, using lower case characters for nibbles between 10
+/// and 15 (`a` through `f`).
+///
+/// This is equivalent to `base16::encode_config(bytes, base16::EncodeUpper)`.
+///
+/// # Example
+///
+/// ```
+/// assert_eq!(base16::encode_lower(b"Hello World"), "48656c6c6f20576f726c64");
+/// assert_eq!(base16::encode_lower(&[0xff, 0xcc, 0xaa]), "ffccaa");
+/// ```
+///
+/// # Availability
+///
+/// This function is only available when the `alloc` feature is enabled, as it
+/// needs to produce a String.
+#[cfg(feature = "alloc")]
+#[inline]
+pub fn encode_lower<T: ?Sized + AsRef<[u8]>>(input: &T) -> String {
+ encode_to_string(input.as_ref(), EncodeLower)
+}
+
+/// Encode bytes as base16, using upper case characters for nibbles between
+/// 10 and 15 (`A` through `F`).
+///
+/// This is equivalent to `base16::encode_config(bytes, base16::EncodeUpper)`.
+///
+/// # Example
+///
+/// ```
+/// assert_eq!(base16::encode_upper(b"Hello World"), "48656C6C6F20576F726C64");
+/// assert_eq!(base16::encode_upper(&[0xff, 0xcc, 0xaa]), "FFCCAA");
+/// ```
+///
+/// # Availability
+///
+/// This function is only available when the `alloc` feature is enabled, as it
+/// needs to produce a `String`.
+#[cfg(feature = "alloc")]
+#[inline]
+pub fn encode_upper<T: ?Sized + AsRef<[u8]>>(input: &T) -> String {
+ encode_to_string(input.as_ref(), EncodeUpper)
+}
+
+
+/// Encode `input` into a string using the listed config. The resulting string
+/// contains `input.len() * 2` bytes.
+///
+/// # Example
+///
+/// ```
+/// let data = [1, 2, 3, 0xaa, 0xbb, 0xcc];
+/// assert_eq!(base16::encode_config(&data, base16::EncodeLower), "010203aabbcc");
+/// assert_eq!(base16::encode_config(&data, base16::EncodeUpper), "010203AABBCC");
+/// ```
+///
+/// # Availability
+///
+/// This function is only available when the `alloc` feature is enabled, as it
+/// needs to produce a `String`.
+#[cfg(feature = "alloc")]
+#[inline]
+pub fn encode_config<T: ?Sized + AsRef<[u8]>>(input: &T, cfg: EncConfig) -> String {
+ encode_to_string(input.as_ref(), cfg)
+}
+
+/// Encode `input` into the end of the provided buffer. Returns the number of
+/// bytes that were written.
+///
+/// Only allocates when `dst.size() + (input.len() * 2) >= dst.capacity()`.
+///
+/// # Example
+///
+/// ```
+/// let messages = &["Taako, ", "Merle, ", "Magnus"];
+/// let mut buffer = String::new();
+/// for msg in messages {
+/// let bytes_written = base16::encode_config_buf(msg.as_bytes(),
+/// base16::EncodeUpper,
+/// &mut buffer);
+/// assert_eq!(bytes_written, msg.len() * 2);
+/// }
+/// assert_eq!(buffer, "5461616B6F2C204D65726C652C204D61676E7573");
+/// ```
+/// # Availability
+///
+/// This function is only available when the `alloc` feature is enabled, as it
+/// needs write to a `String`.
+#[cfg(feature = "alloc")]
+#[inline]
+pub fn encode_config_buf<T: ?Sized + AsRef<[u8]>>(input: &T,
+ cfg: EncConfig,
+ dst: &mut String) -> usize {
+ let src = input.as_ref();
+ let bytes_to_write = encoded_size(src.len());
+ // Swap the string out while we work on it, so that if we panic, we don't
+ // leave behind garbage (we do clear the string if we panic, but that's
+ // better than UB)
+ let mut buf = core::mem::replace(dst, String::new()).into_bytes();
+ let cur_size = unsafe { grow_vec_uninitialized(&mut buf, bytes_to_write) };
+
+ encode_slice_raw(src, cfg, &mut buf[cur_size..]);
+
+ debug_assert!(core::str::from_utf8(&buf).is_ok());
+ // Put `buf` back into `dst`.
+ *dst = unsafe { String::from_utf8_unchecked(buf) };
+
+ bytes_to_write
+}
+
+/// Write bytes as base16 into the provided output buffer. Never allocates.
+///
+/// This is useful if you wish to avoid allocation entirely (e.g. your
+/// destination buffer is on the stack), or control it precisely.
+///
+/// # Panics
+///
+/// Panics if the desination buffer is insufficiently large.
+///
+/// # Example
+///
+/// ```
+/// # extern crate core as std;
+/// // Writing to a statically sized buffer on the stack.
+/// let message = b"Wu-Tang Killa Bees";
+/// let mut buffer = [0u8; 1024];
+///
+/// let wrote = base16::encode_config_slice(message,
+/// base16::EncodeLower,
+/// &mut buffer);
+///
+/// assert_eq!(message.len() * 2, wrote);
+/// assert_eq!(std::str::from_utf8(&buffer[..wrote]).unwrap(),
+/// "57752d54616e67204b696c6c612042656573");
+///
+/// // Appending to an existing buffer is possible too.
+/// let wrote2 = base16::encode_config_slice(b": The Swarm",
+/// base16::EncodeLower,
+/// &mut buffer[wrote..]);
+/// let write_end = wrote + wrote2;
+/// assert_eq!(std::str::from_utf8(&buffer[..write_end]).unwrap(),
+/// "57752d54616e67204b696c6c6120426565733a2054686520537761726d");
+/// ```
+/// # Availability
+///
+/// This function is available whether or not the `alloc` feature is enabled.
+#[inline]
+pub fn encode_config_slice<T: ?Sized + AsRef<[u8]>>(input: &T,
+ cfg: EncConfig,
+ dst: &mut [u8]) -> usize {
+ let src = input.as_ref();
+ let need_size = encoded_size(src.len());
+ if dst.len() < need_size {
+ dest_too_small_enc(dst.len(), need_size);
+ }
+ encode_slice_raw(src, cfg, &mut dst[..need_size]);
+ need_size
+}
+
+/// Encode a single character as hex, returning a tuple containing the two
+/// encoded bytes in big-endian order -- the order the characters would be in
+/// when written out (e.g. the top nibble is the first item in the tuple)
+///
+/// # Example
+/// ```
+/// assert_eq!(base16::encode_byte(0xff, base16::EncodeLower), [b'f', b'f']);
+/// assert_eq!(base16::encode_byte(0xa0, base16::EncodeUpper), [b'A', b'0']);
+/// assert_eq!(base16::encode_byte(3, base16::EncodeUpper), [b'0', b'3']);
+/// ```
+/// # Availability
+///
+/// This function is available whether or not the `alloc` feature is enabled.
+#[inline]
+pub fn encode_byte(byte: u8, cfg: EncConfig) -> [u8; 2] {
+ let lut = if cfg == EncodeLower { HEX_LOWER } else { HEX_UPPER };
+ let lo = lut[(byte & 15) as usize];
+ let hi = lut[(byte >> 4) as usize];
+ [hi, lo]
+}
+
+/// Convenience wrapper for `base16::encode_byte(byte, base16::EncodeLower)`
+///
+/// See also `base16::encode_byte_u`.
+///
+/// # Example
+/// ```
+/// assert_eq!(base16::encode_byte_l(0xff), [b'f', b'f']);
+/// assert_eq!(base16::encode_byte_l(30), [b'1', b'e']);
+/// assert_eq!(base16::encode_byte_l(0x2d), [b'2', b'd']);
+/// ```
+/// # Availability
+///
+/// This function is available whether or not the `alloc` feature is enabled.
+#[inline]
+pub fn encode_byte_l(byte: u8) -> [u8; 2] {
+ encode_byte(byte, EncodeLower)
+}
+
+/// Convenience wrapper for `base16::encode_byte(byte, base16::EncodeUpper)`
+///
+/// See also `base16::encode_byte_l`.
+///
+/// # Example
+/// ```
+/// assert_eq!(base16::encode_byte_u(0xff), [b'F', b'F']);
+/// assert_eq!(base16::encode_byte_u(30), [b'1', b'E']);
+/// assert_eq!(base16::encode_byte_u(0x2d), [b'2', b'D']);
+/// ```
+/// # Availability
+///
+/// This function is available whether or not the `alloc` feature is enabled.
+#[inline]
+pub fn encode_byte_u(byte: u8) -> [u8; 2] {
+ encode_byte(byte, EncodeUpper)
+}
+
+/// Represents a problem with the data we want to decode.
+///
+/// This implements `std::error::Error` and `Display` if the `std`
+/// feature is enabled, but only `Display` if it is not.
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub enum DecodeError {
+ /// An invalid byte was found in the input (bytes must be `[0-9a-fA-F]`)
+ InvalidByte {
+ /// The index at which the problematic byte was found.
+ index: usize,
+ /// The byte that we cannot decode.
+ byte: u8
+ },
+ /// The length of the input not a multiple of two
+ InvalidLength {
+ /// The input length.
+ length: usize
+ },
+}
+
+#[cold]
+fn invalid_length(length: usize) -> DecodeError {
+ DecodeError::InvalidLength { length }
+}
+
+#[cold]
+fn invalid_byte(index: usize, src: &[u8]) -> DecodeError {
+ DecodeError::InvalidByte { index, byte: src[index] }
+}
+
+impl core::fmt::Display for DecodeError {
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ match *self {
+ DecodeError::InvalidByte { index, byte } => {
+ write!(f, "Invalid byte `b{:?}`, at index {}.",
+ byte as char, index)
+ }
+ DecodeError::InvalidLength { length } =>
+ write!(f, "Base16 data cannot have length {} (must be even)",
+ length),
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for DecodeError {
+ fn description(&self) -> &str {
+ match *self {
+ DecodeError::InvalidByte { .. } => "Illegal byte in base16 data",
+ DecodeError::InvalidLength { .. } => "Illegal length for base16 data",
+ }
+ }
+
+ fn cause(&self) -> Option<&dyn std::error::Error> {
+ None
+ }
+}
+
+#[inline]
+fn decode_slice_raw(src: &[u8], dst: &mut[u8]) -> Result<(), usize> {
+ // checked in caller.
+ debug_assert!(src.len() / 2 == dst.len());
+ debug_assert!((src.len() & 1) == 0);
+ src.chunks_exact(2).enumerate().zip(dst.iter_mut()).try_for_each(|((si, s), d)| {
+ let r0 = DECODE_LUT[s[0] as usize];
+ let r1 = DECODE_LUT[s[1] as usize];
+ if (r0 | r1) >= 0 {
+ *d = ((r0 << 4) | r1) as u8;
+ Ok(())
+ } else {
+ Err(si * 2)
+ }
+ }).map_err(|bad_idx| raw_decode_err(bad_idx, src))
+}
+
+#[cold]
+#[inline(never)]
+fn raw_decode_err(idx: usize, src: &[u8]) -> usize {
+ let b0 = src[idx];
+ if decode_byte(b0).is_none() {
+ idx
+ } else {
+ idx + 1
+ }
+}
+
+/// Decode bytes from base16, and return a new `Vec<u8>` containing the results.
+///
+/// # Example
+///
+/// ```
+/// assert_eq!(&base16::decode("48656c6c6f20576f726c64".as_bytes()).unwrap(),
+/// b"Hello World");
+/// assert_eq!(&base16::decode(b"deadBEEF").unwrap(),
+/// &[0xde, 0xad, 0xbe, 0xef]);
+/// // Error cases:
+/// assert_eq!(base16::decode(b"Not Hexadecimal!"),
+/// Err(base16::DecodeError::InvalidByte { byte: b'N', index: 0 }));
+/// assert_eq!(base16::decode(b"a"),
+/// Err(base16::DecodeError::InvalidLength { length: 1 }));
+/// ```
+/// # Availability
+///
+/// This function is only available when the `alloc` feature is enabled, as it
+/// needs to produce a Vec.
+#[cfg(feature = "alloc")]
+#[inline]
+pub fn decode<T: ?Sized + AsRef<[u8]>>(input: &T) -> Result<Vec<u8>, DecodeError> {
+ let src = input.as_ref();
+ if (src.len() & 1) != 0 {
+ return Err(invalid_length(src.len()));
+ }
+ let need_size = src.len() >> 1;
+ let mut dst = Vec::with_capacity(need_size);
+ unsafe { dst.set_len(need_size); }
+ match decode_slice_raw(src, &mut dst) {
+ Ok(()) => Ok(dst),
+ Err(index) => Err(invalid_byte(index, src))
+ }
+}
+
+
+/// Decode bytes from base16, and appends into the provided buffer. Only
+/// allocates if the buffer could not fit the data. Returns the number of bytes
+/// written.
+///
+/// In the case of an error, the buffer should remain the same size.
+///
+/// # Example
+///
+/// ```
+/// # extern crate core as std;
+/// # extern crate alloc;
+/// # use alloc::vec::Vec;
+/// let mut result = Vec::new();
+/// assert_eq!(base16::decode_buf(b"4d61646f6b61", &mut result).unwrap(), 6);
+/// assert_eq!(base16::decode_buf(b"486F6D757261", &mut result).unwrap(), 6);
+/// assert_eq!(std::str::from_utf8(&result).unwrap(), "MadokaHomura");
+/// ```
+/// # Availability
+///
+/// This function is only available when the `alloc` feature is enabled, as it
+/// needs to write to a Vec.
+#[cfg(feature = "alloc")]
+#[inline]
+pub fn decode_buf<T: ?Sized + AsRef<[u8]>>(input: &T, v: &mut Vec<u8>) -> Result<usize, DecodeError> {
+ let src = input.as_ref();
+ if (src.len() & 1) != 0 {
+ return Err(invalid_length(src.len()));
+ }
+ // Swap the vec out while we work on it, so that if we panic, we don't leave
+ // behind garbage (this will end up cleared if we panic, but that's better
+ // than UB)
+ let mut work = core::mem::replace(v, Vec::default());
+ let need_size = src.len() >> 1;
+ let current_size = unsafe {
+ grow_vec_uninitialized(&mut work, need_size)
+ };
+ match decode_slice_raw(src, &mut work[current_size..]) {
+ Ok(()) => {
+ // Swap back
+ core::mem::swap(v, &mut work);
+ Ok(need_size)
+ }
+ Err(index) => {
+ work.truncate(current_size);
+ // Swap back
+ core::mem::swap(v, &mut work);
+ Err(invalid_byte(index, src))
+ }
+ }
+}
+
+/// Decode bytes from base16, and write into the provided buffer. Never
+/// allocates.
+///
+/// In the case of a decoder error, the output is not specified, but in practice
+/// will remain untouched for an `InvalidLength` error, and will contain the
+/// decoded input up to the problem byte in the case of an InvalidByte error.
+///
+/// # Panics
+///
+/// Panics if the provided buffer is not large enough for the input.
+///
+/// # Example
+/// ```
+/// let msg = "476f6f642072757374206c6962726172696573207573652073696c6c79206578616d706c6573";
+/// let mut buf = [0u8; 1024];
+/// assert_eq!(base16::decode_slice(&msg[..], &mut buf).unwrap(), 38);
+/// assert_eq!(&buf[..38], b"Good rust libraries use silly examples".as_ref());
+///
+/// let msg2 = b"2E20416C736F2C20616E696D65207265666572656e636573";
+/// assert_eq!(base16::decode_slice(&msg2[..], &mut buf[38..]).unwrap(), 24);
+/// assert_eq!(&buf[38..62], b". Also, anime references".as_ref());
+/// ```
+/// # Availability
+///
+/// This function is available whether or not the `alloc` feature is enabled.
+#[inline]
+pub fn decode_slice<T: ?Sized + AsRef<[u8]>>(input: &T, out: &mut [u8]) -> Result<usize, DecodeError> {
+ let src = input.as_ref();
+ if (src.len() & 1) != 0 {
+ return Err(invalid_length(src.len()));
+ }
+ let need_size = src.len() >> 1;
+ if out.len() < need_size {
+ dest_too_small_dec(out.len(), need_size);
+ }
+ match decode_slice_raw(src, &mut out[..need_size]) {
+ Ok(()) => Ok(need_size),
+ Err(index) => Err(invalid_byte(index, src))
+ }
+}
+
+/// Decode a single character as hex.
+///
+/// Returns `None` for values outside the ASCII hex range.
+///
+/// # Example
+/// ```
+/// assert_eq!(base16::decode_byte(b'a'), Some(10));
+/// assert_eq!(base16::decode_byte(b'B'), Some(11));
+/// assert_eq!(base16::decode_byte(b'0'), Some(0));
+/// assert_eq!(base16::decode_byte(b'q'), None);
+/// assert_eq!(base16::decode_byte(b'x'), None);
+/// ```
+/// # Availability
+///
+/// This function is available whether or not the `alloc` feature is enabled.
+#[inline]
+pub fn decode_byte(c: u8) -> Option<u8> {
+ if c.wrapping_sub(b'0') <= 9 {
+ Some(c.wrapping_sub(b'0'))
+ } else if c.wrapping_sub(b'a') < 6 {
+ Some(c.wrapping_sub(b'a') + 10)
+ } else if c.wrapping_sub(b'A') < 6 {
+ Some(c.wrapping_sub(b'A') + 10)
+ } else {
+ None
+ }
+}
+static HEX_UPPER: [u8; 16] = *b"0123456789ABCDEF";
+static HEX_LOWER: [u8; 16] = *b"0123456789abcdef";
+static DECODE_LUT: [i8; 256] = [
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1
+];
+// Outlined assertions.
+#[inline(never)]
+#[cold]
+fn usize_overflow(len: usize) -> ! {
+ panic!("usize overflow when computing size of destination: {}", len);
+}
+
+#[cold]
+#[inline(never)]
+fn dest_too_small_enc(dst_len: usize, need_size: usize) -> ! {
+ panic!("Destination is not large enough to encode input: {} < {}", dst_len, need_size);
+}
+
+#[cold]
+#[inline(never)]
+fn dest_too_small_dec(dst_len: usize, need_size: usize) -> ! {
+ panic!("Destination buffer not large enough for decoded input {} < {}", dst_len, need_size);
+}
+
+// encoded_size smoke tests
+#[cfg(test)]
+mod tests {
+ use super::*;
+ #[test]
+ #[should_panic]
+ #[cfg(pointer_size )]
+ fn test_encoded_size_panic_top_bit() {
+ #[cfg(target_pointer_width = "64")]
+ let usz = 0x8000_0000_0000_0000usize;
+ #[cfg(target_pointer_width = "32")]
+ let usz = 0x8000_0000usize;
+ let _ = encoded_size(usz);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_encoded_size_panic_max() {
+ let _ = encoded_size(usize::max_value());
+ }
+
+ #[test]
+ fn test_encoded_size_allows_almost_max() {
+ #[cfg(target_pointer_width = "64")]
+ let usz = 0x7fff_ffff_ffff_ffffusize;
+ #[cfg(target_pointer_width = "32")]
+ let usz = 0x7fff_ffffusize;
+ assert_eq!(encoded_size(usz), usz * 2);
+ }
+}