der/asn1/
utf8_string.rs

1//! ASN.1 `UTF8String` support.
2
3use crate::{
4    asn1::Any, ByteSlice, DecodeValue, Decoder, EncodeValue, Encoder, Error, FixedTag, Length,
5    OrdIsValueOrd, Result, StrSlice, Tag,
6};
7use core::{fmt, str};
8
9#[cfg(feature = "alloc")]
10use alloc::{borrow::ToOwned, string::String};
11
12/// ASN.1 `UTF8String` type.
13///
14/// Supports the full UTF-8 encoding.
15///
16/// Note that the [`Decodable`][`crate::Decodable`] and
17/// [`Encodable`][`crate::Encodable`] traits are impl'd for Rust's
18/// [`str`][`prim@str`] primitive, which decodes/encodes as a [`Utf8String`].
19///
20/// You are free to use [`str`][`prim@str`] instead of this type, however it's
21/// still provided for explicitness in cases where it might be ambiguous with
22/// other ASN.1 string encodings such as
23/// [`PrintableString`][`crate::asn1::PrintableString`].
24#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
25pub struct Utf8String<'a> {
26    /// Inner value
27    inner: StrSlice<'a>,
28}
29
30impl<'a> Utf8String<'a> {
31    /// Create a new ASN.1 `UTF8String`.
32    pub fn new<T>(input: &'a T) -> Result<Self>
33    where
34        T: AsRef<[u8]> + ?Sized,
35    {
36        StrSlice::from_bytes(input.as_ref()).map(|inner| Self { inner })
37    }
38
39    /// Borrow the string as a `str`.
40    pub fn as_str(&self) -> &'a str {
41        self.inner.as_str()
42    }
43
44    /// Borrow the string as bytes.
45    pub fn as_bytes(&self) -> &'a [u8] {
46        self.inner.as_bytes()
47    }
48
49    /// Get the length of the inner byte slice.
50    pub fn len(&self) -> Length {
51        self.inner.len()
52    }
53
54    /// Is the inner string empty?
55    pub fn is_empty(&self) -> bool {
56        self.inner.is_empty()
57    }
58}
59
60impl AsRef<str> for Utf8String<'_> {
61    fn as_ref(&self) -> &str {
62        self.as_str()
63    }
64}
65
66impl AsRef<[u8]> for Utf8String<'_> {
67    fn as_ref(&self) -> &[u8] {
68        self.as_bytes()
69    }
70}
71
72impl<'a> DecodeValue<'a> for Utf8String<'a> {
73    fn decode_value(decoder: &mut Decoder<'a>, length: Length) -> Result<Self> {
74        Self::new(ByteSlice::decode_value(decoder, length)?.as_bytes())
75    }
76}
77
78impl EncodeValue for Utf8String<'_> {
79    fn value_len(&self) -> Result<Length> {
80        self.inner.value_len()
81    }
82
83    fn encode_value(&self, encoder: &mut Encoder<'_>) -> Result<()> {
84        self.inner.encode_value(encoder)
85    }
86}
87
88impl FixedTag for Utf8String<'_> {
89    const TAG: Tag = Tag::Utf8String;
90}
91
92impl OrdIsValueOrd for Utf8String<'_> {}
93
94impl<'a> From<&Utf8String<'a>> for Utf8String<'a> {
95    fn from(value: &Utf8String<'a>) -> Utf8String<'a> {
96        *value
97    }
98}
99
100impl<'a> TryFrom<Any<'a>> for Utf8String<'a> {
101    type Error = Error;
102
103    fn try_from(any: Any<'a>) -> Result<Utf8String<'a>> {
104        any.decode_into()
105    }
106}
107
108impl<'a> From<Utf8String<'a>> for Any<'a> {
109    fn from(printable_string: Utf8String<'a>) -> Any<'a> {
110        Any::from_tag_and_value(Tag::Utf8String, printable_string.inner.into())
111    }
112}
113
114impl<'a> From<Utf8String<'a>> for &'a [u8] {
115    fn from(utf8_string: Utf8String<'a>) -> &'a [u8] {
116        utf8_string.as_bytes()
117    }
118}
119
120impl<'a> fmt::Display for Utf8String<'a> {
121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122        f.write_str(self.as_str())
123    }
124}
125
126impl<'a> fmt::Debug for Utf8String<'a> {
127    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128        write!(f, "Utf8String({:?})", self.as_str())
129    }
130}
131
132impl<'a> TryFrom<Any<'a>> for &'a str {
133    type Error = Error;
134
135    fn try_from(any: Any<'a>) -> Result<&'a str> {
136        Utf8String::try_from(any).map(|s| s.as_str())
137    }
138}
139
140impl EncodeValue for str {
141    fn value_len(&self) -> Result<Length> {
142        Utf8String::new(self)?.value_len()
143    }
144
145    fn encode_value(&self, encoder: &mut Encoder<'_>) -> Result<()> {
146        Utf8String::new(self)?.encode_value(encoder)
147    }
148}
149
150impl FixedTag for str {
151    const TAG: Tag = Tag::Utf8String;
152}
153
154impl OrdIsValueOrd for str {}
155
156#[cfg(feature = "alloc")]
157#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
158impl<'a> From<Utf8String<'a>> for String {
159    fn from(s: Utf8String<'a>) -> String {
160        s.as_str().to_owned()
161    }
162}
163
164#[cfg(feature = "alloc")]
165#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
166impl<'a> TryFrom<Any<'a>> for String {
167    type Error = Error;
168
169    fn try_from(any: Any<'a>) -> Result<String> {
170        Utf8String::try_from(any).map(|s| s.as_str().to_owned())
171    }
172}
173
174#[cfg(feature = "alloc")]
175#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
176impl EncodeValue for String {
177    fn value_len(&self) -> Result<Length> {
178        Utf8String::new(self)?.value_len()
179    }
180
181    fn encode_value(&self, encoder: &mut Encoder<'_>) -> Result<()> {
182        Utf8String::new(self)?.encode_value(encoder)
183    }
184}
185
186#[cfg(feature = "alloc")]
187#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
188impl FixedTag for String {
189    const TAG: Tag = Tag::Utf8String;
190}
191
192#[cfg(feature = "alloc")]
193#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
194impl OrdIsValueOrd for String {}
195
196#[cfg(test)]
197mod tests {
198    use super::Utf8String;
199    use crate::Decodable;
200
201    #[test]
202    fn parse_ascii_bytes() {
203        let example_bytes = &[
204            0x0c, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31,
205        ];
206
207        let utf8_string = Utf8String::from_der(example_bytes).unwrap();
208        assert_eq!(utf8_string.as_str(), "Test User 1");
209    }
210
211    #[test]
212    fn parse_utf8_bytes() {
213        let example_bytes = &[0x0c, 0x06, 0x48, 0x65, 0x6c, 0x6c, 0xc3, 0xb3];
214        let utf8_string = Utf8String::from_der(example_bytes).unwrap();
215        assert_eq!(utf8_string.as_str(), "Helló");
216    }
217}