der/asn1/
printable_string.rs1use crate::{FixedTag, Result, StringRef, Tag, asn1::AnyRef};
4use core::{fmt, ops::Deref};
5
6macro_rules! impl_printable_string {
7 ($type: ty) => {
8 impl_printable_string!($type,);
9 };
10 ($type: ty, $($li: lifetime)?) => {
11 impl_string_type!($type, $($li),*);
12
13 impl<$($li),*> FixedTag for $type {
14 const TAG: Tag = Tag::PrintableString;
15 }
16
17 impl<$($li),*> fmt::Debug for $type {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 write!(f, "PrintableString({:?})", self.as_str())
20 }
21 }
22 };
23}
24
25#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
55pub struct PrintableStringRef<'a> {
56 inner: &'a StringRef,
58}
59
60impl<'a> PrintableStringRef<'a> {
61 pub fn new<T>(input: &'a T) -> Result<Self>
66 where
67 T: AsRef<[u8]> + ?Sized,
68 {
69 let input = input.as_ref();
70
71 for &c in input.iter() {
73 match c {
74 b'A'..=b'Z'
75 | b'a'..=b'z'
76 | b'0'..=b'9'
77 | b' '
78 | b'\''
79 | b'('
80 | b')'
81 | b'+'
82 | b','
83 | b'-'
84 | b'.'
85 | b'/'
86 | b':'
87 | b'='
88 | b'?' => (),
89 _ => return Err(Self::TAG.value_error().into()),
90 }
91 }
92
93 StringRef::from_bytes(input)
94 .map(|inner| Self { inner })
95 .map_err(|_| Self::TAG.value_error().into())
96 }
97
98 #[must_use]
100 pub fn as_str(&self) -> &'a str {
101 self.inner.as_str()
102 }
103}
104
105impl_printable_string!(PrintableStringRef<'a>, 'a);
106
107impl<'a> Deref for PrintableStringRef<'a> {
108 type Target = StringRef;
109
110 fn deref(&self) -> &Self::Target {
111 self.inner
112 }
113}
114impl<'a> From<&PrintableStringRef<'a>> for PrintableStringRef<'a> {
115 fn from(value: &PrintableStringRef<'a>) -> PrintableStringRef<'a> {
116 *value
117 }
118}
119
120impl<'a> From<PrintableStringRef<'a>> for AnyRef<'a> {
121 fn from(printable_string: PrintableStringRef<'a>) -> AnyRef<'a> {
122 AnyRef::from_tag_and_value(Tag::PrintableString, printable_string.inner.as_ref())
123 }
124}
125
126#[cfg(feature = "alloc")]
127pub use self::allocation::PrintableString;
128
129#[cfg(feature = "alloc")]
130mod allocation {
131 use super::PrintableStringRef;
132
133 use crate::{
134 BytesRef, Error, FixedTag, Result, StringOwned, Tag,
135 asn1::AnyRef,
136 referenced::{OwnedToRef, RefToOwned},
137 };
138 use alloc::{borrow::ToOwned, string::String};
139 use core::{fmt, ops::Deref};
140
141 #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)]
169 pub struct PrintableString {
170 inner: StringOwned,
172 }
173
174 impl PrintableString {
175 pub fn new<T>(input: &T) -> Result<Self>
180 where
181 T: AsRef<[u8]> + ?Sized,
182 {
183 let input = input.as_ref();
184 PrintableStringRef::new(input)?;
185
186 StringOwned::from_bytes(input)
187 .map(|inner| Self { inner })
188 .map_err(|_| Self::TAG.value_error().into())
189 }
190 }
191
192 impl_printable_string!(PrintableString);
193
194 impl Deref for PrintableString {
195 type Target = StringOwned;
196
197 fn deref(&self) -> &Self::Target {
198 &self.inner
199 }
200 }
201
202 impl<'a> From<PrintableStringRef<'a>> for PrintableString {
203 fn from(value: PrintableStringRef<'a>) -> PrintableString {
204 let inner =
205 StringOwned::from_bytes(value.inner.as_bytes()).expect("Invalid PrintableString");
206 Self { inner }
207 }
208 }
209
210 impl<'a> From<&'a PrintableString> for AnyRef<'a> {
211 fn from(printable_string: &'a PrintableString) -> AnyRef<'a> {
212 AnyRef::from_tag_and_value(
213 Tag::PrintableString,
214 BytesRef::new(printable_string.inner.as_bytes()).expect("Invalid PrintableString"),
215 )
216 }
217 }
218
219 impl<'a> From<&'a PrintableString> for PrintableStringRef<'a> {
220 fn from(printable_string: &'a PrintableString) -> PrintableStringRef<'a> {
221 printable_string.owned_to_ref()
222 }
223 }
224
225 impl<'a> RefToOwned<'a> for PrintableStringRef<'a> {
226 type Owned = PrintableString;
227 fn ref_to_owned(&self) -> Self::Owned {
228 PrintableString {
229 inner: self.inner.to_owned(),
230 }
231 }
232 }
233
234 impl OwnedToRef for PrintableString {
235 type Borrowed<'a> = PrintableStringRef<'a>;
236 fn owned_to_ref(&self) -> Self::Borrowed<'_> {
237 PrintableStringRef {
238 inner: self.inner.as_ref(),
239 }
240 }
241 }
242
243 impl TryFrom<String> for PrintableString {
244 type Error = Error;
245
246 fn try_from(input: String) -> Result<Self> {
247 PrintableStringRef::new(&input)?;
248
249 StringOwned::new(input)
250 .map(|inner| Self { inner })
251 .map_err(|_| Self::TAG.value_error().into())
252 }
253 }
254}
255
256#[cfg(test)]
257#[allow(clippy::unwrap_used)]
258mod tests {
259 use super::PrintableStringRef;
260 use crate::Decode;
261
262 #[test]
263 fn parse_bytes() {
264 let example_bytes = &[
265 0x13, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31,
266 ];
267
268 let printable_string = PrintableStringRef::from_der(example_bytes).unwrap();
269 assert_eq!(printable_string.as_str(), "Test User 1");
270 }
271}