lowercase_hex/
traits.rs

1//! Modified from `hex`.
2
3#![allow(clippy::ptr_as_ptr, clippy::borrow_as_ptr, clippy::missing_errors_doc)]
4
5use core::iter;
6
7#[cfg(feature = "alloc")]
8#[allow(unused_imports)]
9use alloc::{
10    borrow::{Cow, ToOwned},
11    boxed::Box,
12    rc::Rc,
13    string::String,
14    vec::Vec,
15};
16
17#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
18#[allow(unused_imports)]
19use alloc::sync::Arc;
20
21/// Encoding values as hex string.
22///
23/// This trait is implemented for all `T` which implement `AsRef<[u8]>`. This
24/// includes `String`, `str`, `Vec<u8>` and `[u8]`.
25///
26/// # Examples
27///
28/// ```
29/// #![allow(deprecated)]
30/// use lowercase_hex::ToHex;
31///
32/// assert_eq!("Hello world!".encode_hex::<String>(), "48656c6c6f20776f726c6421");
33/// ```
34#[cfg_attr(feature = "alloc", doc = "\n[`encode`]: crate::encode")]
35#[cfg_attr(not(feature = "alloc"), doc = "\n[`encode`]: crate::encode_to_slice")]
36#[deprecated(note = "use `ToHexExt` instead")]
37pub trait ToHex {
38    /// Encode the hex strict representing `self` into the result.
39    /// Lower case letters are used (e.g. `f9b4ca`).
40    fn encode_hex<T: iter::FromIterator<char>>(&self) -> T;
41}
42
43/// Encoding values as hex string.
44///
45/// This trait is implemented for all `T` which implement `AsRef<[u8]>`. This
46/// includes `String`, `str`, `Vec<u8>` and `[u8]`.
47///
48/// # Examples
49///
50/// ```
51/// use lowercase_hex::ToHexExt;
52///
53/// assert_eq!("Hello world!".encode_hex(), "48656c6c6f20776f726c6421");
54/// assert_eq!("Hello world!".encode_hex_with_prefix(), "0x48656c6c6f20776f726c6421");
55/// ```
56#[cfg(feature = "alloc")]
57pub trait ToHexExt {
58    /// Encode the hex strict representing `self` into the result.
59    /// Lower case letters are used (e.g. `f9b4ca`).
60    fn encode_hex(&self) -> String;
61
62    /// Encode the hex strict representing `self` into the result with prefix `0x`.
63    /// Lower case letters are used (e.g. `0xf9b4ca`).
64    fn encode_hex_with_prefix(&self) -> String;
65}
66
67struct BytesToHexChars<'a> {
68    inner: core::slice::Iter<'a, u8>,
69    next: Option<char>,
70}
71
72impl<'a> BytesToHexChars<'a> {
73    fn new(inner: &'a [u8]) -> Self {
74        BytesToHexChars {
75            inner: inner.iter(),
76            next: None,
77        }
78    }
79}
80
81impl Iterator for BytesToHexChars<'_> {
82    type Item = char;
83
84    fn next(&mut self) -> Option<Self::Item> {
85        match self.next.take() {
86            Some(current) => Some(current),
87            None => self.inner.next().map(|byte| {
88                let (high, low) = crate::byte2hex(*byte);
89                self.next = Some(low as char);
90                high as char
91            }),
92        }
93    }
94}
95
96#[inline]
97fn encode_to_iter<T: iter::FromIterator<char>>(source: &[u8]) -> T {
98    BytesToHexChars::new(source).collect()
99}
100
101#[allow(deprecated)]
102impl<T: AsRef<[u8]>> ToHex for T {
103    #[inline]
104    fn encode_hex<U: iter::FromIterator<char>>(&self) -> U {
105        encode_to_iter(self.as_ref())
106    }
107}
108
109#[cfg(feature = "alloc")]
110impl<T: AsRef<[u8]>> ToHexExt for T {
111    #[inline]
112    fn encode_hex(&self) -> String {
113        crate::encode(self)
114    }
115
116    #[inline]
117    fn encode_hex_with_prefix(&self) -> String {
118        crate::encode_prefixed(self)
119    }
120}
121
122/// Types that can be decoded from a hex string.
123///
124/// This trait is implemented for `Vec<u8>` and small `u8`-arrays.
125///
126/// # Example
127///
128/// ```
129/// use lowercase_hex::FromHex;
130///
131/// let buffer = <[u8; 12]>::from_hex("48656c6c6f20776f726c6421")?;
132/// assert_eq!(buffer, *b"Hello world!");
133/// # Ok::<(), lowercase_hex::FromHexError>(())
134/// ```
135pub trait FromHex: Sized {
136    /// The associated error which can be returned from parsing.
137    type Error;
138
139    /// Creates an instance of type `Self` from the given hex string, or fails
140    /// with a custom error type.
141    ///
142    /// Both, upper and lower case characters are valid and can even be
143    /// mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings).
144    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error>;
145}
146
147#[cfg(feature = "alloc")]
148impl<T: FromHex> FromHex for Box<T> {
149    type Error = T::Error;
150
151    #[inline]
152    fn from_hex<U: AsRef<[u8]>>(hex: U) -> Result<Self, Self::Error> {
153        FromHex::from_hex(hex.as_ref()).map(Self::new)
154    }
155}
156
157#[cfg(feature = "alloc")]
158impl<T> FromHex for Cow<'_, T>
159where
160    T: ToOwned + ?Sized,
161    T::Owned: FromHex,
162{
163    type Error = <T::Owned as FromHex>::Error;
164
165    #[inline]
166    fn from_hex<U: AsRef<[u8]>>(hex: U) -> Result<Self, Self::Error> {
167        FromHex::from_hex(hex.as_ref()).map(Cow::Owned)
168    }
169}
170
171#[cfg(feature = "alloc")]
172impl<T: FromHex> FromHex for Rc<T> {
173    type Error = T::Error;
174
175    #[inline]
176    fn from_hex<U: AsRef<[u8]>>(hex: U) -> Result<Self, Self::Error> {
177        FromHex::from_hex(hex.as_ref()).map(Self::new)
178    }
179}
180
181#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
182impl<T: FromHex> FromHex for Arc<T> {
183    type Error = T::Error;
184
185    #[inline]
186    fn from_hex<U: AsRef<[u8]>>(hex: U) -> Result<Self, Self::Error> {
187        FromHex::from_hex(hex.as_ref()).map(Self::new)
188    }
189}
190
191#[cfg(feature = "alloc")]
192impl FromHex for Vec<u8> {
193    type Error = crate::FromHexError;
194
195    #[inline]
196    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
197        crate::decode(hex.as_ref())
198    }
199}
200
201#[cfg(feature = "alloc")]
202impl FromHex for Vec<i8> {
203    type Error = crate::FromHexError;
204
205    #[inline]
206    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
207        // SAFETY: transmuting `u8` to `i8` is safe.
208        crate::decode(hex.as_ref()).map(|vec| unsafe { core::mem::transmute::<Vec<u8>, Self>(vec) })
209    }
210}
211
212#[cfg(feature = "alloc")]
213impl FromHex for Box<[u8]> {
214    type Error = crate::FromHexError;
215
216    #[inline]
217    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
218        <Vec<u8>>::from_hex(hex).map(Vec::into_boxed_slice)
219    }
220}
221
222#[cfg(feature = "alloc")]
223impl FromHex for Box<[i8]> {
224    type Error = crate::FromHexError;
225
226    #[inline]
227    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
228        <Vec<i8>>::from_hex(hex).map(Vec::into_boxed_slice)
229    }
230}
231
232impl<const N: usize> FromHex for [u8; N] {
233    type Error = crate::FromHexError;
234
235    #[inline]
236    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
237        crate::decode_to_array(hex.as_ref())
238    }
239}
240
241impl<const N: usize> FromHex for [i8; N] {
242    type Error = crate::FromHexError;
243
244    #[inline]
245    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
246        // SAFETY: casting `[u8]` to `[i8]` is safe.
247        crate::decode_to_array(hex.as_ref())
248            .map(|buf| unsafe { *(&buf as *const [u8; N] as *const [i8; N]) })
249    }
250}