lowlevel_types/ascii/
fixedlengthstring.rs1use std::fmt::Display;
2
3use serde::{Deserialize, Deserializer, Serialize, de::Visitor};
4
5use crate::ascii::{char::Char, error::ASCIIError};
6
7#[derive(Clone, Debug, Hash, PartialOrd)]
9pub struct FixedLengthString<const N: usize>(pub [Char; N]);
10
11impl<const N: usize> FixedLengthString<N> {
12 pub fn new() -> Self {
14 Self([Char(0x00); N])
15 }
16
17 pub fn len(&self) -> usize {
19 self.0.len()
20 }
21
22 pub fn as_bytes(&self) -> [u8; N] {
24 self.0.map(|c| u8::from(c)).clone()
25 }
26}
27
28impl<const N: usize> Display for FixedLengthString<N> {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 self.0
31 .iter()
32 .for_each(|c| f.write_str(c.char().to_string().as_str()).unwrap());
33 Ok(())
34 }
35}
36
37impl<const N: usize> PartialEq<FixedLengthString<N>> for FixedLengthString<N> {
38 fn eq(&self, other: &FixedLengthString<N>) -> bool {
39 self.0 == other.0
40 }
41}
42
43impl<const N: usize> PartialEq<&str> for FixedLengthString<N> {
44 fn eq(&self, other: &&str) -> bool {
45 let s = String::from(self.clone());
46 s.as_str() == *other
47 }
48}
49
50impl<const N: usize> From<Vec<u8>> for FixedLengthString<N> {
51 fn from(value: Vec<u8>) -> Self {
52 FixedLengthString::<N>::try_from(value.as_slice()).unwrap()
53 }
54}
55
56impl<const N: usize> TryFrom<&[u8]> for FixedLengthString<N> {
57 type Error = ASCIIError;
58
59 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
60 if value.len() > N {
61 Err(ASCIIError {
62 message: format!(
63 "array &[u8] of length {} too long for AString<{}>",
64 value.len(),
65 N
66 ),
67 })
68 } else {
69 let v: &mut [Char; N] = &mut [Char(0x00); N];
70 for i in 0..value.len() {
71 v[i] = Char(value[i].clone());
72 }
73 Ok(FixedLengthString(v.clone()))
74 }
75 }
76}
77
78impl<const N: usize> From<[u8; N]> for FixedLengthString<N> {
79 fn from(value: [u8; N]) -> Self {
80 FixedLengthString(value.map(|c| Char(c)))
81 }
82}
83
84impl<const N: usize> TryFrom<&String> for FixedLengthString<N> {
85 type Error = ASCIIError;
86
87 fn try_from(value: &String) -> Result<Self, Self::Error> {
88 FixedLengthString::<N>::try_from(value.as_str())
89 }
90}
91
92impl<const N: usize> TryFrom<&str> for FixedLengthString<N> {
93 type Error = ASCIIError;
94
95 fn try_from(value: &str) -> Result<Self, Self::Error> {
96 if !value.is_ascii() {
97 Err(ASCIIError {
98 message: format!("attempt to convert an Unicode string to an AString"),
99 })
100 } else {
101 let v: &mut Vec<u8> = &mut Vec::new();
102 for c in value.chars() {
103 v.push(c as u8);
104 }
105 Ok(FixedLengthString::from(v.clone()))
106 }
107 }
108}
109
110impl<const N: usize> From<FixedLengthString<N>> for String {
111 fn from(value: FixedLengthString<N>) -> Self {
112 let s = &mut String::new();
113 for c in value.0 {
114 s.push(c.char());
115 }
116 s.clone()
117 }
118}
119
120#[cfg(feature = "serde")]
121impl<const N: usize> Serialize for FixedLengthString<N> {
122 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
123 where
124 S: serde::Serializer,
125 {
126 let bytes = &self.as_bytes() as &[u8];
127 serializer.serialize_bytes(bytes)
128 }
129}
130
131#[cfg(feature = "serde")]
132impl<'de, const N: usize> Deserialize<'de> for FixedLengthString<N> {
133 fn deserialize<D>(deserializer: D) -> Result<FixedLengthString<N>, D::Error>
134 where
135 D: Deserializer<'de>,
136 {
137 deserializer.deserialize_bytes(AStringVisitor::<N>)
138 }
139}
140
141#[cfg(feature = "serde")]
142pub struct AStringVisitor<const N: usize>;
143
144#[cfg(feature = "serde")]
145impl<'de, const N: usize> Visitor<'de> for AStringVisitor<N> {
146 type Value = FixedLengthString<N>;
147
148 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
149 formatter.write_str(format!("an array of {} ASCII bytes", N).as_str())
150 }
151
152 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
153 where
154 E: serde::de::Error,
155 {
156 if v.len() != N {
157 Err(serde::de::Error::invalid_length(v.len(), &self))
158 } else {
159 Ok(FixedLengthString::try_from(v).unwrap())
160 }
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use crate::ascii::{self, char::Char, fixedlengthstring::FixedLengthString};
167
168 #[test]
169 fn test_create() {
170 let s1 = FixedLengthString([Char(0x00)]);
171 assert_eq!(s1.len(), 1);
172 assert_eq!(s1, "\0");
173 let s: FixedLengthString<10> = FixedLengthString::new();
174 assert_eq!(s.len(), 10);
175 }
176
177 #[test]
178 fn test_from_vec_of_u8() {
179 let v: Vec<u8> = vec![0x41 as u8];
180 let s1: FixedLengthString<1> = FixedLengthString::from(v);
181 assert_eq!(s1, "A");
182 }
183
184 #[test]
185 fn test_from_array_of_u8() {
186 let s1: FixedLengthString<1> = FixedLengthString::try_from(&[0x41 as u8] as &[u8]).unwrap();
187 assert_eq!(s1, "A");
188 let s2: FixedLengthString<1> = FixedLengthString::from([0x41 as u8; 1]);
189 assert_eq!(s2, "A");
190 assert!(FixedLengthString::<1>::try_from(&[0x41 as u8; 2] as &[u8]).is_err());
191 }
192
193 #[test]
194 fn test_from_string() {
195 let s1: FixedLengthString<1> = FixedLengthString::try_from(&String::from("A")).unwrap();
196 assert_eq!(s1, "A");
197 assert!(FixedLengthString::<1>::try_from(&String::from("👿")).is_err());
198 }
199
200 #[test]
201 fn test_string_try_from_astring() {
202 let s4 = String::from(FixedLengthString::<1>::try_from("A").unwrap());
203 assert_eq!(s4, "A");
204 }
205
206 #[test]
207 fn test_display() {
208 let s = FixedLengthString([ascii::Char(0x41); 1]);
209 assert_eq!(format!("{}", s), "A");
210 }
211}