1 //! ASN.1 `UTF8String` support.
2 
3 use crate::{
4     asn1::AnyRef, ord::OrdIsValueOrd, EncodeValue, Error, FixedTag, Length, Result, StrRef, Tag,
5     Writer,
6 };
7 use core::{fmt, ops::Deref, str};
8 
9 #[cfg(feature = "alloc")]
10 use {
11     crate::{DecodeValue, Header, Reader},
12     alloc::{borrow::ToOwned, string::String},
13 };
14 
15 /// ASN.1 `UTF8String` type.
16 ///
17 /// Supports the full UTF-8 encoding.
18 ///
19 /// Note that the [`Decode`][`crate::Decode`] and [`Encode`][`crate::Encode`]
20 /// traits are impl'd for Rust's [`str`][`prim@str`] primitive, which
21 /// decodes/encodes as a [`Utf8StringRef`].
22 ///
23 /// You are free to use [`str`][`prim@str`] instead of this type, however it's
24 /// still provided for explicitness in cases where it might be ambiguous with
25 /// other ASN.1 string encodings such as
26 /// [`PrintableStringRef`][`crate::asn1::PrintableStringRef`].
27 ///
28 /// This is a zero-copy reference type which borrows from the input data.
29 #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
30 pub struct Utf8StringRef<'a> {
31     /// Inner value
32     inner: StrRef<'a>,
33 }
34 
35 impl<'a> Utf8StringRef<'a> {
36     /// Create a new ASN.1 `UTF8String`.
new<T>(input: &'a T) -> Result<Self> where T: AsRef<[u8]> + ?Sized,37     pub fn new<T>(input: &'a T) -> Result<Self>
38     where
39         T: AsRef<[u8]> + ?Sized,
40     {
41         StrRef::from_bytes(input.as_ref()).map(|inner| Self { inner })
42     }
43 }
44 
45 impl_string_type!(Utf8StringRef<'a>, 'a);
46 
47 impl<'a> Deref for Utf8StringRef<'a> {
48     type Target = StrRef<'a>;
49 
deref(&self) -> &Self::Target50     fn deref(&self) -> &Self::Target {
51         &self.inner
52     }
53 }
54 
55 impl FixedTag for Utf8StringRef<'_> {
56     const TAG: Tag = Tag::Utf8String;
57 }
58 
59 impl<'a> From<&Utf8StringRef<'a>> for Utf8StringRef<'a> {
from(value: &Utf8StringRef<'a>) -> Utf8StringRef<'a>60     fn from(value: &Utf8StringRef<'a>) -> Utf8StringRef<'a> {
61         *value
62     }
63 }
64 
65 impl<'a> From<Utf8StringRef<'a>> for AnyRef<'a> {
from(utf_string: Utf8StringRef<'a>) -> AnyRef<'a>66     fn from(utf_string: Utf8StringRef<'a>) -> AnyRef<'a> {
67         AnyRef::from_tag_and_value(Tag::Utf8String, utf_string.inner.into())
68     }
69 }
70 
71 impl<'a> fmt::Debug for Utf8StringRef<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result72     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73         write!(f, "Utf8String({:?})", self.as_str())
74     }
75 }
76 
77 impl<'a> TryFrom<AnyRef<'a>> for &'a str {
78     type Error = Error;
79 
try_from(any: AnyRef<'a>) -> Result<&'a str>80     fn try_from(any: AnyRef<'a>) -> Result<&'a str> {
81         Utf8StringRef::try_from(any).map(|s| s.as_str())
82     }
83 }
84 
85 impl EncodeValue for str {
value_len(&self) -> Result<Length>86     fn value_len(&self) -> Result<Length> {
87         Utf8StringRef::new(self)?.value_len()
88     }
89 
encode_value(&self, writer: &mut impl Writer) -> Result<()>90     fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
91         Utf8StringRef::new(self)?.encode_value(writer)
92     }
93 }
94 
95 impl FixedTag for str {
96     const TAG: Tag = Tag::Utf8String;
97 }
98 
99 impl OrdIsValueOrd for str {}
100 
101 #[cfg(feature = "alloc")]
102 impl<'a> From<Utf8StringRef<'a>> for String {
from(s: Utf8StringRef<'a>) -> String103     fn from(s: Utf8StringRef<'a>) -> String {
104         s.as_str().to_owned()
105     }
106 }
107 
108 #[cfg(feature = "alloc")]
109 impl<'a> TryFrom<AnyRef<'a>> for String {
110     type Error = Error;
111 
try_from(any: AnyRef<'a>) -> Result<String>112     fn try_from(any: AnyRef<'a>) -> Result<String> {
113         Utf8StringRef::try_from(any).map(|s| s.as_str().to_owned())
114     }
115 }
116 
117 #[cfg(feature = "alloc")]
118 impl<'a> DecodeValue<'a> for String {
decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self>119     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
120         Ok(String::from_utf8(reader.read_vec(header.length)?)?)
121     }
122 }
123 
124 #[cfg(feature = "alloc")]
125 impl EncodeValue for String {
value_len(&self) -> Result<Length>126     fn value_len(&self) -> Result<Length> {
127         Utf8StringRef::new(self)?.value_len()
128     }
129 
encode_value(&self, writer: &mut impl Writer) -> Result<()>130     fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
131         Utf8StringRef::new(self)?.encode_value(writer)
132     }
133 }
134 
135 #[cfg(feature = "alloc")]
136 impl FixedTag for String {
137     const TAG: Tag = Tag::Utf8String;
138 }
139 
140 #[cfg(feature = "alloc")]
141 impl OrdIsValueOrd for String {}
142 
143 #[cfg(test)]
144 mod tests {
145     use super::Utf8StringRef;
146     use crate::Decode;
147 
148     #[test]
parse_ascii_bytes()149     fn parse_ascii_bytes() {
150         let example_bytes = &[
151             0x0c, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31,
152         ];
153 
154         let utf8_string = Utf8StringRef::from_der(example_bytes).unwrap();
155         assert_eq!(utf8_string.as_str(), "Test User 1");
156     }
157 
158     #[test]
parse_utf8_bytes()159     fn parse_utf8_bytes() {
160         let example_bytes = &[0x0c, 0x06, 0x48, 0x65, 0x6c, 0x6c, 0xc3, 0xb3];
161         let utf8_string = Utf8StringRef::from_der(example_bytes).unwrap();
162         assert_eq!(utf8_string.as_str(), "Helló");
163     }
164 }
165