1use crate::{
4 EncodeValue, Error, FixedTag, Length, Result, StringRef, Tag, Writer, asn1::AnyRef,
5 ord::OrdIsValueOrd,
6};
7use core::{fmt, ops::Deref, str};
8
9#[cfg(feature = "alloc")]
10use {
11 crate::{DecodeValue, Header, Reader},
12 alloc::{borrow::ToOwned, string::String},
13};
14
15#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
30pub struct Utf8StringRef<'a> {
31 inner: &'a StringRef,
33}
34
35impl<'a> Utf8StringRef<'a> {
36 pub fn new<T>(input: &'a T) -> Result<Self>
41 where
42 T: AsRef<[u8]> + ?Sized,
43 {
44 StringRef::from_bytes(input.as_ref()).map(|inner| Self { inner })
45 }
46
47 #[must_use]
49 pub fn as_str(&self) -> &'a str {
50 self.inner.as_str()
51 }
52}
53
54impl_string_type!(Utf8StringRef<'a>, 'a);
55
56impl<'a> Deref for Utf8StringRef<'a> {
57 type Target = StringRef;
58
59 fn deref(&self) -> &Self::Target {
60 self.inner
61 }
62}
63
64impl FixedTag for Utf8StringRef<'_> {
65 const TAG: Tag = Tag::Utf8String;
66}
67
68impl<'a> From<&Utf8StringRef<'a>> for Utf8StringRef<'a> {
69 fn from(value: &Utf8StringRef<'a>) -> Utf8StringRef<'a> {
70 *value
71 }
72}
73
74impl<'a> From<Utf8StringRef<'a>> for AnyRef<'a> {
75 fn from(utf_string: Utf8StringRef<'a>) -> AnyRef<'a> {
76 AnyRef::from_tag_and_value(Tag::Utf8String, utf_string.inner.as_ref())
77 }
78}
79
80impl<'a> TryFrom<&'a str> for Utf8StringRef<'a> {
81 type Error = Error;
82
83 fn try_from(s: &'a str) -> Result<Self> {
84 Self::new(s)
85 }
86}
87
88impl fmt::Debug for Utf8StringRef<'_> {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 write!(f, "Utf8String({:?})", self.as_str())
91 }
92}
93
94impl<'a> TryFrom<AnyRef<'a>> for &'a str {
95 type Error = Error;
96
97 fn try_from(any: AnyRef<'a>) -> Result<&'a str> {
98 Utf8StringRef::try_from(any).map(|s| s.as_str())
99 }
100}
101
102impl EncodeValue for str {
103 fn value_len(&self) -> Result<Length> {
104 Utf8StringRef::new(self)?.value_len()
105 }
106
107 fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
108 Utf8StringRef::new(self)?.encode_value(writer)
109 }
110}
111
112impl FixedTag for str {
113 const TAG: Tag = Tag::Utf8String;
114}
115
116impl OrdIsValueOrd for str {}
117
118#[cfg(feature = "alloc")]
119impl<'a> From<Utf8StringRef<'a>> for String {
120 fn from(s: Utf8StringRef<'a>) -> String {
121 s.as_str().to_owned()
122 }
123}
124
125#[cfg(feature = "alloc")]
126impl<'a> TryFrom<AnyRef<'a>> for String {
127 type Error = Error;
128
129 fn try_from(any: AnyRef<'a>) -> Result<String> {
130 Utf8StringRef::try_from(any).map(|s| s.as_str().to_owned())
131 }
132}
133
134#[cfg(feature = "alloc")]
135impl<'a> TryFrom<&'a String> for Utf8StringRef<'a> {
136 type Error = Error;
137
138 fn try_from(s: &'a String) -> Result<Self> {
139 Self::new(s.as_str())
140 }
141}
142
143#[cfg(feature = "alloc")]
144impl<'a> DecodeValue<'a> for String {
145 type Error = Error;
146
147 fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
148 Ok(String::from_utf8(reader.read_vec(header.length())?)?)
149 }
150}
151
152#[cfg(feature = "alloc")]
153impl EncodeValue for String {
154 fn value_len(&self) -> Result<Length> {
155 Utf8StringRef::new(self)?.value_len()
156 }
157
158 fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
159 Utf8StringRef::new(self)?.encode_value(writer)
160 }
161}
162
163#[cfg(feature = "alloc")]
164impl FixedTag for String {
165 const TAG: Tag = Tag::Utf8String;
166}
167
168#[cfg(feature = "alloc")]
169impl OrdIsValueOrd for String {}
170
171#[cfg(test)]
172#[allow(clippy::unwrap_used)]
173mod tests {
174 use super::Utf8StringRef;
175 use crate::Decode;
176
177 #[test]
178 fn parse_ascii_bytes() {
179 let example_bytes = &[
180 0x0c, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31,
181 ];
182
183 let utf8_string = Utf8StringRef::from_der(example_bytes).unwrap();
184 assert_eq!(utf8_string.as_str(), "Test User 1");
185 }
186
187 #[test]
188 fn parse_utf8_bytes() {
189 let example_bytes = &[0x0c, 0x06, 0x48, 0x65, 0x6c, 0x6c, 0xc3, 0xb3];
190 let utf8_string = Utf8StringRef::from_der(example_bytes).unwrap();
191 assert_eq!(utf8_string.as_str(), "Helló");
192 }
193}