1use core::{fmt, fmt::Debug};
2use std::{
3 borrow::Cow,
4 hash::{Hash, Hasher},
5 marker::PhantomData,
6 mem::ManuallyDrop,
7};
8
9use crate::errors::SetBytesError;
10
11#[derive(Eq, PartialOrd, Ord)]
13pub struct Bytes<'a> {
14 data: BytesInner,
16 _lt: PhantomData<&'a [u8]>,
18}
19
20#[derive(PartialEq, Eq, PartialOrd, Ord)]
27enum BytesInner {
28 Borrowed(*const u8, u32),
30 Owned(*mut u8, u32),
34}
35
36impl<'a> PartialEq<str> for Bytes<'a> {
37 #[inline]
38 fn eq(&self, other: &str) -> bool {
39 self == other.as_bytes()
40 }
41}
42
43impl<'a> PartialEq<[u8]> for Bytes<'a> {
44 #[inline]
45 fn eq(&self, other: &[u8]) -> bool {
46 self.as_bytes() == other
47 }
48}
49
50impl<'a> PartialEq for Bytes<'a> {
51 #[inline]
52 fn eq(&self, other: &Self) -> bool {
53 let this = self.as_bytes();
54 let that = other.as_bytes();
55 this == that
56 }
57}
58
59impl<'a> Hash for Bytes<'a> {
60 #[inline]
61 fn hash<H: Hasher>(&self, state: &mut H) {
62 let this = self.as_bytes();
64 this.hash(state);
65 }
66}
67
68impl<'a> Clone for Bytes<'a> {
69 fn clone(&self) -> Self {
70 match &self.data {
76 BytesInner::Borrowed(data, len) => {
77 Bytes::from(unsafe { compact_bytes_to_slice(*data, *len) })
78 }
79 BytesInner::Owned(data, len) => {
80 let (ptr, len) = unsafe { clone_compact_bytes_parts(*data, *len) };
81 Bytes {
82 data: BytesInner::Owned(ptr, len),
83 _lt: PhantomData,
84 }
85 }
86 }
87 }
88}
89
90impl<'a> From<&'a str> for Bytes<'a> {
91 #[inline]
92 fn from(s: &'a str) -> Self {
93 <Self as From<&'a [u8]>>::from(s.as_bytes())
94 }
95}
96
97impl<'a> From<&'a [u8]> for Bytes<'a> {
98 #[inline]
99 fn from(s: &'a [u8]) -> Self {
100 Bytes {
101 data: BytesInner::Borrowed(s.as_ptr(), s.len() as u32),
102 _lt: PhantomData,
103 }
104 }
105}
106
107impl TryFrom<String> for Bytes<'static> {
108 type Error = SetBytesError;
109
110 #[inline]
111 fn try_from(s: String) -> Result<Self, Self::Error> {
112 let mut bytes = Bytes::new();
113 bytes.set(s)?;
114 Ok(bytes)
115 }
116}
117
118#[inline]
120unsafe fn compact_bytes_to_slice<'a>(ptr: *const u8, l: u32) -> &'a [u8] {
121 std::slice::from_raw_parts(ptr, l as usize)
122}
123
124unsafe fn boxed_slice_into_compact_parts(slice: Box<[u8]>) -> (*mut u8, u32) {
128 let mut slice = ManuallyDrop::new(slice);
130 let len = slice.len();
131 let ptr = slice.as_mut_ptr();
132
133 (ptr, len as u32)
134}
135
136#[inline]
138unsafe fn clone_compact_bytes_parts(ptr: *mut u8, len: u32) -> (*mut u8, u32) {
139 let slice = compact_bytes_to_slice(ptr, len).to_vec().into_boxed_slice();
140 boxed_slice_into_compact_parts(slice)
141}
142
143impl<'a> Debug for Bytes<'a> {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 f.debug_tuple("Bytes").field(&self.as_utf8_str()).finish()
148 }
149}
150
151impl<'a> Default for Bytes<'a> {
152 fn default() -> Self {
153 Self::new()
154 }
155}
156
157impl<'a> Bytes<'a> {
158 #[inline]
160 pub fn new() -> Self {
161 Self {
162 data: BytesInner::Borrowed("".as_bytes().as_ptr(), 0),
163 _lt: PhantomData,
164 }
165 }
166
167 #[inline]
169 pub fn as_utf8_str(&self) -> Cow<'_, str> {
170 String::from_utf8_lossy(self.as_bytes())
171 }
172
173 #[inline]
176 pub fn try_as_utf8_str(&self) -> Option<&str> {
177 std::str::from_utf8(self.as_bytes()).ok()
178 }
179
180 #[inline]
182 pub fn as_bytes(&self) -> &[u8] {
183 match &self.data {
184 BytesInner::Borrowed(b, l) => unsafe { compact_bytes_to_slice(*b, *l) },
185 BytesInner::Owned(o, l) => unsafe { compact_bytes_to_slice(*o, *l) },
186 }
187 }
188
189 pub(crate) fn into_ascii_lowercase(mut self) -> Self {
190 if self.as_bytes().iter().any(u8::is_ascii_uppercase) {
191 let normalized = self.as_bytes().to_ascii_lowercase();
192 drop(
193 self.set(normalized)
194 .expect("ASCII lowercasing cannot increase the byte length"),
195 );
196 }
197
198 self
199 }
200
201 #[inline]
206 pub fn as_bytes_borrowed(&self) -> Option<&'a [u8]> {
207 match &self.data {
208 BytesInner::Borrowed(b, l) => Some(unsafe { compact_bytes_to_slice(*b, *l) }),
209 _ => None,
210 }
211 }
212
213 #[inline]
215 pub fn as_ptr(&self) -> *const u8 {
216 match &self.data {
217 BytesInner::Borrowed(b, _) => *b,
218 BytesInner::Owned(o, _) => *o,
219 }
220 }
221
222 pub fn set<B: IntoOwnedBytes>(&mut self, data: B) -> Result<Option<Box<[u8]>>, SetBytesError> {
224 const MAX: usize = u32::MAX as usize;
225
226 let data = <B as IntoOwnedBytes>::into_bytes(data);
227
228 if data.len() > MAX {
229 return Err(SetBytesError::LengthOverflow);
230 }
231
232 Ok(unsafe { self.set_unchecked(data) })
234 }
235
236 #[inline]
241 pub unsafe fn set_unchecked<B: IntoOwnedBytes>(&mut self, data: B) -> Option<Box<[u8]>> {
242 let data = <B as IntoOwnedBytes>::into_bytes(data);
243
244 let (ptr, len) = boxed_slice_into_compact_parts(data);
245
246 let bytes = BytesInner::Owned(ptr, len);
247 let old = std::mem::replace(&mut self.data, bytes);
248
249 let old = ManuallyDrop::new(old);
251
252 match &*old {
253 BytesInner::Borrowed(_, _) => None,
254 BytesInner::Owned(ptr, len) => {
255 let len = *len as usize;
256 Some(Vec::from_raw_parts(*ptr, len, len).into_boxed_slice())
257 }
258 }
259 }
260}
261
262mod private {
263 pub trait Sealed {}
264}
265
266pub trait IntoOwnedBytes: private::Sealed {
270 fn into_bytes(self) -> Box<[u8]>;
271}
272
273macro_rules! impl_into_owned_bytes_trivial {
274 ($($t:ty),*) => {
275 $(
276 impl private::Sealed for $t {}
277 impl IntoOwnedBytes for $t {
278 #[inline]
279 fn into_bytes(self) -> Box<[u8]> {
280 self.into()
281 }
282 }
283 )*
284 };
285}
286
287impl_into_owned_bytes_trivial!(Box<[u8]>, &[u8], Vec<u8>);
288
289impl private::Sealed for &str {}
290impl IntoOwnedBytes for &str {
291 #[inline]
292 fn into_bytes(self) -> Box<[u8]> {
293 self.as_bytes().into()
294 }
295}
296
297impl private::Sealed for String {}
298impl IntoOwnedBytes for String {
299 #[inline]
300 fn into_bytes(self) -> Box<[u8]> {
301 self.into_bytes().into()
302 }
303}
304
305impl Drop for BytesInner {
306 fn drop(&mut self) {
307 if let BytesInner::Owned(ptr, len) = self {
310 let ptr = *ptr;
311 let len = *len as usize;
312
313 unsafe { drop(Vec::from_raw_parts(ptr, len, len).into_boxed_slice()) };
316 }
317 }
318}