sp_core/
const_hex2array.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Provides a const function for converting a hex string to a `u8` array at compile time, when used
19//! in the proper context.
20
21/// Provides a const array from given string literal.
22///
23/// Valid characters are `[0-9a-fA-F]`, and the hex string should not start
24/// with the `0x` prefix.
25#[macro_export]
26macro_rules! hex2array {
27	($input:expr) => {{
28		const BYTES: [u8; $input.len() / 2] = $crate::const_hex2array::private_hex2array($input);
29		BYTES
30	}};
31}
32
33/// Generates array from (static) string literal.
34///
35/// Valid characters are `[0-9a-fA-F]`, and the hex string should not start
36/// with the `0x` prefix.
37///
38/// # Panics
39///
40/// The function will panic at compile time when used in a const context if:
41/// - The given hex string has an invalid length.
42/// - It contains invalid characters.
43///
44/// The function will panic at runtime when used in a non-const context if the above conditions are
45/// met.
46#[doc(hidden)]
47pub const fn private_hex2array<const N: usize>(hex: &str) -> [u8; N] {
48	const fn c2b(c: u8) -> u8 {
49		match c as char {
50			'0'..='9' => c - b'0',
51			'a'..='f' => c - (b'a' - 10),
52			'A'..='F' => c - (b'A' - 10),
53			_ => panic!("hex string contains invalid character"),
54		}
55	}
56	let mut output = [0; N];
57	let mut i = 0;
58	if hex.len() != 2 * N {
59		panic!("hex string length is not valid");
60	}
61	while i < N {
62		output[i] = 16 * c2b(hex.as_bytes()[2 * i]) + c2b(hex.as_bytes()[2 * i + 1]);
63		i += 1;
64	}
65	output
66}
67
68#[cfg(test)]
69mod testh2b {
70	use super::private_hex2array;
71
72	#[test]
73	fn t00() {
74		const T0: [u8; 0] = private_hex2array("");
75		const EMPTY: [u8; 0] = [];
76		assert_eq!(T0, EMPTY);
77	}
78
79	macro_rules! test_byte {
80		($a:expr, $b:expr) => {{
81			const X: [u8; 1] = private_hex2array($a);
82			assert_eq!(X, [$b]);
83		}};
84	}
85
86	#[test]
87	fn t01() {
88		test_byte!("00", 0);
89		test_byte!("01", 1);
90		test_byte!("02", 2);
91		test_byte!("03", 3);
92		test_byte!("04", 4);
93		test_byte!("05", 5);
94		test_byte!("06", 6);
95		test_byte!("07", 7);
96		test_byte!("08", 8);
97		test_byte!("09", 9);
98		test_byte!("0a", 10);
99		test_byte!("0A", 10);
100		test_byte!("0b", 11);
101		test_byte!("0B", 11);
102		test_byte!("0c", 12);
103		test_byte!("0C", 12);
104		test_byte!("0d", 13);
105		test_byte!("0D", 13);
106		test_byte!("0e", 14);
107		test_byte!("0E", 14);
108		test_byte!("0f", 15);
109		test_byte!("0F", 15);
110	}
111
112	#[test]
113	fn t02() {
114		const T0: [u8; 2] = private_hex2array("0a10");
115		assert_eq!(T0, [10, 16]);
116		const T1: [u8; 2] = private_hex2array("4545");
117		assert_eq!(T1, [69, 69]);
118	}
119
120	#[test]
121	fn t02m() {
122		assert_eq!(hex2array!("0a10"), [10, 16]);
123		assert_eq!(hex2array!("4545"), [69, 69]);
124		assert_eq!(
125			hex2array!("000102030405060708090a0b0c0d0e0f"),
126			[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
127		);
128	}
129
130	#[test]
131	fn t16() {
132		const T16: [u8; 16] = private_hex2array("000102030405060708090a0b0c0d0e0f");
133
134		assert_eq!(T16, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
135	}
136
137	#[test]
138	fn t33() {
139		const T33: [u8; 33] =
140			private_hex2array("9c8af77d3a4e3f6f076853922985b9e6724fc9675329087f47aff1ceaaae772180");
141
142		assert_eq!(
143			T33,
144			[
145				156, 138, 247, 125, 58, 78, 63, 111, 7, 104, 83, 146, 41, 133, 185, 230, 114, 79,
146				201, 103, 83, 41, 8, 127, 71, 175, 241, 206, 170, 174, 119, 33, 128
147			]
148		);
149	}
150
151	#[test]
152	#[should_panic = "hex string length is not valid"]
153	fn t_panic_incorrect_length2() {
154		let _ = private_hex2array::<2>("454");
155	}
156
157	#[test]
158	#[should_panic = "hex string contains invalid character"]
159	fn t_panic_invalid_character() {
160		let _ = private_hex2array::<2>("45ag");
161	}
162}