Skip to main content

umya_spreadsheet/helper/
utils.rs

1#![allow(unused_imports)]
2
3use md5::Digest as _;
4
5pub(crate) fn md5_hash(input: impl AsRef<[u8]>) -> String {
6    const HEX: &[u8; 16] = b"0123456789abcdef";
7
8    let digest = md5::Md5::digest(input);
9    let mut output = String::with_capacity(digest.len() * 2);
10    for byte in digest.iter().copied() {
11        output.push(HEX[(byte >> 4) as usize] as char);
12        output.push(HEX[(byte & 0x0f) as usize] as char);
13    }
14    output
15}
16
17pub(crate) fn unescape_xml_text(e: &quick_xml::events::BytesText<'_>) -> String {
18    let decoded = e.decode().unwrap();
19    quick_xml::escape::unescape(decoded.as_ref())
20        .unwrap()
21        .into_owned()
22}
23
24/// A macro that implements the `From` trait for converting from one error type
25/// to another.
26///
27/// # Usage
28/// ```
29/// # use std::{io,fmt};
30///
31/// use umya_spreadsheet::from_err;
32///
33/// #[derive(Debug)]
34/// enum MyError {
35///     Io(std::io::Error),
36/// };
37/// # impl fmt::Display for MyError {
38/// #   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39/// #       unimplemented!()
40/// #   }
41/// # }
42/// # impl std::error::Error for MyError {}
43///
44/// from_err!(std::io::Error, MyError, Io);
45///
46/// let io_err = io::Error::new(io::ErrorKind::Other, "An I/O error occurred");
47/// let my_err: MyError = io_err.into();
48/// ```
49#[macro_export]
50macro_rules! from_err {
51    ($from:ty, $to:tt, $var:tt) => {
52        impl From<$from> for $to {
53            #[inline]
54            fn from(e: $from) -> $to {
55                $to::$var(e)
56            }
57        }
58    };
59}
60
61/// Asserts that the SHA-256 hash of a given input matches the expected
62/// hexadecimal string.
63///
64/// # Arguments
65///
66/// * `$input` - The input data to hash.
67/// * `$expected_hex` - The expected SHA-256 hash as a hexadecimal string.
68///
69/// # Panics
70///
71/// This macro will panic if the actual SHA-256 hash does not match the
72/// expected hash.
73///
74/// # Examples
75///
76/// ```ignore
77/// let data = b"Hello, world!";
78/// assert_sha256!(
79///     data,
80///     "a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e"
81/// );
82/// // This will not panic
83///
84/// assert_sha256!(data, "invalid_hash");
85/// // This will panic with a message indicating the mismatch
86/// ```
87macro_rules! assert_sha256 {
88    ($input:expr, $expected_hex:expr) => {{
89        let hash = Sha256::digest($input).to_vec();
90        let expected_bytes = hex_literal::hex!($expected_hex);
91        assert_eq!(
92            &hash,
93            &expected_bytes,
94            "SHA256({}) mismatch! Expected: {:?}, Actual: {:?}",
95            stringify!($input),
96            &expected_bytes
97                .iter()
98                .map(|b| format!("{:02x}", b))
99                .collect::<String>(),
100            &hash
101                .iter()
102                .map(|b| format!("{:02x}", b))
103                .collect::<String>()
104        );
105    }};
106}
107
108/// A macro that compiles a regular expression and caches it.
109///
110/// # Usage
111/// ```rust,ignore
112/// // Unable to run because function is private
113/// let re = compile_regex!(r"^\d+$");
114///
115/// assert!(re.is_match("123").unwrap());
116/// assert!(!re.is_match("abc").unwrap());
117/// ```
118macro_rules! compile_regex {
119    ($re:literal $(,)?) => {{
120        static RE: std::sync::OnceLock<fancy_regex::Regex> = std::sync::OnceLock::new();
121        RE.get_or_init(|| fancy_regex::Regex::new($re).unwrap())
122    }};
123}
124
125/// Prints a byte slice as a hex string, prefixed with the variable name.
126///
127/// This macro takes a reference to a byte slice (`&[u8]`) and prints both
128/// the variable name and its hexadecimal representation to stdout.
129macro_rules! print_hex {
130    ($var:expr) => {
131        println!(
132            "{} = {}",
133            stringify!($var),
134            $var.iter()
135                .map(|b| format!("{:02x}", b))
136                .collect::<String>()
137        );
138    };
139}
140
141/// Prints the SHA-256 hash of a given input as a hexadecimal string.
142///
143/// # Examples
144///
145/// ```ignore
146/// let data = b"Hello, world!";
147/// print_sha256_hex!(data);
148/// // Output: SHA256(data) = 5eb63bbbe01eeed093cb22bb8f5acdc3
149/// ```
150macro_rules! print_sha256_hex {
151    ($var:expr) => {
152        let hash = Sha256::digest($var);
153        println!(
154            "SHA256({}) = {}",
155            stringify!($var),
156            hash.iter()
157                .map(|b| format!("{:02x}", b))
158                .collect::<String>()
159        );
160    };
161}
162
163pub(crate) use assert_sha256;
164pub(crate) use compile_regex;
165pub(crate) use print_hex;
166pub(crate) use print_sha256_hex;