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 fn zeroize(&mut self) {
91 self.inner.zeroize();
92 }
93}
94
95impl<V, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> zeroize::ZeroizeOnDrop
96 for GSecret<V, MIN, MAX, ASCII_ONLY>
97where
98 V: Validator,
99{
100}
101
102impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> Debug
103 for GSecret<V, MIN, MAX, ASCII_ONLY>
104{
105 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
106 write!(f, "GSecret(<REDACTED>)")
107 }
108}
109
110impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> FromStr
111 for GSecret<V, MIN, MAX, ASCII_ONLY>
112{
113 type Err = GStringError<V::Err>;
114
115 fn from_str(s: &str) -> Result<Self, Self::Err> {
116 let secret = GSecret::try_new(s)?;
117
118 Ok(secret)
119 }
120}
121
122impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> TryFrom<&str>
123 for GSecret<V, MIN, MAX, ASCII_ONLY>
124{
125 type Error = GStringError<V::Err>;
126
127 fn try_from(value: &str) -> Result<Self, Self::Error> {
128 let secret = GSecret::try_new(value)?;
129
130 Ok(secret)
131 }
132}
133
134#[cfg(feature = "alloc")]
135extern crate alloc;
136
137#[cfg(feature = "alloc")]
138use alloc::string::String;
139
140#[cfg(feature = "alloc")]
141impl<V, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> TryFrom<String>
142 for GSecret<V, MIN, MAX, ASCII_ONLY>
143where
144 V: Validator,
145{
146 type Error = GStringError<V::Err>;
147
148 fn try_from(mut value: String) -> Result<Self, Self::Error> {
149 use zeroize::Zeroize;
150
151 let secret = GSecret::try_new(&value);
152
153 value.zeroize();
154
155 secret
156 }
157}
158
159impl<
160 GSTRINGV: Validator,
161 GSECRETV: Validator,
162 const MIN: usize,
163 const MAX: usize,
164 const ASCII_ONLY: bool,
165> TryFrom<GString<GSTRINGV, MIN, MAX, ASCII_ONLY>> for GSecret<GSECRETV, MIN, MAX, ASCII_ONLY>
166{
167 type Error = GStringError<GSECRETV::Err>;
168
169 fn try_from(value: GString<GSTRINGV, MIN, MAX, ASCII_ONLY>) -> Result<Self, Self::Error> {
170 Self::try_new(value.as_str())
171 }
172}
173
174impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> core::hash::Hash
175 for GSecret<V, MIN, MAX, ASCII_ONLY>
176{
177 #[inline]
178 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
179 self.inner.hash(state)
180 }
181}