cuprate_hex/
array.rs

1//! Hexadecimal serde wrappers for arrays.
2//!
3//! This module provides transparent wrapper types for
4//! arrays that (de)serialize from hexadecimal input/output.
5
6use std::{
7    borrow::Borrow,
8    ops::{Deref, DerefMut},
9};
10
11use hex::{FromHex, FromHexError};
12use serde::{Deserialize, Deserializer, Serialize};
13
14/// Wrapper type for a byte array that (de)serializes from/to hexadecimal strings.
15///
16/// ```rust
17/// # use cuprate_hex::Hex;
18/// let hash = [1; 32];
19/// let hex_bytes = Hex::<32>(hash);
20/// let expected_json = r#""0101010101010101010101010101010101010101010101010101010101010101""#;
21///
22/// let to_string = serde_json::to_string(&hex_bytes).unwrap();
23/// assert_eq!(to_string, expected_json);
24///
25/// let from_str = serde_json::from_str::<Hex<32>>(expected_json).unwrap();
26/// assert_eq!(hex_bytes, from_str);
27///
28/// //------
29///
30/// let vec = vec![hex_bytes; 2];
31/// let expected_json = r#"["0101010101010101010101010101010101010101010101010101010101010101","0101010101010101010101010101010101010101010101010101010101010101"]"#;
32///
33/// let to_string = serde_json::to_string(&vec).unwrap();
34/// assert_eq!(to_string, expected_json);
35///
36/// let from_str = serde_json::from_str::<Vec<Hex<32>>>(expected_json).unwrap();
37/// assert_eq!(vec, from_str);
38/// ```
39///
40/// # Deserialization
41/// This struct has a custom deserialization that only applies to certain
42/// `N` lengths because [`FromHex`] does not implement for a generic `N`:
43/// <https://docs.rs/hex/0.4.3/src/hex/lib.rs.html#220-230>
44#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
45#[serde(transparent)]
46#[repr(transparent)]
47pub struct Hex<const N: usize>(#[serde(with = "hex::serde")] pub [u8; N]);
48
49impl<const N: usize> Hex<N> {
50    /// Returns `true` if the inner array is zeroed.
51    ///
52    /// ```rust
53    /// # use cuprate_hex::Hex;
54    /// assert!(Hex([0; 32]).is_zeroed());
55    /// assert!(!Hex([1; 32]).is_zeroed());
56    /// ```
57    pub fn is_zeroed(&self) -> bool {
58        *self == Self([0; N])
59    }
60}
61
62impl<'de, const N: usize> Deserialize<'de> for Hex<N>
63where
64    [u8; N]: FromHex,
65    <[u8; N] as FromHex>::Error: std::fmt::Display,
66{
67    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
68    where
69        D: Deserializer<'de>,
70    {
71        Ok(Self(hex::serde::deserialize(deserializer)?))
72    }
73}
74
75// Default is not implemented for arrays >32, so we must do it manually.
76impl<const N: usize> Default for Hex<N> {
77    fn default() -> Self {
78        Self([0; N])
79    }
80}
81
82impl<const N: usize> Deref for Hex<N> {
83    type Target = [u8; N];
84    fn deref(&self) -> &Self::Target {
85        &self.0
86    }
87}
88
89impl<const N: usize> DerefMut for Hex<N> {
90    fn deref_mut(&mut self) -> &mut Self::Target {
91        &mut self.0
92    }
93}
94
95impl<const N: usize> Borrow<[u8; N]> for Hex<N> {
96    fn borrow(&self) -> &[u8; N] {
97        &self.0
98    }
99}
100
101impl<const N: usize> AsRef<[u8; N]> for Hex<N> {
102    fn as_ref(&self) -> &[u8; N] {
103        &self.0
104    }
105}
106
107impl<const N: usize> From<Hex<N>> for [u8; N] {
108    fn from(hex: Hex<N>) -> Self {
109        hex.0
110    }
111}
112
113impl<const N: usize> From<[u8; N]> for Hex<N> {
114    fn from(value: [u8; N]) -> Self {
115        Self(value)
116    }
117}
118
119impl<const N: usize> TryFrom<String> for Hex<N> {
120    type Error = FromHexError;
121    fn try_from(value: String) -> Result<Self, Self::Error> {
122        let vec = hex::decode(value)?;
123        match <[u8; N]>::try_from(vec) {
124            Ok(s) => Ok(Self(s)),
125            Err(_) => Err(FromHexError::InvalidStringLength),
126        }
127    }
128}
129
130impl<const N: usize> TryFrom<&str> for Hex<N> {
131    type Error = FromHexError;
132    fn try_from(value: &str) -> Result<Self, Self::Error> {
133        let mut bytes = [0; N];
134        hex::decode_to_slice(value, &mut bytes).map(|()| Self(bytes))
135    }
136}
137
138#[cfg(test)]
139mod test {
140    use super::*;
141
142    #[test]
143    fn asdf() {
144        let hash = [0; 32];
145        let hex_bytes = Hex::<32>(hash);
146        let expected_json = r#""0000000000000000000000000000000000000000000000000000000000000000""#;
147
148        let to_string = serde_json::to_string(&hex_bytes).unwrap();
149        assert_eq!(to_string, expected_json);
150
151        let from_str = serde_json::from_str::<Hex<32>>(expected_json).unwrap();
152        assert_eq!(hex_bytes, from_str);
153    }
154}