1use core::fmt;
2use core::str;
3
4#[derive(Clone, Copy, PartialEq, Eq)]
23pub struct LiteStr<const N: usize> {
24 pub bytes: [u8; N],
25}
26
27impl<const N: usize> Default for LiteStr<N> {
28 #[inline(always)]
29 fn default() -> Self {
30 Self { bytes: [0; N] }
31 }
32}
33
34impl<const N: usize> LiteStr<N> {
35 pub const SIZE: usize = N;
36
37 #[inline(always)]
42 pub fn new(s: &str) -> Self {
43 let mut bytes = [0u8; N];
44 copy_valid_utf8_prefix(&mut bytes, s.as_bytes(), N);
45 Self { bytes }
46 }
47
48 #[inline(always)]
58 pub fn as_str(&self) -> &str {
59 let end = find_first_nul(&self.bytes);
60 let slice = &self.bytes[..end];
61
62 match str::from_utf8(slice) {
63 Ok(s) => s,
64 Err(e) => {
65 let valid = e.valid_up_to();
66 if valid == 0 {
67 "\u{FFFD}" } else {
69 unsafe { str::from_utf8_unchecked(&slice[..valid]) }
71 }
72 }
73 }
74 }
75
76 #[inline(always)]
83 pub fn from_bytes(bytes: &[u8]) -> Self {
84 let mut arr = [0u8; N];
85 let len = bytes.len().min(N);
86 arr[..len].copy_from_slice(&bytes[..len]);
87 Self { bytes: arr }
88 }
89
90 #[inline(always)]
92 pub fn as_bytes(&self) -> &[u8] {
93 &self.bytes[..find_first_nul(&self.bytes)]
94 }
95}
96
97impl<const N: usize> fmt::Write for LiteStr<N> {
98 #[inline(never)]
99 fn write_str(&mut self, s: &str) -> fmt::Result {
100 let current = self.as_bytes().len();
101 let remaining = N.saturating_sub(current);
102 if remaining == 0 {
103 return Ok(());
104 }
105
106 copy_valid_utf8_prefix(&mut self.bytes[current..], s.as_bytes(), remaining);
107 Ok(())
108 }
109}
110
111impl<const N: usize> fmt::Display for LiteStr<N> {
112 #[inline(always)]
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 f.write_str(self.as_str())
115 }
116}
117
118impl<const N: usize> fmt::Debug for LiteStr<N> {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 write!(f, "{:?}", self.as_str())
121 }
122}
123
124#[cfg(feature = "serde")]
125impl<const N: usize> serde::Serialize for LiteStr<N> {
126 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
127 where
128 S: serde::Serializer,
129 {
130 self.as_str().serialize(serializer)
131 }
132}
133
134#[cfg(feature = "serde")]
135impl<'de, const N: usize> serde::Deserialize<'de> for LiteStr<N> {
136 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
137 where
138 D: serde::Deserializer<'de>,
139 {
140 let s: &str = serde::Deserialize::deserialize(deserializer)?;
141 Ok(LiteStr::new(s))
142 }
143}
144
145#[inline(never)]
146fn find_first_nul(bytes: &[u8]) -> usize {
147 bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len())
148}
149
150#[inline(never)]
151fn copy_valid_utf8_prefix(dst: &mut [u8], src: &[u8], max_len: usize) -> usize {
152 let len = src.len().min(max_len);
153 match str::from_utf8(&src[..len]) {
154 Ok(_) => {
155 dst[..len].copy_from_slice(&src[..len]);
156 len
157 }
158 Err(e) => {
159 let valid = e.valid_up_to();
160 dst[..valid].copy_from_slice(&src[..valid]);
161 valid
162 }
163 }
164}