1#![allow(unreachable_pub)]
5
6use core::ops::{Deref, Index, IndexMut};
7
8pub use _ascii_char::AsciiChar;
9
10#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
12#[repr(transparent)]
13pub struct AsciiStr([AsciiChar]);
14
15impl AsciiStr {
16 #[inline]
17 pub const fn new_sized<const N: usize>(src: &str) -> [AsciiChar; N] {
18 if !src.is_ascii() || src.len() > N {
19 panic!();
20 }
21
22 let src = src.as_bytes();
23 let mut result = [AsciiChar::NULL; N];
24 let mut i = 0;
25 while i < src.len() {
26 result[i] = AsciiChar::new(src[i]);
27 i += 1;
28 }
29 result
30 }
31
32 #[inline]
33 pub const fn from_slice(src: &[AsciiChar]) -> &Self {
34 unsafe { core::mem::transmute::<&[AsciiChar], &AsciiStr>(src) }
36 }
37
38 #[inline]
39 pub const fn as_str(&self) -> &str {
40 unsafe { core::mem::transmute::<&AsciiStr, &str>(self) }
43 }
44
45 #[inline]
46 pub const fn len(&self) -> usize {
47 self.0.len()
48 }
49
50 #[inline]
51 pub const fn is_empty(&self) -> bool {
52 self.0.is_empty()
53 }
54}
55
56impl Deref for AsciiStr {
58 type Target = str;
59
60 #[inline]
61 fn deref(&self) -> &Self::Target {
62 self.as_str()
63 }
64}
65
66impl<Idx> Index<Idx> for AsciiStr
67where
68 [AsciiChar]: Index<Idx, Output = [AsciiChar]>,
69{
70 type Output = [AsciiChar];
71
72 #[inline]
73 fn index(&self, index: Idx) -> &Self::Output {
74 &self.0[index]
75 }
76}
77
78impl<Idx> IndexMut<Idx> for AsciiStr
79where
80 [AsciiChar]: IndexMut<Idx, Output = [AsciiChar]>,
81{
82 #[inline]
83 fn index_mut(&mut self, index: Idx) -> &mut Self::Output {
84 &mut self.0[index]
85 }
86}
87
88impl Default for &'static AsciiStr {
89 #[inline]
90 fn default() -> Self {
91 unsafe { core::mem::transmute::<&str, &AsciiStr>("") }
93 }
94}
95
96impl AsciiChar {
97 pub const NULL: AsciiChar = AsciiChar::new(0);
98
99 #[inline]
100 pub const fn slice_as_bytes<const N: usize>(src: &[AsciiChar; N]) -> &[u8; N] {
101 unsafe { core::mem::transmute::<&[AsciiChar; N], &[u8; N]>(src) }
103 }
104
105 #[inline]
106 pub const fn two_digits(d: u32) -> [Self; 2] {
107 const ALPHABET: &[u8; 10] = b"0123456789";
108
109 if d >= ALPHABET.len().pow(2) as u32 {
110 panic!();
111 }
112 [
113 Self::new(ALPHABET[d as usize / ALPHABET.len()]),
114 Self::new(ALPHABET[d as usize % ALPHABET.len()]),
115 ]
116 }
117
118 #[inline]
119 pub const fn two_hex_digits(d: u32) -> [Self; 2] {
120 const ALPHABET: &[u8; 16] = b"0123456789abcdef";
121
122 if d >= ALPHABET.len().pow(2) as u32 {
123 panic!();
124 }
125 [
126 Self::new(ALPHABET[d as usize / ALPHABET.len()]),
127 Self::new(ALPHABET[d as usize % ALPHABET.len()]),
128 ]
129 }
130}
131
132mod _ascii_char {
133 #[derive(Debug, Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
135 #[repr(transparent)]
136 pub struct AsciiChar(u8);
137
138 impl AsciiChar {
139 #[inline]
140 pub const fn new(c: u8) -> Self {
141 if c.is_ascii() { Self(c) } else { panic!() }
142 }
143 }
144}