der/asn1/
teletex_string.rs

1//! ASN.1 `TeletexString` support.
2//!
3use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag};
4use core::{fmt, ops::Deref};
5
6macro_rules! impl_teletex_string {
7    ($type: ty) => {
8        impl_teletex_string!($type,);
9    };
10    ($type: ty, $($li: lifetime)?) => {
11        impl_string_type!($type, $($li),*);
12
13        impl<$($li),*> FixedTag for $type {
14            const TAG: Tag = Tag::TeletexString;
15        }
16
17        impl<$($li),*> fmt::Debug for $type {
18            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19                write!(f, "TeletexString({:?})", self.as_str())
20            }
21        }
22    };
23}
24
25/// ASN.1 `TeletexString` type.
26///
27/// Supports a subset the ASCII character set (described below).
28///
29/// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead.
30/// For the full ASCII character set, use
31/// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`].
32///
33/// This is a zero-copy reference type which borrows from the input data.
34///
35/// # Supported characters
36///
37/// The standard defines a complex character set allowed in this type. However, quoting the ASN.1
38/// mailing list, "a sizable volume of software in the world treats TeletexString (T61String) as a
39/// simple 8-bit string with mostly Windows Latin 1 (superset of iso-8859-1) encoding".
40///
41#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
42pub struct TeletexStringRef<'a> {
43    /// Inner value
44    inner: StrRef<'a>,
45}
46
47impl<'a> TeletexStringRef<'a> {
48    /// Create a new ASN.1 `TeletexString`.
49    pub fn new<T>(input: &'a T) -> Result<Self>
50    where
51        T: AsRef<[u8]> + ?Sized,
52    {
53        let input = input.as_ref();
54
55        // FIXME: support higher part of the charset
56        if input.iter().any(|&c| c > 0x7F) {
57            return Err(Self::TAG.value_error());
58        }
59
60        StrRef::from_bytes(input)
61            .map(|inner| Self { inner })
62            .map_err(|_| Self::TAG.value_error())
63    }
64}
65
66impl_teletex_string!(TeletexStringRef<'a>, 'a);
67
68impl<'a> Deref for TeletexStringRef<'a> {
69    type Target = StrRef<'a>;
70
71    fn deref(&self) -> &Self::Target {
72        &self.inner
73    }
74}
75
76impl<'a> From<&TeletexStringRef<'a>> for TeletexStringRef<'a> {
77    fn from(value: &TeletexStringRef<'a>) -> TeletexStringRef<'a> {
78        *value
79    }
80}
81
82impl<'a> From<TeletexStringRef<'a>> for AnyRef<'a> {
83    fn from(teletex_string: TeletexStringRef<'a>) -> AnyRef<'a> {
84        AnyRef::from_tag_and_value(Tag::TeletexString, teletex_string.inner.into())
85    }
86}
87
88#[cfg(feature = "alloc")]
89pub use self::allocation::TeletexString;
90
91#[cfg(feature = "alloc")]
92mod allocation {
93    use super::TeletexStringRef;
94
95    use crate::{
96        asn1::AnyRef,
97        referenced::{OwnedToRef, RefToOwned},
98        BytesRef, Error, FixedTag, Result, StrOwned, Tag,
99    };
100    use alloc::string::String;
101    use core::{fmt, ops::Deref};
102
103    /// ASN.1 `TeletexString` type.
104    ///
105    /// Supports a subset the ASCII character set (described below).
106    ///
107    /// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead.
108    /// For the full ASCII character set, use
109    /// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`].
110    ///
111    /// # Supported characters
112    ///
113    /// The standard defines a complex character set allowed in this type. However, quoting the ASN.1
114    /// mailing list, "a sizable volume of software in the world treats TeletexString (T61String) as a
115    /// simple 8-bit string with mostly Windows Latin 1 (superset of iso-8859-1) encoding".
116    ///
117    #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)]
118    pub struct TeletexString {
119        /// Inner value
120        inner: StrOwned,
121    }
122
123    impl TeletexString {
124        /// Create a new ASN.1 `TeletexString`.
125        pub fn new<T>(input: &T) -> Result<Self>
126        where
127            T: AsRef<[u8]> + ?Sized,
128        {
129            let input = input.as_ref();
130
131            TeletexStringRef::new(input)?;
132
133            StrOwned::from_bytes(input)
134                .map(|inner| Self { inner })
135                .map_err(|_| Self::TAG.value_error())
136        }
137    }
138
139    impl_teletex_string!(TeletexString);
140
141    impl Deref for TeletexString {
142        type Target = StrOwned;
143
144        fn deref(&self) -> &Self::Target {
145            &self.inner
146        }
147    }
148
149    impl<'a> From<TeletexStringRef<'a>> for TeletexString {
150        fn from(value: TeletexStringRef<'a>) -> TeletexString {
151            let inner =
152                StrOwned::from_bytes(value.inner.as_bytes()).expect("Invalid TeletexString");
153            Self { inner }
154        }
155    }
156
157    impl<'a> From<&'a TeletexString> for AnyRef<'a> {
158        fn from(teletex_string: &'a TeletexString) -> AnyRef<'a> {
159            AnyRef::from_tag_and_value(
160                Tag::TeletexString,
161                BytesRef::new(teletex_string.inner.as_bytes()).expect("Invalid TeletexString"),
162            )
163        }
164    }
165
166    impl<'a> RefToOwned<'a> for TeletexStringRef<'a> {
167        type Owned = TeletexString;
168        fn ref_to_owned(&self) -> Self::Owned {
169            TeletexString {
170                inner: self.inner.ref_to_owned(),
171            }
172        }
173    }
174
175    impl OwnedToRef for TeletexString {
176        type Borrowed<'a> = TeletexStringRef<'a>;
177        fn owned_to_ref(&self) -> Self::Borrowed<'_> {
178            TeletexStringRef {
179                inner: self.inner.owned_to_ref(),
180            }
181        }
182    }
183
184    impl TryFrom<String> for TeletexString {
185        type Error = Error;
186
187        fn try_from(input: String) -> Result<Self> {
188            TeletexStringRef::new(&input)?;
189
190            StrOwned::new(input)
191                .map(|inner| Self { inner })
192                .map_err(|_| Self::TAG.value_error())
193        }
194    }
195}
196
197#[cfg(test)]
198mod tests {
199    use super::TeletexStringRef;
200    use crate::Decode;
201    use crate::SliceWriter;
202
203    #[test]
204    fn parse_bytes() {
205        let example_bytes = &[
206            0x14, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31,
207        ];
208
209        let teletex_string = TeletexStringRef::from_der(example_bytes).unwrap();
210        assert_eq!(teletex_string.as_str(), "Test User 1");
211        let mut out = [0_u8; 30];
212        let mut writer = SliceWriter::new(&mut out);
213        writer.encode(&teletex_string).unwrap();
214        let encoded = writer.finish().unwrap();
215        assert_eq!(encoded, example_bytes);
216    }
217}