1use core::{convert::Infallible, fmt::Debug, str::FromStr};
2
3use crate::{
4 DEFAULT_ASCII_ONLY, DEFAULT_MAX, DEFAULT_MIN, GString, GStringError, NoValidation, Validator,
5};
6
7#[derive(Clone, PartialEq, Eq)]
19pub struct GSecret<
20 V: Validator = NoValidation,
21 const MIN: usize = DEFAULT_MIN,
22 const MAX: usize = DEFAULT_MAX,
23 const ASCII_ONLY: bool = DEFAULT_ASCII_ONLY,
24> {
25 inner: GString<V, MIN, MAX, ASCII_ONLY>,
26}
27
28impl GSecret {
29 #[inline]
31 pub fn try_default<S>(secret: S) -> Result<Self, GStringError<Infallible>>
32 where
33 S: AsRef<str>,
34 {
35 Ok(Self {
36 inner: GString::try_default(secret)?,
37 })
38 }
39}
40
41impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
42 GSecret<V, MIN, MAX, ASCII_ONLY>
43{
44 #[inline]
46 pub fn try_new<S>(secret: S) -> Result<Self, GStringError<V::Err>>
47 where
48 S: AsRef<str>,
49 {
50 Ok(Self {
51 inner: GString::<V, MIN, MAX, ASCII_ONLY>::try_new(secret)?,
52 })
53 }
54
55 pub fn reveal<R>(&self, func: impl FnOnce(&str) -> R) -> R {
65 func(self.inner.as_str())
66 }
67
68 #[inline]
72 pub fn zeroize(&mut self) {
73 self.inner.zeroize();
74 }
75}
76
77impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> Drop
78 for GSecret<V, MIN, MAX, ASCII_ONLY>
79{
80 fn drop(&mut self) {
81 self.inner.zeroize();
82 }
83}
84
85impl<V, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> zeroize::Zeroize
86 for GSecret<V, MIN, MAX, ASCII_ONLY>
87where
88 V: Validator,
89{
90 #[inline]
91 fn zeroize(&mut self) {
92 self.inner.zeroize();
93 }
94}
95
96impl<V, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> zeroize::ZeroizeOnDrop
97 for GSecret<V, MIN, MAX, ASCII_ONLY>
98where
99 V: Validator,
100{
101}
102
103impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> Debug
104 for GSecret<V, MIN, MAX, ASCII_ONLY>
105{
106 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
107 write!(f, "GSecret(<REDACTED>)")
108 }
109}
110
111impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> FromStr
112 for GSecret<V, MIN, MAX, ASCII_ONLY>
113{
114 type Err = GStringError<V::Err>;
115
116 fn from_str(s: &str) -> Result<Self, Self::Err> {
117 let secret = GSecret::try_new(s)?;
118
119 Ok(secret)
120 }
121}
122
123impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> TryFrom<&str>
124 for GSecret<V, MIN, MAX, ASCII_ONLY>
125{
126 type Error = GStringError<V::Err>;
127
128 fn try_from(value: &str) -> Result<Self, Self::Error> {
129 let secret = GSecret::try_new(value)?;
130
131 Ok(secret)
132 }
133}
134
135#[cfg(feature = "alloc")]
136extern crate alloc;
137
138#[cfg(feature = "alloc")]
139use alloc::string::String;
140
141#[cfg(feature = "alloc")]
142impl<V, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> TryFrom<String>
143 for GSecret<V, MIN, MAX, ASCII_ONLY>
144where
145 V: Validator,
146{
147 type Error = GStringError<V::Err>;
148
149 fn try_from(mut value: String) -> Result<Self, Self::Error> {
150 use zeroize::Zeroize;
151
152 let secret = GSecret::try_new(&value);
153
154 value.zeroize();
155
156 secret
157 }
158}
159
160impl<
161 GSTRINGV: Validator,
162 GSECRETV: Validator,
163 const MIN: usize,
164 const MAX: usize,
165 const ASCII_ONLY: bool,
166> TryFrom<GString<GSTRINGV, MIN, MAX, ASCII_ONLY>> for GSecret<GSECRETV, MIN, MAX, ASCII_ONLY>
167{
168 type Error = GStringError<GSECRETV::Err>;
169
170 fn try_from(value: GString<GSTRINGV, MIN, MAX, ASCII_ONLY>) -> Result<Self, Self::Error> {
171 Self::try_new(value.as_str())
172 }
173}
174
175impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> core::hash::Hash
176 for GSecret<V, MIN, MAX, ASCII_ONLY>
177{
178 #[inline]
179 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
180 self.inner.hash(state)
181 }
182}