asn1_rs/asn1_types/strings/
universalstring.rs1use crate::*;
5use alloc::borrow::Cow;
6#[cfg(not(feature = "std"))]
7use alloc::string::{String, ToString};
8#[cfg(not(feature = "std"))]
9use alloc::vec::Vec;
10use core::convert::TryFrom;
11use core::iter::FromIterator;
12
13#[derive(Debug, PartialEq, Eq)]
17pub struct UniversalString<'a> {
18 pub(crate) data: Cow<'a, str>,
19}
20
21impl<'a> UniversalString<'a> {
22 pub const fn new(s: &'a str) -> Self {
23 UniversalString {
24 data: Cow::Borrowed(s),
25 }
26 }
27
28 pub fn string(&self) -> String {
29 self.data.to_string()
30 }
31}
32
33impl<'a> AsRef<str> for UniversalString<'a> {
34 fn as_ref(&self) -> &str {
35 &self.data
36 }
37}
38
39impl<'a> From<&'a str> for UniversalString<'a> {
40 fn from(s: &'a str) -> Self {
41 Self::new(s)
42 }
43}
44
45impl From<String> for UniversalString<'_> {
46 fn from(s: String) -> Self {
47 Self {
48 data: Cow::Owned(s),
49 }
50 }
51}
52
53impl<'a> TryFrom<Any<'a>> for UniversalString<'a> {
54 type Error = Error;
55
56 fn try_from(any: Any<'a>) -> Result<UniversalString<'a>> {
57 TryFrom::try_from(&any)
58 }
59}
60
61impl<'a, 'b> TryFrom<&'b Any<'a>> for UniversalString<'a> {
62 type Error = Error;
63
64 fn try_from(any: &'b Any<'a>) -> Result<UniversalString<'a>> {
65 any.tag().assert_eq(Self::TAG)?;
66
67 if any.data.len() % 4 != 0 {
68 return Err(Error::StringInvalidCharset);
69 }
70
71 let v = &any
73 .data
74 .chunks(4)
75 .map(|s| match s {
76 [a, b, c, d] => {
77 let u32_val = ((*a as u32) << 24)
78 | ((*b as u32) << 16)
79 | ((*c as u32) << 8)
80 | (*d as u32);
81 char::from_u32(u32_val)
82 }
83 _ => unreachable!(),
84 })
85 .collect::<Option<Vec<_>>>()
86 .ok_or(Error::StringInvalidCharset)?;
87
88 let s = String::from_iter(v);
89 let data = Cow::Owned(s);
90
91 Ok(UniversalString { data })
92 }
93}
94
95impl<'a> CheckDerConstraints for UniversalString<'a> {
96 fn check_constraints(any: &Any) -> Result<()> {
97 any.header.assert_primitive()?;
98 Ok(())
99 }
100}
101
102impl DerAutoDerive for UniversalString<'_> {}
103
104impl<'a> Tagged for UniversalString<'a> {
105 const TAG: Tag = Tag::UniversalString;
106}
107
108#[cfg(feature = "std")]
109impl ToDer for UniversalString<'_> {
110 fn to_der_len(&self) -> Result<usize> {
111 let sz = self.data.as_bytes().len() * 4;
113 if sz < 127 {
114 Ok(2 + sz)
116 } else {
117 let n = Length::Definite(sz).to_der_len()?;
119 Ok(1 + n + sz)
120 }
121 }
122
123 fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
124 let header = Header::new(
125 Class::Universal,
126 false,
127 Self::TAG,
128 Length::Definite(self.data.as_bytes().len() * 4),
129 );
130 header.write_der_header(writer).map_err(Into::into)
131 }
132
133 fn write_der_content(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
134 self.data
135 .chars()
136 .try_for_each(|c| writer.write(&(c as u32).to_be_bytes()[..]).map(|_| ()))?;
137 Ok(self.data.as_bytes().len() * 4)
138 }
139}