faster_hex/heapless_08.rs
1//! Fixed-capacity strings using `heapless` 0.8.
2//!
3//! Available with the `heapless-08` feature, independently of `alloc` or `std`.
4//! These functions return [`heapless::String`] values with inline storage and
5//! report insufficient capacity as an error. Capacity counts encoded ASCII
6//! characters: storing `N` input bytes requires at least `2 * N` characters.
7//!
8//! The exposed dependency type is always from `heapless` 0.8. Support for an
9//! incompatible dependency version uses a separate module and feature; enabling
10//! heapless support does not change the allocated string APIs.
11//!
12//! # Examples
13//!
14//! ```
15//! use faster_hex::heapless_08;
16//!
17//! let id = heapless_08::hex_string::<8>(&[0x12, 0xab, 0, 0xff])?;
18//! assert_eq!(id.as_str(), "12ab00ff");
19//! # Ok::<(), faster_hex::Error>(())
20//! ```
21
22use crate::{encode::hex_encode_custom, Error};
23use heapless::{String, Vec};
24
25/// Encodes `src` as a lowercase hexadecimal string with inline capacity `N`.
26///
27/// Every byte produces two ASCII digits, with no prefix or separators. The
28/// result owns its storage without allocating. Empty input succeeds even when
29/// `N` is zero. Any unused capacity remains available on the returned string.
30///
31/// # Errors
32///
33/// Returns [`Error::Overflow`] if twice the input length cannot be represented,
34/// or [`Error::OutputTooSmall`] if `N` is less than the encoded byte length.
35/// Insufficient capacity is an error rather than a panic.
36///
37/// # Examples
38///
39/// ```
40/// use faster_hex::{heapless_08::hex_string, Error};
41///
42/// assert_eq!(hex_string::<4>(&[0xab, 1])?.as_str(), "ab01");
43/// assert!(matches!(hex_string::<3>(&[0xab, 1]),
44/// Err(Error::OutputTooSmall { required: 4, .. })));
45/// assert_eq!(hex_string::<0>(&[])?.as_str(), "");
46/// # Ok::<(), Error>(())
47/// ```
48pub fn hex_string<const N: usize>(src: &[u8]) -> Result<String<N>, Error> {
49 hex_string_custom_case(src, false)
50}
51
52/// Encodes `src` as an uppercase hexadecimal string with inline capacity `N`.
53///
54/// This has the ownership and allocation-free behavior of [`hex_string`], using
55/// `A` through `F` for letter digits. Capacity counts encoded characters.
56///
57/// # Errors
58///
59/// Returns [`Error::Overflow`] or [`Error::OutputTooSmall`] under the same
60/// conditions as [`hex_string`].
61///
62/// # Examples
63///
64/// ```
65/// assert_eq!(faster_hex::heapless_08::hex_string_upper::<4>(&[0xab, 1])?.as_str(),
66/// "AB01");
67/// # Ok::<(), faster_hex::Error>(())
68/// ```
69pub fn hex_string_upper<const N: usize>(src: &[u8]) -> Result<String<N>, Error> {
70 hex_string_custom_case(src, true)
71}
72
73fn hex_string_custom_case<const N: usize>(src: &[u8], upper: bool) -> Result<String<N>, Error> {
74 let len = src.len().checked_mul(2).ok_or(Error::Overflow)?;
75 let mut buffer = Vec::<u8, N>::new();
76 buffer
77 .resize(len, 0)
78 .map_err(|_| Error::OutputTooSmall { required: len })?;
79 hex_encode_custom(src, &mut buffer, upper)?;
80 // SAFETY: Every byte in the vector was encoded as ASCII hex.
81 Ok(unsafe { String::from_utf8_unchecked(buffer) })
82}