storekey/
types.rs

1use std::fmt::{self};
2use std::io::Write;
3use std::{slice, str};
4
5use super::reader::BorrowReader;
6use super::{BorrowDecode, Encode, Writer};
7use crate::{DecodeError, EncodeError};
8
9/// A slice buffer which is in an escaped format:
10/// containing possible 0u8 and 1u8 bytes escaped with a 1u8 as well as a final terminating null
11/// byte.
12#[repr(transparent)]
13pub struct EscapedSlice([u8]);
14
15impl EscapedSlice {
16	/// Create an escaped slice from a byte slice.
17	///
18	/// # Safety
19	/// User must ensure the slice is properly escaped.
20	pub unsafe fn from_slice(b: &[u8]) -> &EscapedSlice {
21		// Safety: Safe because EscapedSlice has repr(transparent)
22		unsafe { std::mem::transmute(b) }
23	}
24
25	/// Returns the raw underlying byte representation of the escaped string, including escaped
26	/// bytes.
27	pub fn as_bytes(&self) -> &[u8] {
28		&self.0
29	}
30
31	/// Returns an iterator over the bytes in this slice, unescaping escaped bytes.
32	pub fn iter(&self) -> EscapedIter<'_> {
33		EscapedIter(self.0[..self.0.len() - 1].iter())
34	}
35}
36
37impl<F> Encode<F> for EscapedSlice {
38	fn encode<W: Write>(&self, w: &mut Writer<W>) -> Result<(), EncodeError> {
39		w.write_escaped_slice(self)
40	}
41}
42
43impl<'de, F> BorrowDecode<'de, F> for &'de EscapedSlice {
44	fn borrow_decode(w: &mut BorrowReader<'de>) -> Result<Self, DecodeError> {
45		w.read_escaped_slice()
46	}
47}
48
49impl fmt::Debug for EscapedSlice {
50	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51		let mut escaped = false;
52		let iter = self.0[..self.0.len() - 1].iter().copied().filter(|x| {
53			if escaped {
54				escaped = false;
55				true
56			} else if *x == 1 {
57				escaped = true;
58				false
59			} else {
60				true
61			}
62		});
63
64		f.debug_list().entries(iter).finish()
65	}
66}
67
68impl PartialEq<[u8]> for EscapedSlice {
69	fn eq(&self, other: &[u8]) -> bool {
70		let mut iter = other.iter().copied();
71		for a in self.iter().copied() {
72			let Some(b) = iter.next() else {
73				return false;
74			};
75			if a != b {
76				return false;
77			}
78		}
79		iter.next().is_none()
80	}
81}
82
83impl PartialEq<EscapedSlice> for [u8] {
84	fn eq(&self, other: &EscapedSlice) -> bool {
85		EscapedSlice::eq(other, self)
86	}
87}
88
89impl Eq for EscapedSlice {}
90impl PartialEq for EscapedSlice {
91	fn eq(&self, other: &Self) -> bool {
92		self.0 == other.0
93	}
94}
95
96impl<'a> IntoIterator for &'a EscapedSlice {
97	type Item = &'a u8;
98
99	type IntoIter = EscapedIter<'a>;
100
101	fn into_iter(self) -> Self::IntoIter {
102		self.iter()
103	}
104}
105
106pub struct EscapedIter<'a>(slice::Iter<'a, u8>);
107
108impl<'a> Iterator for EscapedIter<'a> {
109	type Item = &'a u8;
110
111	fn next(&mut self) -> Option<Self::Item> {
112		let c = self.0.next()?;
113		if *c == 1 {
114			self.0.next()
115		} else {
116			Some(c)
117		}
118	}
119}
120
121/// A slice buffer which is in an escaped format:
122/// containing possible 0u8 and 1u8 bytes escaped with a 1u8 as well as a final terminating null
123/// byte
124#[repr(transparent)]
125pub struct EscapedStr(str);
126
127impl EscapedStr {
128	/// Create an escaped str from a normal str.
129	///
130	/// # Safety
131	/// User must ensure the str is properly escaped.
132	pub unsafe fn from_str(b: &str) -> &EscapedStr {
133		// Safety: Safe because EscapedStr has repr(transparent)
134		unsafe { std::mem::transmute(b) }
135	}
136
137	/// Returns the raw underlying byte representation of the escaped string, including escaped
138	/// bytes.
139	pub fn as_bytes(&self) -> &[u8] {
140		self.0.as_bytes()
141	}
142
143	pub fn as_slice(&self) -> &EscapedSlice {
144		unsafe { EscapedSlice::from_slice(self.0.as_bytes()) }
145	}
146
147	/// Returns a iterator over the characters in this string, unescaping escaped characters.
148	pub fn chars(&self) -> EscapedChars<'_> {
149		EscapedChars(self.0[..self.0.len() - 1].chars())
150	}
151}
152
153impl<F> Encode<F> for EscapedStr {
154	fn encode<W: Write>(&self, w: &mut Writer<W>) -> Result<(), EncodeError> {
155		w.write_escaped_slice(self.as_slice())
156	}
157}
158
159impl<'de, F> BorrowDecode<'de, F> for &'de EscapedStr {
160	fn borrow_decode(w: &mut BorrowReader<'de>) -> Result<Self, DecodeError> {
161		w.read_escaped_str()
162	}
163}
164
165impl PartialEq<str> for EscapedStr {
166	fn eq(&self, other: &str) -> bool {
167		let mut iter = other.chars();
168		for a in self.chars() {
169			let Some(b) = iter.next() else {
170				return false;
171			};
172			if a != b {
173				return false;
174			}
175		}
176		iter.next().is_none()
177	}
178}
179
180impl PartialEq<EscapedStr> for str {
181	fn eq(&self, other: &EscapedStr) -> bool {
182		EscapedStr::eq(other, self)
183	}
184}
185
186impl Eq for EscapedStr {}
187impl PartialEq for EscapedStr {
188	fn eq(&self, other: &Self) -> bool {
189		self.0 == other.0
190	}
191}
192
193impl fmt::Debug for EscapedStr {
194	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195		use std::fmt::Write;
196		f.write_char('"')?;
197		for c in self.chars() {
198			for c in c.escape_debug() {
199				f.write_char(c)?;
200			}
201		}
202		f.write_char('"')?;
203		Ok(())
204	}
205}
206
207impl fmt::Display for EscapedStr {
208	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209		use std::fmt::Write;
210		for c in self.chars() {
211			f.write_char(c)?;
212		}
213		Ok(())
214	}
215}
216
217pub struct EscapedChars<'a>(str::Chars<'a>);
218
219impl<'a> Iterator for EscapedChars<'a> {
220	type Item = char;
221
222	fn next(&mut self) -> Option<Self::Item> {
223		let c = self.0.next()?;
224		if c == '\x01' {
225			self.0.next()
226		} else {
227			Some(c)
228		}
229	}
230}