| Add closures and unsafe; base16ct's lower.rs and upper.rs go through 0a375d8 nandithebull 20h ago | 1 | use crate::{Error, decode_inner, encoded_len}; |
| 2 | #[cfg(feature = "alloc")] |
| 3 | use crate::{String, Vec, decoded_len}; |
| 4 | |
| 5 | /// Decode an upper Base16 (hex) string into the provided destination buffer. |
| 6 | pub fn decode(src: impl AsRef<[u8]>, dst: &mut [u8]) -> Result<&[u8], Error> { |
| 7 | decode_inner(src.as_ref(), dst, decode_nibble) |
| 8 | } |
| 9 | |
| 10 | /// Decode an upper Base16 (hex) string into a byte vector. |
| 11 | #[cfg(feature = "alloc")] |
| 12 | pub fn decode_vec(input: impl AsRef<[u8]>) -> Result<Vec<u8>, Error> { |
| 13 | let mut output = vec![0u8; decoded_len(input.as_ref())?]; |
| 14 | decode(input, &mut output)?; |
| 15 | Ok(output) |
| 16 | } |
| 17 | |
| 18 | /// Encode the input byte slice as upper Base16. |
| 19 | /// |
| 20 | /// Writes the result into the provided destination slice, returning an |
| 21 | /// ASCII-encoded upper Base16 (hex) string value. |
| 22 | pub fn encode<'a>(src: &[u8], dst: &'a mut [u8]) -> Result<&'a [u8], Error> { |
| 23 | let dst = dst |
| 24 | .get_mut(..encoded_len(src)) |
| 25 | .ok_or(Error::InvalidLength)?; |
| 26 | for (src, dst) in src.iter().zip(dst.chunks_exact_mut(2)) { |
| 27 | dst[0] = encode_nibble(src >> 4); |
| 28 | dst[1] = encode_nibble(src & 0x0f); |
| 29 | } |
| 30 | Ok(dst) |
| 31 | } |
| 32 | |
| 33 | /// Encode input byte slice into a [`&str`] containing upper Base16 (hex). |
| 34 | pub fn encode_str<'a>(src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, Error> { |
| 35 | encode(src, dst).map(|r| unsafe { core::str::from_utf8_unchecked(r) }) |
| 36 | } |
| 37 | |
| 38 | /// Encode input byte slice into a [`String`] containing upper Base16 (hex). |
| 39 | /// |
| 40 | /// # Panics |
| 41 | /// If `input` length is greater than `usize::MAX/2`. |
| 42 | #[cfg(feature = "alloc")] |
| 43 | pub fn encode_string(input: &[u8]) -> String { |
| 44 | let elen = encoded_len(input); |
| 45 | let mut dst = vec![0u8; elen]; |
| 46 | let res = encode(input, &mut dst).expect("dst length is correct"); |
| 47 | |
| 48 | debug_assert_eq!(elen, res.len()); |
| 49 | unsafe { String::from_utf8_unchecked(dst) } |
| 50 | } |
| 51 | |
| 52 | /// Decode a single nibble of upper hex |
| 53 | #[inline(always)] |
| 54 | fn decode_nibble(src: u8) -> u16 { |
| 55 | // 0-9 0x30-0x39 |
| 56 | // A-F 0x41-0x46 or a-f 0x61-0x66 |
| 57 | let byte = src as i16; |
| 58 | let mut ret: i16 = -1; |
| 59 | |
| 60 | // 0-9 0x30-0x39 |
| 61 | // if (byte > 0x2f && byte < 0x3a) ret += byte - 0x30 + 1; // -47 |
| 62 | ret += (((0x2fi16 - byte) & (byte - 0x3a)) >> 8) & (byte - 47); |
| 63 | // A-F 0x41-0x46 |
| 64 | // if (byte > 0x40 && byte < 0x47) ret += byte - 0x41 + 10 + 1; // -54 |
| 65 | ret += (((0x40i16 - byte) & (byte - 0x47)) >> 8) & (byte - 54); |
| 66 | |
| 67 | ret as u16 |
| 68 | } |
| 69 | |
| 70 | /// Encode a single nibble of hex |
| 71 | #[inline(always)] |
| 72 | fn encode_nibble(src: u8) -> u8 { |
| 73 | let mut ret = src as i16 + 0x30; |
| 74 | // 0-9 0x30-0x39 |
| 75 | // A-F 0x41-0x46 |
| 76 | ret += ((0x39i16 - ret) >> 8) & (0x41i16 - 0x3a); |
| 77 | ret as u8 |
| 78 | } |