secure_gate/encoding/extensions/
hex.rs

1use ::hex as hex_crate;
2
3// ========================================
4// Consuming (into_) methods on RNG types
5// ========================================
6
7#[cfg(feature = "rand")]
8impl crate::DynamicRandom {
9    /// Consume self and return the random bytes as a validated hex string.
10    ///
11    /// The raw bytes are zeroized immediately after encoding.
12    pub fn into_hex(self) -> crate::encoding::hex::HexString {
13        let hex_str = hex_crate::encode(self.expose_secret());
14        crate::encoding::hex::HexString::new_unchecked(hex_str)
15    }
16}
17
18#[cfg(feature = "rand")]
19impl<const N: usize> crate::FixedRandom<N> {
20    /// Consume self and return the random bytes as a validated hex string.
21    ///
22    /// The raw bytes are zeroized immediately after encoding.
23    pub fn into_hex(self) -> crate::encoding::hex::HexString {
24        let hex_str = hex_crate::encode(self.expose_secret());
25        crate::encoding::hex::HexString::new_unchecked(hex_str)
26    }
27}
28
29// ========================================
30// Borrowing (to_) methods on RNG types
31// ========================================
32
33#[cfg(feature = "rand")]
34impl<const N: usize> crate::FixedRandom<N> {
35    /// Borrow and encode the random bytes as a validated lowercase hex string (allocates).
36    ///
37    /// The original secret remains intact and usable.
38    pub fn to_hex(&self) -> crate::encoding::hex::HexString {
39        let hex_str = hex_crate::encode(self.expose_secret());
40        crate::encoding::hex::HexString::new_unchecked(hex_str)
41    }
42}
43
44#[cfg(feature = "rand")]
45impl crate::DynamicRandom {
46    /// Borrow and encode the random bytes as a validated lowercase hex string (allocates).
47    ///
48    /// The original secret remains intact and usable.
49    pub fn to_hex(&self) -> crate::encoding::hex::HexString {
50        let hex_str = hex_crate::encode(self.expose_secret());
51        crate::encoding::hex::HexString::new_unchecked(hex_str)
52    }
53}
54
55// ========================================
56// View types and their implementations
57// ========================================
58
59/// View struct for exposed hex strings, allowing decoding without direct access.
60pub struct HexStringView<'a>(pub(crate) &'a String);
61
62impl<'a> HexStringView<'a> {
63    /// Decode the validated hex string into raw bytes (allocates).
64    pub fn to_bytes(&self) -> Vec<u8> {
65        hex_crate::decode(self.0.as_str()).expect("HexString is always valid")
66    }
67}
68
69impl<'a> core::ops::Deref for HexStringView<'a> {
70    type Target = str;
71    fn deref(&self) -> &Self::Target {
72        self.0.as_str()
73    }
74}
75
76impl<'a> core::fmt::Debug for HexStringView<'a> {
77    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
78        f.write_str("[REDACTED]")
79    }
80}
81
82impl<'a> core::fmt::Display for HexStringView<'a> {
83    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
84        f.write_str(self.0)
85    }
86}
87
88impl<'a> core::cmp::PartialEq<&str> for HexStringView<'a> {
89    fn eq(&self, other: &&str) -> bool {
90        self.0 == *other
91    }
92}
93
94// ========================================
95// expose_secret → view implementations
96// ========================================
97
98impl crate::encoding::hex::HexString {
99    pub fn expose_secret(&self) -> HexStringView<'_> {
100        HexStringView(self.0.expose_secret())
101    }
102}
103
104// ========================================
105// Consuming decode (into_bytes) for secure zeroization
106// ========================================
107
108impl crate::encoding::hex::HexString {
109    /// Decode the validated hex string into raw bytes, consuming and zeroizing the wrapper.
110    pub fn into_bytes(self) -> Vec<u8> {
111        hex_crate::decode(self.expose_secret().0.as_str()).expect("HexString is always valid")
112    }
113}