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