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