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