• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::borrow::Borrow;
2 use std::borrow::Cow;
3 use std::borrow::ToOwned;
4 use std::ffi::OsStr;
5 use std::ffi::OsString;
6 use std::fmt;
7 use std::fmt::Debug;
8 use std::fmt::Display;
9 use std::fmt::Formatter;
10 use std::mem;
11 use std::ops::Deref;
12 use std::ops::Index;
13 use std::ops::Range;
14 use std::ops::RangeFrom;
15 use std::ops::RangeFull;
16 use std::ops::RangeInclusive;
17 use std::ops::RangeTo;
18 use std::ops::RangeToInclusive;
19 use std::result;
20 use std::str;
21 
22 #[cfg(feature = "memchr")]
23 use memchr::memmem::find;
24 #[cfg(feature = "memchr")]
25 use memchr::memmem::rfind;
26 
27 use super::imp;
28 use super::imp::raw;
29 use super::iter::Split;
30 use super::pattern::Encoded as EncodedPattern;
31 use super::private;
32 use super::Pattern;
33 
34 if_checked_conversions! {
35     use super::EncodingError;
36     use super::Result;
37 }
38 
39 #[cfg(not(feature = "memchr"))]
find(string: &[u8], pat: &[u8]) -> Option<usize>40 fn find(string: &[u8], pat: &[u8]) -> Option<usize> {
41     (0..=string.len().checked_sub(pat.len())?)
42         .find(|&x| string[x..].starts_with(pat))
43 }
44 
45 #[cfg(not(feature = "memchr"))]
rfind(string: &[u8], pat: &[u8]) -> Option<usize>46 fn rfind(string: &[u8], pat: &[u8]) -> Option<usize> {
47     (pat.len()..=string.len())
48         .rfind(|&x| string[..x].ends_with(pat))
49         .map(|x| x - pat.len())
50 }
51 
52 #[allow(clippy::missing_safety_doc)]
53 unsafe trait TransmuteBox {
transmute_box<R>(self: Box<Self>) -> Box<R> where R: ?Sized + TransmuteBox,54     fn transmute_box<R>(self: Box<Self>) -> Box<R>
55     where
56         R: ?Sized + TransmuteBox,
57     {
58         let value = Box::into_raw(self);
59         // SAFETY: This trait is only implemented for types that can be
60         // transmuted.
61         unsafe { Box::from_raw(mem::transmute_copy(&value)) }
62     }
63 }
64 
65 // SAFETY: This struct has a layout that makes this operation safe.
66 unsafe impl TransmuteBox for RawOsStr {}
67 unsafe impl TransmuteBox for [u8] {}
68 
69 /// A container for borrowed byte strings converted by this crate.
70 ///
71 /// This wrapper is intended to prevent violating the invariants of the
72 /// [unspecified encoding] used by this crate and minimize encoding
73 /// conversions.
74 ///
75 /// # Indices
76 ///
77 /// Methods of this struct that accept indices require that the index lie on a
78 /// UTF-8 boundary. Although it is possible to manipulate platform strings
79 /// based on other indices, this crate currently does not support them for
80 /// slicing methods. They would add significant complication to the
81 /// implementation and are generally not necessary. However, all indices
82 /// returned by this struct can be used for slicing.
83 ///
84 /// On Unix, all indices are permitted, to avoid false positives. However,
85 /// relying on this implementation detail is discouraged. Platform-specific
86 /// indices are error-prone.
87 ///
88 /// # Complexity
89 ///
90 /// All searching methods have worst-case multiplicative time complexity (i.e.,
91 /// `O(self.raw_len() * pat.len())`). Enabling the "memchr" feature allows
92 /// these methods to instead run in linear time in the worst case (documented
93 /// for [`memchr::memmem::find`][memchr complexity]).
94 ///
95 /// # Safety
96 ///
97 /// Although this type is annotated with `#[repr(transparent)]`, the inner
98 /// representation is not stable. Transmuting between this type and any other
99 /// causes immediate undefined behavior.
100 ///
101 /// [memchr complexity]: memchr::memmem::find#complexity
102 /// [unspecified encoding]: super#encoding
103 #[derive(Eq, Hash, Ord, PartialEq, PartialOrd)]
104 #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "raw_os_str")))]
105 #[repr(transparent)]
106 pub struct RawOsStr([u8]);
107 
108 impl RawOsStr {
from_inner(string: &[u8]) -> &Self109     const fn from_inner(string: &[u8]) -> &Self {
110         // SAFETY: This struct has a layout that makes this operation safe.
111         unsafe { mem::transmute(string) }
112     }
113 
114     /// Converts a platform-native string into a representation that can be
115     /// more easily manipulated.
116     ///
117     /// This method performs the necessary conversion immediately, so it can be
118     /// expensive to call. It is recommended to continue using the returned
119     /// instance as long as possible (instead of the original [`OsStr`]), to
120     /// avoid repeated conversions.
121     ///
122     /// # Examples
123     ///
124     /// ```
125     /// use std::env;
126     /// # use std::io;
127     ///
128     /// use os_str_bytes::RawOsStr;
129     ///
130     /// let os_string = env::current_exe()?.into_os_string();
131     /// println!("{:?}", RawOsStr::new(&os_string));
132     /// #
133     /// # Ok::<_, io::Error>(())
134     /// ```
135     #[inline]
136     #[must_use]
new(string: &OsStr) -> Cow<'_, Self>137     pub fn new(string: &OsStr) -> Cow<'_, Self> {
138         match imp::os_str_to_bytes(string) {
139             Cow::Borrowed(string) => Cow::Borrowed(Self::from_inner(string)),
140             Cow::Owned(string) => Cow::Owned(RawOsString(string)),
141         }
142     }
143 
144     /// Wraps a string, without copying or encoding conversion.
145     ///
146     /// This method is much more efficient than [`RawOsStr::new`], since the
147     /// [encoding] used by this crate is compatible with UTF-8.
148     ///
149     /// # Examples
150     ///
151     /// ```
152     /// use os_str_bytes::RawOsStr;
153     ///
154     /// let string = "foobar";
155     /// let raw = RawOsStr::from_str(string);
156     /// assert_eq!(string, raw);
157     /// ```
158     ///
159     /// [encoding]: super#encoding
160     #[allow(clippy::should_implement_trait)]
161     #[inline]
162     #[must_use]
from_str(string: &str) -> &Self163     pub fn from_str(string: &str) -> &Self {
164         Self::from_inner(string.as_bytes())
165     }
166 
167     /// Wraps a byte string, without copying or encoding conversion.
168     ///
169     /// # Panics
170     ///
171     /// Panics if the string is not valid for the [unspecified encoding] used
172     /// by this crate.
173     ///
174     /// # Examples
175     ///
176     /// ```
177     /// use std::env;
178     /// # use std::io;
179     ///
180     /// use os_str_bytes::RawOsStr;
181     ///
182     /// let os_string = env::current_exe()?.into_os_string();
183     /// let raw = RawOsStr::new(&os_string);
184     /// let raw_bytes = raw.as_raw_bytes();
185     /// assert_eq!(&*raw, RawOsStr::assert_from_raw_bytes(raw_bytes));
186     /// #
187     /// # Ok::<_, io::Error>(())
188     /// ```
189     ///
190     /// [unspecified encoding]: super#encoding
191     #[inline]
192     #[must_use = "method should not be used for validation"]
193     #[track_caller]
assert_from_raw_bytes(string: &[u8]) -> &Self194     pub fn assert_from_raw_bytes(string: &[u8]) -> &Self {
195         expect_encoded!(raw::validate_bytes(string));
196 
197         Self::from_inner(string)
198     }
199 
200     if_checked_conversions! {
201         /// Wraps a byte string, without copying or encoding conversion.
202         ///
203         /// [`assert_from_raw_bytes`] should almost always be used instead. For
204         /// more information, see [`EncodingError`].
205         ///
206         /// # Errors
207         ///
208         /// See documentation for [`EncodingError`].
209         ///
210         /// # Examples
211         ///
212         /// ```
213         /// use std::env;
214         /// # use std::io;
215         ///
216         /// use os_str_bytes::RawOsStr;
217         ///
218         /// let os_string = env::current_exe()?.into_os_string();
219         /// let raw = RawOsStr::new(&os_string);
220         /// assert_eq!(Ok(&*raw), RawOsStr::from_raw_bytes(raw.as_raw_bytes()));
221         /// #
222         /// # Ok::<_, io::Error>(())
223         /// ```
224         ///
225         /// [`assert_from_raw_bytes`]: Self::assert_from_raw_bytes
226         #[cfg_attr(
227             os_str_bytes_docs_rs,
228             doc(cfg(feature = "checked_conversions"))
229         )]
230         #[inline]
231         pub fn from_raw_bytes(string: &[u8]) -> Result<&Self> {
232             raw::validate_bytes(string)
233                 .map(|()| Self::from_inner(string))
234                 .map_err(EncodingError)
235         }
236     }
237 
238     /// Wraps a byte string, without copying or encoding conversion.
239     ///
240     /// # Safety
241     ///
242     /// The string must be valid for the [unspecified encoding] used by this
243     /// crate.
244     ///
245     /// # Examples
246     ///
247     /// ```
248     /// use std::env;
249     /// # use std::io;
250     ///
251     /// use os_str_bytes::RawOsStr;
252     ///
253     /// let os_string = env::current_exe()?.into_os_string();
254     /// let raw = RawOsStr::new(&os_string);
255     /// let raw_bytes = raw.as_raw_bytes();
256     /// assert_eq!(&*raw, unsafe {
257     ///     RawOsStr::from_raw_bytes_unchecked(raw_bytes)
258     /// });
259     /// #
260     /// # Ok::<_, io::Error>(())
261     /// ```
262     ///
263     /// [unspecified encoding]: super#encoding
264     #[inline]
265     #[must_use]
266     #[track_caller]
from_raw_bytes_unchecked(string: &[u8]) -> &Self267     pub unsafe fn from_raw_bytes_unchecked(string: &[u8]) -> &Self {
268         if cfg!(debug_assertions) {
269             expect_encoded!(raw::validate_bytes(string));
270         }
271 
272         Self::from_inner(string)
273     }
274 
275     /// Returns the byte string stored by this container.
276     ///
277     /// The returned string will use an [unspecified encoding].
278     ///
279     /// # Examples
280     ///
281     /// ```
282     /// use os_str_bytes::RawOsStr;
283     ///
284     /// let string = "foobar";
285     /// let raw = RawOsStr::from_str(string);
286     /// assert_eq!(string.as_bytes(), raw.as_raw_bytes());
287     /// ```
288     ///
289     /// [unspecified encoding]: super#encoding
290     #[inline]
291     #[must_use]
as_raw_bytes(&self) -> &[u8]292     pub fn as_raw_bytes(&self) -> &[u8] {
293         &self.0
294     }
295 
296     /// Equivalent to [`str::contains`].
297     ///
298     /// # Examples
299     ///
300     /// ```
301     /// use os_str_bytes::RawOsStr;
302     ///
303     /// let raw = RawOsStr::from_str("foobar");
304     /// assert!(raw.contains("oo"));
305     /// assert!(!raw.contains("of"));
306     /// ```
307     #[inline]
308     #[must_use]
contains<P>(&self, pat: P) -> bool where P: Pattern,309     pub fn contains<P>(&self, pat: P) -> bool
310     where
311         P: Pattern,
312     {
313         self.find(pat).is_some()
314     }
315 
316     /// Equivalent to [`str::ends_with`].
317     ///
318     /// # Examples
319     ///
320     /// ```
321     /// use os_str_bytes::RawOsStr;
322     ///
323     /// let raw = RawOsStr::from_str("foobar");
324     /// assert!(raw.ends_with("bar"));
325     /// assert!(!raw.ends_with("foo"));
326     /// ```
327     #[inline]
328     #[must_use]
ends_with<P>(&self, pat: P) -> bool where P: Pattern,329     pub fn ends_with<P>(&self, pat: P) -> bool
330     where
331         P: Pattern,
332     {
333         let pat = pat.__encode();
334         let pat = pat.__get();
335 
336         self.0.ends_with(pat)
337     }
338 
339     /// Equivalent to [`str::ends_with`] but accepts this type for the pattern.
340     ///
341     /// # Examples
342     ///
343     /// ```
344     /// use os_str_bytes::RawOsStr;
345     ///
346     /// let raw = RawOsStr::from_str("foobar");
347     /// assert!(raw.ends_with_os(RawOsStr::from_str("bar")));
348     /// assert!(!raw.ends_with_os(RawOsStr::from_str("foo")));
349     /// ```
350     #[inline]
351     #[must_use]
ends_with_os(&self, pat: &Self) -> bool352     pub fn ends_with_os(&self, pat: &Self) -> bool {
353         raw::ends_with(&self.0, &pat.0)
354     }
355 
356     /// Equivalent to [`str::find`].
357     ///
358     /// # Examples
359     ///
360     /// ```
361     /// use os_str_bytes::RawOsStr;
362     ///
363     /// let raw = RawOsStr::from_str("foobar");
364     /// assert_eq!(Some(1), raw.find("o"));
365     /// assert_eq!(None, raw.find("of"));
366     /// ```
367     #[inline]
368     #[must_use]
find<P>(&self, pat: P) -> Option<usize> where P: Pattern,369     pub fn find<P>(&self, pat: P) -> Option<usize>
370     where
371         P: Pattern,
372     {
373         let pat = pat.__encode();
374         let pat = pat.__get();
375 
376         find(&self.0, pat)
377     }
378 
379     /// Equivalent to [`str::is_empty`].
380     ///
381     /// # Examples
382     ///
383     /// ```
384     /// use os_str_bytes::RawOsStr;
385     ///
386     /// assert!(RawOsStr::from_str("").is_empty());
387     /// assert!(!RawOsStr::from_str("foobar").is_empty());
388     /// ```
389     #[inline]
390     #[must_use]
is_empty(&self) -> bool391     pub fn is_empty(&self) -> bool {
392         self.0.is_empty()
393     }
394 
395     /// Returns the length of the byte string stored by this container.
396     ///
397     /// Only the following assumptions can be made about the result:
398     /// - The length of any Unicode character is the length of its UTF-8
399     ///   representation (i.e., [`char::len_utf8`]).
400     /// - Splitting a string at a UTF-8 boundary will return two strings with
401     ///   lengths that sum to the length of the original string.
402     ///
403     /// This method may return a different result than would [`OsStr::len`]
404     /// when called on same string, since [`OsStr`] uses an unspecified
405     /// encoding.
406     ///
407     /// # Examples
408     ///
409     /// ```
410     /// use os_str_bytes::RawOsStr;
411     ///
412     /// assert_eq!(6, RawOsStr::from_str("foobar").raw_len());
413     /// assert_eq!(0, RawOsStr::from_str("").raw_len());
414     /// ```
415     #[inline]
416     #[must_use]
raw_len(&self) -> usize417     pub fn raw_len(&self) -> usize {
418         self.0.len()
419     }
420 
421     /// Equivalent to [`str::rfind`].
422     ///
423     /// # Examples
424     ///
425     /// ```
426     /// use os_str_bytes::RawOsStr;
427     ///
428     /// let raw = RawOsStr::from_str("foobar");
429     /// assert_eq!(Some(2), raw.rfind("o"));
430     /// assert_eq!(None, raw.rfind("of"));
431     /// ```
432     #[inline]
433     #[must_use]
rfind<P>(&self, pat: P) -> Option<usize> where P: Pattern,434     pub fn rfind<P>(&self, pat: P) -> Option<usize>
435     where
436         P: Pattern,
437     {
438         let pat = pat.__encode();
439         let pat = pat.__get();
440 
441         rfind(&self.0, pat)
442     }
443 
split_once_raw_with<P, F>( &self, pat: &P, find_fn: F, ) -> Option<(&Self, &Self)> where F: FnOnce(&[u8], &[u8]) -> Option<usize>, P: EncodedPattern,444     fn split_once_raw_with<P, F>(
445         &self,
446         pat: &P,
447         find_fn: F,
448     ) -> Option<(&Self, &Self)>
449     where
450         F: FnOnce(&[u8], &[u8]) -> Option<usize>,
451         P: EncodedPattern,
452     {
453         let pat = pat.__get();
454 
455         let index = find_fn(&self.0, pat)?;
456         let prefix = &self.0[..index];
457         let suffix = &self.0[index + pat.len()..];
458         Some((Self::from_inner(prefix), Self::from_inner(suffix)))
459     }
460 
rsplit_once_raw<P>(&self, pat: &P) -> Option<(&Self, &Self)> where P: EncodedPattern,461     pub(super) fn rsplit_once_raw<P>(&self, pat: &P) -> Option<(&Self, &Self)>
462     where
463         P: EncodedPattern,
464     {
465         self.split_once_raw_with(pat, rfind)
466     }
467 
468     /// Equivalent to [`str::rsplit_once`].
469     ///
470     /// # Examples
471     ///
472     /// ```
473     /// use os_str_bytes::RawOsStr;
474     ///
475     /// let raw = RawOsStr::from_str("foobar");
476     /// assert_eq!(
477     ///     Some((RawOsStr::from_str("fo"), RawOsStr::from_str("bar"))),
478     ///     raw.rsplit_once("o"),
479     /// );
480     /// assert_eq!(None, raw.rsplit_once("of"));
481     /// ```
482     #[inline]
483     #[must_use]
rsplit_once<P>(&self, pat: P) -> Option<(&Self, &Self)> where P: Pattern,484     pub fn rsplit_once<P>(&self, pat: P) -> Option<(&Self, &Self)>
485     where
486         P: Pattern,
487     {
488         self.rsplit_once_raw(&pat.__encode())
489     }
490 
491     // https://github.com/rust-lang/rust/blob/49c68bd53f90e375bfb3cbba8c1c67a9e0adb9c0/src/libcore/str/mod.rs#L2184-L2221
492     #[cold]
493     #[inline(never)]
494     #[track_caller]
index_boundary_error(&self, index: usize) -> !495     fn index_boundary_error(&self, index: usize) -> ! {
496         debug_assert!(raw::is_continuation(self.0[index]));
497 
498         let start = expect_encoded!(self.0[..index]
499             .iter()
500             .rposition(|&x| !raw::is_continuation(x)));
501         let mut end = index + 1;
502         end += self.0[end..]
503             .iter()
504             .take_while(|&&x| raw::is_continuation(x))
505             .count();
506         let code_point = raw::decode_code_point(&self.0[start..end]);
507         panic!(
508             "byte index {} is not a valid boundary; it is inside U+{:04X} \
509              (bytes {}..{})",
510             index, code_point, start, end,
511         );
512     }
513 
514     #[track_caller]
check_bound(&self, index: usize)515     fn check_bound(&self, index: usize) {
516         if let Some(&byte) = self.0.get(index) {
517             if raw::is_continuation(byte) {
518                 self.index_boundary_error(index);
519             }
520         }
521     }
522 
523     /// Equivalent to [`str::split`], but empty patterns are not accepted.
524     ///
525     /// # Panics
526     ///
527     /// Panics if the pattern is empty.
528     ///
529     /// # Examples
530     ///
531     /// ```
532     /// use os_str_bytes::RawOsStr;
533     ///
534     /// let raw = RawOsStr::from_str("foobar");
535     /// assert_eq!(["f", "", "bar"], *raw.split("o").collect::<Vec<_>>());
536     /// ```
537     #[inline]
538     #[must_use]
539     #[track_caller]
split<P>(&self, pat: P) -> Split<'_, P> where P: Pattern,540     pub fn split<P>(&self, pat: P) -> Split<'_, P>
541     where
542         P: Pattern,
543     {
544         Split::new(self, pat)
545     }
546 
547     /// Equivalent to [`str::split_at`].
548     ///
549     /// # Panics
550     ///
551     /// Panics if the index is not a [valid boundary].
552     ///
553     /// # Examples
554     ///
555     /// ```
556     /// use os_str_bytes::RawOsStr;
557     ///
558     /// let raw = RawOsStr::from_str("foobar");
559     /// assert_eq!(
560     ///     ((RawOsStr::from_str("fo"), RawOsStr::from_str("obar"))),
561     ///     raw.split_at(2),
562     /// );
563     /// ```
564     ///
565     /// [valid boundary]: #indices
566     #[inline]
567     #[must_use]
568     #[track_caller]
split_at(&self, mid: usize) -> (&Self, &Self)569     pub fn split_at(&self, mid: usize) -> (&Self, &Self) {
570         self.check_bound(mid);
571 
572         let (prefix, suffix) = self.0.split_at(mid);
573         (Self::from_inner(prefix), Self::from_inner(suffix))
574     }
575 
split_once_raw<P>(&self, pat: &P) -> Option<(&Self, &Self)> where P: EncodedPattern,576     pub(super) fn split_once_raw<P>(&self, pat: &P) -> Option<(&Self, &Self)>
577     where
578         P: EncodedPattern,
579     {
580         self.split_once_raw_with(pat, find)
581     }
582 
583     /// Equivalent to [`str::split_once`].
584     ///
585     /// # Examples
586     ///
587     /// ```
588     /// use os_str_bytes::RawOsStr;
589     ///
590     /// let raw = RawOsStr::from_str("foobar");
591     /// assert_eq!(
592     ///     Some((RawOsStr::from_str("f"), RawOsStr::from_str("obar"))),
593     ///     raw.split_once("o"),
594     /// );
595     /// assert_eq!(None, raw.split_once("of"));
596     /// ```
597     #[inline]
598     #[must_use]
split_once<P>(&self, pat: P) -> Option<(&Self, &Self)> where P: Pattern,599     pub fn split_once<P>(&self, pat: P) -> Option<(&Self, &Self)>
600     where
601         P: Pattern,
602     {
603         self.split_once_raw(&pat.__encode())
604     }
605 
606     /// Equivalent to [`str::starts_with`].
607     ///
608     /// # Examples
609     ///
610     /// ```
611     /// use os_str_bytes::RawOsStr;
612     ///
613     /// let raw = RawOsStr::from_str("foobar");
614     /// assert!(raw.starts_with("foo"));
615     /// assert!(!raw.starts_with("bar"));
616     /// ```
617     #[inline]
618     #[must_use]
starts_with<P>(&self, pat: P) -> bool where P: Pattern,619     pub fn starts_with<P>(&self, pat: P) -> bool
620     where
621         P: Pattern,
622     {
623         let pat = pat.__encode();
624         let pat = pat.__get();
625 
626         self.0.starts_with(pat)
627     }
628 
629     /// Equivalent to [`str::starts_with`] but accepts this type for the
630     /// pattern.
631     ///
632     /// # Examples
633     ///
634     /// ```
635     /// use os_str_bytes::RawOsStr;
636     ///
637     /// let raw = RawOsStr::from_str("foobar");
638     /// assert!(raw.starts_with_os(RawOsStr::from_str("foo")));
639     /// assert!(!raw.starts_with_os(RawOsStr::from_str("bar")));
640     /// ```
641     #[inline]
642     #[must_use]
starts_with_os(&self, pat: &Self) -> bool643     pub fn starts_with_os(&self, pat: &Self) -> bool {
644         raw::starts_with(&self.0, &pat.0)
645     }
646 
647     /// Equivalent to [`str::strip_prefix`].
648     ///
649     /// # Examples
650     ///
651     /// ```
652     /// use os_str_bytes::RawOsStr;
653     ///
654     /// let raw = RawOsStr::from_str("111foo1bar111");
655     /// assert_eq!(
656     ///     Some(RawOsStr::from_str("11foo1bar111")),
657     ///     raw.strip_prefix("1"),
658     /// );
659     /// assert_eq!(None, raw.strip_prefix("o"));
660     /// ```
661     #[inline]
662     #[must_use]
strip_prefix<P>(&self, pat: P) -> Option<&Self> where P: Pattern,663     pub fn strip_prefix<P>(&self, pat: P) -> Option<&Self>
664     where
665         P: Pattern,
666     {
667         let pat = pat.__encode();
668         let pat = pat.__get();
669 
670         self.0.strip_prefix(pat).map(Self::from_inner)
671     }
672 
673     /// Equivalent to [`str::strip_suffix`].
674     ///
675     /// # Examples
676     ///
677     /// ```
678     /// use os_str_bytes::RawOsStr;
679     ///
680     /// let raw = RawOsStr::from_str("111foo1bar111");
681     /// assert_eq!(
682     ///     Some(RawOsStr::from_str("111foo1bar11")),
683     ///     raw.strip_suffix("1"),
684     /// );
685     /// assert_eq!(None, raw.strip_suffix("o"));
686     /// ```
687     #[inline]
688     #[must_use]
strip_suffix<P>(&self, pat: P) -> Option<&Self> where P: Pattern,689     pub fn strip_suffix<P>(&self, pat: P) -> Option<&Self>
690     where
691         P: Pattern,
692     {
693         let pat = pat.__encode();
694         let pat = pat.__get();
695 
696         self.0.strip_suffix(pat).map(Self::from_inner)
697     }
698 
699     /// Converts this representation back to a platform-native string.
700     ///
701     /// When possible, use [`RawOsStrCow::into_os_str`] for a more efficient
702     /// conversion on some platforms.
703     ///
704     /// # Examples
705     ///
706     /// ```
707     /// use std::env;
708     /// # use std::io;
709     ///
710     /// use os_str_bytes::RawOsStr;
711     ///
712     /// let os_string = env::current_exe()?.into_os_string();
713     /// let raw = RawOsStr::new(&os_string);
714     /// assert_eq!(os_string, raw.to_os_str());
715     /// #
716     /// # Ok::<_, io::Error>(())
717     /// ```
718     #[inline]
719     #[must_use]
to_os_str(&self) -> Cow<'_, OsStr>720     pub fn to_os_str(&self) -> Cow<'_, OsStr> {
721         expect_encoded!(imp::os_str_from_bytes(&self.0))
722     }
723 
724     /// Equivalent to [`OsStr::to_str`].
725     ///
726     /// # Examples
727     ///
728     /// ```
729     /// use os_str_bytes::RawOsStr;
730     ///
731     /// let string = "foobar";
732     /// let raw = RawOsStr::from_str(string);
733     /// assert_eq!(Some(string), raw.to_str());
734     /// ```
735     #[inline]
736     #[must_use]
to_str(&self) -> Option<&str>737     pub fn to_str(&self) -> Option<&str> {
738         str::from_utf8(&self.0).ok()
739     }
740 
741     /// Converts this string to the best UTF-8 representation possible.
742     ///
743     /// Invalid sequences will be replaced with
744     /// [`char::REPLACEMENT_CHARACTER`].
745     ///
746     /// This method may return a different result than would
747     /// [`OsStr::to_string_lossy`] when called on same string, since [`OsStr`]
748     /// uses an unspecified encoding.
749     ///
750     /// # Examples
751     ///
752     /// ```
753     /// use std::env;
754     /// # use std::io;
755     ///
756     /// use os_str_bytes::RawOsStr;
757     ///
758     /// let os_string = env::current_exe()?.into_os_string();
759     /// let raw = RawOsStr::new(&os_string);
760     /// println!("{}", raw.to_str_lossy());
761     /// #
762     /// # Ok::<_, io::Error>(())
763     /// ```
764     #[inline]
765     #[must_use]
to_str_lossy(&self) -> Cow<'_, str>766     pub fn to_str_lossy(&self) -> Cow<'_, str> {
767         String::from_utf8_lossy(&self.0)
768     }
769 
trim_matches_raw_with<P, F>(&self, pat: &P, strip_fn: F) -> &Self where F: for<'a> Fn(&'a [u8], &[u8]) -> Option<&'a [u8]>, P: EncodedPattern,770     fn trim_matches_raw_with<P, F>(&self, pat: &P, strip_fn: F) -> &Self
771     where
772         F: for<'a> Fn(&'a [u8], &[u8]) -> Option<&'a [u8]>,
773         P: EncodedPattern,
774     {
775         let pat = pat.__get();
776         if pat.is_empty() {
777             return self;
778         }
779 
780         let mut string = &self.0;
781         while let Some(substring) = strip_fn(string, pat) {
782             string = substring;
783         }
784         Self::from_inner(string)
785     }
786 
trim_end_matches_raw<P>(&self, pat: &P) -> &Self where P: EncodedPattern,787     fn trim_end_matches_raw<P>(&self, pat: &P) -> &Self
788     where
789         P: EncodedPattern,
790     {
791         self.trim_matches_raw_with(pat, <[_]>::strip_suffix)
792     }
793 
794     /// Equivalent to [`str::trim_end_matches`].
795     ///
796     /// # Examples
797     ///
798     /// ```
799     /// use os_str_bytes::RawOsStr;
800     ///
801     /// let raw = RawOsStr::from_str("111foo1bar111");
802     /// assert_eq!("111foo1bar", raw.trim_end_matches("1"));
803     /// assert_eq!("111foo1bar111", raw.trim_end_matches("o"));
804     /// ```
805     #[inline]
806     #[must_use]
trim_end_matches<P>(&self, pat: P) -> &Self where P: Pattern,807     pub fn trim_end_matches<P>(&self, pat: P) -> &Self
808     where
809         P: Pattern,
810     {
811         self.trim_end_matches_raw(&pat.__encode())
812     }
813 
814     /// Equivalent to [`str::trim_matches`].
815     ///
816     /// # Examples
817     ///
818     /// ```
819     /// use os_str_bytes::RawOsStr;
820     ///
821     /// let raw = RawOsStr::from_str("111foo1bar111");
822     /// assert_eq!("foo1bar", raw.trim_matches("1"));
823     /// assert_eq!("111foo1bar111", raw.trim_matches("o"));
824     /// ```
825     #[inline]
826     #[must_use]
trim_matches<P>(&self, pat: P) -> &Self where P: Pattern,827     pub fn trim_matches<P>(&self, pat: P) -> &Self
828     where
829         P: Pattern,
830     {
831         let pat = pat.__encode();
832         self.trim_start_matches_raw(&pat).trim_end_matches_raw(&pat)
833     }
834 
trim_start_matches_raw<P>(&self, pat: &P) -> &Self where P: EncodedPattern,835     fn trim_start_matches_raw<P>(&self, pat: &P) -> &Self
836     where
837         P: EncodedPattern,
838     {
839         self.trim_matches_raw_with(pat, <[_]>::strip_prefix)
840     }
841 
842     /// Equivalent to [`str::trim_start_matches`].
843     ///
844     /// # Examples
845     ///
846     /// ```
847     /// use os_str_bytes::RawOsStr;
848     ///
849     /// let raw = RawOsStr::from_str("111foo1bar111");
850     /// assert_eq!("foo1bar111", raw.trim_start_matches("1"));
851     /// assert_eq!("111foo1bar111", raw.trim_start_matches("o"));
852     /// ```
853     #[inline]
854     #[must_use]
trim_start_matches<P>(&self, pat: P) -> &Self where P: Pattern,855     pub fn trim_start_matches<P>(&self, pat: P) -> &Self
856     where
857         P: Pattern,
858     {
859         self.trim_start_matches_raw(&pat.__encode())
860     }
861 }
862 
863 impl AsRef<Self> for RawOsStr {
864     #[inline]
as_ref(&self) -> &Self865     fn as_ref(&self) -> &Self {
866         self
867     }
868 }
869 
870 impl AsRef<RawOsStr> for str {
871     #[inline]
as_ref(&self) -> &RawOsStr872     fn as_ref(&self) -> &RawOsStr {
873         RawOsStr::from_str(self)
874     }
875 }
876 
877 impl AsRef<RawOsStr> for String {
878     #[inline]
as_ref(&self) -> &RawOsStr879     fn as_ref(&self) -> &RawOsStr {
880         (**self).as_ref()
881     }
882 }
883 
884 impl Default for &RawOsStr {
885     #[inline]
default() -> Self886     fn default() -> Self {
887         RawOsStr::from_str("")
888     }
889 }
890 
891 impl<'a> From<&'a RawOsStr> for Cow<'a, RawOsStr> {
892     #[inline]
from(value: &'a RawOsStr) -> Self893     fn from(value: &'a RawOsStr) -> Self {
894         Cow::Borrowed(value)
895     }
896 }
897 
898 impl From<Box<str>> for Box<RawOsStr> {
899     #[inline]
from(value: Box<str>) -> Self900     fn from(value: Box<str>) -> Self {
901         value.into_boxed_bytes().transmute_box()
902     }
903 }
904 
905 impl ToOwned for RawOsStr {
906     type Owned = RawOsString;
907 
908     #[inline]
to_owned(&self) -> Self::Owned909     fn to_owned(&self) -> Self::Owned {
910         RawOsString(self.0.to_owned())
911     }
912 }
913 
914 /// Extensions to [`Cow<RawOsStr>`] for additional conversions.
915 ///
916 /// [`Cow<RawOsStr>`]: Cow
917 #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "raw_os_str")))]
918 pub trait RawOsStrCow<'a>: private::Sealed {
919     /// Converts this representation back to a platform-native string.
920     ///
921     /// # Examples
922     ///
923     /// ```
924     /// use std::env;
925     /// # use std::io;
926     ///
927     /// use os_str_bytes::RawOsStr;
928     /// use os_str_bytes::RawOsStrCow;
929     ///
930     /// let os_string = env::current_exe()?.into_os_string();
931     /// let raw = RawOsStr::new(&os_string);
932     /// assert_eq!(os_string, raw.into_os_str());
933     /// #
934     /// # Ok::<_, io::Error>(())
935     /// ```
936     #[must_use]
into_os_str(self) -> Cow<'a, OsStr>937     fn into_os_str(self) -> Cow<'a, OsStr>;
938 
939     /// Returns the byte string stored by this container.
940     ///
941     /// The returned string will use an [unspecified encoding].
942     ///
943     /// # Examples
944     ///
945     /// ```
946     /// use std::borrow::Cow;
947     ///
948     /// use os_str_bytes::RawOsStr;
949     /// use os_str_bytes::RawOsStrCow;
950     ///
951     /// let string = "foobar";
952     /// let raw = Cow::Borrowed(RawOsStr::from_str(string));
953     /// assert_eq!(string.as_bytes(), &*raw.into_raw_bytes());
954     /// ```
955     ///
956     /// [unspecified encoding]: super#encoding
957     #[must_use]
into_raw_bytes(self) -> Cow<'a, [u8]>958     fn into_raw_bytes(self) -> Cow<'a, [u8]>;
959 }
960 
961 impl<'a> RawOsStrCow<'a> for Cow<'a, RawOsStr> {
962     #[inline]
into_os_str(self) -> Cow<'a, OsStr>963     fn into_os_str(self) -> Cow<'a, OsStr> {
964         match self {
965             Cow::Borrowed(string) => string.to_os_str(),
966             Cow::Owned(string) => Cow::Owned(string.into_os_string()),
967         }
968     }
969 
970     #[inline]
into_raw_bytes(self) -> Cow<'a, [u8]>971     fn into_raw_bytes(self) -> Cow<'a, [u8]> {
972         match self {
973             Cow::Borrowed(string) => Cow::Borrowed(&string.0),
974             Cow::Owned(string) => Cow::Owned(string.0),
975         }
976     }
977 }
978 
979 /// A container for owned byte strings converted by this crate.
980 ///
981 /// For more information, see [`RawOsStr`].
982 #[derive(Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
983 #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "raw_os_str")))]
984 pub struct RawOsString(Vec<u8>);
985 
986 impl RawOsString {
987     /// Converts a platform-native string into a representation that can be
988     /// more easily manipulated.
989     ///
990     /// For more information, see [`RawOsStr::new`].
991     ///
992     /// # Examples
993     ///
994     /// ```
995     /// use std::env;
996     /// # use std::io;
997     ///
998     /// use os_str_bytes::RawOsString;
999     ///
1000     /// let os_string = env::current_exe()?.into_os_string();
1001     /// println!("{:?}", RawOsString::new(os_string));
1002     /// #
1003     /// # Ok::<_, io::Error>(())
1004     /// ```
1005     #[inline]
1006     #[must_use]
new(string: OsString) -> Self1007     pub fn new(string: OsString) -> Self {
1008         Self(imp::os_string_into_vec(string))
1009     }
1010 
1011     /// Wraps a string, without copying or encoding conversion.
1012     ///
1013     /// This method is much more efficient than [`RawOsString::new`], since the
1014     /// [encoding] used by this crate is compatible with UTF-8.
1015     ///
1016     /// # Examples
1017     ///
1018     /// ```
1019     /// use os_str_bytes::RawOsString;
1020     ///
1021     /// let string = "foobar".to_owned();
1022     /// let raw = RawOsString::from_string(string.clone());
1023     /// assert_eq!(string, raw);
1024     /// ```
1025     ///
1026     /// [encoding]: super#encoding
1027     #[inline]
1028     #[must_use]
from_string(string: String) -> Self1029     pub fn from_string(string: String) -> Self {
1030         Self(string.into_bytes())
1031     }
1032 
1033     /// Wraps a byte string, without copying or encoding conversion.
1034     ///
1035     /// # Panics
1036     ///
1037     /// Panics if the string is not valid for the [unspecified encoding] used
1038     /// by this crate.
1039     ///
1040     /// # Examples
1041     ///
1042     /// ```
1043     /// use std::env;
1044     /// # use std::io;
1045     ///
1046     /// use os_str_bytes::RawOsString;
1047     ///
1048     /// let os_string = env::current_exe()?.into_os_string();
1049     /// let raw = RawOsString::new(os_string);
1050     /// let raw_bytes = raw.clone().into_raw_vec();
1051     /// assert_eq!(raw, RawOsString::assert_from_raw_vec(raw_bytes));
1052     /// #
1053     /// # Ok::<_, io::Error>(())
1054     /// ```
1055     ///
1056     /// [unspecified encoding]: super#encoding
1057     #[inline]
1058     #[must_use = "method should not be used for validation"]
1059     #[track_caller]
assert_from_raw_vec(string: Vec<u8>) -> Self1060     pub fn assert_from_raw_vec(string: Vec<u8>) -> Self {
1061         expect_encoded!(raw::validate_bytes(&string));
1062 
1063         Self(string)
1064     }
1065 
1066     if_checked_conversions! {
1067         /// Wraps a byte string, without copying or encoding conversion.
1068         ///
1069         /// [`assert_from_raw_vec`] should almost always be used instead. For
1070         /// more information, see [`EncodingError`].
1071         ///
1072         /// # Errors
1073         ///
1074         /// See documentation for [`EncodingError`].
1075         ///
1076         /// # Examples
1077         ///
1078         /// ```
1079         /// use std::env;
1080         /// # use std::io;
1081         ///
1082         /// use os_str_bytes::RawOsString;
1083         ///
1084         /// let os_string = env::current_exe()?.into_os_string();
1085         /// let raw = RawOsString::new(os_string);
1086         /// let raw_clone = raw.clone();
1087         /// assert_eq!(Ok(raw), RawOsString::from_raw_vec(raw_clone.into_raw_vec()));
1088         /// #
1089         /// # Ok::<_, io::Error>(())
1090         /// ```
1091         ///
1092         /// [`assert_from_raw_vec`]: Self::assert_from_raw_vec
1093         #[cfg_attr(
1094             os_str_bytes_docs_rs,
1095             doc(cfg(feature = "checked_conversions"))
1096         )]
1097         #[inline]
1098         pub fn from_raw_vec(string: Vec<u8>) -> Result<Self> {
1099             raw::validate_bytes(&string)
1100                 .map(|()| Self(string))
1101                 .map_err(EncodingError)
1102         }
1103     }
1104 
1105     /// Wraps a byte string, without copying or encoding conversion.
1106     ///
1107     /// # Safety
1108     ///
1109     /// The string must be valid for the [unspecified encoding] used by this
1110     /// crate.
1111     ///
1112     /// # Examples
1113     ///
1114     /// ```
1115     /// use std::env;
1116     /// # use std::io;
1117     ///
1118     /// use os_str_bytes::RawOsString;
1119     ///
1120     /// let os_string = env::current_exe()?.into_os_string();
1121     /// let raw = RawOsString::new(os_string);
1122     /// let raw_bytes = raw.clone().into_raw_vec();
1123     /// assert_eq!(raw, unsafe {
1124     ///     RawOsString::from_raw_vec_unchecked(raw_bytes)
1125     /// });
1126     /// #
1127     /// # Ok::<_, io::Error>(())
1128     /// ```
1129     ///
1130     /// [unspecified encoding]: super#encoding
1131     #[inline]
1132     #[must_use]
1133     #[track_caller]
from_raw_vec_unchecked(string: Vec<u8>) -> Self1134     pub unsafe fn from_raw_vec_unchecked(string: Vec<u8>) -> Self {
1135         if cfg!(debug_assertions) {
1136             expect_encoded!(raw::validate_bytes(&string));
1137         }
1138 
1139         Self(string)
1140     }
1141 
1142     /// Equivalent to [`String::clear`].
1143     ///
1144     /// # Examples
1145     ///
1146     /// ```
1147     /// use std::env;
1148     /// # use std::io;
1149     ///
1150     /// use os_str_bytes::RawOsString;
1151     ///
1152     /// let os_string = env::current_exe()?.into_os_string();
1153     /// let mut raw = RawOsString::new(os_string);
1154     /// raw.clear();
1155     /// assert!(raw.is_empty());
1156     /// #
1157     /// # Ok::<_, io::Error>(())
1158     /// ```
1159     #[inline]
clear(&mut self)1160     pub fn clear(&mut self) {
1161         self.0.clear();
1162     }
1163 
1164     /// Equivalent to [`String::into_boxed_str`].
1165     ///
1166     /// # Examples
1167     ///
1168     /// ```
1169     /// use os_str_bytes::RawOsString;
1170     ///
1171     /// let string = "foobar".to_owned();
1172     /// let raw = RawOsString::from_string(string.clone());
1173     /// assert_eq!(string, *raw.into_box());
1174     /// ```
1175     #[inline]
1176     #[must_use]
into_box(self) -> Box<RawOsStr>1177     pub fn into_box(self) -> Box<RawOsStr> {
1178         self.0.into_boxed_slice().transmute_box()
1179     }
1180 
1181     /// Converts this representation back to a platform-native string.
1182     ///
1183     /// # Examples
1184     ///
1185     /// ```
1186     /// use std::env;
1187     /// # use std::io;
1188     ///
1189     /// use os_str_bytes::RawOsString;
1190     ///
1191     /// let os_string = env::current_exe()?.into_os_string();
1192     /// let raw = RawOsString::new(os_string.clone());
1193     /// assert_eq!(os_string, raw.into_os_string());
1194     /// #
1195     /// # Ok::<_, io::Error>(())
1196     /// ```
1197     #[inline]
1198     #[must_use]
into_os_string(self) -> OsString1199     pub fn into_os_string(self) -> OsString {
1200         expect_encoded!(imp::os_string_from_vec(self.0))
1201     }
1202 
1203     /// Returns the byte string stored by this container.
1204     ///
1205     /// The returned string will use an [unspecified encoding].
1206     ///
1207     /// # Examples
1208     ///
1209     /// ```
1210     /// use os_str_bytes::RawOsString;
1211     ///
1212     /// let string = "foobar".to_owned();
1213     /// let raw = RawOsString::from_string(string.clone());
1214     /// assert_eq!(string.into_bytes(), raw.into_raw_vec());
1215     /// ```
1216     ///
1217     /// [unspecified encoding]: super#encoding
1218     #[inline]
1219     #[must_use]
into_raw_vec(self) -> Vec<u8>1220     pub fn into_raw_vec(self) -> Vec<u8> {
1221         self.0
1222     }
1223 
1224     /// Equivalent to [`OsString::into_string`].
1225     ///
1226     /// # Examples
1227     ///
1228     /// ```
1229     /// use os_str_bytes::RawOsString;
1230     ///
1231     /// let string = "foobar".to_owned();
1232     /// let raw = RawOsString::from_string(string.clone());
1233     /// assert_eq!(Ok(string), raw.into_string());
1234     /// ```
1235     #[inline]
into_string(self) -> result::Result<String, Self>1236     pub fn into_string(self) -> result::Result<String, Self> {
1237         String::from_utf8(self.0).map_err(|x| Self(x.into_bytes()))
1238     }
1239 
1240     /// Equivalent to [`String::shrink_to_fit`].
1241     ///
1242     /// # Examples
1243     ///
1244     /// ```
1245     /// use os_str_bytes::RawOsString;
1246     ///
1247     /// let string = "foobar".to_owned();
1248     /// let mut raw = RawOsString::from_string(string.clone());
1249     /// raw.shrink_to_fit();
1250     /// assert_eq!(string, raw);
1251     /// ```
1252     #[inline]
shrink_to_fit(&mut self)1253     pub fn shrink_to_fit(&mut self) {
1254         self.0.shrink_to_fit();
1255     }
1256 
1257     /// Equivalent to [`String::split_off`].
1258     ///
1259     /// # Panics
1260     ///
1261     /// Panics if the index is not a [valid boundary].
1262     ///
1263     /// # Examples
1264     ///
1265     /// ```
1266     /// use os_str_bytes::RawOsString;
1267     ///
1268     /// let mut raw = RawOsString::from_string("foobar".to_owned());
1269     /// assert_eq!("bar", raw.split_off(3));
1270     /// assert_eq!("foo", raw);
1271     /// ```
1272     ///
1273     /// [valid boundary]: RawOsStr#indices
1274     #[inline]
1275     #[must_use]
1276     #[track_caller]
split_off(&mut self, at: usize) -> Self1277     pub fn split_off(&mut self, at: usize) -> Self {
1278         self.check_bound(at);
1279 
1280         Self(self.0.split_off(at))
1281     }
1282 
1283     /// Equivalent to [`String::truncate`].
1284     ///
1285     /// # Panics
1286     ///
1287     /// Panics if the index is not a [valid boundary].
1288     ///
1289     /// # Examples
1290     ///
1291     /// ```
1292     /// use os_str_bytes::RawOsString;
1293     ///
1294     /// let mut raw = RawOsString::from_string("foobar".to_owned());
1295     /// raw.truncate(3);
1296     /// assert_eq!("foo", raw);
1297     /// ```
1298     ///
1299     /// [valid boundary]: RawOsStr#indices
1300     #[inline]
1301     #[track_caller]
truncate(&mut self, new_len: usize)1302     pub fn truncate(&mut self, new_len: usize) {
1303         self.check_bound(new_len);
1304 
1305         self.0.truncate(new_len);
1306     }
1307 }
1308 
1309 impl AsRef<RawOsStr> for RawOsString {
1310     #[inline]
as_ref(&self) -> &RawOsStr1311     fn as_ref(&self) -> &RawOsStr {
1312         self
1313     }
1314 }
1315 
1316 impl Borrow<RawOsStr> for RawOsString {
1317     #[inline]
borrow(&self) -> &RawOsStr1318     fn borrow(&self) -> &RawOsStr {
1319         self
1320     }
1321 }
1322 
1323 impl Deref for RawOsString {
1324     type Target = RawOsStr;
1325 
1326     #[inline]
deref(&self) -> &Self::Target1327     fn deref(&self) -> &Self::Target {
1328         RawOsStr::from_inner(&self.0)
1329     }
1330 }
1331 
1332 impl From<RawOsString> for Box<RawOsStr> {
1333     #[inline]
from(value: RawOsString) -> Self1334     fn from(value: RawOsString) -> Self {
1335         value.into_box()
1336     }
1337 }
1338 
1339 impl From<Box<RawOsStr>> for RawOsString {
1340     #[inline]
from(value: Box<RawOsStr>) -> Self1341     fn from(value: Box<RawOsStr>) -> Self {
1342         Self(value.transmute_box::<[_]>().into_vec())
1343     }
1344 }
1345 
1346 impl From<RawOsString> for Cow<'_, RawOsStr> {
1347     #[inline]
from(value: RawOsString) -> Self1348     fn from(value: RawOsString) -> Self {
1349         Cow::Owned(value)
1350     }
1351 }
1352 
1353 impl From<String> for RawOsString {
1354     #[inline]
from(value: String) -> Self1355     fn from(value: String) -> Self {
1356         Self::from_string(value)
1357     }
1358 }
1359 
1360 struct DebugBuffer<'a>(&'a [u8]);
1361 
1362 impl Debug for DebugBuffer<'_> {
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result1363     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1364         f.write_str("\"")?;
1365 
1366         let mut string = self.0;
1367         let mut invalid_length = 0;
1368         while !string.is_empty() {
1369             let (invalid, substring) = string.split_at(invalid_length);
1370 
1371             let valid = match str::from_utf8(substring) {
1372                 Ok(valid) => {
1373                     string = &[];
1374                     valid
1375                 }
1376                 Err(error) => {
1377                     let (valid, substring) =
1378                         substring.split_at(error.valid_up_to());
1379 
1380                     let invalid_char_length =
1381                         error.error_len().unwrap_or_else(|| substring.len());
1382                     if valid.is_empty() {
1383                         invalid_length += invalid_char_length;
1384                         continue;
1385                     }
1386                     string = substring;
1387                     invalid_length = invalid_char_length;
1388 
1389                     // SAFETY: This slice was validated to be UTF-8.
1390                     unsafe { str::from_utf8_unchecked(valid) }
1391                 }
1392             };
1393 
1394             raw::debug(invalid, f)?;
1395             Display::fmt(&valid.escape_debug(), f)?;
1396         }
1397 
1398         f.write_str("\"")
1399     }
1400 }
1401 
1402 macro_rules! r#impl {
1403     ( $type:ty ) => {
1404         impl Debug for $type {
1405             #[inline]
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result1406             fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1407                 f.debug_tuple(stringify!($type))
1408                     .field(&DebugBuffer(&self.0))
1409                     .finish()
1410             }
1411         }
1412     };
1413 }
1414 r#impl!(RawOsStr);
1415 r#impl!(RawOsString);
1416 
1417 macro_rules! r#impl {
1418     ( $index_type:ty $(, $index_var:ident , $($bound:expr),+)? ) => {
1419         impl Index<$index_type> for RawOsStr {
1420             type Output = Self;
1421 
1422             #[inline]
index(&self, idx: $index_type) -> &Self::Output1423             fn index(&self, idx: $index_type) -> &Self::Output {
1424                 $(
1425                     let $index_var = &idx;
1426                     $(self.check_bound($bound);)+
1427                 )?
1428 
1429                 Self::from_inner(&self.0[idx])
1430             }
1431         }
1432 
1433         impl Index<$index_type> for RawOsString {
1434             type Output = RawOsStr;
1435 
1436             #[allow(clippy::indexing_slicing)]
1437             #[inline]
index(&self, idx: $index_type) -> &Self::Output1438             fn index(&self, idx: $index_type) -> &Self::Output {
1439                 &(**self)[idx]
1440             }
1441         }
1442     };
1443 }
1444 r#impl!(Range<usize>, x, x.start, x.end);
1445 r#impl!(RangeFrom<usize>, x, x.start);
1446 r#impl!(RangeFull);
1447 // [usize::MAX] will always be a valid inclusive end index.
1448 #[rustfmt::skip]
1449 r#impl!(RangeInclusive<usize>, x, *x.start(), x.end().wrapping_add(1));
1450 r#impl!(RangeTo<usize>, x, x.end);
1451 r#impl!(RangeToInclusive<usize>, x, x.end.wrapping_add(1));
1452 
1453 macro_rules! r#impl {
1454     ( $type:ty , $other_type:ty ) => {
1455         impl PartialEq<$other_type> for $type {
1456             #[inline]
eq(&self, other: &$other_type) -> bool1457             fn eq(&self, other: &$other_type) -> bool {
1458                 let raw: &RawOsStr = self;
1459                 let other: &RawOsStr = other.as_ref();
1460                 raw == other
1461             }
1462         }
1463 
1464         impl PartialEq<$type> for $other_type {
1465             #[inline]
eq(&self, other: &$type) -> bool1466             fn eq(&self, other: &$type) -> bool {
1467                 other == self
1468             }
1469         }
1470     };
1471 }
1472 r#impl!(RawOsStr, RawOsString);
1473 r#impl!(&RawOsStr, RawOsString);
1474 r#impl!(RawOsStr, str);
1475 r#impl!(RawOsStr, String);
1476 r#impl!(&RawOsStr, String);
1477 r#impl!(RawOsString, str);
1478 r#impl!(RawOsString, &str);
1479 r#impl!(RawOsString, String);
1480 
1481 #[cfg(feature = "print_bytes")]
1482 #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "print_bytes")))]
1483 mod print_bytes {
1484     use print_bytes::ByteStr;
1485     use print_bytes::ToBytes;
1486     #[cfg(windows)]
1487     use print_bytes::WideStr;
1488 
1489     #[cfg(windows)]
1490     use crate::imp::raw;
1491 
1492     use super::RawOsStr;
1493     use super::RawOsString;
1494 
1495     impl ToBytes for RawOsStr {
1496         #[inline]
to_bytes(&self) -> ByteStr<'_>1497         fn to_bytes(&self) -> ByteStr<'_> {
1498             self.0.to_bytes()
1499         }
1500 
1501         #[cfg(windows)]
1502         #[inline]
to_wide(&self) -> Option<WideStr>1503         fn to_wide(&self) -> Option<WideStr> {
1504             Some(WideStr::new(raw::encode_wide_unchecked(&self.0).collect()))
1505         }
1506     }
1507 
1508     impl ToBytes for RawOsString {
1509         #[inline]
to_bytes(&self) -> ByteStr<'_>1510         fn to_bytes(&self) -> ByteStr<'_> {
1511             (**self).to_bytes()
1512         }
1513 
1514         #[cfg(windows)]
1515         #[inline]
to_wide(&self) -> Option<WideStr>1516         fn to_wide(&self) -> Option<WideStr> {
1517             (**self).to_wide()
1518         }
1519     }
1520 }
1521 
1522 #[cfg(feature = "uniquote")]
1523 #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "uniquote")))]
1524 mod uniquote {
1525     use uniquote::Formatter;
1526     use uniquote::Quote;
1527     use uniquote::Result;
1528 
1529     use crate::imp::raw;
1530 
1531     use super::RawOsStr;
1532     use super::RawOsString;
1533 
1534     impl Quote for RawOsStr {
1535         #[inline]
escape(&self, f: &mut Formatter<'_>) -> Result1536         fn escape(&self, f: &mut Formatter<'_>) -> Result {
1537             raw::uniquote::escape(&self.0, f)
1538         }
1539     }
1540 
1541     impl Quote for RawOsString {
1542         #[inline]
escape(&self, f: &mut Formatter<'_>) -> Result1543         fn escape(&self, f: &mut Formatter<'_>) -> Result {
1544             (**self).escape(f)
1545         }
1546     }
1547 }
1548