1#![no_std]
6#![deny(rust_2018_idioms, nonstandard_style)]
7#![warn(future_incompatible, missing_docs)]
8
9extern crate alloc;
10
11use alloc::{
12 boxed::Box,
13 string::{String, ToString},
14 vec::Vec,
15};
16use core::{borrow::Borrow, convert::TryFrom, fmt, hash, ops, str};
17
18use bytes::Bytes;
19
20#[derive(Clone, Default, Eq, PartialOrd, Ord)]
22pub struct ByteString(Bytes);
23
24impl ByteString {
25 pub const fn new() -> Self {
27 ByteString(Bytes::new())
28 }
29
30 pub fn as_bytes(&self) -> &Bytes {
32 &self.0
33 }
34
35 pub fn into_bytes(self) -> Bytes {
37 self.0
38 }
39
40 pub const fn from_static(src: &'static str) -> ByteString {
42 Self(Bytes::from_static(src.as_bytes()))
43 }
44
45 pub const unsafe fn from_bytes_unchecked(src: Bytes) -> ByteString {
53 Self(src)
54 }
55
56 pub fn slice_ref(&self, subset: &str) -> Self {
91 Self(self.0.slice_ref(subset.as_bytes()))
92 }
93}
94
95impl PartialEq<str> for ByteString {
96 fn eq(&self, other: &str) -> bool {
97 &self[..] == other
98 }
99}
100
101impl<T: AsRef<str>> PartialEq<T> for ByteString {
102 fn eq(&self, other: &T) -> bool {
103 &self[..] == other.as_ref()
104 }
105}
106
107impl AsRef<ByteString> for ByteString {
108 fn as_ref(&self) -> &ByteString {
109 self
110 }
111}
112
113impl AsRef<[u8]> for ByteString {
114 fn as_ref(&self) -> &[u8] {
115 self.0.as_ref()
116 }
117}
118
119impl AsRef<str> for ByteString {
120 fn as_ref(&self) -> &str {
121 self
122 }
123}
124
125impl hash::Hash for ByteString {
126 fn hash<H: hash::Hasher>(&self, state: &mut H) {
127 (**self).hash(state);
128 }
129}
130
131impl ops::Deref for ByteString {
132 type Target = str;
133
134 #[inline]
135 fn deref(&self) -> &str {
136 let bytes = self.0.as_ref();
137 unsafe { str::from_utf8_unchecked(bytes) }
139 }
140}
141
142impl Borrow<str> for ByteString {
143 fn borrow(&self) -> &str {
144 self
145 }
146}
147
148impl From<String> for ByteString {
149 #[inline]
150 fn from(value: String) -> Self {
151 Self(Bytes::from(value))
152 }
153}
154
155impl From<&str> for ByteString {
156 #[inline]
157 fn from(value: &str) -> Self {
158 Self(Bytes::copy_from_slice(value.as_ref()))
159 }
160}
161
162impl From<Box<str>> for ByteString {
163 #[inline]
164 fn from(value: Box<str>) -> Self {
165 Self(Bytes::from(value.into_boxed_bytes()))
166 }
167}
168
169impl From<ByteString> for String {
170 #[inline]
171 fn from(value: ByteString) -> Self {
172 value.to_string()
173 }
174}
175
176impl TryFrom<&[u8]> for ByteString {
177 type Error = str::Utf8Error;
178
179 #[inline]
180 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
181 let _ = str::from_utf8(value)?;
182 Ok(ByteString(Bytes::copy_from_slice(value)))
183 }
184}
185
186impl TryFrom<Vec<u8>> for ByteString {
187 type Error = str::Utf8Error;
188
189 #[inline]
190 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
191 let buf = String::from_utf8(value).map_err(|err| err.utf8_error())?;
192 Ok(ByteString(Bytes::from(buf)))
193 }
194}
195
196impl TryFrom<Bytes> for ByteString {
197 type Error = str::Utf8Error;
198
199 #[inline]
200 fn try_from(value: Bytes) -> Result<Self, Self::Error> {
201 let _ = str::from_utf8(value.as_ref())?;
202 Ok(ByteString(value))
203 }
204}
205
206impl TryFrom<bytes::BytesMut> for ByteString {
207 type Error = str::Utf8Error;
208
209 #[inline]
210 fn try_from(value: bytes::BytesMut) -> Result<Self, Self::Error> {
211 let _ = str::from_utf8(&value)?;
212 Ok(ByteString(value.freeze()))
213 }
214}
215
216macro_rules! array_impls {
217 ($($len:expr)+) => {
218 $(
219 impl TryFrom<[u8; $len]> for ByteString {
220 type Error = str::Utf8Error;
221
222 #[inline]
223 fn try_from(value: [u8; $len]) -> Result<Self, Self::Error> {
224 ByteString::try_from(&value[..])
225 }
226 }
227
228 impl TryFrom<&[u8; $len]> for ByteString {
229 type Error = str::Utf8Error;
230
231 #[inline]
232 fn try_from(value: &[u8; $len]) -> Result<Self, Self::Error> {
233 ByteString::try_from(&value[..])
234 }
235 }
236 )+
237 }
238}
239
240array_impls!(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32);
241
242impl fmt::Debug for ByteString {
243 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
244 (**self).fmt(fmt)
245 }
246}
247
248impl fmt::Display for ByteString {
249 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
250 (**self).fmt(fmt)
251 }
252}
253
254#[cfg(feature = "serde")]
255mod serde {
256 use alloc::string::String;
257
258 use serde::{
259 de::{Deserialize, Deserializer},
260 ser::{Serialize, Serializer},
261 };
262
263 use super::ByteString;
264
265 impl Serialize for ByteString {
266 #[inline]
267 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
268 where
269 S: Serializer,
270 {
271 serializer.serialize_str(self.as_ref())
272 }
273 }
274
275 impl<'de> Deserialize<'de> for ByteString {
276 #[inline]
277 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
278 where
279 D: Deserializer<'de>,
280 {
281 String::deserialize(deserializer).map(ByteString::from)
282 }
283 }
284
285 #[cfg(test)]
286 mod serde_impl_tests {
287 use serde::de::DeserializeOwned;
288 use static_assertions::assert_impl_all;
289
290 use super::*;
291
292 assert_impl_all!(ByteString: Serialize, DeserializeOwned);
293 }
294}
295
296#[cfg(test)]
297mod test {
298 use alloc::{borrow::ToOwned, format, vec};
299 use core::{
300 hash::{Hash, Hasher},
301 panic::{RefUnwindSafe, UnwindSafe},
302 };
303
304 use ahash::AHasher;
305 use static_assertions::assert_impl_all;
306
307 use super::*;
308
309 assert_impl_all!(ByteString: Send, Sync, Unpin, Sized);
310 assert_impl_all!(ByteString: Clone, Default, Eq, PartialOrd, Ord);
311 assert_impl_all!(ByteString: fmt::Debug, fmt::Display);
312 assert_impl_all!(ByteString: UnwindSafe, RefUnwindSafe);
313
314 #[test]
315 fn eq() {
316 let s: ByteString = ByteString::from_static("test");
317 assert_eq!(s, "test");
318 assert_eq!(s, *"test");
319 assert_eq!(s, "test".to_owned());
320 }
321
322 #[test]
323 fn new() {
324 let _: ByteString = ByteString::new();
325 }
326
327 #[test]
328 fn as_bytes() {
329 let buf = ByteString::new();
330 assert!(buf.as_bytes().is_empty());
331
332 let buf = ByteString::from("hello");
333 assert_eq!(buf.as_bytes(), "hello");
334 }
335
336 #[test]
337 fn from_bytes_unchecked() {
338 let buf = unsafe { ByteString::from_bytes_unchecked(Bytes::new()) };
339 assert!(buf.is_empty());
340
341 let buf = unsafe { ByteString::from_bytes_unchecked(Bytes::from("hello")) };
342 assert_eq!(buf, "hello");
343 }
344
345 #[test]
346 fn as_ref() {
347 let buf = ByteString::new();
348
349 let _: &ByteString = buf.as_ref();
350 let _: &[u8] = buf.as_ref();
351 }
352
353 #[test]
354 fn borrow() {
355 let buf = ByteString::new();
356
357 let _: &str = buf.borrow();
358 }
359
360 #[test]
361 fn hash() {
362 let mut hasher1 = AHasher::default();
363 "str".hash(&mut hasher1);
364
365 let mut hasher2 = AHasher::default();
366 let s = ByteString::from_static("str");
367 s.hash(&mut hasher2);
368 assert_eq!(hasher1.finish(), hasher2.finish());
369 }
370
371 #[test]
372 fn from_string() {
373 let s: ByteString = "hello".to_owned().into();
374 assert_eq!(&s, "hello");
375 let t: &str = s.as_ref();
376 assert_eq!(t, "hello");
377 }
378
379 #[test]
380 fn from_str() {
381 let _: ByteString = "str".into();
382 let _: ByteString = "str".to_owned().into_boxed_str().into();
383 }
384
385 #[test]
386 fn to_string() {
387 let buf = ByteString::from("foo");
388 assert_eq!(String::from(buf), "foo");
389 }
390
391 #[test]
392 fn from_static_str() {
393 static _S: ByteString = ByteString::from_static("hello");
394 let _ = ByteString::from_static("str");
395 }
396
397 #[test]
398 fn try_from_slice() {
399 let _ = ByteString::try_from(b"nice bytes").unwrap();
400 }
401
402 #[test]
403 fn try_from_array() {
404 assert_eq!(
405 ByteString::try_from([b'h', b'i']).unwrap(),
406 ByteString::from_static("hi")
407 );
408 }
409
410 #[test]
411 fn try_from_vec() {
412 let _ = ByteString::try_from(vec![b'f', b'o', b'o']).unwrap();
413 ByteString::try_from(vec![0, 159, 146, 150]).unwrap_err();
414 }
415
416 #[test]
417 fn try_from_bytes() {
418 let _ = ByteString::try_from(Bytes::from_static(b"nice bytes")).unwrap();
419 }
420
421 #[test]
422 fn try_from_bytes_mut() {
423 let _ = ByteString::try_from(bytes::BytesMut::from(&b"nice bytes"[..])).unwrap();
424 }
425
426 #[test]
427 fn display() {
428 let buf = ByteString::from("bar");
429 assert_eq!(format!("{buf}"), "bar");
430 }
431
432 #[test]
433 fn debug() {
434 let buf = ByteString::from("baz");
435 assert_eq!(format!("{buf:?}"), r#""baz""#);
436 }
437
438 #[cfg(feature = "serde")]
439 #[test]
440 fn serialize() {
441 let s: ByteString = serde_json::from_str(r#""nice bytes""#).unwrap();
442 assert_eq!(s, "nice bytes");
443 }
444
445 #[cfg(feature = "serde")]
446 #[test]
447 fn deserialize() {
448 let s = serde_json::to_string(&ByteString::from_static("nice bytes")).unwrap();
449 assert_eq!(s, r#""nice bytes""#);
450 }
451
452 #[test]
453 fn slice_ref() {
454 let string = ByteString::from_static(" foo ");
455 let subset = string.trim();
456 let substring = string.slice_ref(subset);
458 assert_eq!(substring, "foo");
459 }
460
461 #[test]
462 #[should_panic]
463 fn slice_ref_catches_not_a_subset() {
464 ByteString::from_static("foo bar").slice_ref("foo");
467 }
468}