array_bytes/lib.rs
1#![allow(clippy::tabs_in_doc_comments)]
2#![deny(missing_docs)]
3#![no_std]
4
5//! A collection of array/bytes/hex utilities.
6//!
7//! Completely optimized for blockchain development.
8//! Especially the Substrate.
9
10extern crate alloc;
11
12#[cfg(test)] mod test;
13
14// core
15use core::{cmp::Ordering, convert::TryInto, result::Result as CoreResult, str};
16// alloc
17use alloc::{format, string::String, vec::Vec};
18// crates.io
19#[cfg(feature = "serde")] use serde::{de::Error as DeError, Deserialize, Deserializer};
20// use thiserror::Error as ThisError;
21
22/// The main result of array-bytes.
23pub type Result<T> = CoreResult<T, Error>;
24
25/// Try to convert the given hex to a specific type.
26///
27/// # Examples
28/// ```
29/// use array_bytes::TryFromHex;
30///
31/// assert_eq!(u128::try_from_hex("0x1a2b3c4d5e6f"), Ok(28772997619311));
32/// ```
33pub trait TryFromHex
34where
35 Self: Sized,
36{
37 /// Try to convert [`Self`] from hex.
38 fn try_from_hex<H>(hex: H) -> Result<Self>
39 where
40 H: AsRef<[u8]>;
41}
42macro_rules! impl_num_try_from_hex {
43 ($($t:ty,)+) => {
44 $(impl TryFromHex for $t {
45 fn try_from_hex<H>(hex: H) -> Result<Self>
46 where
47 H: AsRef<[u8]>,
48 {
49 let hex = strip_0x(hex.as_ref());
50 let hex = str::from_utf8(hex).map_err(Error::Utf8Error)?;
51
52 Self::from_str_radix(hex, 16).map_err(Error::ParseIntError)
53 }
54 })+
55 };
56}
57impl_num_try_from_hex! {
58 isize,
59 i8,
60 i16,
61 i32,
62 i64,
63 i128,
64 usize,
65 u8,
66 u16,
67 u32,
68 u64,
69 u128,
70}
71macro_rules! impl_array_try_from_hex {
72 ($($t:ty,)+) => {
73 $(impl TryFromHex for $t {
74 fn try_from_hex<H>(hex: H) -> Result<Self>
75 where
76 H: AsRef<[u8]>,
77 {
78 hex2array(hex)
79 }
80 })+
81 };
82}
83impl_array_try_from_hex! {
84 [u8; 1],
85 [u8; 2],
86 [u8; 3],
87 [u8; 4],
88 [u8; 5],
89 [u8; 6],
90 [u8; 7],
91 [u8; 8],
92 [u8; 9],
93 [u8; 10],
94 [u8; 11],
95 [u8; 12],
96 [u8; 13],
97 [u8; 14],
98 [u8; 15],
99 [u8; 16],
100 [u8; 17],
101 [u8; 18],
102 [u8; 19],
103 [u8; 20],
104 [u8; 21],
105 [u8; 22],
106 [u8; 23],
107 [u8; 24],
108 [u8; 25],
109 [u8; 26],
110 [u8; 27],
111 [u8; 28],
112 [u8; 29],
113 [u8; 30],
114 [u8; 31],
115 [u8; 32],
116 [u8; 33],
117 [u8; 34],
118 [u8; 35],
119 [u8; 36],
120 [u8; 37],
121 [u8; 38],
122 [u8; 39],
123 [u8; 40],
124 [u8; 41],
125 [u8; 42],
126 [u8; 43],
127 [u8; 44],
128 [u8; 45],
129 [u8; 46],
130 [u8; 47],
131 [u8; 48],
132 [u8; 49],
133 [u8; 50],
134 [u8; 51],
135 [u8; 52],
136 [u8; 53],
137 [u8; 54],
138 [u8; 55],
139 [u8; 56],
140 [u8; 57],
141 [u8; 58],
142 [u8; 59],
143 [u8; 60],
144 [u8; 61],
145 [u8; 62],
146 [u8; 63],
147 [u8; 64],
148 [u8; 128],
149 [u8; 256],
150 [u8; 512],
151}
152impl TryFromHex for Vec<u8> {
153 fn try_from_hex<H>(hex: H) -> Result<Self>
154 where
155 H: AsRef<[u8]>,
156 {
157 hex2bytes(hex)
158 }
159}
160
161/// Convert the given type to hex.
162///
163/// # Examples
164/// ```
165/// use array_bytes::Hex;
166///
167/// assert_eq!(28772997619311_u128.hex("0x"), "0x1a2b3c4d5e6f");
168/// ```
169pub trait Hex {
170 /// Convert [`Self`] to hex with the given prefix.
171 fn hex(self, prefix: &str) -> String;
172}
173macro_rules! impl_num_hex {
174 ($($t:ty,)+) => {
175 $(
176 impl Hex for $t {
177 fn hex(self, prefix: &str) -> String {
178 format!("{prefix}{self:x}")
179 }
180 }
181 impl Hex for &$t {
182 fn hex(self, prefix: &str) -> String {
183 format!("{prefix}{self:x}")
184 }
185 }
186 )+
187 };
188}
189impl_num_hex! {
190 isize,
191 i8,
192 i16,
193 i32,
194 i64,
195 i128,
196 usize,
197 u8,
198 u16,
199 u32,
200 u64,
201 u128,
202}
203macro_rules! impl_array_hex {
204 ($($t:ty,)+) => {
205 $(
206 impl Hex for $t {
207 fn hex(self, prefix: &str) -> String {
208 bytes2hex(prefix, self)
209 }
210 }
211 impl Hex for &$t {
212 fn hex(self, prefix: &str) -> String {
213 bytes2hex(prefix, self)
214 }
215 }
216 )+
217 };
218}
219impl_array_hex! {
220 Vec<u8>,
221 [u8; 1],
222 [u8; 2],
223 [u8; 3],
224 [u8; 4],
225 [u8; 5],
226 [u8; 6],
227 [u8; 7],
228 [u8; 8],
229 [u8; 9],
230 [u8; 10],
231 [u8; 11],
232 [u8; 12],
233 [u8; 13],
234 [u8; 14],
235 [u8; 15],
236 [u8; 16],
237 [u8; 17],
238 [u8; 18],
239 [u8; 19],
240 [u8; 20],
241 [u8; 21],
242 [u8; 22],
243 [u8; 23],
244 [u8; 24],
245 [u8; 25],
246 [u8; 26],
247 [u8; 27],
248 [u8; 28],
249 [u8; 29],
250 [u8; 30],
251 [u8; 31],
252 [u8; 32],
253 [u8; 33],
254 [u8; 34],
255 [u8; 35],
256 [u8; 36],
257 [u8; 37],
258 [u8; 38],
259 [u8; 39],
260 [u8; 40],
261 [u8; 41],
262 [u8; 42],
263 [u8; 43],
264 [u8; 44],
265 [u8; 45],
266 [u8; 46],
267 [u8; 47],
268 [u8; 48],
269 [u8; 49],
270 [u8; 50],
271 [u8; 51],
272 [u8; 52],
273 [u8; 53],
274 [u8; 54],
275 [u8; 55],
276 [u8; 56],
277 [u8; 57],
278 [u8; 58],
279 [u8; 59],
280 [u8; 60],
281 [u8; 61],
282 [u8; 62],
283 [u8; 63],
284 [u8; 64],
285 [u8; 128],
286 [u8; 256],
287 [u8; 512],
288}
289impl Hex for &[u8] {
290 fn hex(self, prefix: &str) -> String {
291 bytes2hex(prefix, self)
292 }
293}
294
295/// The main error of array-bytes.
296#[derive(Debug, PartialEq, Eq)]
297pub enum Error {
298 /// The length must not be odd.
299 InvalidLength,
300 /// Found the invalid character at `index`.
301 InvalidCharacter {
302 /// The invalid character.
303 character: char,
304 /// The invalid character's index.
305 index: usize,
306 },
307 /// The data can not fit the array/slice length well.
308 MismatchedLength {
309 /// Expected length.
310 expect: usize,
311 },
312 /// Failed to parse the hex number from hex string.
313 Utf8Error(core::str::Utf8Error),
314 /// Failed to parse the hex number from hex string.
315 ParseIntError(core::num::ParseIntError),
316}
317
318/// `&[T]` to `[T; N]`.
319///
320/// # Examples
321/// ```
322/// assert_eq!(array_bytes::slice2array::<_, 8>(&[0; 8]), Ok([0; 8]));
323/// ```
324pub fn slice2array<T, const N: usize>(slice: &[T]) -> Result<[T; N]>
325where
326 T: Copy,
327{
328 slice.try_into().map_err(|_| Error::MismatchedLength { expect: N })
329}
330
331/// Just like [`slice2array`] but without the checking.
332///
333/// # Examples
334/// ```
335/// assert_eq!(array_bytes::slice2array_unchecked::<_, 8>(&[0; 8]), [0; 8]);
336/// ```
337pub fn slice2array_unchecked<T, const N: usize>(slice: &[T]) -> [T; N]
338where
339 T: Copy,
340{
341 slice2array(slice).unwrap()
342}
343
344/// `&[T]` to `&[T; N]`.
345///
346/// # Examples
347/// ```
348/// assert_eq!(array_bytes::slice2array::<_, 8>(&[0; 8]), Ok(&[0; 8]));
349/// ```
350pub fn slice2array_ref<T, const N: usize>(slice: &[T]) -> Result<&[T; N]>
351where
352 T: Copy,
353{
354 slice.try_into().map_err(|_| Error::MismatchedLength { expect: N })
355}
356
357/// Just like [`slice2array_ref`] but without the checking.
358///
359/// # Examples
360/// ```
361/// assert_eq!(array_bytes::slice2array_unchecked::<_, 8>(&[0; 8]), &[0; 8]);
362/// ```
363pub fn slice2array_ref_unchecked<T, const N: usize>(slice: &[T]) -> &[T; N]
364where
365 T: Copy,
366{
367 slice2array_ref(slice).unwrap()
368}
369
370/// Prefixes the given element to the given array/slice/vector to make it a fixed-size array of
371/// length `N`.
372///
373/// If the length of the array/slice/vector is already equal to `N`, it returns the
374/// array/slice/vector as a fixed-size array.
375/// If the length of the array/slice/vector is greater than `N`, it returns the first `N` elements
376/// of the array/slice/vector as a fixed-size array.
377/// If the length of the array/slice/vector is less than `N`, it creates a new fixed-size array of
378/// length `N` and copies the array/slice/vector into it, padding the remaining elements with the
379/// given element.
380///
381/// # Examples
382/// ```
383/// assert_eq!(array_bytes::prefix_with::<_, _, 4>([1, 2, 3, 4], 0), [1, 2, 3, 4]);
384/// assert_eq!(array_bytes::prefix_with::<_, _, 4>([1, 2, 3, 4, 5, 6], 0), [1, 2, 3, 4]);
385/// assert_eq!(array_bytes::prefix_with::<_, _, 5>([1, 2, 3], 0), [0, 0, 1, 2, 3]);
386/// ```
387pub fn prefix_with<A, T, const N: usize>(any: A, element: T) -> [T; N]
388where
389 A: AsRef<[T]>,
390 T: Copy,
391{
392 let a = any.as_ref();
393
394 match a.len().cmp(&N) {
395 Ordering::Equal => slice2array_unchecked(a),
396 Ordering::Greater => slice2array_unchecked(&a[..N]),
397 Ordering::Less => {
398 let mut padded = [element; N];
399
400 padded[N - a.len()..].copy_from_slice(a);
401
402 padded
403 },
404 }
405}
406
407/// Suffixes the given element to the given array/slice/vector to make it a fixed-size array of
408/// length `N`.
409///
410/// If the length of the array/slice/vector is already equal to `N`, it returns the
411/// array/slice/vector as a fixed-size array.
412/// If the length of the array/slice/vector is greater than `N`, it returns the first `N` elements
413/// of the array/slice/vector as a fixed-size array.
414/// If the length of the array/slice/vector is less than `N`, it creates a new fixed-size array of
415/// length `N` and copies the array/slice/vector into it, padding the remaining elements with the
416/// given element.
417///
418/// # Examples
419/// ```
420/// assert_eq!(array_bytes::suffix_with::<_, _, 4>([1, 2, 3, 4], 0), [1, 2, 3, 4]);
421/// assert_eq!(array_bytes::suffix_with::<_, _, 4>([1, 2, 3, 4, 5, 6], 0), [1, 2, 3, 4]);
422/// assert_eq!(array_bytes::suffix_with::<_, _, 5>([1, 2, 3], 0), [1, 2, 3, 0, 0]);
423/// ```
424pub fn suffix_with<A, T, const N: usize>(any: A, element: T) -> [T; N]
425where
426 A: AsRef<[T]>,
427 T: Copy,
428{
429 let a = any.as_ref();
430
431 match a.len().cmp(&N) {
432 Ordering::Equal => slice2array_unchecked(a),
433 Ordering::Greater => slice2array_unchecked(&a[..N]),
434 Ordering::Less => {
435 let mut padded = [element; N];
436
437 padded[..a.len()].copy_from_slice(a);
438
439 padded
440 },
441 }
442}
443
444/// Convert `&[T]` to a type directly.
445///
446/// # Examples
447/// ```
448/// #[derive(Debug, PartialEq)]
449/// struct LJF([u8; 17]);
450/// impl From<[u8; 17]> for LJF {
451/// fn from(array: [u8; 17]) -> Self {
452/// Self(array)
453/// }
454/// }
455///
456/// assert_eq!(
457/// array_bytes::slice_n_into::<u8, LJF, 17>(b"Love Jane Forever"),
458/// Ok(LJF(*b"Love Jane Forever"))
459/// );
460/// ```
461pub fn slice_n_into<T, V, const N: usize>(slice: &[T]) -> Result<V>
462where
463 T: Copy,
464 V: From<[T; N]>,
465{
466 Ok(slice2array(slice)?.into())
467}
468
469/// Just like [`slice_n_into`] but without the checking.
470///
471/// # Examples
472/// ```
473/// #[derive(Debug, PartialEq)]
474/// struct LJF([u8; 17]);
475/// impl From<[u8; 17]> for LJF {
476/// fn from(array: [u8; 17]) -> Self {
477/// Self(array)
478/// }
479/// }
480///
481/// assert_eq!(
482/// array_bytes::slice_n_into_unchecked::<u8, LJF, 17>(b"Love Jane Forever"),
483/// LJF(*b"Love Jane Forever")
484/// );
485/// ```
486pub fn slice_n_into_unchecked<T, V, const N: usize>(slice: &[T]) -> V
487where
488 T: Copy,
489 V: From<[T; N]>,
490{
491 slice2array_unchecked(slice).into()
492}
493
494/// [`Vec<T>`] to `[T; N]`.
495///
496/// # Examples
497/// ```
498/// assert_eq!(array_bytes::vec2array::<_, 8>(vec![0; 8]), Ok([0; 8]));
499/// ```
500pub fn vec2array<T, const N: usize>(vec: Vec<T>) -> Result<[T; N]> {
501 vec.try_into().map_err(|_| Error::MismatchedLength { expect: N })
502}
503
504/// Just like [`vec2array`] but without the checking.
505///
506/// # Examples
507/// ```
508/// assert_eq!(array_bytes::vec2array_unchecked::<_, 8>(vec![0; 8]), [0; 8]);
509/// ```
510pub fn vec2array_unchecked<T, const N: usize>(vec: Vec<T>) -> [T; N] {
511 vec2array(vec).unwrap()
512}
513
514/// Convert [`Vec<T>`] to a type directly.
515///
516/// # Examples
517///
518/// ```
519/// #[derive(Debug, PartialEq)]
520/// struct LJF([u8; 17]);
521/// impl From<[u8; 17]> for LJF {
522/// fn from(array: [u8; 17]) -> Self {
523/// Self(array)
524/// }
525/// }
526///
527/// assert_eq!(
528/// array_bytes::vec_n_into::<u8, LJF, 17>(b"Love Jane Forever".to_vec()),
529/// Ok(LJF(*b"Love Jane Forever"))
530/// );
531/// ```
532pub fn vec_n_into<T, V, const N: usize>(vec: Vec<T>) -> Result<V>
533where
534 V: From<[T; N]>,
535{
536 Ok(vec2array(vec)?.into())
537}
538
539/// Just like [`vec_n_into`] but without the checking.
540///
541/// # Examples
542/// ```
543/// #[derive(Debug, PartialEq)]
544/// struct LJF([u8; 17]);
545/// impl From<[u8; 17]> for LJF {
546/// fn from(array: [u8; 17]) -> Self {
547/// Self(array)
548/// }
549/// }
550///
551/// assert_eq!(
552/// array_bytes::vec_n_into_unchecked::<u8, LJF, 17>(b"Love Jane Forever".to_vec()),
553/// LJF(*b"Love Jane Forever")
554/// );
555/// ```
556pub fn vec_n_into_unchecked<T, V, const N: usize>(vec: Vec<T>) -> V
557where
558 V: From<[T; N]>,
559{
560 vec2array_unchecked(vec).into()
561}
562
563/// Convert hex bytes to hex string.
564///
565/// This is useful when you are interacting with the IO.
566///
567/// # Examples
568/// ```
569/// assert_eq!(
570/// array_bytes::hex_bytes2hex_str(b"0x4c6f7665204a616e6520466f7265766572"),
571/// Ok("0x4c6f7665204a616e6520466f7265766572"),
572/// );
573/// ```
574pub fn hex_bytes2hex_str(bytes: &[u8]) -> Result<&str> {
575 for (i, byte) in bytes.iter().enumerate().skip(if bytes.starts_with(b"0x") { 2 } else { 0 }) {
576 if !is_hex_ascii(byte) {
577 Err(Error::InvalidCharacter { character: *byte as _, index: i })?;
578 }
579 }
580
581 Ok(
582 // Validated in previous step, never fails here; qed.
583 unsafe { str::from_utf8_unchecked(bytes) },
584 )
585}
586
587/// Just like [`hex_bytes2hex_str`] but without the checking.
588///
589/// # Safety
590/// See the [`str::from_utf8_unchecked`].
591///
592/// # Examples
593/// ```
594/// unsafe {
595/// assert_eq!(
596/// array_bytes::hex_bytes2hex_str_unchecked(b"0x4c6f7665204a616e6520466f7265766572"),
597/// "0x4c6f7665204a616e6520466f7265766572",
598/// );
599/// }
600/// ```
601pub unsafe fn hex_bytes2hex_str_unchecked(bytes: &[u8]) -> &str {
602 str::from_utf8_unchecked(bytes)
603}
604
605/// `AsRef<[u8]>` to [`String`].
606///
607/// # Examples
608/// ```
609/// assert_eq!(
610/// array_bytes::bytes2hex("0x", b"Love Jane Forever"),
611/// String::from("0x4c6f7665204a616e6520466f7265766572")
612/// );
613/// ```
614pub fn bytes2hex<B>(prefix: &str, bytes: B) -> String
615where
616 B: AsRef<[u8]>,
617{
618 let bytes = bytes.as_ref();
619 let mut hex = String::with_capacity(prefix.len() + bytes.len() * 2);
620
621 prefix.chars().for_each(|byte| hex.push(byte));
622 bytes.iter().for_each(|byte| {
623 hex.push(char::from_digit((byte >> 4) as _, 16).unwrap());
624 hex.push(char::from_digit((byte & 0xf) as _, 16).unwrap());
625 });
626
627 hex
628}
629
630/// Just like [`hex2bytes`] but to a fixed length array.
631///
632/// # Examples
633/// ```
634/// assert_eq!(
635/// array_bytes::hex2array("0x4c6f7665204a616e6520466f7265766572"),
636/// Ok(*b"Love Jane Forever")
637/// );
638/// ```
639pub fn hex2array<H, const N: usize>(hex: H) -> Result<[u8; N]>
640where
641 H: AsRef<[u8]>,
642{
643 vec2array(hex2bytes(hex.as_ref())?)
644}
645
646/// Just like [`hex2array`] but without the checking.
647///
648/// # Examples
649/// ```
650/// assert_eq!(
651/// array_bytes::hex2array_unchecked("0x4c6f7665204a616e6520466f7265766572"),
652/// *b"Love Jane Forever"
653/// );
654/// ```
655pub fn hex2array_unchecked<H, const N: usize>(hex: H) -> [u8; N]
656where
657 H: AsRef<[u8]>,
658{
659 hex2bytes_unchecked(hex).try_into().unwrap()
660}
661
662/// `AsRef<[u8]>` to [`Vec<u8>`].
663///
664/// Return error if:
665/// - length is odd
666/// - encounter invalid hex ascii
667///
668/// # Examples
669/// ```
670/// assert_eq!(
671/// array_bytes::hex2bytes("0x4c6f7665204a616e6520466f7265766572"),
672/// Ok(b"Love Jane Forever".to_vec())
673/// );
674/// ```
675pub fn hex2bytes<H>(hex: H) -> Result<Vec<u8>>
676where
677 H: AsRef<[u8]>,
678{
679 let hex = strip_0x(hex.as_ref());
680
681 if hex.len() % 2 != 0 {
682 Err(Error::InvalidLength)?;
683 }
684
685 let mut bytes = Vec::new();
686
687 for i in (0..hex.len()).step_by(2) {
688 bytes.push(hex2byte((&hex[i], i), (&hex[i + 1], i + 1))?);
689 }
690
691 Ok(bytes)
692}
693
694/// Just like [`hex2bytes`] but without checking.
695///
696/// # Examples
697/// ```
698/// assert_eq!(
699/// array_bytes::hex2bytes_unchecked("0x4c6f7665204a616e6520466f7265766572"),
700/// *b"Love Jane Forever"
701/// );
702/// ```
703pub fn hex2bytes_unchecked<H>(hex: H) -> Vec<u8>
704where
705 H: AsRef<[u8]>,
706{
707 let hex = strip_0x(hex.as_ref());
708
709 (0..hex.len()).step_by(2).map(|i| hex2byte_unchecked(&hex[i], &hex[i + 1])).collect()
710}
711
712/// `AsRef<[u8]>` to `&[u8]`.
713///
714/// This function will modify the given slice's source and return the revised result.
715///
716/// Return error if:
717/// - length is odd
718/// - encounter invalid hex ascii
719/// - mismatched slice size
720///
721/// # Examples
722/// ```
723/// let mut bytes = [0; 17];
724///
725/// assert_eq!(
726/// array_bytes::hex2slice("0x4c6f7665204a616e6520466f7265766572", &mut bytes),
727/// Ok(b"Love Jane Forever".as_slice())
728/// );
729/// assert_eq!(bytes, *b"Love Jane Forever");
730/// ```
731pub fn hex2slice<H>(hex: H, slice: &mut [u8]) -> Result<&[u8]>
732where
733 H: AsRef<[u8]>,
734{
735 let hex = strip_0x(hex.as_ref());
736
737 if hex.len() % 2 != 0 {
738 Err(Error::InvalidLength)?;
739 }
740
741 let expected_len = hex.len() >> 1;
742
743 if expected_len != slice.len() {
744 Err(Error::MismatchedLength { expect: expected_len })?;
745 }
746
747 for (byte, i) in slice.iter_mut().zip((0..hex.len()).step_by(2)) {
748 *byte = hex2byte((&hex[i], i), (&hex[i + 1], i + 1))?;
749 }
750
751 Ok(slice)
752}
753
754/// Just like [`hex2slice`] but without checking.
755///
756/// # Examples
757/// ```
758/// let mut bytes = [0; 17];
759///
760/// assert_eq!(
761/// array_bytes::hex2slice_unchecked("0x4c6f7665204a616e6520466f7265766572", &mut bytes),
762/// b"Love Jane Forever"
763/// );
764/// assert_eq!(bytes, *b"Love Jane Forever");
765/// ```
766pub fn hex2slice_unchecked<H>(hex: H, slice: &mut [u8]) -> &[u8]
767where
768 H: AsRef<[u8]>,
769{
770 let hex = strip_0x(hex.as_ref());
771
772 slice
773 .iter_mut()
774 .zip((0..hex.len()).step_by(2))
775 .for_each(|(byte, i)| *byte = hex2byte_unchecked(&hex[i], &hex[i + 1]));
776
777 slice
778}
779
780/// Try to convert `AsRef<[u8]>` to `T` directly, where `T: From<Vec<u8>>`.
781///
782/// # Examples
783/// ```
784/// #[derive(Debug, PartialEq)]
785/// struct LJF(Vec<u8>);
786/// impl From<Vec<u8>> for LJF {
787/// fn from(vec: Vec<u8>) -> Self {
788/// Self(vec)
789/// }
790/// }
791///
792/// assert_eq!(
793/// array_bytes::hex_into::<_, LJF>("0x4c6f7665204a616e6520466f7265766572"),
794/// Ok(LJF(b"Love Jane Forever".to_vec()))
795/// );
796/// ```
797pub fn hex_into<H, T>(hex: H) -> Result<T>
798where
799 H: AsRef<[u8]>,
800 T: From<Vec<u8>>,
801{
802 Ok(hex2bytes(hex.as_ref())?.into())
803}
804
805/// Just like [`hex_into`] but without the checking.
806///
807/// # Examples
808/// ```
809/// #[derive(Debug, PartialEq)]
810/// struct LJF(Vec<u8>);
811/// impl From<Vec<u8>> for LJF {
812/// fn from(vec: Vec<u8>) -> Self {
813/// Self(vec)
814/// }
815/// }
816///
817/// assert_eq!(
818/// array_bytes::hex_into_unchecked::<_, LJF>("0x4c6f7665204a616e6520466f7265766572"),
819/// LJF(b"Love Jane Forever".to_vec())
820/// );
821/// ```
822pub fn hex_into_unchecked<H, T>(hex: H) -> T
823where
824 H: AsRef<[u8]>,
825 T: From<Vec<u8>>,
826{
827 hex2bytes_unchecked(hex).into()
828}
829
830/// Try to convert `AsRef<[u8]>` to `T` directly, where `T: From<[u8; N]>`.
831///
832/// # Examples
833/// ```
834/// #[derive(Debug, PartialEq)]
835/// struct LJF([u8; 17]);
836/// impl From<[u8; 17]> for LJF {
837/// fn from(array: [u8; 17]) -> Self {
838/// Self(array)
839/// }
840/// }
841///
842/// assert_eq!(
843/// array_bytes::hex_n_into::<_, LJF, 17>("0x4c6f7665204a616e6520466f7265766572"),
844/// Ok(LJF(*b"Love Jane Forever"))
845/// );
846/// ```
847pub fn hex_n_into<H, T, const N: usize>(hex: H) -> Result<T>
848where
849 H: AsRef<[u8]>,
850 T: From<[u8; N]>,
851{
852 Ok(hex2array(hex)?.into())
853}
854
855/// Just like [`hex_n_into`] but without the checking.
856///
857/// # Examples
858/// ```
859/// #[derive(Debug, PartialEq)]
860/// struct LJF([u8; 17]);
861/// impl From<[u8; 17]> for LJF {
862/// fn from(array: [u8; 17]) -> Self {
863/// Self(array)
864/// }
865/// }
866///
867/// assert_eq!(
868/// array_bytes::hex_n_into_unchecked::<_, LJF, 17>("0x4c6f7665204a616e6520466f7265766572"),
869/// LJF(*b"Love Jane Forever")
870/// );
871/// ```
872pub fn hex_n_into_unchecked<H, T, const N: usize>(hex: H) -> T
873where
874 H: AsRef<[u8]>,
875 T: From<[u8; N]>,
876{
877 hex2array_unchecked(hex).into()
878}
879
880/// Deserialize hex to `T`, where `T: From<Vec<u8>>`.
881///
882/// # Examples
883/// ```
884/// use serde::Deserialize;
885///
886/// #[derive(Debug, PartialEq)]
887/// struct LJF(Vec<u8>);
888/// impl From<Vec<u8>> for LJF {
889/// fn from(vec: Vec<u8>) -> Self {
890/// Self(vec)
891/// }
892/// }
893///
894/// #[derive(Debug, PartialEq, Deserialize)]
895/// struct WrappedLJF {
896/// #[serde(deserialize_with = "array_bytes::hex_deserialize_into")]
897/// ljf: LJF,
898/// }
899///
900/// assert_eq!(
901/// serde_json::from_str::<WrappedLJF>(r#"{
902/// "ljf": "0x4c6f7665204a616e6520466f7265766572"
903/// }"#).unwrap(),
904/// WrappedLJF {
905/// ljf: LJF(b"Love Jane Forever".to_vec())
906/// }
907/// );
908#[cfg(feature = "serde")]
909pub fn hex_deserialize_into<'de, D, T>(hex: D) -> CoreResult<T, D::Error>
910where
911 D: Deserializer<'de>,
912 T: From<Vec<u8>>,
913{
914 Ok(hex2bytes_unchecked(<&str>::deserialize(hex)?).into())
915}
916
917/// Deserialize hex to `T`, where `T: From<[u8; N]>`.
918///
919/// # Examples
920/// ```
921/// use serde::Deserialize;
922///
923/// #[derive(Debug, PartialEq)]
924/// struct LJF([u8; 17]);
925/// impl From<[u8; 17]> for LJF {
926/// fn from(array: [u8; 17]) -> Self {
927/// Self(array)
928/// }
929/// }
930///
931/// #[derive(Debug, PartialEq, Deserialize)]
932/// struct WrappedLJF {
933/// #[serde(deserialize_with = "array_bytes::hex_deserialize_n_into")]
934/// ljf: LJF,
935/// }
936///
937/// assert_eq!(
938/// serde_json::from_str::<WrappedLJF>(r#"{
939/// "ljf": "0x4c6f7665204a616e6520466f7265766572"
940/// }"#).unwrap(),
941/// WrappedLJF {
942/// ljf: LJF(*b"Love Jane Forever")
943/// }
944/// );
945#[cfg(feature = "serde")]
946pub fn hex_deserialize_n_into<'de, D, T, const N: usize>(hex: D) -> CoreResult<T, D::Error>
947where
948 D: Deserializer<'de>,
949 T: From<[u8; N]>,
950{
951 Ok(hex2array_unchecked(<&str>::deserialize(hex)?).into())
952}
953
954/// Deserialize hex to any Rust primitive num types.
955///
956/// # Examples
957/// ```
958/// use serde::Deserialize;
959///
960/// #[derive(Debug, PartialEq, Deserialize)]
961/// struct LJF {
962/// #[serde(deserialize_with = "array_bytes::de_hex2num")]
963/// _0: u8,
964/// #[serde(deserialize_with = "array_bytes::de_hex2num")]
965/// _1: u8,
966/// #[serde(deserialize_with = "array_bytes::de_hex2num")]
967/// _2: u8,
968/// #[serde(deserialize_with = "array_bytes::de_hex2num")]
969/// _3: u32,
970/// }
971///
972/// assert_eq!(
973/// serde_json::from_str::<LJF>(
974/// r#"{
975/// "_0": "0x5",
976/// "_1": "0x2",
977/// "_2": "0x0",
978/// "_3": "0x522"
979/// }"#
980/// )
981/// .unwrap(),
982/// LJF { _0: 5, _1: 2, _2: 0, _3: 1314 }
983/// );
984/// ```
985#[cfg(feature = "serde")]
986pub fn de_hex2num<'de, D, T>(hex: D) -> CoreResult<T, D::Error>
987where
988 D: Deserializer<'de>,
989 T: TryFromHex,
990{
991 let hex = <&str>::deserialize(hex)?;
992
993 T::try_from_hex(hex).map_err(|_| D::Error::custom(alloc::format!("Invalid hex str `{}`", hex)))
994}
995
996/// Deserialize hex to [`Vec<u8>`].
997///
998/// # Examples
999/// ```
1000/// use serde::Deserialize;
1001///
1002/// #[derive(Debug, PartialEq, Deserialize)]
1003/// struct LJF {
1004/// #[serde(deserialize_with = "array_bytes::de_hex2bytes")]
1005/// ljf: Vec<u8>,
1006/// }
1007///
1008/// assert_eq!(
1009/// serde_json::from_str::<LJF>(
1010/// r#"{
1011/// "ljf": "0x4c6f7665204a616e6520466f7265766572"
1012/// }"#
1013/// )
1014/// .unwrap(),
1015/// LJF { ljf: (*b"Love Jane Forever").to_vec() }
1016/// );
1017/// ```
1018#[cfg(feature = "serde")]
1019pub fn de_hex2bytes<'de, D>(hex: D) -> CoreResult<Vec<u8>, D::Error>
1020where
1021 D: Deserializer<'de>,
1022{
1023 let hex = <&str>::deserialize(hex)?;
1024
1025 hex2bytes(hex).map_err(|_| D::Error::custom(alloc::format!("Invalid hex str `{}`", hex)))
1026}
1027
1028fn strip_0x(hex: &[u8]) -> &[u8] {
1029 if let Some(hex) = hex.strip_prefix(b"0x") {
1030 hex
1031 } else {
1032 hex
1033 }
1034}
1035
1036fn is_hex_ascii(byte: &u8) -> bool {
1037 // Convert to lowercase.
1038 let byte = byte | 0b10_0000;
1039
1040 matches!(byte, b'0'..=b'9' | b'a'..=b'f')
1041}
1042
1043fn hex_ascii2digit(hex_ascii: &u8) -> Option<u8> {
1044 // Convert to lowercase.
1045 let hex_ascii = hex_ascii | 0b10_0000;
1046
1047 match hex_ascii {
1048 b'0'..=b'9' => Some(hex_ascii - b'0'),
1049 b'a'..=b'f' => Some(hex_ascii - b'a' + 10),
1050 _ => None,
1051 }
1052}
1053
1054fn hex2byte(hex_ascii_1: (&u8, usize), hex_ascii_2: (&u8, usize)) -> Result<u8> {
1055 let byte = hex_ascii2digit(hex_ascii_1.0)
1056 .ok_or(Error::InvalidCharacter { character: *hex_ascii_1.0 as _, index: hex_ascii_1.1 })?
1057 << 4 | hex_ascii2digit(hex_ascii_2.0)
1058 .ok_or(Error::InvalidCharacter { character: *hex_ascii_2.0 as _, index: hex_ascii_2.1 })?;
1059
1060 Ok(byte)
1061}
1062
1063fn hex2byte_unchecked(hex_ascii_1: &u8, hex_ascii_2: &u8) -> u8 {
1064 hex_ascii2digit(hex_ascii_1).unwrap() << 4 | hex_ascii2digit(hex_ascii_2).unwrap()
1065}