1use std::marker::PhantomData;
8use std::ops::Deref;
9use std::ptr;
10
11#[derive(Debug)]
12pub enum VisibleAscii {}
13
14#[derive(Debug)]
15pub enum Latin1 {}
16
17pub trait BytePredicate: private::Sealed {}
18
19impl<T: private::Sealed> BytePredicate for T {}
20
21mod private {
22 use crate::string::byte::{Latin1, VisibleAscii};
23
24 pub trait Sealed {
25 fn predicate(_byte: u8) -> bool {
26 true
27 }
28 }
29
30 impl Sealed for VisibleAscii {
31 fn predicate(byte: u8) -> bool {
32 (0x20..=0x7E).contains(&byte)
33 }
34 }
35
36 impl Sealed for Latin1 {}
37}
38
39#[derive(Debug)]
40#[repr(transparent)]
41pub struct ByteStr<T: BytePredicate> {
42 _predicate: PhantomData<T>,
43 bytes: [u8],
44}
45
46impl<T: BytePredicate> ByteStr<T> {
47 pub fn from(bytes: &[u8]) -> Option<&ByteStr<T>> {
48 bytes.iter().copied().all(T::predicate).then(|| unsafe { ByteStr::from_unchecked(bytes) })
49 }
50
51 pub unsafe fn from_unchecked(bytes: &[u8]) -> &ByteStr<T> {
52 unsafe { &*(ptr::from_ref(bytes) as *const ByteStr<T>) }
53 }
54
55 pub fn as_bytes(&self) -> &[u8] {
56 &self.bytes
57 }
58}
59
60impl<T: BytePredicate> Deref for ByteStr<T> {
61 type Target = [u8];
62
63 fn deref(&self) -> &[u8] {
64 self.as_bytes()
65 }
66}
67
68#[derive(Clone, Debug, Default)]
69pub struct ByteString<T: BytePredicate = Latin1> {
70 _predicate: PhantomData<T>,
71 bytes: Vec<u8>,
72}
73
74impl<T: BytePredicate> ByteString<T> {
75 pub fn from(bytes: Vec<u8>) -> Option<ByteString<T>> {
76 bytes
77 .iter()
78 .copied()
79 .all(T::predicate)
80 .then(|| unsafe { ByteString::from_unchecked(bytes) })
81 }
82
83 pub unsafe fn from_unchecked(bytes: Vec<u8>) -> ByteString<T> {
84 ByteString { _predicate: PhantomData, bytes }
85 }
86
87 pub fn as_byte_str(&self) -> &ByteStr<T> {
88 unsafe { ByteStr::from_unchecked(&self.bytes) }
89 }
90
91 pub fn into_vec(self) -> Vec<u8> {
92 self.bytes
93 }
94}
95
96impl<T: BytePredicate> Deref for ByteString<T> {
97 type Target = ByteStr<T>;
98
99 fn deref(&self) -> &ByteStr<T> {
100 self.as_byte_str()
101 }
102}