Skip to main content

workflow_core/
hex.rs

1//! Hex serialization traits
2
3use serde::{Deserialize, Deserializer, Serializer};
4use std::str;
5
6/// Trait for types that can render themselves as a hexadecimal string.
7pub trait ToHex {
8    /// Returns the hexadecimal string representation of `self`.
9    fn to_hex(&self) -> String;
10}
11
12/// `serde` serialize helper that encodes a [`ToHex`] value as a hex string.
13pub fn serialize<S, T>(this: T, serializer: S) -> Result<S::Ok, S::Error>
14where
15    S: Serializer,
16    T: ToHex,
17{
18    let hex = this.to_hex();
19    serializer.serialize_str(&hex)
20}
21
22/// Trait for types that can be parsed from a hexadecimal string.
23pub trait FromHex: Sized {
24    /// Error type returned when hex decoding fails.
25    type Error: std::fmt::Display;
26    /// Parses `hex_str` into `Self`, returning an error on invalid hex input.
27    fn from_hex(hex_str: &str) -> Result<Self, Self::Error>;
28}
29
30/// `serde` deserialize helper that decodes a hex string into a [`FromHex`] value.
31pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
32where
33    D: Deserializer<'de>,
34    T: FromHex,
35{
36    use serde::de::Error;
37    let buff: &[u8] = Deserialize::deserialize(deserializer)?;
38    T::from_hex(str::from_utf8(buff).unwrap()).map_err(D::Error::custom)
39}
40
41/// Little endian format of full slice content
42/// (so string lengths are always even).
43impl ToHex for &[u8] {
44    fn to_hex(&self) -> String {
45        // an empty vector is allowed
46        if self.is_empty() {
47            return "".to_string();
48        }
49
50        let mut hex = vec![0u8; self.len() * 2];
51        faster_hex::hex_encode(self, hex.as_mut_slice())
52            .expect("The output is exactly twice the size of the input");
53        let result = unsafe { str::from_utf8_unchecked(&hex) };
54        result.to_string()
55    }
56}
57
58/// Little endian format of full content
59/// (so string lengths are always even).
60impl ToHex for Vec<u8> {
61    fn to_hex(&self) -> String {
62        (&**self).to_hex()
63    }
64}
65
66/// Little endian format of full content
67/// (so string lengths must be even).
68impl FromHex for Vec<u8> {
69    type Error = faster_hex::Error;
70    fn from_hex(hex_str: &str) -> Result<Self, Self::Error> {
71        // an empty string is allowed
72        if hex_str.is_empty() {
73            return Ok(vec![]);
74        }
75
76        let mut bytes = vec![0u8; hex_str.len() / 2];
77        faster_hex::hex_decode(hex_str.as_bytes(), bytes.as_mut_slice())?;
78        Ok(bytes)
79    }
80}