revision/implementations/
string.rs

1use core::str;
2
3use crate::{DeserializeRevisioned, Error, Revisioned, SerializeRevisioned};
4
5use super::vecs::serialize_bytes;
6
7impl SerializeRevisioned for String {
8	#[inline]
9	fn serialize_revisioned<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
10		serialize_bytes(self.as_bytes(), writer)
11	}
12}
13
14impl DeserializeRevisioned for String {
15	#[inline]
16	fn deserialize_revisioned<R: std::io::Read>(reader: &mut R) -> Result<Self, Error> {
17		let bytes = Vec::<u8>::deserialize_revisioned(reader)?;
18		String::from_utf8(bytes).map_err(|x| Error::Utf8Error(x.utf8_error()))
19	}
20}
21
22impl Revisioned for String {
23	#[inline]
24	fn revision() -> u16 {
25		1
26	}
27}
28
29impl SerializeRevisioned for str {
30	#[inline]
31	fn serialize_revisioned<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
32		serialize_bytes(self.as_bytes(), writer)
33	}
34}
35
36impl Revisioned for str {
37	#[inline]
38	fn revision() -> u16 {
39		1
40	}
41}
42
43impl SerializeRevisioned for char {
44	#[inline]
45	fn serialize_revisioned<W: std::io::Write>(&self, w: &mut W) -> Result<(), Error> {
46		let buffer = &mut [0u8; 4];
47		w.write_all(self.encode_utf8(buffer).as_bytes()).map_err(Error::Io)
48	}
49}
50
51impl DeserializeRevisioned for char {
52	#[inline]
53	fn deserialize_revisioned<R: std::io::Read>(r: &mut R) -> Result<Self, Error> {
54		let mut buffer = [0u8; 4];
55		r.read_exact(&mut buffer[..1]).map_err(Error::Io)?;
56
57		let len = CHAR_LENGTH[buffer[0] as usize];
58
59		if len == 0 {
60			return Err(Error::InvalidCharEncoding);
61		}
62
63		r.read_exact(&mut buffer[1..(len as usize)]).map_err(Error::Io)?;
64
65		str::from_utf8(&buffer[..(len as usize)])
66			.map_err(|_| Error::InvalidCharEncoding)
67			.map(|x| x.chars().next().unwrap())
68	}
69}
70
71impl Revisioned for char {
72	#[inline]
73	fn revision() -> u16 {
74		1
75	}
76}
77
78static CHAR_LENGTH: [u8; 256] = const {
79	let mut r = [0u8; 256];
80	let mut i = 0;
81	while i < 256 {
82		if i & 0b1000_0000 == 0 {
83			r[i] = 1;
84		} else if i & 0b1110_0000 == 0b1100_0000 {
85			r[i] = 2;
86		} else if i & 0b1111_0000 == 0b1110_0000 {
87			r[i] = 3;
88		} else if i & 0b1111_1000 == 0b1111_0000 {
89			r[i] = 4;
90		}
91
92		i += 1;
93	}
94
95	r
96};
97
98#[cfg(test)]
99mod tests {
100
101	use super::*;
102
103	use crate::implementations::assert_bincode_compat;
104
105	#[test]
106	fn test_string() {
107		let val = String::from("this is a test");
108		let mut mem: Vec<u8> = vec![];
109		val.serialize_revisioned(&mut mem).unwrap();
110		#[cfg(not(feature = "fixed-width-encoding"))]
111		assert_eq!(mem.len(), 15);
112		#[cfg(feature = "fixed-width-encoding")]
113		assert_eq!(mem.len(), 22);
114		let out =
115			<String as DeserializeRevisioned>::deserialize_revisioned(&mut mem.as_slice()).unwrap();
116		assert_eq!(val, out);
117	}
118
119	#[test]
120	fn test_char() {
121		let char = '𐃌';
122		let mut mem = Vec::new();
123		char.serialize_revisioned(&mut mem).unwrap();
124		let out = DeserializeRevisioned::deserialize_revisioned(&mut mem.as_slice()).unwrap();
125		assert_eq!(char, out);
126	}
127
128	#[test]
129	fn bincode_compat_char() {
130		assert_bincode_compat(&char::MAX);
131		assert_bincode_compat(&'\0');
132		assert_bincode_compat(&'z');
133		assert_bincode_compat(&'0');
134		// in the 0x7F - 0x07FF range
135		assert_bincode_compat(&'ʘ');
136		// in the 0x7FF - 0xFFFF range
137		assert_bincode_compat(&'ꚸ');
138		// in the 0xFFFF - 0x10FFFF range
139		assert_bincode_compat(&'𐃌');
140	}
141
142	#[test]
143	fn bincode_compat_string() {
144		assert_bincode_compat(&char::MAX.to_string());
145		assert_bincode_compat(&'\0'.to_string());
146		assert_bincode_compat(&'z'.to_string());
147		assert_bincode_compat(&'0'.to_string());
148		// in the 0x7F - 0x07FF range
149		assert_bincode_compat(&'ʘ'.to_string());
150		// in the 0x7FF - 0xFFFF range
151		assert_bincode_compat(&'ꚸ'.to_string());
152		// in the 0xFFFF - 0x10FFFF range
153		assert_bincode_compat(&'𐃌'.to_string());
154	}
155}