1mod traits;
4
5#[unstable(feature = "bstr_internals", issue = "none")]
6pub use traits::{impl_partial_eq, impl_partial_eq_n, impl_partial_eq_ord};
7
8use crate::borrow::{Borrow, BorrowMut};
9use crate::fmt;
10use crate::fmt::Alignment;
11use crate::ops::{Deref, DerefMut, DerefPure};
12
13#[unstable(feature = "bstr", issue = "134915")]
42#[rustc_has_incoherent_inherent_impls]
43#[repr(transparent)]
44#[doc(alias = "BStr")]
45#[ferrocene::prevalidated]
46pub struct ByteStr(pub [u8]);
47
48impl ByteStr {
49 #[inline]
68 #[unstable(feature = "bstr", issue = "134915")]
69 #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
70 pub const fn new<B: ?Sized + [const] AsRef<[u8]>>(bytes: &B) -> &Self {
71 ByteStr::from_bytes(bytes.as_ref())
72 }
73
74 #[inline]
80 #[unstable(feature = "bstr", issue = "134915")]
82 pub const fn as_byte_str(&self) -> &ByteStr {
83 self
84 }
85
86 #[inline]
92 #[unstable(feature = "bstr", issue = "134915")]
94 pub const fn as_mut_byte_str(&mut self) -> &mut ByteStr {
95 self
96 }
97
98 #[doc(hidden)]
99 #[unstable(feature = "bstr_internals", issue = "none")]
100 #[inline]
101 #[rustc_const_unstable(feature = "bstr_internals", issue = "none")]
102 #[ferrocene::prevalidated]
103 pub const fn from_bytes(slice: &[u8]) -> &Self {
104 unsafe { &*(slice as *const [u8] as *const Self) }
107 }
108
109 #[doc(hidden)]
110 #[unstable(feature = "bstr_internals", issue = "none")]
111 #[inline]
112 #[rustc_const_unstable(feature = "bstr_internals", issue = "none")]
113 pub const fn from_bytes_mut(slice: &mut [u8]) -> &mut Self {
114 unsafe { &mut *(slice as *mut [u8] as *mut Self) }
117 }
118
119 #[doc(hidden)]
120 #[unstable(feature = "bstr_internals", issue = "none")]
121 #[inline]
122 #[rustc_const_unstable(feature = "bstr_internals", issue = "none")]
123 pub const fn as_bytes(&self) -> &[u8] {
124 &self.0
125 }
126
127 #[doc(hidden)]
128 #[unstable(feature = "bstr_internals", issue = "none")]
129 #[inline]
130 #[rustc_const_unstable(feature = "bstr_internals", issue = "none")]
131 pub const fn as_bytes_mut(&mut self) -> &mut [u8] {
132 &mut self.0
133 }
134}
135
136#[unstable(feature = "bstr", issue = "134915")]
137#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
138const impl Deref for ByteStr {
139 type Target = [u8];
140
141 #[inline]
142 #[ferrocene::prevalidated]
143 fn deref(&self) -> &[u8] {
144 &self.0
145 }
146}
147
148#[unstable(feature = "bstr", issue = "134915")]
149#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
150const impl DerefMut for ByteStr {
151 #[inline]
152 #[ferrocene::prevalidated]
153 fn deref_mut(&mut self) -> &mut [u8] {
154 &mut self.0
155 }
156}
157
158#[unstable(feature = "deref_pure_trait", issue = "87121")]
159unsafe impl DerefPure for ByteStr {}
160
161#[unstable(feature = "bstr", issue = "134915")]
162impl fmt::Debug for ByteStr {
163 #[ferrocene::prevalidated]
164 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165 write!(f, "\"")?;
166 for chunk in self.utf8_chunks() {
167 for c in chunk.valid().chars() {
168 match c {
169 '\0' => write!(f, "\\0")?,
170 '\x01'..='\x7f' => write!(f, "{}", (c as u8).escape_ascii())?,
171 _ => write!(f, "{}", c.escape_debug())?,
172 }
173 }
174 write!(f, "{}", chunk.invalid().escape_ascii())?;
175 }
176 write!(f, "\"")?;
177 Ok(())
178 }
179}
180
181#[unstable(feature = "bstr_to_string", issue = "134915")]
182impl fmt::Display for ByteStr {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 fn emit(byte_str: &ByteStr, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 for chunk in byte_str.utf8_chunks() {
186 f.write_str(chunk.valid())?;
187 if !chunk.invalid().is_empty() {
188 f.write_str("\u{FFFD}")?;
189 }
190 }
191
192 Ok(())
193 }
194
195 let requested_width = f.width().unwrap_or(0);
196 if requested_width == 0 && f.precision().is_none() {
197 return emit(self, f);
200 }
201
202 let (truncated, actual_width) = match f.precision() {
203 Some(0) => (ByteStr::new(&[]), 0),
205 Some(precision) => {
207 let mut remaining_width = precision;
208 let mut chunks = self.utf8_chunks();
209 let mut current_width = 0;
210 let mut offset = 0;
211 loop {
212 let Some(chunk) = chunks.next() else {
213 break (self, current_width);
216 };
217
218 let mut chars = chunk.valid().char_indices();
219 let Err(remaining) = chars.advance_by(remaining_width) else {
220 break (&self[..offset + chars.offset()], precision);
223 };
224
225 offset += chunk.valid().len();
226 current_width += remaining_width - remaining.get();
227 remaining_width = remaining.get();
228
229 if !chunk.invalid().is_empty() {
233 offset += chunk.invalid().len();
234 current_width += 1;
235 remaining_width -= 1;
236
237 if remaining_width == 0 {
238 break (&self[..offset], precision);
239 }
240 }
241 }
242 }
243 None => {
246 let actual_width = self
247 .utf8_chunks()
248 .map(|chunk| {
249 chunk.valid().chars().count()
250 + if chunk.invalid().is_empty() { 0 } else { 1 }
251 })
252 .sum();
253 (self, actual_width)
254 }
255 };
256
257 let padding = u16::try_from(requested_width.saturating_sub(actual_width)).unwrap();
259
260 let post_padding = f.padding(padding, Alignment::Left)?;
261 emit(truncated, f)?;
262 post_padding.write(f)
263 }
264}
265
266#[unstable(feature = "bstr", issue = "134915")]
267#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
268const impl AsRef<[u8]> for ByteStr {
269 #[inline]
270 fn as_ref(&self) -> &[u8] {
271 &self.0
272 }
273}
274
275#[unstable(feature = "bstr", issue = "134915")]
276#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
277const impl AsRef<ByteStr> for ByteStr {
278 #[inline]
279 fn as_ref(&self) -> &ByteStr {
280 self
281 }
282}
283
284#[unstable(feature = "bstr", issue = "134915")]
287#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
288const impl AsRef<ByteStr> for str {
289 #[inline]
290 fn as_ref(&self) -> &ByteStr {
291 ByteStr::new(self)
292 }
293}
294
295#[unstable(feature = "bstr", issue = "134915")]
296#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
297const impl AsMut<[u8]> for ByteStr {
298 #[inline]
299 fn as_mut(&mut self) -> &mut [u8] {
300 &mut self.0
301 }
302}
303
304#[unstable(feature = "bstr", issue = "134915")]
311#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
312const impl Borrow<[u8]> for ByteStr {
313 #[inline]
314 fn borrow(&self) -> &[u8] {
315 &self.0
316 }
317}
318
319#[unstable(feature = "bstr", issue = "134915")]
322#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
323const impl BorrowMut<[u8]> for ByteStr {
324 #[inline]
325 fn borrow_mut(&mut self) -> &mut [u8] {
326 &mut self.0
327 }
328}
329
330#[unstable(feature = "bstr", issue = "134915")]
331impl<'a> Default for &'a ByteStr {
332 fn default() -> Self {
333 ByteStr::from_bytes(b"")
334 }
335}
336
337#[unstable(feature = "bstr", issue = "134915")]
338impl<'a> Default for &'a mut ByteStr {
339 fn default() -> Self {
340 ByteStr::from_bytes_mut(&mut [])
341 }
342}
343
344#[unstable(feature = "bstr", issue = "134915")]
391#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
392const impl<'a> TryFrom<&'a ByteStr> for &'a str {
393 type Error = crate::str::Utf8Error;
394
395 #[inline]
396 fn try_from(s: &'a ByteStr) -> Result<Self, Self::Error> {
397 crate::str::from_utf8(&s.0)
398 }
399}
400
401#[unstable(feature = "bstr", issue = "134915")]
402#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
403const impl<'a> TryFrom<&'a mut ByteStr> for &'a mut str {
404 type Error = crate::str::Utf8Error;
405
406 #[inline]
407 fn try_from(s: &'a mut ByteStr) -> Result<Self, Self::Error> {
408 crate::str::from_utf8_mut(&mut s.0)
409 }
410}