Make use of FixedString for hex encoding

main
pantonshire 3 years ago
parent 8b605ca5c9
commit 5435784506

@ -1,8 +1,10 @@
use core::{ use core::{
fmt::{self, Write}, fmt,
marker::PhantomData, marker::PhantomData,
}; };
use crate::strings::FixedString;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[repr(transparent)] #[repr(transparent)]
pub struct HexBytes<'a, E = Lowercase> { pub struct HexBytes<'a, E = Lowercase> {
@ -70,30 +72,25 @@ impl<E> HexByte<E> {
impl<E: Encode> fmt::Debug for HexByte<E> { impl<E: Encode> fmt::Debug for HexByte<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let [b0, b1] = <E as Encode>::byte_to_hex(self.inner); write!(f, "0x{}", <E as Encode>::byte_to_hex(self.inner))
f.write_str("0x")
.and_then(|_| f.write_char(char::from(b0)))
.and_then(|_| f.write_char(char::from(b1)))
} }
} }
impl<E: Encode> fmt::Display for HexByte<E> { impl<E: Encode> fmt::Display for HexByte<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let [b0, b1] = <E as Encode>::byte_to_hex(self.inner); fmt::Display::fmt(&<E as Encode>::byte_to_hex(self.inner), f)
f.write_char(char::from(b0))
.and_then(|_| f.write_char(char::from(b1)))
} }
} }
pub trait Encode: sealed::Sealed { pub trait Encode: sealed::Sealed {
fn byte_to_hex(byte: u8) -> [u8; 2]; fn byte_to_hex(byte: u8) -> FixedString<2>;
} }
pub struct Lowercase; pub struct Lowercase;
impl Encode for Lowercase { impl Encode for Lowercase {
#[inline] #[inline]
fn byte_to_hex(byte: u8) -> [u8; 2] { fn byte_to_hex(byte: u8) -> FixedString<2> {
byte_to_hex_lower(byte) byte_to_hex_lower(byte)
} }
} }
@ -102,7 +99,7 @@ pub struct Uppercase;
impl Encode for Uppercase { impl Encode for Uppercase {
#[inline] #[inline]
fn byte_to_hex(byte: u8) -> [u8; 2] { fn byte_to_hex(byte: u8) -> FixedString<2> {
byte_to_hex_upper(byte) byte_to_hex_upper(byte)
} }
} }
@ -114,21 +111,28 @@ mod sealed {
impl Sealed for super::Uppercase {} impl Sealed for super::Uppercase {}
} }
/// Converts the given byte to its lowercase hexadecimal representation. The first byte returned /// Converts the given byte to its lowercase hexadecimal representation. The first character
/// encodes the most significant 4 bits, and the second byte encodes the least significant 4 bits. /// encodes the most significant 4 bits, and the second byte encodes the least significant 4 bits.
/// ///
/// ``` /// ```
/// # use libshire::encoding::hex::byte_to_hex_lower; /// # use libshire::encoding::hex::byte_to_hex_lower;
/// assert_eq!(byte_to_hex_lower(15), (b'0', b'f')); /// assert_eq!(&*byte_to_hex_lower(15), "0f");
/// assert_eq!(byte_to_hex_lower(139), (b'8', b'b')); /// assert_eq!(&*byte_to_hex_lower(139), "8b");
/// ``` /// ```
#[inline] #[inline]
#[must_use] #[must_use]
pub fn byte_to_hex_lower(byte: u8) -> [u8; 2] { pub fn byte_to_hex_lower(byte: u8) -> FixedString<2> {
[ // SAFETY:
nybble_to_hex_lower(byte >> 4), // `nybble_to_hex_lower` always retruns a valid ASCII character, provided that the input value
nybble_to_hex_lower(byte & 0xF), // is less than 16. `byte >> 4` and `byte & 0xF` are both always less than 16, since only the 4
] // least significant bits can possibly be set. Any sequence of valid ASCII characters is valid
// UTF-8, so the array is valid UTF-8.
unsafe {
FixedString::from_raw_array([
nybble_to_hex_lower(byte >> 4),
nybble_to_hex_lower(byte & 0xF),
])
}
} }
/// Returns the ASCII byte corresponding to the given hex nybble, using lowercase for the digits A /// Returns the ASCII byte corresponding to the given hex nybble, using lowercase for the digits A
@ -141,21 +145,28 @@ fn nybble_to_hex_lower(nybble: u8) -> u8 {
} }
} }
/// Converts the given byte to its uppercase hexadecimal representation. The first byte returned /// Converts the given byte to its uppercase hexadecimal representation. The first character
/// encodes the most significant 4 bits, and the second byte encodes the least significant 4 bits. /// encodes the most significant 4 bits, and the second byte encodes the least significant 4 bits.
/// ///
/// ``` /// ```
/// # use libshire::encoding::hex::byte_to_hex_upper; /// # use libshire::encoding::hex::byte_to_hex_upper;
/// assert_eq!(byte_to_hex_upper(15), (b'0', b'F')); /// assert_eq!(&*byte_to_hex_upper(15), "0F");
/// assert_eq!(byte_to_hex_upper(139), (b'8', b'B')); /// assert_eq!(&*byte_to_hex_upper(139), "8B");
/// ``` /// ```
#[inline] #[inline]
#[must_use] #[must_use]
pub fn byte_to_hex_upper(byte: u8) -> [u8; 2] { pub fn byte_to_hex_upper(byte: u8) -> FixedString<2> {
[ // SAFETY:
nybble_to_hex_upper(byte >> 4), // `nybble_to_hex_upper` always retruns a valid ASCII character, provided that the input value
nybble_to_hex_upper(byte & 0xF), // is less than 16. `byte >> 4` and `byte & 0xF` are both always less than 16, since only the 4
] // least significant bits can possibly be set. Any sequence of valid ASCII characters is valid
// UTF-8, so the array is valid UTF-8.
unsafe {
FixedString::from_raw_array([
nybble_to_hex_upper(byte >> 4),
nybble_to_hex_upper(byte & 0xF),
])
}
} }
/// Returns the ASCII byte corresponding to the given hex nybble, using uppercase for the digits A /// Returns the ASCII byte corresponding to the given hex nybble, using uppercase for the digits A
@ -328,28 +339,28 @@ mod tests {
#[test] #[test]
fn test_byte_to_hex_lower() { fn test_byte_to_hex_lower() {
assert_eq!(byte_to_hex_lower(0x00), [b'0', b'0']); assert_eq!(&*byte_to_hex_lower(0x00), "00");
assert_eq!(byte_to_hex_lower(0x01), [b'0', b'1']); assert_eq!(&*byte_to_hex_lower(0x01), "01");
assert_eq!(byte_to_hex_lower(0x0F), [b'0', b'f']); assert_eq!(&*byte_to_hex_lower(0x0F), "0f");
assert_eq!(byte_to_hex_lower(0x10), [b'1', b'0']); assert_eq!(&*byte_to_hex_lower(0x10), "10");
assert_eq!(byte_to_hex_lower(0x1F), [b'1', b'f']); assert_eq!(&*byte_to_hex_lower(0x1F), "1f");
assert_eq!(byte_to_hex_lower(0x9A), [b'9', b'a']); assert_eq!(&*byte_to_hex_lower(0x9A), "9a");
assert_eq!(byte_to_hex_lower(0xA9), [b'a', b'9']); assert_eq!(&*byte_to_hex_lower(0xA9), "a9");
assert_eq!(byte_to_hex_lower(0xF0), [b'f', b'0']); assert_eq!(&*byte_to_hex_lower(0xF0), "f0");
assert_eq!(byte_to_hex_lower(0xFF), [b'f', b'f']); assert_eq!(&*byte_to_hex_lower(0xFF), "ff");
} }
#[test] #[test]
fn test_byte_to_hex_upper() { fn test_byte_to_hex_upper() {
assert_eq!(byte_to_hex_upper(0x00), [b'0', b'0']); assert_eq!(&*byte_to_hex_upper(0x00), "00");
assert_eq!(byte_to_hex_upper(0x01), [b'0', b'1']); assert_eq!(&*byte_to_hex_upper(0x01), "01");
assert_eq!(byte_to_hex_upper(0x0F), [b'0', b'F']); assert_eq!(&*byte_to_hex_upper(0x0F), "0F");
assert_eq!(byte_to_hex_upper(0x10), [b'1', b'0']); assert_eq!(&*byte_to_hex_upper(0x10), "10");
assert_eq!(byte_to_hex_upper(0x1F), [b'1', b'F']); assert_eq!(&*byte_to_hex_upper(0x1F), "1F");
assert_eq!(byte_to_hex_upper(0x9A), [b'9', b'A']); assert_eq!(&*byte_to_hex_upper(0x9A), "9A");
assert_eq!(byte_to_hex_upper(0xA9), [b'A', b'9']); assert_eq!(&*byte_to_hex_upper(0xA9), "A9");
assert_eq!(byte_to_hex_upper(0xF0), [b'F', b'0']); assert_eq!(&*byte_to_hex_upper(0xF0), "F0");
assert_eq!(byte_to_hex_upper(0xFF), [b'F', b'F']); assert_eq!(&*byte_to_hex_upper(0xFF), "FF");
} }
#[test] #[test]

@ -75,7 +75,7 @@ impl Uuid {
let mut buf = [0u8; 36]; let mut buf = [0u8; 36];
for (i, byte) in self.0.iter().copied().enumerate() { for (i, byte) in self.0.iter().copied().enumerate() {
let [b0, b1] = hex::byte_to_hex_lower(byte); let [b0, b1] = hex::byte_to_hex_lower(byte).into_raw();
let offset = match i { let offset = match i {
0..=3 => 0, 0..=3 => 0,
4..=5 => 1, 4..=5 => 1,

Loading…
Cancel
Save