base16/
lib.rs

1//! This is a base16 (e.g. hexadecimal) encoding and decoding library with an
2//! emphasis on performance. The API is very similar and inspired by the base64
3//! crate's API, however it's less complex (base16 is much more simple than
4//! base64).
5//!
6//! # Encoding
7//!
8//! The config options at the moment are limited to the output case (upper vs
9//! lower).
10//!
11//! | Function                           | Output                       | Allocates               | Requires `alloc` feature |
12//! | ---------------------------------- | ---------------------------- | ----------------------- | ------------------------ |
13//! | [`encode_upper`], [`encode_lower`] | Returns a new `String`       | Always                  | Yes                      |
14//! | [`encode_config`]                  | Returns a new `String`       | Always                  | Yes                      |
15//! | [`encode_config_buf`]              | Appends to provided `String` | If buffer needs to grow | Yes                      |
16//! | [`encode_config_slice`]            | Writes to provided `&[u8]`   | Never                   | No                       |
17//!
18//! # Decoding
19//!
20//! Note that there are no config options (In the future one might be added to
21//! restrict the input character set, but it's not clear to me that this is
22//! useful).
23//!
24//! | Function          | Output                        | Allocates               | Requires `alloc` feature |
25//! | ----------------- | ----------------------------- | ----------------------- | ------------------------ |
26//! | [`decode`]        | Returns a new `Vec<u8>`       | Always                  | Yes                      |
27//! | [`decode_slice`]  | Writes to provided `&[u8]`    | Never                   | No                       |
28//! | [`decode_buf`]    | Appends to provided `Vec<u8>` | If buffer needs to grow | Yes                      |
29//!
30//! # Features
31//!
32//! This crate has two features, both are enabled by default and exist to allow
33//! users in `no_std` environments to disable various portions of .
34//!
35//! - The `"alloc"` feature, which is on by default, adds a number of helpful
36//!   functions that require use of the [`alloc`][alloc_crate] crate, but not the
37//!   rest of `std`.
38//!     - This is `no_std` compatible.
39//!     - Each function should list whether or not it requires this feature
40//!       under the `Availability` of its documentation.
41//!
42//! - The `"std"` feature, which is on by default, enables the `"alloc"`
43//!   feature, and additionally makes [`DecodeError`] implement the
44//!   `std::error::Error` trait.
45//!
46//!     - Frustratingly, this trait is in `std` (and not in `core` or `alloc`),
47//!       but not implementing it would be quite annoying for some users, so
48//!       it's kept, even though it's what prevents us from being `no_std`
49//!       compatible in all configurations.
50//!
51//! [alloc_crate]: https://doc.rust-lang.org/alloc/index.html
52
53#![cfg_attr(not(feature = "std"), no_std)]
54#![deny(missing_docs)]
55
56#[cfg(feature = "alloc")]
57extern crate alloc;
58
59#[cfg(feature = "alloc")]
60use alloc::{vec::Vec, string::String};
61
62/// Configuration options for encoding. Just specifies whether or not output
63/// should be uppercase or lowercase.
64#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
65pub enum EncConfig {
66    /// Encode using lower case characters for hex values >= 10
67    EncodeLower,
68    /// Encode using upper case characters for hex values >= 10
69    EncodeUpper,
70}
71
72pub use EncConfig::*;
73
74#[inline]
75fn encoded_size(source_len: usize) -> usize {
76    const USIZE_TOP_BIT: usize = 1usize << (core::mem::size_of::<usize>() * 8 - 1);
77    if (source_len & USIZE_TOP_BIT) != 0 {
78        usize_overflow(source_len)
79    }
80    source_len << 1
81}
82
83#[inline]
84fn encode_slice_raw(src: &[u8], cfg: EncConfig, dst: &mut [u8]) {
85    let lut = if cfg == EncodeLower { HEX_LOWER } else { HEX_UPPER };
86    debug_assert!(dst.len() == encoded_size(src.len()));
87    dst.chunks_exact_mut(2).zip(src.iter().copied()).for_each(|(d, sb)| {
88        d[0] = lut[(sb >> 4) as usize];
89        d[1] = lut[(sb & 0xf) as usize];
90    })
91}
92
93#[cfg(feature = "alloc")]
94#[inline]
95fn encode_to_string(bytes: &[u8], cfg: EncConfig) -> String {
96    let size = encoded_size(bytes.len());
97    let mut buf: Vec<u8> = Vec::with_capacity(size);
98    unsafe { buf.set_len(size); }
99    encode_slice_raw(bytes, cfg, &mut buf);
100    debug_assert!(core::str::from_utf8(&buf).is_ok());
101    unsafe { String::from_utf8_unchecked(buf) }
102}
103
104#[cfg(feature = "alloc")]
105#[inline]
106unsafe fn grow_vec_uninitialized(v: &mut Vec<u8>, grow_by: usize) -> usize {
107    v.reserve(grow_by);
108    let initial_len = v.len();
109    let new_len = initial_len + grow_by;
110    debug_assert!(new_len <= v.capacity());
111    v.set_len(new_len);
112    initial_len
113}
114
115/// Encode bytes as base16, using lower case characters for nibbles between 10
116/// and 15 (`a` through `f`).
117///
118/// This is equivalent to `base16::encode_config(bytes, base16::EncodeUpper)`.
119///
120/// # Example
121///
122/// ```
123/// assert_eq!(base16::encode_lower(b"Hello World"), "48656c6c6f20576f726c64");
124/// assert_eq!(base16::encode_lower(&[0xff, 0xcc, 0xaa]), "ffccaa");
125/// ```
126///
127/// # Availability
128///
129/// This function is only available when the `alloc` feature is enabled, as it
130/// needs to produce a String.
131#[cfg(feature = "alloc")]
132#[inline]
133pub fn encode_lower<T: ?Sized + AsRef<[u8]>>(input: &T) -> String {
134    encode_to_string(input.as_ref(), EncodeLower)
135}
136
137/// Encode bytes as base16, using upper case characters for nibbles between
138/// 10 and 15 (`A` through `F`).
139///
140/// This is equivalent to `base16::encode_config(bytes, base16::EncodeUpper)`.
141///
142/// # Example
143///
144/// ```
145/// assert_eq!(base16::encode_upper(b"Hello World"), "48656C6C6F20576F726C64");
146/// assert_eq!(base16::encode_upper(&[0xff, 0xcc, 0xaa]), "FFCCAA");
147/// ```
148///
149/// # Availability
150///
151/// This function is only available when the `alloc` feature is enabled, as it
152/// needs to produce a `String`.
153#[cfg(feature = "alloc")]
154#[inline]
155pub fn encode_upper<T: ?Sized + AsRef<[u8]>>(input: &T) -> String {
156    encode_to_string(input.as_ref(), EncodeUpper)
157}
158
159
160/// Encode `input` into a string using the listed config. The resulting string
161/// contains `input.len() * 2` bytes.
162///
163/// # Example
164///
165/// ```
166/// let data = [1, 2, 3, 0xaa, 0xbb, 0xcc];
167/// assert_eq!(base16::encode_config(&data, base16::EncodeLower), "010203aabbcc");
168/// assert_eq!(base16::encode_config(&data, base16::EncodeUpper), "010203AABBCC");
169/// ```
170///
171/// # Availability
172///
173/// This function is only available when the `alloc` feature is enabled, as it
174/// needs to produce a `String`.
175#[cfg(feature = "alloc")]
176#[inline]
177pub fn encode_config<T: ?Sized + AsRef<[u8]>>(input: &T, cfg: EncConfig) -> String {
178    encode_to_string(input.as_ref(), cfg)
179}
180
181/// Encode `input` into the end of the provided buffer. Returns the number of
182/// bytes that were written.
183///
184/// Only allocates when `dst.size() + (input.len() * 2) >= dst.capacity()`.
185///
186/// # Example
187///
188/// ```
189/// let messages = &["Taako, ", "Merle, ", "Magnus"];
190/// let mut buffer = String::new();
191/// for msg in messages {
192///     let bytes_written = base16::encode_config_buf(msg.as_bytes(),
193///                                                   base16::EncodeUpper,
194///                                                   &mut buffer);
195///     assert_eq!(bytes_written, msg.len() * 2);
196/// }
197/// assert_eq!(buffer, "5461616B6F2C204D65726C652C204D61676E7573");
198/// ```
199/// # Availability
200///
201/// This function is only available when the `alloc` feature is enabled, as it
202/// needs write to a `String`.
203#[cfg(feature = "alloc")]
204#[inline]
205pub fn encode_config_buf<T: ?Sized + AsRef<[u8]>>(input: &T,
206                                                  cfg: EncConfig,
207                                                  dst: &mut String) -> usize {
208    let src = input.as_ref();
209    let bytes_to_write = encoded_size(src.len());
210    // Swap the string out while we work on it, so that if we panic, we don't
211    // leave behind garbage (we do clear the string if we panic, but that's
212    // better than UB)
213    let mut buf = core::mem::replace(dst, String::new()).into_bytes();
214    let cur_size = unsafe { grow_vec_uninitialized(&mut buf, bytes_to_write) };
215
216    encode_slice_raw(src, cfg, &mut buf[cur_size..]);
217
218    debug_assert!(core::str::from_utf8(&buf).is_ok());
219    // Put `buf` back into `dst`.
220    *dst = unsafe { String::from_utf8_unchecked(buf) };
221
222    bytes_to_write
223}
224
225/// Write bytes as base16 into the provided output buffer. Never allocates.
226///
227/// This is useful if you wish to avoid allocation entirely (e.g. your
228/// destination buffer is on the stack), or control it precisely.
229///
230/// # Panics
231///
232/// Panics if the desination buffer is insufficiently large.
233///
234/// # Example
235///
236/// ```
237/// # extern crate core as std;
238/// // Writing to a statically sized buffer on the stack.
239/// let message = b"Wu-Tang Killa Bees";
240/// let mut buffer = [0u8; 1024];
241///
242/// let wrote = base16::encode_config_slice(message,
243///                                         base16::EncodeLower,
244///                                         &mut buffer);
245///
246/// assert_eq!(message.len() * 2, wrote);
247/// assert_eq!(std::str::from_utf8(&buffer[..wrote]).unwrap(),
248///            "57752d54616e67204b696c6c612042656573");
249///
250/// // Appending to an existing buffer is possible too.
251/// let wrote2 = base16::encode_config_slice(b": The Swarm",
252///                                          base16::EncodeLower,
253///                                          &mut buffer[wrote..]);
254/// let write_end = wrote + wrote2;
255/// assert_eq!(std::str::from_utf8(&buffer[..write_end]).unwrap(),
256///            "57752d54616e67204b696c6c6120426565733a2054686520537761726d");
257/// ```
258/// # Availability
259///
260/// This function is available whether or not the `alloc` feature is enabled.
261#[inline]
262pub fn encode_config_slice<T: ?Sized + AsRef<[u8]>>(input: &T,
263                                                    cfg: EncConfig,
264                                                    dst: &mut [u8]) -> usize {
265    let src = input.as_ref();
266    let need_size = encoded_size(src.len());
267    if dst.len() < need_size {
268        dest_too_small_enc(dst.len(), need_size);
269    }
270    encode_slice_raw(src, cfg, &mut dst[..need_size]);
271    need_size
272}
273
274/// Encode a single character as hex, returning a tuple containing the two
275/// encoded bytes in big-endian order -- the order the characters would be in
276/// when written out (e.g. the top nibble is the first item in the tuple)
277///
278/// # Example
279/// ```
280/// assert_eq!(base16::encode_byte(0xff, base16::EncodeLower), [b'f', b'f']);
281/// assert_eq!(base16::encode_byte(0xa0, base16::EncodeUpper), [b'A', b'0']);
282/// assert_eq!(base16::encode_byte(3, base16::EncodeUpper), [b'0', b'3']);
283/// ```
284/// # Availability
285///
286/// This function is available whether or not the `alloc` feature is enabled.
287#[inline]
288pub fn encode_byte(byte: u8, cfg: EncConfig) -> [u8; 2] {
289    let lut = if cfg == EncodeLower { HEX_LOWER } else { HEX_UPPER };
290    let lo = lut[(byte & 15) as usize];
291    let hi = lut[(byte >> 4) as usize];
292    [hi, lo]
293}
294
295/// Convenience wrapper for `base16::encode_byte(byte, base16::EncodeLower)`
296///
297/// See also `base16::encode_byte_u`.
298///
299/// # Example
300/// ```
301/// assert_eq!(base16::encode_byte_l(0xff), [b'f', b'f']);
302/// assert_eq!(base16::encode_byte_l(30), [b'1', b'e']);
303/// assert_eq!(base16::encode_byte_l(0x2d), [b'2', b'd']);
304/// ```
305/// # Availability
306///
307/// This function is available whether or not the `alloc` feature is enabled.
308#[inline]
309pub fn encode_byte_l(byte: u8) -> [u8; 2] {
310    encode_byte(byte, EncodeLower)
311}
312
313/// Convenience wrapper for `base16::encode_byte(byte, base16::EncodeUpper)`
314///
315/// See also `base16::encode_byte_l`.
316///
317/// # Example
318/// ```
319/// assert_eq!(base16::encode_byte_u(0xff), [b'F', b'F']);
320/// assert_eq!(base16::encode_byte_u(30), [b'1', b'E']);
321/// assert_eq!(base16::encode_byte_u(0x2d), [b'2', b'D']);
322/// ```
323/// # Availability
324///
325/// This function is available whether or not the `alloc` feature is enabled.
326#[inline]
327pub fn encode_byte_u(byte: u8) -> [u8; 2] {
328    encode_byte(byte, EncodeUpper)
329}
330
331/// Represents a problem with the data we want to decode.
332///
333/// This implements `std::error::Error` and `Display` if the `std`
334/// feature is enabled, but only `Display` if it is not.
335#[derive(Debug, PartialEq, Eq, Clone)]
336pub enum DecodeError {
337    /// An invalid byte was found in the input (bytes must be `[0-9a-fA-F]`)
338    InvalidByte {
339        /// The index at which the problematic byte was found.
340        index: usize,
341        /// The byte that we cannot decode.
342        byte: u8
343    },
344    /// The length of the input not a multiple of two
345    InvalidLength {
346        /// The input length.
347        length: usize
348    },
349}
350
351#[cold]
352fn invalid_length(length: usize) -> DecodeError {
353    DecodeError::InvalidLength { length }
354}
355
356#[cold]
357fn invalid_byte(index: usize, src: &[u8]) -> DecodeError {
358    DecodeError::InvalidByte { index, byte: src[index] }
359}
360
361impl core::fmt::Display for DecodeError {
362    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
363        match *self {
364            DecodeError::InvalidByte { index, byte } => {
365                write!(f, "Invalid byte `b{:?}`, at index {}.",
366                       byte as char, index)
367            }
368            DecodeError::InvalidLength { length } =>
369                write!(f, "Base16 data cannot have length {} (must be even)",
370                       length),
371        }
372    }
373}
374
375#[cfg(feature = "std")]
376impl std::error::Error for DecodeError {
377    fn description(&self) -> &str {
378        match *self {
379            DecodeError::InvalidByte { .. } => "Illegal byte in base16 data",
380            DecodeError::InvalidLength { .. } => "Illegal length for base16 data",
381        }
382    }
383
384    fn cause(&self) -> Option<&dyn std::error::Error> {
385        None
386    }
387}
388
389#[inline]
390fn decode_slice_raw(src: &[u8], dst: &mut[u8]) -> Result<(), usize> {
391    // checked in caller.
392    debug_assert!(src.len() / 2 == dst.len());
393    debug_assert!((src.len() & 1) == 0);
394    src.chunks_exact(2).enumerate().zip(dst.iter_mut()).try_for_each(|((si, s), d)| {
395        let r0 = DECODE_LUT[s[0] as usize];
396        let r1 = DECODE_LUT[s[1] as usize];
397        if (r0 | r1) >= 0 {
398            *d = ((r0 << 4) | r1) as u8;
399            Ok(())
400        } else {
401            Err(si * 2)
402        }
403    }).map_err(|bad_idx| raw_decode_err(bad_idx, src))
404}
405
406#[cold]
407#[inline(never)]
408fn raw_decode_err(idx: usize, src: &[u8]) -> usize {
409    let b0 = src[idx];
410    if decode_byte(b0).is_none() {
411        idx
412    } else {
413        idx + 1
414    }
415}
416
417/// Decode bytes from base16, and return a new `Vec<u8>` containing the results.
418///
419/// # Example
420///
421/// ```
422/// assert_eq!(&base16::decode("48656c6c6f20576f726c64".as_bytes()).unwrap(),
423///            b"Hello World");
424/// assert_eq!(&base16::decode(b"deadBEEF").unwrap(),
425///            &[0xde, 0xad, 0xbe, 0xef]);
426/// // Error cases:
427/// assert_eq!(base16::decode(b"Not Hexadecimal!"),
428///            Err(base16::DecodeError::InvalidByte { byte: b'N', index: 0 }));
429/// assert_eq!(base16::decode(b"a"),
430///            Err(base16::DecodeError::InvalidLength { length: 1 }));
431/// ```
432/// # Availability
433///
434/// This function is only available when the `alloc` feature is enabled, as it
435/// needs to produce a Vec.
436#[cfg(feature = "alloc")]
437#[inline]
438pub fn decode<T: ?Sized + AsRef<[u8]>>(input: &T) -> Result<Vec<u8>, DecodeError> {
439    let src = input.as_ref();
440    if (src.len() & 1) != 0 {
441        return Err(invalid_length(src.len()));
442    }
443    let need_size = src.len() >> 1;
444    let mut dst = Vec::with_capacity(need_size);
445    unsafe { dst.set_len(need_size); }
446    match decode_slice_raw(src, &mut dst) {
447        Ok(()) => Ok(dst),
448        Err(index) => Err(invalid_byte(index, src))
449    }
450}
451
452
453/// Decode bytes from base16, and appends into the provided buffer. Only
454/// allocates if the buffer could not fit the data. Returns the number of bytes
455/// written.
456///
457/// In the case of an error, the buffer should remain the same size.
458///
459/// # Example
460///
461/// ```
462/// # extern crate core as std;
463/// # extern crate alloc;
464/// # use alloc::vec::Vec;
465/// let mut result = Vec::new();
466/// assert_eq!(base16::decode_buf(b"4d61646f6b61", &mut result).unwrap(), 6);
467/// assert_eq!(base16::decode_buf(b"486F6D757261", &mut result).unwrap(), 6);
468/// assert_eq!(std::str::from_utf8(&result).unwrap(), "MadokaHomura");
469/// ```
470/// # Availability
471///
472/// This function is only available when the `alloc` feature is enabled, as it
473/// needs to write to a Vec.
474#[cfg(feature = "alloc")]
475#[inline]
476pub fn decode_buf<T: ?Sized + AsRef<[u8]>>(input: &T, v: &mut Vec<u8>) -> Result<usize, DecodeError> {
477    let src = input.as_ref();
478    if (src.len() & 1) != 0 {
479        return Err(invalid_length(src.len()));
480    }
481    // Swap the vec out while we work on it, so that if we panic, we don't leave
482    // behind garbage (this will end up cleared if we panic, but that's better
483    // than UB)
484    let mut work = core::mem::replace(v, Vec::default());
485    let need_size = src.len() >> 1;
486    let current_size = unsafe {
487        grow_vec_uninitialized(&mut work, need_size)
488    };
489    match decode_slice_raw(src, &mut work[current_size..]) {
490        Ok(()) => {
491            // Swap back
492            core::mem::swap(v, &mut work);
493            Ok(need_size)
494        }
495        Err(index) => {
496            work.truncate(current_size);
497            // Swap back
498            core::mem::swap(v, &mut work);
499            Err(invalid_byte(index, src))
500        }
501    }
502}
503
504/// Decode bytes from base16, and write into the provided buffer. Never
505/// allocates.
506///
507/// In the case of a decoder error, the output is not specified, but in practice
508/// will remain untouched for an `InvalidLength` error, and will contain the
509/// decoded input up to the problem byte in the case of an InvalidByte error.
510///
511/// # Panics
512///
513/// Panics if the provided buffer is not large enough for the input.
514///
515/// # Example
516/// ```
517/// let msg = "476f6f642072757374206c6962726172696573207573652073696c6c79206578616d706c6573";
518/// let mut buf = [0u8; 1024];
519/// assert_eq!(base16::decode_slice(&msg[..], &mut buf).unwrap(), 38);
520/// assert_eq!(&buf[..38], b"Good rust libraries use silly examples".as_ref());
521///
522/// let msg2 = b"2E20416C736F2C20616E696D65207265666572656e636573";
523/// assert_eq!(base16::decode_slice(&msg2[..], &mut buf[38..]).unwrap(), 24);
524/// assert_eq!(&buf[38..62], b". Also, anime references".as_ref());
525/// ```
526/// # Availability
527///
528/// This function is available whether or not the `alloc` feature is enabled.
529#[inline]
530pub fn decode_slice<T: ?Sized + AsRef<[u8]>>(input: &T, out: &mut [u8]) -> Result<usize, DecodeError> {
531    let src = input.as_ref();
532    if (src.len() & 1) != 0 {
533        return Err(invalid_length(src.len()));
534    }
535    let need_size = src.len() >> 1;
536    if out.len() < need_size {
537        dest_too_small_dec(out.len(), need_size);
538    }
539    match decode_slice_raw(src, &mut out[..need_size]) {
540        Ok(()) => Ok(need_size),
541        Err(index) => Err(invalid_byte(index, src))
542    }
543}
544
545/// Decode a single character as hex.
546///
547/// Returns `None` for values outside the ASCII hex range.
548///
549/// # Example
550/// ```
551/// assert_eq!(base16::decode_byte(b'a'), Some(10));
552/// assert_eq!(base16::decode_byte(b'B'), Some(11));
553/// assert_eq!(base16::decode_byte(b'0'), Some(0));
554/// assert_eq!(base16::decode_byte(b'q'), None);
555/// assert_eq!(base16::decode_byte(b'x'), None);
556/// ```
557/// # Availability
558///
559/// This function is available whether or not the `alloc` feature is enabled.
560#[inline]
561pub fn decode_byte(c: u8) -> Option<u8> {
562    if c.wrapping_sub(b'0') <= 9 {
563        Some(c.wrapping_sub(b'0'))
564    } else if c.wrapping_sub(b'a') < 6 {
565        Some(c.wrapping_sub(b'a') + 10)
566    } else if c.wrapping_sub(b'A') < 6 {
567        Some(c.wrapping_sub(b'A') + 10)
568    } else {
569        None
570    }
571}
572static HEX_UPPER: [u8; 16] = *b"0123456789ABCDEF";
573static HEX_LOWER: [u8; 16] = *b"0123456789abcdef";
574static DECODE_LUT: [i8; 256] = [
575    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
576    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
577    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5,
578        6,  7,  8,  9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1,
579    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
580    -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1,
581    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
582    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
583    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
584    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
585    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
586    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
587    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
588    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
589    -1, -1, -1, -1
590];
591// Outlined assertions.
592#[inline(never)]
593#[cold]
594fn usize_overflow(len: usize) -> ! {
595    panic!("usize overflow when computing size of destination: {}", len);
596}
597
598#[cold]
599#[inline(never)]
600fn dest_too_small_enc(dst_len: usize, need_size: usize) -> ! {
601    panic!("Destination is not large enough to encode input: {} < {}", dst_len, need_size);
602}
603
604#[cold]
605#[inline(never)]
606fn dest_too_small_dec(dst_len: usize, need_size: usize) -> ! {
607    panic!("Destination buffer not large enough for decoded input {} < {}", dst_len, need_size);
608}
609
610// encoded_size smoke tests
611#[cfg(test)]
612mod tests {
613    use super::*;
614    #[test]
615    #[should_panic]
616    #[cfg(pointer_size )]
617    fn test_encoded_size_panic_top_bit() {
618        #[cfg(target_pointer_width = "64")]
619        let usz = 0x8000_0000_0000_0000usize;
620        #[cfg(target_pointer_width = "32")]
621        let usz = 0x8000_0000usize;
622        let _ = encoded_size(usz);
623    }
624
625    #[test]
626    #[should_panic]
627    fn test_encoded_size_panic_max() {
628        let _ = encoded_size(usize::max_value());
629    }
630
631    #[test]
632    fn test_encoded_size_allows_almost_max() {
633        #[cfg(target_pointer_width = "64")]
634        let usz = 0x7fff_ffff_ffff_ffffusize;
635        #[cfg(target_pointer_width = "32")]
636        let usz = 0x7fff_ffffusize;
637        assert_eq!(encoded_size(usz), usz * 2);
638    }
639}