rasn/types/strings/
ia5.rs

1use super::*;
2
3use crate::error::strings::InvalidIso646Character;
4use alloc::{borrow::ToOwned, boxed::Box, string::String, vec::Vec};
5use once_cell::race::OnceBox;
6
7/// An string which only contains ASCII characters.
8#[derive(Debug, Default, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
9pub struct Ia5String(Vec<u8>);
10static CHARACTER_MAP: OnceBox<alloc::collections::BTreeMap<u32, u32>> = OnceBox::new();
11static INDEX_MAP: OnceBox<alloc::collections::BTreeMap<u32, u32>> = OnceBox::new();
12
13impl Ia5String {
14    pub fn from_iso646_bytes(bytes: &[u8]) -> Result<Self, InvalidIso646Character> {
15        bytes.iter().try_for_each(|byte| {
16            if Self::CHARACTER_SET.contains(&(*byte as u32)) {
17                Ok(())
18            } else {
19                Err(InvalidIso646Character { character: *byte })
20            }
21        })?;
22
23        Ok(Self(bytes.to_owned()))
24    }
25
26    pub fn as_iso646_bytes(&self) -> &[u8] {
27        &self.0
28    }
29}
30
31impl core::fmt::Display for Ia5String {
32    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
33        f.write_str(&String::from_utf8(self.as_iso646_bytes().to_owned()).unwrap())
34    }
35}
36
37impl AsnType for Ia5String {
38    const TAG: Tag = Tag::IA5_STRING;
39}
40
41impl Encode for Ia5String {
42    fn encode_with_tag_and_constraints<E: Encoder>(
43        &self,
44        encoder: &mut E,
45        tag: Tag,
46        constraints: Constraints,
47    ) -> Result<(), E::Error> {
48        encoder.encode_ia5_string(tag, constraints, self).map(drop)
49    }
50}
51
52impl Decode for Ia5String {
53    fn decode_with_tag_and_constraints<D: Decoder>(
54        decoder: &mut D,
55        tag: Tag,
56        constraints: Constraints,
57    ) -> Result<Self, D::Error> {
58        decoder.decode_ia5_string(tag, constraints)
59    }
60}
61
62impl TryFrom<alloc::string::String> for Ia5String {
63    type Error = InvalidIso646Character;
64
65    fn try_from(value: alloc::string::String) -> Result<Self, Self::Error> {
66        Self::from_iso646_bytes(value.as_bytes())
67    }
68}
69
70impl TryFrom<&'_ str> for Ia5String {
71    type Error = InvalidIso646Character;
72
73    fn try_from(value: &str) -> Result<Self, Self::Error> {
74        Self::from_iso646_bytes(value.as_bytes())
75    }
76}
77
78impl TryFrom<alloc::vec::Vec<u8>> for Ia5String {
79    type Error = InvalidIso646Character;
80
81    fn try_from(value: alloc::vec::Vec<u8>) -> Result<Self, Self::Error> {
82        Self::from_iso646_bytes(&value)
83    }
84}
85
86impl TryFrom<&'_ [u8]> for Ia5String {
87    type Error = InvalidIso646Character;
88
89    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
90        Self::from_iso646_bytes(value)
91    }
92}
93
94impl TryFrom<bytes::Bytes> for Ia5String {
95    type Error = InvalidIso646Character;
96
97    fn try_from(value: bytes::Bytes) -> Result<Self, Self::Error> {
98        Self::try_from(&*value)
99    }
100}
101
102impl From<Ia5String> for bytes::Bytes {
103    fn from(value: Ia5String) -> Self {
104        value.0.into()
105    }
106}
107
108impl From<Ia5String> for alloc::string::String {
109    fn from(value: Ia5String) -> Self {
110        Self::from_utf8(value.as_iso646_bytes().to_owned()).unwrap()
111    }
112}
113
114impl super::StaticPermittedAlphabet for Ia5String {
115    const CHARACTER_SET: &'static [u32] = &[
116        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
117        0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
118        0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C,
119        0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
120        0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
121        0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
122        0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
123        0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
124        0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
125    ];
126
127    fn chars(&self) -> Box<dyn Iterator<Item = u32> + '_> {
128        Box::from(self.0.iter().map(|byte| *byte as u32))
129    }
130
131    fn push_char(&mut self, ch: u32) {
132        debug_assert!(
133            Self::CHARACTER_SET.contains(&ch),
134            "{} not in character set",
135            ch
136        );
137        self.0.push(ch as u8);
138    }
139
140    fn index_map() -> &'static alloc::collections::BTreeMap<u32, u32> {
141        INDEX_MAP.get_or_init(Self::build_index_map)
142    }
143
144    fn character_map() -> &'static alloc::collections::BTreeMap<u32, u32> {
145        CHARACTER_MAP.get_or_init(Self::build_character_map)
146    }
147}