• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #![cfg_attr(feature = "nightly", allow(unreachable_code))]
2 
3 use std::borrow::Borrow;
4 use std::borrow::Cow;
5 use std::borrow::ToOwned;
6 use std::ffi::OsStr;
7 use std::ffi::OsString;
8 use std::fmt;
9 use std::fmt::Debug;
10 use std::fmt::Display;
11 use std::fmt::Formatter;
12 use std::mem;
13 use std::ops::Deref;
14 use std::ops::Index;
15 use std::ops::Range;
16 use std::ops::RangeFrom;
17 use std::ops::RangeFull;
18 use std::ops::RangeInclusive;
19 use std::ops::RangeTo;
20 use std::ops::RangeToInclusive;
21 use std::result;
22 use std::str;
23 
24 #[cfg(feature = "memchr")]
25 use memchr::memmem::find;
26 #[cfg(feature = "memchr")]
27 use memchr::memmem::rfind;
28 
29 use super::imp;
30 use super::imp::raw;
31 use super::iter::RawSplit;
32 use super::pattern::Encoded as EncodedPattern;
33 use super::private;
34 use super::Pattern;
35 
36 if_checked_conversions! {
37     use super::EncodingError;
38     use super::Result;
39 }
40 
41 if_nightly! {
42     use super::util;
43 }
44 
45 #[cfg(not(feature = "memchr"))]
find(string: &[u8], pat: &[u8]) -> Option<usize>46 fn find(string: &[u8], pat: &[u8]) -> Option<usize> {
47     (0..=string.len().checked_sub(pat.len())?)
48         .find(|&x| string[x..].starts_with(pat))
49 }
50 
51 #[cfg(not(feature = "memchr"))]
rfind(string: &[u8], pat: &[u8]) -> Option<usize>52 fn rfind(string: &[u8], pat: &[u8]) -> Option<usize> {
53     (pat.len()..=string.len())
54         .rfind(|&x| string[..x].ends_with(pat))
55         .map(|x| x - pat.len())
56 }
57 
58 #[allow(clippy::missing_safety_doc)]
59 unsafe trait TransmuteBox {
transmute_box<R>(self: Box<Self>) -> Box<R> where R: ?Sized + TransmuteBox,60     fn transmute_box<R>(self: Box<Self>) -> Box<R>
61     where
62         R: ?Sized + TransmuteBox,
63     {
64         let value = Box::into_raw(self);
65         // SAFETY: This trait is only implemented for types that can be
66         // transmuted.
67         unsafe { Box::from_raw(mem::transmute_copy(&value)) }
68     }
69 }
70 
71 // SAFETY: This struct has a layout that makes this operation safe.
72 unsafe impl TransmuteBox for RawOsStr {}
73 unsafe impl TransmuteBox for [u8] {}
74 
75 #[inline]
leak_cow(string: Cow<'_, RawOsStr>) -> &'_ RawOsStr76 fn leak_cow(string: Cow<'_, RawOsStr>) -> &'_ RawOsStr {
77     match string {
78         Cow::Borrowed(string) => string,
79         #[cfg_attr(not(feature = "nightly"), allow(unused_variables))]
80         Cow::Owned(string) => {
81             if_nightly_return! {{
82                 Box::leak(string.into_box())
83             }}
84             unreachable!();
85         }
86     }
87 }
88 
89 /// A container for borrowed byte strings converted by this crate.
90 ///
91 /// This wrapper is intended to prevent violating the invariants of the
92 /// [unspecified encoding] used by this crate and minimize encoding
93 /// conversions.
94 ///
95 /// # Indices
96 ///
97 /// Methods of this struct that accept indices require that the index lie on a
98 /// UTF-8 boundary. Although it is possible to manipulate platform strings
99 /// based on other indices, this crate currently does not support them for
100 /// slicing methods. They would add significant complication to the
101 /// implementation and are generally not necessary. However, all indices
102 /// returned by this struct can be used for slicing.
103 ///
104 /// On Unix, all indices are permitted, to avoid false positives. However,
105 /// relying on this implementation detail is discouraged. Platform-specific
106 /// indices are error-prone.
107 ///
108 /// # Complexity
109 ///
110 /// All searching methods have worst-case multiplicative time complexity (i.e.,
111 /// `O(self.raw_len() * pat.len())`). Enabling the "memchr" feature allows
112 /// these methods to instead run in linear time in the worst case (documented
113 /// for [`memchr::memmem::find`][memchr complexity]).
114 ///
115 /// # Safety
116 ///
117 /// Although this type is annotated with `#[repr(transparent)]`, the inner
118 /// representation is not stable. Transmuting between this type and any other
119 /// causes immediate undefined behavior.
120 ///
121 /// # Nightly Notes
122 ///
123 /// Indices are validated on all platforms.
124 ///
125 /// [memchr complexity]: memchr::memmem::find#complexity
126 /// [unspecified encoding]: super#encoding
127 #[derive(Eq, Hash, Ord, PartialEq, PartialOrd)]
128 #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "raw_os_str")))]
129 #[repr(transparent)]
130 pub struct RawOsStr([u8]);
131 
132 impl RawOsStr {
from_inner(string: &[u8]) -> &Self133     const fn from_inner(string: &[u8]) -> &Self {
134         // SAFETY: This struct has a layout that makes this operation safe.
135         unsafe { mem::transmute(string) }
136     }
137 
138     /// Converts a platform-native string into a representation that can be
139     /// more easily manipulated.
140     ///
141     /// This method performs the necessary conversion immediately, so it can be
142     /// expensive to call. It is recommended to continue using the returned
143     /// instance as long as possible (instead of the original [`OsStr`]), to
144     /// avoid repeated conversions.
145     ///
146     /// # Nightly Notes
147     ///
148     /// This method is deprecated. Use [`from_os_str`] instead.
149     ///
150     /// # Examples
151     ///
152     /// ```
153     /// use std::env;
154     /// # use std::io;
155     ///
156     /// use os_str_bytes::RawOsStr;
157     ///
158     /// let os_string = env::current_exe()?.into_os_string();
159     /// println!("{:?}", RawOsStr::new(&os_string));
160     /// #
161     /// # Ok::<_, io::Error>(())
162     /// ```
163     ///
164     /// [`from_os_str`]: Self::from_os_str
165     #[cfg_attr(
166         all(not(os_str_bytes_docs_rs), feature = "nightly"),
167         deprecated(since = "6.6.0", note = "use `from_os_str` instead")
168     )]
169     #[inline]
170     #[must_use]
new(string: &OsStr) -> Cow<'_, Self>171     pub fn new(string: &OsStr) -> Cow<'_, Self> {
172         if_nightly_return! {{
173             Cow::Borrowed(Self::from_os_str(string))
174         }}
175         match imp::os_str_to_bytes(string) {
176             Cow::Borrowed(string) => Cow::Borrowed(Self::from_inner(string)),
177             Cow::Owned(string) => Cow::Owned(RawOsString(string)),
178         }
179     }
180 
181     if_nightly! {
182         /// Wraps a platform-native string, without copying or encoding
183         /// conversion.
184         ///
185         /// # Examples
186         ///
187         /// ```
188         /// use std::env;
189         /// # use std::io;
190         ///
191         /// use os_str_bytes::RawOsStr;
192         ///
193         /// let os_string = env::current_exe()?.into_os_string();
194         /// println!("{:?}", RawOsStr::from_os_str(&os_string));
195         /// #
196         /// # Ok::<_, io::Error>(())
197         /// ```
198         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "nightly")))]
199         #[inline]
200         #[must_use]
201         pub fn from_os_str(string: &OsStr) -> &Self {
202             Self::from_inner(string.as_encoded_bytes())
203         }
204     }
205 
206     /// Wraps a string, without copying or encoding conversion.
207     ///
208     /// This method is much more efficient than [`RawOsStr::new`], since the
209     /// [encoding] used by this crate is compatible with UTF-8.
210     ///
211     /// # Examples
212     ///
213     /// ```
214     /// use os_str_bytes::RawOsStr;
215     ///
216     /// let string = "foobar";
217     /// let raw = RawOsStr::from_str(string);
218     /// assert_eq!(string, raw);
219     /// ```
220     ///
221     /// [encoding]: super#encoding
222     #[allow(clippy::should_implement_trait)]
223     #[inline]
224     #[must_use]
from_str(string: &str) -> &Self225     pub fn from_str(string: &str) -> &Self {
226         Self::from_inner(string.as_bytes())
227     }
228 
229     if_nightly! {
230         /// Equivalent to [`OsStr::from_encoded_bytes_unchecked`].
231         ///
232         /// # Examples
233         ///
234         /// ```
235         /// use std::env;
236         /// # use std::io;
237         ///
238         /// use os_str_bytes::RawOsStr;
239         ///
240         /// let os_string = env::current_exe()?.into_os_string();
241         /// let raw = RawOsStr::from_os_str(&os_string);
242         /// let raw_bytes = raw.as_encoded_bytes();
243         /// assert_eq!(raw, unsafe {
244         ///     RawOsStr::from_encoded_bytes_unchecked(raw_bytes)
245         /// });
246         /// #
247         /// # Ok::<_, io::Error>(())
248         /// ```
249         ///
250         /// [unspecified encoding]: super#encoding
251         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "nightly")))]
252         #[inline]
253         #[must_use]
254         pub unsafe fn from_encoded_bytes_unchecked(string: &[u8]) -> &Self {
255             Self::from_inner(string)
256         }
257     }
258 
cow_from_raw_bytes_checked( string: &[u8], ) -> imp::Result<Cow<'_, Self>>259     fn cow_from_raw_bytes_checked(
260         string: &[u8],
261     ) -> imp::Result<Cow<'_, Self>> {
262         if_nightly_return! {
263             {
264                 imp::os_str_from_bytes(string).map(RawOsStrCow::from_os_str)
265             }
266             raw::validate_bytes(string)
267                 .map(|()| Cow::Borrowed(Self::from_inner(string)))
268         }
269     }
270 
271     deprecated_conversions! {
272         /// Wraps a byte string, without copying or encoding conversion.
273         ///
274         /// # Panics
275         ///
276         /// Panics if the string is not valid for the [unspecified encoding]
277         /// used by this crate.
278         ///
279         /// # Examples
280         ///
281         /// ```
282         /// use std::env;
283         /// # use std::io;
284         ///
285         /// use os_str_bytes::RawOsStr;
286         ///
287         /// let os_string = env::current_exe()?.into_os_string();
288         /// let raw = RawOsStr::new(&os_string);
289         /// let raw_bytes = raw.to_raw_bytes();
290         /// assert_eq!(&*raw, RawOsStr::assert_from_raw_bytes(&raw_bytes));
291         /// #
292         /// # Ok::<_, io::Error>(())
293         /// ```
294         ///
295         /// [unspecified encoding]: super#encoding
296         #[cfg_attr(
297             feature = "conversions",
298             deprecated(
299                 since = "6.6.0",
300                 note = "use `assert_cow_from_raw_bytes` instead"
301             )
302         )]
303         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
304         #[inline]
305         #[must_use = "method should not be used for validation"]
306         #[track_caller]
307         pub fn assert_from_raw_bytes(string: &[u8]) -> &Self {
308             leak_cow(Self::assert_cow_from_raw_bytes(string))
309         }
310 
311         /// Converts and wraps a byte string.
312         ///
313         /// This method should be avoided if other safe methods can be used.
314         ///
315         /// # Panics
316         ///
317         /// Panics if the string is not valid for the [unspecified encoding]
318         /// used by this crate.
319         ///
320         /// # Examples
321         ///
322         /// ```
323         /// use std::env;
324         /// # use std::io;
325         ///
326         /// use os_str_bytes::RawOsStr;
327         ///
328         /// let os_string = env::current_exe()?.into_os_string();
329         /// let raw = RawOsStr::new(&os_string);
330         /// let raw_bytes = raw.to_raw_bytes();
331         /// assert_eq!(raw, RawOsStr::assert_cow_from_raw_bytes(&raw_bytes));
332         /// #
333         /// # Ok::<_, io::Error>(())
334         /// ```
335         ///
336         /// [unspecified encoding]: super#encoding
337         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
338         #[inline]
339         #[must_use = "method should not be used for validation"]
340         #[track_caller]
341         pub fn assert_cow_from_raw_bytes(string: &[u8]) -> Cow<'_, Self> {
342             expect_encoded!(Self::cow_from_raw_bytes_checked(string))
343         }
344     }
345 
346     if_checked_conversions! {
347         /// Wraps a byte string, without copying or encoding conversion.
348         ///
349         /// [`assert_from_raw_bytes`] should almost always be used instead. For
350         /// more information, see [`EncodingError`].
351         ///
352         /// # Errors
353         ///
354         /// See documentation for [`EncodingError`].
355         ///
356         /// # Examples
357         ///
358         /// ```
359         /// use std::env;
360         /// # use std::io;
361         ///
362         /// use os_str_bytes::RawOsStr;
363         ///
364         /// let os_string = env::current_exe()?.into_os_string();
365         /// let raw = RawOsStr::new(&os_string);
366         /// let raw_bytes = raw.to_raw_bytes();
367         /// assert_eq!(Ok(&*raw), RawOsStr::from_raw_bytes(&raw_bytes));
368         /// #
369         /// # Ok::<_, io::Error>(())
370         /// ```
371         ///
372         /// [`assert_from_raw_bytes`]: Self::assert_from_raw_bytes
373         #[deprecated(
374             since = "6.6.0",
375             note = "use `cow_from_raw_bytes` instead",
376         )]
377         #[cfg_attr(
378             os_str_bytes_docs_rs,
379             doc(cfg(feature = "checked_conversions"))
380         )]
381         #[inline]
382         pub fn from_raw_bytes(string: &[u8]) -> Result<&Self> {
383             Self::cow_from_raw_bytes(string).map(leak_cow)
384         }
385 
386         /// Converts and wraps a byte string.
387         ///
388         /// [`assert_cow_from_raw_bytes`] should almost always be used instead.
389         /// For more information, see [`EncodingError`].
390         ///
391         /// # Errors
392         ///
393         /// See documentation for [`EncodingError`].
394         ///
395         /// # Examples
396         ///
397         /// ```
398         /// use std::env;
399         /// # use std::io;
400         ///
401         /// use os_str_bytes::RawOsStr;
402         ///
403         /// let os_string = env::current_exe()?.into_os_string();
404         /// let raw = RawOsStr::new(&os_string);
405         /// let raw_bytes = raw.to_raw_bytes();
406         /// assert_eq!(
407         ///     Ok(&raw),
408         ///     RawOsStr::cow_from_raw_bytes(&raw_bytes).as_ref(),
409         /// );
410         /// #
411         /// # Ok::<_, io::Error>(())
412         /// ```
413         ///
414         /// [`assert_cow_from_raw_bytes`]: Self::assert_cow_from_raw_bytes
415         #[cfg_attr(
416             os_str_bytes_docs_rs,
417             doc(cfg(feature = "checked_conversions"))
418         )]
419         #[inline]
420         pub fn cow_from_raw_bytes(string: &[u8]) -> Result<Cow<'_, Self>> {
421             Self::cow_from_raw_bytes_checked(string).map_err(EncodingError)
422         }
423     }
424 
425     deprecated_conversions! {
426         /// Wraps a byte string, without copying or encoding conversion.
427         ///
428         /// # Safety
429         ///
430         /// The string must be valid for the [unspecified encoding] used by
431         /// this crate.
432         ///
433         /// # Examples
434         ///
435         /// ```
436         /// use std::env;
437         /// # use std::io;
438         ///
439         /// use os_str_bytes::RawOsStr;
440         ///
441         /// let os_string = env::current_exe()?.into_os_string();
442         /// let raw = RawOsStr::new(&os_string);
443         /// let raw_bytes = raw.to_raw_bytes();
444         /// assert_eq!(&*raw, unsafe {
445         ///     RawOsStr::from_raw_bytes_unchecked(&raw_bytes)
446         /// });
447         /// #
448         /// # Ok::<_, io::Error>(())
449         /// ```
450         ///
451         /// [unspecified encoding]: super#encoding
452         #[cfg_attr(feature = "nightly", allow(deprecated))]
453         #[cfg_attr(
454             feature = "conversions",
455             deprecated(
456                 since = "6.6.0",
457                 note = "use `cow_from_raw_bytes_unchecked` instead"
458             )
459         )]
460         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
461         #[inline]
462         #[must_use]
463         #[track_caller]
464         pub unsafe fn from_raw_bytes_unchecked(string: &[u8]) -> &Self {
465             // SAFETY: This method has equivalent safety requirements.
466             leak_cow(unsafe { Self::cow_from_raw_bytes_unchecked(string) })
467         }
468 
469         /// Converts and wraps a byte string.
470         ///
471         /// # Safety
472         ///
473         /// The string must be valid for the [unspecified encoding] used by
474         /// this crate.
475         ///
476         /// # Nightly Notes
477         ///
478         /// This method is deprecated. Use [`assert_cow_from_raw_bytes`] or
479         /// [`from_encoded_bytes_unchecked`] instead.
480         ///
481         /// # Examples
482         ///
483         /// ```
484         /// use std::env;
485         /// # use std::io;
486         ///
487         /// use os_str_bytes::RawOsStr;
488         ///
489         /// let os_string = env::current_exe()?.into_os_string();
490         /// let raw = RawOsStr::new(&os_string);
491         /// let raw_bytes = raw.to_raw_bytes();
492         /// assert_eq!(raw, unsafe {
493         ///     RawOsStr::cow_from_raw_bytes_unchecked(&raw_bytes)
494         /// });
495         /// #
496         /// # Ok::<_, io::Error>(())
497         /// ```
498         ///
499         /// [`assert_cow_from_raw_bytes`]: Self::assert_cow_from_raw_bytes
500         /// [`from_encoded_bytes_unchecked`]: Self::from_encoded_bytes_unchecked
501         /// [unspecified encoding]: super#encoding
502         #[cfg_attr(feature = "nightly", allow(deprecated))]
503         #[cfg_attr(
504             all(
505                 not(os_str_bytes_docs_rs),
506                 feature = "conversions",
507                 feature = "nightly",
508             ),
509             deprecated(
510                 since = "6.6.0",
511                 note = "use `assert_cow_from_raw_bytes` or
512                         `from_encoded_bytes_unchecked` instead",
513             )
514         )]
515         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
516         #[inline]
517         #[must_use]
518         #[track_caller]
519         pub unsafe fn cow_from_raw_bytes_unchecked(
520             string: &[u8],
521         ) -> Cow<'_, Self> {
522             if_nightly_return! {
523                 {
524                     Self::assert_cow_from_raw_bytes(string)
525                 }
526                 if cfg!(debug_assertions) {
527                     expect_encoded!(raw::validate_bytes(string));
528                 }
529             }
530             Cow::Borrowed(Self::from_inner(string))
531         }
532     }
533 
534     if_nightly! {
535         /// Equivalent to [`OsStr::as_encoded_bytes`].
536         ///
537         /// The returned string will not use the [unspecified encoding]. It can
538         /// only be passed to methods accepting the encoding from the standard
539         /// library, such as [`from_encoded_bytes_unchecked`].
540         ///
541         /// # Examples
542         ///
543         /// ```
544         /// use os_str_bytes::RawOsStr;
545         ///
546         /// let string = "foobar";
547         /// let raw = RawOsStr::from_str(string);
548         /// assert_eq!(string.as_bytes(), raw.as_encoded_bytes());
549         /// ```
550         ///
551         /// [`from_encoded_bytes_unchecked`]: Self::from_encoded_bytes_unchecked
552         /// [unspecified encoding]: super#encoding
553         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "nightly")))]
554         #[inline]
555         #[must_use]
556         pub fn as_encoded_bytes(&self) -> &[u8] {
557             &self.0
558         }
559     }
560 
561     deprecated_conversions! {
562         /// Returns the byte string stored by this container.
563         ///
564         /// The returned string will use an [unspecified encoding].
565         ///
566         /// # Examples
567         ///
568         /// ```
569         /// use os_str_bytes::RawOsStr;
570         ///
571         /// let string = "foobar";
572         /// let raw = RawOsStr::from_str(string);
573         /// assert_eq!(string.as_bytes(), raw.as_raw_bytes());
574         /// ```
575         ///
576         /// [unspecified encoding]: super#encoding
577         #[cfg_attr(
578             feature = "conversions",
579             deprecated(since = "6.6.0", note = "use `to_raw_bytes` instead")
580         )]
581         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
582         #[inline]
583         #[must_use]
584         pub fn as_raw_bytes(&self) -> &[u8] {
585             match self.to_raw_bytes() {
586                 Cow::Borrowed(string) => string,
587                 #[cfg_attr(not(feature = "nightly"), allow(unused_variables))]
588                 Cow::Owned(string) => {
589                     if_nightly_return! {{
590                         string.leak()
591                     }}
592                     unreachable!();
593                 }
594             }
595         }
596     }
597 
598     if_nightly! {
599         /// Converts this representation back to a platform-native string,
600         /// without copying or encoding conversion.
601         ///
602         /// # Examples
603         ///
604         /// ```
605         /// use std::env;
606         /// # use std::io;
607         ///
608         /// use os_str_bytes::RawOsStr;
609         ///
610         /// let os_string = env::current_exe()?.into_os_string();
611         /// let raw = RawOsStr::from_os_str(&os_string);
612         /// assert_eq!(os_string, raw.as_os_str());
613         /// #
614         /// # Ok::<_, io::Error>(())
615         /// ```
616         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "nightly")))]
617         #[inline]
618         #[must_use]
619         pub fn as_os_str(&self) -> &OsStr {
620             // SAFETY: This wrapper prevents violating the invariants of the
621             // encoding used by the standard library.
622             unsafe { OsStr::from_encoded_bytes_unchecked(&self.0) }
623         }
624     }
625 
626     /// Equivalent to [`str::contains`].
627     ///
628     /// # Examples
629     ///
630     /// ```
631     /// use os_str_bytes::RawOsStr;
632     ///
633     /// let raw = RawOsStr::from_str("foobar");
634     /// assert!(raw.contains("oo"));
635     /// assert!(!raw.contains("of"));
636     /// ```
637     #[inline]
638     #[must_use]
contains<P>(&self, pat: P) -> bool where P: Pattern,639     pub fn contains<P>(&self, pat: P) -> bool
640     where
641         P: Pattern,
642     {
643         self.find(pat).is_some()
644     }
645 
646     /// Equivalent to [`str::ends_with`].
647     ///
648     /// # Examples
649     ///
650     /// ```
651     /// use os_str_bytes::RawOsStr;
652     ///
653     /// let raw = RawOsStr::from_str("foobar");
654     /// assert!(raw.ends_with("bar"));
655     /// assert!(!raw.ends_with("foo"));
656     /// ```
657     #[inline]
658     #[must_use]
ends_with<P>(&self, pat: P) -> bool where P: Pattern,659     pub fn ends_with<P>(&self, pat: P) -> bool
660     where
661         P: Pattern,
662     {
663         let pat = pat.__encode();
664         let pat = pat.__get();
665 
666         self.0.ends_with(pat)
667     }
668 
669     deprecated_conversions! {
670         /// Equivalent to [`str::ends_with`] but accepts this type for the
671         /// pattern.
672         ///
673         /// # Examples
674         ///
675         /// ```
676         /// use os_str_bytes::RawOsStr;
677         ///
678         /// let raw = RawOsStr::from_str("foobar");
679         /// assert!(raw.ends_with_os(RawOsStr::from_str("bar")));
680         /// assert!(!raw.ends_with_os(RawOsStr::from_str("foo")));
681         /// ```
682         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
683         #[inline]
684         #[must_use]
685         pub fn ends_with_os(&self, pat: &Self) -> bool {
686             raw::ends_with(&self.to_raw_bytes(), &pat.to_raw_bytes())
687         }
688     }
689 
690     /// Equivalent to [`str::find`].
691     ///
692     /// # Examples
693     ///
694     /// ```
695     /// use os_str_bytes::RawOsStr;
696     ///
697     /// let raw = RawOsStr::from_str("foobar");
698     /// assert_eq!(Some(1), raw.find("o"));
699     /// assert_eq!(None, raw.find("of"));
700     /// ```
701     #[inline]
702     #[must_use]
find<P>(&self, pat: P) -> Option<usize> where P: Pattern,703     pub fn find<P>(&self, pat: P) -> Option<usize>
704     where
705         P: Pattern,
706     {
707         let pat = pat.__encode();
708         let pat = pat.__get();
709 
710         find(&self.0, pat)
711     }
712 
713     /// Equivalent to [`str::is_empty`].
714     ///
715     /// # Examples
716     ///
717     /// ```
718     /// use os_str_bytes::RawOsStr;
719     ///
720     /// assert!(RawOsStr::from_str("").is_empty());
721     /// assert!(!RawOsStr::from_str("foobar").is_empty());
722     /// ```
723     #[inline]
724     #[must_use]
is_empty(&self) -> bool725     pub fn is_empty(&self) -> bool {
726         self.0.is_empty()
727     }
728 
729     deprecated_conversions! {
730         /// Returns the length of the byte string stored by this container.
731         ///
732         /// Only the following assumptions can be made about the result:
733         /// - The length of any Unicode character is the length of its UTF-8
734         ///   representation (i.e., [`char::len_utf8`]).
735         /// - Splitting a string at a UTF-8 boundary will return two strings
736         ///   with lengths that sum to the length of the original string.
737         ///
738         /// This method may return a different result than would [`OsStr::len`]
739         /// when called on same string, since [`OsStr`] uses an unspecified
740         /// encoding.
741         ///
742         /// # Examples
743         ///
744         /// ```
745         /// use os_str_bytes::RawOsStr;
746         ///
747         /// assert_eq!(6, RawOsStr::from_str("foobar").raw_len());
748         /// assert_eq!(0, RawOsStr::from_str("").raw_len());
749         /// ```
750         #[cfg_attr(
751             feature = "conversions",
752             deprecated(
753                 since = "6.6.0",
754                 note = "use `as_encoded_bytes` or `to_raw_bytes` instead",
755             )
756         )]
757         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
758         #[inline]
759         #[must_use]
760         pub fn raw_len(&self) -> usize {
761             self.to_raw_bytes().len()
762         }
763     }
764 
765     /// Equivalent to [`str::rfind`].
766     ///
767     /// # Examples
768     ///
769     /// ```
770     /// use os_str_bytes::RawOsStr;
771     ///
772     /// let raw = RawOsStr::from_str("foobar");
773     /// assert_eq!(Some(2), raw.rfind("o"));
774     /// assert_eq!(None, raw.rfind("of"));
775     /// ```
776     #[inline]
777     #[must_use]
rfind<P>(&self, pat: P) -> Option<usize> where P: Pattern,778     pub fn rfind<P>(&self, pat: P) -> Option<usize>
779     where
780         P: Pattern,
781     {
782         let pat = pat.__encode();
783         let pat = pat.__get();
784 
785         rfind(&self.0, pat)
786     }
787 
split_once_raw_with<P, F>( &self, pat: &P, find_fn: F, ) -> Option<(&Self, &Self)> where F: FnOnce(&[u8], &[u8]) -> Option<usize>, P: EncodedPattern,788     fn split_once_raw_with<P, F>(
789         &self,
790         pat: &P,
791         find_fn: F,
792     ) -> Option<(&Self, &Self)>
793     where
794         F: FnOnce(&[u8], &[u8]) -> Option<usize>,
795         P: EncodedPattern,
796     {
797         let pat = pat.__get();
798 
799         let index = find_fn(&self.0, pat)?;
800         let prefix = &self.0[..index];
801         let suffix = &self.0[index + pat.len()..];
802         Some((Self::from_inner(prefix), Self::from_inner(suffix)))
803     }
804 
rsplit_once_raw<P>(&self, pat: &P) -> Option<(&Self, &Self)> where P: EncodedPattern,805     pub(super) fn rsplit_once_raw<P>(&self, pat: &P) -> Option<(&Self, &Self)>
806     where
807         P: EncodedPattern,
808     {
809         self.split_once_raw_with(pat, rfind)
810     }
811 
812     /// Equivalent to [`str::rsplit_once`].
813     ///
814     /// # Examples
815     ///
816     /// ```
817     /// use os_str_bytes::RawOsStr;
818     ///
819     /// let raw = RawOsStr::from_str("foobar");
820     /// assert_eq!(
821     ///     Some((RawOsStr::from_str("fo"), RawOsStr::from_str("bar"))),
822     ///     raw.rsplit_once("o"),
823     /// );
824     /// assert_eq!(None, raw.rsplit_once("of"));
825     /// ```
826     #[inline]
827     #[must_use]
rsplit_once<P>(&self, pat: P) -> Option<(&Self, &Self)> where P: Pattern,828     pub fn rsplit_once<P>(&self, pat: P) -> Option<(&Self, &Self)>
829     where
830         P: Pattern,
831     {
832         self.rsplit_once_raw(&pat.__encode())
833     }
834 
is_boundary(&self, index: usize) -> bool835     fn is_boundary(&self, index: usize) -> bool {
836         debug_assert!(index < self.0.len());
837 
838         if_nightly_return! {
839             {
840                 const MAX_LENGTH: usize = 4;
841 
842                 if index == 0 {
843                     return true;
844                 }
845                 let byte = self.0[index];
846                 if byte.is_ascii() {
847                     return true;
848                 }
849 
850                 if !util::is_continuation(byte) {
851                     let bytes = &self.0[index..];
852                     let valid =
853                         str::from_utf8(&bytes[..bytes.len().min(MAX_LENGTH)])
854                             .err()
855                             .map(|x| x.valid_up_to() != 0)
856                             .unwrap_or(true);
857                     if valid {
858                         return true;
859                     }
860                 }
861                 let mut start = index;
862                 for _ in 0..MAX_LENGTH {
863                     if let Some(index) = start.checked_sub(1) {
864                         start = index;
865                     } else {
866                         return false;
867                     }
868                     if !util::is_continuation(self.0[start]) {
869                         break;
870                     }
871                 }
872                 str::from_utf8(&self.0[start..index]).is_ok()
873             }
874             !raw::is_continuation(self.0[index])
875         }
876     }
877 
878     #[cfg_attr(feature = "nightly", allow(clippy::diverging_sub_expression))]
879     #[cold]
880     #[inline(never)]
881     #[track_caller]
index_boundary_error(&self, index: usize) -> !882     fn index_boundary_error(&self, index: usize) -> ! {
883         debug_assert!(!self.is_boundary(index));
884 
885         if_nightly_return! {
886             {
887                 panic!("byte index {} is not a valid boundary", index);
888             }
889             let start = expect_encoded!(self.0[..index]
890                 .iter()
891                 .rposition(|&x| !raw::is_continuation(x)));
892             let mut end = index + 1;
893             end += self.0[end..]
894                 .iter()
895                 .take_while(|&&x| raw::is_continuation(x))
896                 .count();
897 
898             let code_point = raw::decode_code_point(&self.0[start..end]);
899             panic!(
900                 "byte index {} is not a valid boundary; it is inside U+{:04X} \
901                  (bytes {}..{})",
902                 index, code_point, start, end,
903             );
904         }
905     }
906 
907     #[track_caller]
check_bound(&self, index: usize)908     fn check_bound(&self, index: usize) {
909         if index < self.0.len() && !self.is_boundary(index) {
910             self.index_boundary_error(index);
911         }
912     }
913 
914     /// Equivalent to [`str::split`], but empty patterns are not accepted.
915     ///
916     /// # Panics
917     ///
918     /// Panics if the pattern is empty.
919     ///
920     /// # Examples
921     ///
922     /// ```
923     /// use os_str_bytes::RawOsStr;
924     ///
925     /// let raw = RawOsStr::from_str("foobar");
926     /// assert!(raw.split("o").eq(["f", "", "bar"]));
927     /// ```
928     #[inline]
929     #[must_use]
930     #[track_caller]
split<P>(&self, pat: P) -> RawSplit<'_, P> where P: Pattern,931     pub fn split<P>(&self, pat: P) -> RawSplit<'_, P>
932     where
933         P: Pattern,
934     {
935         RawSplit::new(self, pat)
936     }
937 
938     /// Equivalent to [`str::split_at`].
939     ///
940     /// # Panics
941     ///
942     /// Panics if the index is not a [valid boundary].
943     ///
944     /// # Examples
945     ///
946     /// ```
947     /// use os_str_bytes::RawOsStr;
948     ///
949     /// let raw = RawOsStr::from_str("foobar");
950     /// assert_eq!(
951     ///     ((RawOsStr::from_str("fo"), RawOsStr::from_str("obar"))),
952     ///     raw.split_at(2),
953     /// );
954     /// ```
955     ///
956     /// [valid boundary]: #indices
957     #[inline]
958     #[must_use]
959     #[track_caller]
split_at(&self, mid: usize) -> (&Self, &Self)960     pub fn split_at(&self, mid: usize) -> (&Self, &Self) {
961         self.check_bound(mid);
962 
963         let (prefix, suffix) = self.0.split_at(mid);
964         (Self::from_inner(prefix), Self::from_inner(suffix))
965     }
966 
split_once_raw<P>(&self, pat: &P) -> Option<(&Self, &Self)> where P: EncodedPattern,967     pub(super) fn split_once_raw<P>(&self, pat: &P) -> Option<(&Self, &Self)>
968     where
969         P: EncodedPattern,
970     {
971         self.split_once_raw_with(pat, find)
972     }
973 
974     /// Equivalent to [`str::split_once`].
975     ///
976     /// # Examples
977     ///
978     /// ```
979     /// use os_str_bytes::RawOsStr;
980     ///
981     /// let raw = RawOsStr::from_str("foobar");
982     /// assert_eq!(
983     ///     Some((RawOsStr::from_str("f"), RawOsStr::from_str("obar"))),
984     ///     raw.split_once("o"),
985     /// );
986     /// assert_eq!(None, raw.split_once("of"));
987     /// ```
988     #[inline]
989     #[must_use]
split_once<P>(&self, pat: P) -> Option<(&Self, &Self)> where P: Pattern,990     pub fn split_once<P>(&self, pat: P) -> Option<(&Self, &Self)>
991     where
992         P: Pattern,
993     {
994         self.split_once_raw(&pat.__encode())
995     }
996 
997     /// Equivalent to [`str::starts_with`].
998     ///
999     /// # Examples
1000     ///
1001     /// ```
1002     /// use os_str_bytes::RawOsStr;
1003     ///
1004     /// let raw = RawOsStr::from_str("foobar");
1005     /// assert!(raw.starts_with("foo"));
1006     /// assert!(!raw.starts_with("bar"));
1007     /// ```
1008     #[inline]
1009     #[must_use]
starts_with<P>(&self, pat: P) -> bool where P: Pattern,1010     pub fn starts_with<P>(&self, pat: P) -> bool
1011     where
1012         P: Pattern,
1013     {
1014         let pat = pat.__encode();
1015         let pat = pat.__get();
1016 
1017         self.0.starts_with(pat)
1018     }
1019 
1020     deprecated_conversions! {
1021         /// Equivalent to [`str::starts_with`] but accepts this type for the
1022         /// pattern.
1023         ///
1024         /// # Examples
1025         ///
1026         /// ```
1027         /// use os_str_bytes::RawOsStr;
1028         ///
1029         /// let raw = RawOsStr::from_str("foobar");
1030         /// assert!(raw.starts_with_os(RawOsStr::from_str("foo")));
1031         /// assert!(!raw.starts_with_os(RawOsStr::from_str("bar")));
1032         /// ```
1033         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
1034         #[inline]
1035         #[must_use]
1036         pub fn starts_with_os(&self, pat: &Self) -> bool {
1037             raw::starts_with(&self.to_raw_bytes(), &pat.to_raw_bytes())
1038         }
1039     }
1040 
1041     /// Equivalent to [`str::strip_prefix`].
1042     ///
1043     /// # Examples
1044     ///
1045     /// ```
1046     /// use os_str_bytes::RawOsStr;
1047     ///
1048     /// let raw = RawOsStr::from_str("111foo1bar111");
1049     /// assert_eq!(
1050     ///     Some(RawOsStr::from_str("11foo1bar111")),
1051     ///     raw.strip_prefix("1"),
1052     /// );
1053     /// assert_eq!(None, raw.strip_prefix("o"));
1054     /// ```
1055     #[inline]
1056     #[must_use]
strip_prefix<P>(&self, pat: P) -> Option<&Self> where P: Pattern,1057     pub fn strip_prefix<P>(&self, pat: P) -> Option<&Self>
1058     where
1059         P: Pattern,
1060     {
1061         let pat = pat.__encode();
1062         let pat = pat.__get();
1063 
1064         self.0.strip_prefix(pat).map(Self::from_inner)
1065     }
1066 
1067     /// Equivalent to [`str::strip_suffix`].
1068     ///
1069     /// # Examples
1070     ///
1071     /// ```
1072     /// use os_str_bytes::RawOsStr;
1073     ///
1074     /// let raw = RawOsStr::from_str("111foo1bar111");
1075     /// assert_eq!(
1076     ///     Some(RawOsStr::from_str("111foo1bar11")),
1077     ///     raw.strip_suffix("1"),
1078     /// );
1079     /// assert_eq!(None, raw.strip_suffix("o"));
1080     /// ```
1081     #[inline]
1082     #[must_use]
strip_suffix<P>(&self, pat: P) -> Option<&Self> where P: Pattern,1083     pub fn strip_suffix<P>(&self, pat: P) -> Option<&Self>
1084     where
1085         P: Pattern,
1086     {
1087         let pat = pat.__encode();
1088         let pat = pat.__get();
1089 
1090         self.0.strip_suffix(pat).map(Self::from_inner)
1091     }
1092 
1093     /// Converts this representation back to a platform-native string.
1094     ///
1095     /// When possible, use [`RawOsStrCow::into_os_str`] for a more efficient
1096     /// conversion on some platforms.
1097     ///
1098     /// # Nightly Notes
1099     ///
1100     /// This method is deprecated. Use [`as_os_str`] instead.
1101     ///
1102     /// # Examples
1103     ///
1104     /// ```
1105     /// use std::env;
1106     /// # use std::io;
1107     ///
1108     /// use os_str_bytes::RawOsStr;
1109     ///
1110     /// let os_string = env::current_exe()?.into_os_string();
1111     /// let raw = RawOsStr::new(&os_string);
1112     /// assert_eq!(os_string, raw.to_os_str());
1113     /// #
1114     /// # Ok::<_, io::Error>(())
1115     /// ```
1116     ///
1117     /// [`as_os_str`]: Self::as_os_str
1118     #[cfg_attr(
1119         all(not(os_str_bytes_docs_rs), feature = "nightly"),
1120         deprecated(since = "6.6.0", note = "use `as_os_str` instead")
1121     )]
1122     #[inline]
1123     #[must_use]
to_os_str(&self) -> Cow<'_, OsStr>1124     pub fn to_os_str(&self) -> Cow<'_, OsStr> {
1125         if_nightly_return! {{
1126             Cow::Borrowed(self.as_os_str())
1127         }}
1128         expect_encoded!(imp::os_str_from_bytes(&self.0))
1129     }
1130 
1131     deprecated_conversions! {
1132         /// Converts and returns the byte string stored by this container.
1133         ///
1134         /// The returned string will use an [unspecified encoding].
1135         ///
1136         /// # Examples
1137         ///
1138         /// ```
1139         /// use os_str_bytes::RawOsStr;
1140         ///
1141         /// let string = "foobar";
1142         /// let raw = RawOsStr::from_str(string);
1143         /// assert_eq!(string.as_bytes(), &*raw.to_raw_bytes());
1144         /// ```
1145         ///
1146         /// [unspecified encoding]: super#encoding
1147         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
1148         #[inline]
1149         #[must_use]
1150         pub fn to_raw_bytes(&self) -> Cow<'_, [u8]> {
1151             if_nightly_return! {{
1152                 imp::os_str_to_bytes(self.as_os_str())
1153             }}
1154             Cow::Borrowed(&self.0)
1155         }
1156     }
1157 
1158     /// Equivalent to [`OsStr::to_str`].
1159     ///
1160     /// # Examples
1161     ///
1162     /// ```
1163     /// use os_str_bytes::RawOsStr;
1164     ///
1165     /// let string = "foobar";
1166     /// let raw = RawOsStr::from_str(string);
1167     /// assert_eq!(Some(string), raw.to_str());
1168     /// ```
1169     #[inline]
1170     #[must_use]
to_str(&self) -> Option<&str>1171     pub fn to_str(&self) -> Option<&str> {
1172         str::from_utf8(&self.0).ok()
1173     }
1174 
1175     /// Converts this string to the best UTF-8 representation possible.
1176     ///
1177     /// Invalid sequences will be replaced with
1178     /// [`char::REPLACEMENT_CHARACTER`].
1179     ///
1180     /// This method may return a different result than would
1181     /// [`OsStr::to_string_lossy`] when called on same string, since [`OsStr`]
1182     /// uses an unspecified encoding.
1183     ///
1184     /// # Examples
1185     ///
1186     /// ```
1187     /// use std::env;
1188     /// # use std::io;
1189     ///
1190     /// use os_str_bytes::RawOsStr;
1191     ///
1192     /// let os_string = env::current_exe()?.into_os_string();
1193     /// let raw = RawOsStr::new(&os_string);
1194     /// println!("{}", raw.to_str_lossy());
1195     /// #
1196     /// # Ok::<_, io::Error>(())
1197     /// ```
1198     #[inline]
1199     #[must_use]
to_str_lossy(&self) -> Cow<'_, str>1200     pub fn to_str_lossy(&self) -> Cow<'_, str> {
1201         String::from_utf8_lossy(&self.0)
1202     }
1203 
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,1204     fn trim_matches_raw_with<P, F>(&self, pat: &P, strip_fn: F) -> &Self
1205     where
1206         F: for<'a> Fn(&'a [u8], &[u8]) -> Option<&'a [u8]>,
1207         P: EncodedPattern,
1208     {
1209         let pat = pat.__get();
1210         if pat.is_empty() {
1211             return self;
1212         }
1213 
1214         let mut string = &self.0;
1215         while let Some(substring) = strip_fn(string, pat) {
1216             string = substring;
1217         }
1218         Self::from_inner(string)
1219     }
1220 
trim_end_matches_raw<P>(&self, pat: &P) -> &Self where P: EncodedPattern,1221     fn trim_end_matches_raw<P>(&self, pat: &P) -> &Self
1222     where
1223         P: EncodedPattern,
1224     {
1225         self.trim_matches_raw_with(pat, <[_]>::strip_suffix)
1226     }
1227 
1228     /// Equivalent to [`str::trim_end_matches`].
1229     ///
1230     /// # Examples
1231     ///
1232     /// ```
1233     /// use os_str_bytes::RawOsStr;
1234     ///
1235     /// let raw = RawOsStr::from_str("111foo1bar111");
1236     /// assert_eq!("111foo1bar", raw.trim_end_matches("1"));
1237     /// assert_eq!("111foo1bar111", raw.trim_end_matches("o"));
1238     /// ```
1239     #[inline]
1240     #[must_use]
trim_end_matches<P>(&self, pat: P) -> &Self where P: Pattern,1241     pub fn trim_end_matches<P>(&self, pat: P) -> &Self
1242     where
1243         P: Pattern,
1244     {
1245         self.trim_end_matches_raw(&pat.__encode())
1246     }
1247 
1248     /// Equivalent to [`str::trim_matches`].
1249     ///
1250     /// # Examples
1251     ///
1252     /// ```
1253     /// use os_str_bytes::RawOsStr;
1254     ///
1255     /// let raw = RawOsStr::from_str("111foo1bar111");
1256     /// assert_eq!("foo1bar", raw.trim_matches("1"));
1257     /// assert_eq!("111foo1bar111", raw.trim_matches("o"));
1258     /// ```
1259     #[inline]
1260     #[must_use]
trim_matches<P>(&self, pat: P) -> &Self where P: Pattern,1261     pub fn trim_matches<P>(&self, pat: P) -> &Self
1262     where
1263         P: Pattern,
1264     {
1265         let pat = pat.__encode();
1266         self.trim_start_matches_raw(&pat).trim_end_matches_raw(&pat)
1267     }
1268 
trim_start_matches_raw<P>(&self, pat: &P) -> &Self where P: EncodedPattern,1269     fn trim_start_matches_raw<P>(&self, pat: &P) -> &Self
1270     where
1271         P: EncodedPattern,
1272     {
1273         self.trim_matches_raw_with(pat, <[_]>::strip_prefix)
1274     }
1275 
1276     /// Equivalent to [`str::trim_start_matches`].
1277     ///
1278     /// # Examples
1279     ///
1280     /// ```
1281     /// use os_str_bytes::RawOsStr;
1282     ///
1283     /// let raw = RawOsStr::from_str("111foo1bar111");
1284     /// assert_eq!("foo1bar111", raw.trim_start_matches("1"));
1285     /// assert_eq!("111foo1bar111", raw.trim_start_matches("o"));
1286     /// ```
1287     #[inline]
1288     #[must_use]
trim_start_matches<P>(&self, pat: P) -> &Self where P: Pattern,1289     pub fn trim_start_matches<P>(&self, pat: P) -> &Self
1290     where
1291         P: Pattern,
1292     {
1293         self.trim_start_matches_raw(&pat.__encode())
1294     }
1295 }
1296 
1297 impl AsRef<Self> for RawOsStr {
1298     #[inline]
as_ref(&self) -> &Self1299     fn as_ref(&self) -> &Self {
1300         self
1301     }
1302 }
1303 
1304 if_nightly! {
1305     #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "nightly")))]
1306     impl AsRef<OsStr> for RawOsStr {
1307         #[inline]
1308         fn as_ref(&self) -> &OsStr {
1309             self.as_os_str()
1310         }
1311     }
1312 
1313     #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "nightly")))]
1314     impl AsRef<RawOsStr> for OsStr {
1315         #[inline]
1316         fn as_ref(&self) -> &RawOsStr {
1317             RawOsStr::from_os_str(self)
1318         }
1319     }
1320 }
1321 
1322 if_nightly! {
1323     #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "nightly")))]
1324     impl AsRef<RawOsStr> for OsString {
1325         #[inline]
1326         fn as_ref(&self) -> &RawOsStr {
1327             (**self).as_ref()
1328         }
1329     }
1330 }
1331 
1332 impl AsRef<RawOsStr> for str {
1333     #[inline]
as_ref(&self) -> &RawOsStr1334     fn as_ref(&self) -> &RawOsStr {
1335         RawOsStr::from_str(self)
1336     }
1337 }
1338 
1339 impl AsRef<RawOsStr> for String {
1340     #[inline]
as_ref(&self) -> &RawOsStr1341     fn as_ref(&self) -> &RawOsStr {
1342         (**self).as_ref()
1343     }
1344 }
1345 
1346 impl Default for &RawOsStr {
1347     #[inline]
default() -> Self1348     fn default() -> Self {
1349         RawOsStr::from_str("")
1350     }
1351 }
1352 
1353 impl<'a> From<&'a RawOsStr> for Cow<'a, RawOsStr> {
1354     #[inline]
from(value: &'a RawOsStr) -> Self1355     fn from(value: &'a RawOsStr) -> Self {
1356         Cow::Borrowed(value)
1357     }
1358 }
1359 
1360 impl From<Box<str>> for Box<RawOsStr> {
1361     #[inline]
from(value: Box<str>) -> Self1362     fn from(value: Box<str>) -> Self {
1363         value.into_boxed_bytes().transmute_box()
1364     }
1365 }
1366 
1367 impl ToOwned for RawOsStr {
1368     type Owned = RawOsString;
1369 
1370     #[inline]
to_owned(&self) -> Self::Owned1371     fn to_owned(&self) -> Self::Owned {
1372         RawOsString(self.0.to_owned())
1373     }
1374 }
1375 
1376 /// Extensions to [`Cow<RawOsStr>`] for additional conversions.
1377 ///
1378 /// [`Cow<RawOsStr>`]: Cow
1379 #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "raw_os_str")))]
1380 pub trait RawOsStrCow<'a>: private::Sealed {
1381     /// Converts a platform-native string back to this representation.
1382     ///
1383     /// # Nightly Notes
1384     ///
1385     /// This method does not require copying or encoding conversion.
1386     ///
1387     /// # Examples
1388     ///
1389     /// ```
1390     /// use std::borrow::Cow;
1391     /// use std::env;
1392     /// # use std::io;
1393     ///
1394     /// use os_str_bytes::RawOsStr;
1395     /// use os_str_bytes::RawOsStrCow;
1396     ///
1397     /// let os_string = Cow::Owned(env::current_exe()?.into_os_string());
1398     /// println!("{:?}", Cow::from_os_str(os_string));
1399     /// #
1400     /// # Ok::<_, io::Error>(())
1401     /// ```
1402     #[must_use]
from_os_str(string: Cow<'a, OsStr>) -> Self1403     fn from_os_str(string: Cow<'a, OsStr>) -> Self;
1404 
1405     /// Converts this representation back to a platform-native string.
1406     ///
1407     /// # Nightly Notes
1408     ///
1409     /// This method does not require copying or encoding conversion.
1410     ///
1411     /// # Examples
1412     ///
1413     /// ```
1414     /// use std::env;
1415     /// # use std::io;
1416     ///
1417     /// use os_str_bytes::RawOsStr;
1418     /// use os_str_bytes::RawOsStrCow;
1419     ///
1420     /// let os_string = env::current_exe()?.into_os_string();
1421     /// let raw = RawOsStr::new(&os_string);
1422     /// assert_eq!(os_string, raw.into_os_str());
1423     /// #
1424     /// # Ok::<_, io::Error>(())
1425     /// ```
1426     #[must_use]
into_os_str(self) -> Cow<'a, OsStr>1427     fn into_os_str(self) -> Cow<'a, OsStr>;
1428 
1429     deprecated_conversions! {
1430         /// Returns the byte string stored by this container.
1431         ///
1432         /// The returned string will use an [unspecified encoding].
1433         ///
1434         /// # Examples
1435         ///
1436         /// ```
1437         /// use std::borrow::Cow;
1438         ///
1439         /// use os_str_bytes::RawOsStr;
1440         /// use os_str_bytes::RawOsStrCow;
1441         ///
1442         /// let string = "foobar";
1443         /// let raw = Cow::Borrowed(RawOsStr::from_str(string));
1444         /// assert_eq!(string.as_bytes(), &*raw.into_raw_bytes());
1445         /// ```
1446         ///
1447         /// [unspecified encoding]: super#encoding
1448         #[cfg_attr(
1449             feature = "conversions",
1450             deprecated(
1451                 since = "6.6.0",
1452                 note = "removal planned due to low usage",
1453             )
1454         )]
1455         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
1456         #[must_use]
1457         fn into_raw_bytes(self) -> Cow<'a, [u8]>;
1458     }
1459 }
1460 
1461 impl<'a> RawOsStrCow<'a> for Cow<'a, RawOsStr> {
1462     #[cfg_attr(feature = "nightly", allow(deprecated))]
1463     #[inline]
from_os_str(string: Cow<'a, OsStr>) -> Self1464     fn from_os_str(string: Cow<'a, OsStr>) -> Self {
1465         match string {
1466             Cow::Borrowed(string) => RawOsStr::new(string),
1467             Cow::Owned(string) => Cow::Owned(RawOsString::new(string)),
1468         }
1469     }
1470 
1471     #[cfg_attr(feature = "nightly", allow(deprecated))]
1472     #[inline]
into_os_str(self) -> Cow<'a, OsStr>1473     fn into_os_str(self) -> Cow<'a, OsStr> {
1474         match self {
1475             Cow::Borrowed(string) => string.to_os_str(),
1476             Cow::Owned(string) => Cow::Owned(string.into_os_string()),
1477         }
1478     }
1479 
1480     #[inline]
into_raw_bytes(self) -> Cow<'a, [u8]>1481     fn into_raw_bytes(self) -> Cow<'a, [u8]> {
1482         match self {
1483             Cow::Borrowed(string) => string.to_raw_bytes(),
1484             Cow::Owned(string) => Cow::Owned(string.into_raw_vec()),
1485         }
1486     }
1487 }
1488 
1489 /// A container for owned byte strings converted by this crate.
1490 ///
1491 /// For more information, see [`RawOsStr`].
1492 #[derive(Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
1493 #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "raw_os_str")))]
1494 pub struct RawOsString(Vec<u8>);
1495 
1496 impl RawOsString {
1497     /// Converts a platform-native string into a representation that can be
1498     /// more easily manipulated.
1499     ///
1500     /// For more information, see [`RawOsStr::new`].
1501     ///
1502     /// # Nightly Notes
1503     ///
1504     /// This method does not require copying or encoding conversion.
1505     ///
1506     /// # Examples
1507     ///
1508     /// ```
1509     /// use std::env;
1510     /// # use std::io;
1511     ///
1512     /// use os_str_bytes::RawOsString;
1513     ///
1514     /// let os_string = env::current_exe()?.into_os_string();
1515     /// println!("{:?}", RawOsString::new(os_string));
1516     /// #
1517     /// # Ok::<_, io::Error>(())
1518     /// ```
1519     #[inline]
1520     #[must_use]
new(string: OsString) -> Self1521     pub fn new(string: OsString) -> Self {
1522         if_nightly_return! {{
1523             Self(string.into_encoded_bytes())
1524         }}
1525         Self(imp::os_string_into_vec(string))
1526     }
1527 
1528     /// Wraps a string, without copying or encoding conversion.
1529     ///
1530     /// This method is much more efficient than [`RawOsString::new`], since the
1531     /// [encoding] used by this crate is compatible with UTF-8.
1532     ///
1533     /// # Examples
1534     ///
1535     /// ```
1536     /// use os_str_bytes::RawOsString;
1537     ///
1538     /// let string = "foobar".to_owned();
1539     /// let raw = RawOsString::from_string(string.clone());
1540     /// assert_eq!(string, raw);
1541     /// ```
1542     ///
1543     /// [encoding]: super#encoding
1544     #[inline]
1545     #[must_use]
from_string(string: String) -> Self1546     pub fn from_string(string: String) -> Self {
1547         Self(string.into_bytes())
1548     }
1549 
1550     if_nightly! {
1551         /// Equivalent to [`OsString::from_encoded_bytes_unchecked`].
1552         ///
1553         /// # Examples
1554         ///
1555         /// ```
1556         /// use std::env;
1557         /// # use std::io;
1558         ///
1559         /// use os_str_bytes::RawOsString;
1560         ///
1561         /// let os_string = env::current_exe()?.into_os_string();
1562         /// let raw = RawOsString::new(os_string);
1563         /// let raw_bytes = raw.clone().into_encoded_vec();
1564         /// assert_eq!(raw, unsafe {
1565         ///     RawOsString::from_encoded_vec_unchecked(raw_bytes)
1566         /// });
1567         /// #
1568         /// # Ok::<_, io::Error>(())
1569         /// ```
1570         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "nightly")))]
1571         #[inline]
1572         #[must_use]
1573         pub unsafe fn from_encoded_vec_unchecked(string: Vec<u8>) -> Self {
1574             Self(string)
1575         }
1576     }
1577 
from_raw_vec_checked(string: Vec<u8>) -> imp::Result<Self>1578     fn from_raw_vec_checked(string: Vec<u8>) -> imp::Result<Self> {
1579         if_nightly_return! {
1580             {
1581                 imp::os_string_from_vec(string).map(Self::new)
1582             }
1583             raw::validate_bytes(&string).map(|()| Self(string))
1584         }
1585     }
1586 
1587     deprecated_conversions! {
1588         /// Wraps a byte string, without copying or encoding conversion.
1589         ///
1590         /// # Panics
1591         ///
1592         /// Panics if the string is not valid for the [unspecified encoding]
1593         /// used by this crate.
1594         ///
1595         /// # Examples
1596         ///
1597         /// ```
1598         /// use std::env;
1599         /// # use std::io;
1600         ///
1601         /// use os_str_bytes::RawOsString;
1602         ///
1603         /// let os_string = env::current_exe()?.into_os_string();
1604         /// let raw = RawOsString::new(os_string);
1605         /// let raw_bytes = raw.clone().into_raw_vec();
1606         /// assert_eq!(raw, RawOsString::assert_from_raw_vec(raw_bytes));
1607         /// #
1608         /// # Ok::<_, io::Error>(())
1609         /// ```
1610         ///
1611         /// [unspecified encoding]: super#encoding
1612         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
1613         #[inline]
1614         #[must_use = "method should not be used for validation"]
1615         #[track_caller]
1616         pub fn assert_from_raw_vec(string: Vec<u8>) -> Self {
1617             expect_encoded!(Self::from_raw_vec_checked(string))
1618         }
1619     }
1620 
1621     if_checked_conversions! {
1622         /// Wraps a byte string, without copying or encoding conversion.
1623         ///
1624         /// [`assert_from_raw_vec`] should almost always be used instead. For
1625         /// more information, see [`EncodingError`].
1626         ///
1627         /// # Errors
1628         ///
1629         /// See documentation for [`EncodingError`].
1630         ///
1631         /// # Examples
1632         ///
1633         /// ```
1634         /// use std::env;
1635         /// # use std::io;
1636         ///
1637         /// use os_str_bytes::RawOsString;
1638         ///
1639         /// let os_string = env::current_exe()?.into_os_string();
1640         /// let raw = RawOsString::new(os_string);
1641         /// let raw_bytes = raw.clone().into_raw_vec();
1642         /// assert_eq!(Ok(raw), RawOsString::from_raw_vec(raw_bytes));
1643         /// #
1644         /// # Ok::<_, io::Error>(())
1645         /// ```
1646         ///
1647         /// [`assert_from_raw_vec`]: Self::assert_from_raw_vec
1648         #[cfg_attr(
1649             os_str_bytes_docs_rs,
1650             doc(cfg(feature = "checked_conversions"))
1651         )]
1652         #[inline]
1653         pub fn from_raw_vec(string: Vec<u8>) -> Result<Self> {
1654             Self::from_raw_vec_checked(string).map_err(EncodingError)
1655         }
1656     }
1657 
1658     deprecated_conversions! {
1659         /// Wraps a byte string, without copying or encoding conversion.
1660         ///
1661         /// # Safety
1662         ///
1663         /// The string must be valid for the [unspecified encoding] used by
1664         /// this crate.
1665         ///
1666         /// # Nightly Notes
1667         ///
1668         /// This method is deprecated. Use [`assert_from_raw_vec`] or
1669         /// [`from_encoded_vec_unchecked`] instead.
1670         ///
1671         /// # Examples
1672         ///
1673         /// ```
1674         /// use std::env;
1675         /// # use std::io;
1676         ///
1677         /// use os_str_bytes::RawOsString;
1678         ///
1679         /// let os_string = env::current_exe()?.into_os_string();
1680         /// let raw = RawOsString::new(os_string);
1681         /// let raw_bytes = raw.clone().into_raw_vec();
1682         /// assert_eq!(raw, unsafe {
1683         ///     RawOsString::from_raw_vec_unchecked(raw_bytes)
1684         /// });
1685         /// #
1686         /// # Ok::<_, io::Error>(())
1687         /// ```
1688         ///
1689         /// [`assert_from_raw_vec`]: Self::assert_from_raw_vec
1690         /// [`from_encoded_vec_unchecked`]: Self::from_encoded_vec_unchecked
1691         /// [unspecified encoding]: super#encoding
1692         #[cfg_attr(
1693             all(
1694                 not(os_str_bytes_docs_rs),
1695                 feature = "conversions",
1696                 feature = "nightly",
1697             ),
1698             deprecated(
1699                 since = "6.6.0",
1700                 note = "use `assert_from_raw_vec` or
1701                         `from_encoded_vec_unchecked` instead",
1702             )
1703         )]
1704         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
1705         #[inline]
1706         #[must_use]
1707         #[track_caller]
1708         pub unsafe fn from_raw_vec_unchecked(string: Vec<u8>) -> Self {
1709             if_nightly_return! {
1710                 {
1711                     Self::assert_from_raw_vec(string)
1712                 }
1713                 if cfg!(debug_assertions) {
1714                     expect_encoded!(raw::validate_bytes(&string));
1715                 }
1716             }
1717 
1718             Self(string)
1719         }
1720     }
1721 
1722     /// Equivalent to [`String::clear`].
1723     ///
1724     /// # Examples
1725     ///
1726     /// ```
1727     /// use std::env;
1728     /// # use std::io;
1729     ///
1730     /// use os_str_bytes::RawOsString;
1731     ///
1732     /// let os_string = env::current_exe()?.into_os_string();
1733     /// let mut raw = RawOsString::new(os_string);
1734     /// raw.clear();
1735     /// assert!(raw.is_empty());
1736     /// #
1737     /// # Ok::<_, io::Error>(())
1738     /// ```
1739     #[inline]
clear(&mut self)1740     pub fn clear(&mut self) {
1741         self.0.clear();
1742     }
1743 
1744     /// Equivalent to [`String::into_boxed_str`].
1745     ///
1746     /// # Examples
1747     ///
1748     /// ```
1749     /// use os_str_bytes::RawOsString;
1750     ///
1751     /// let string = "foobar".to_owned();
1752     /// let raw = RawOsString::from_string(string.clone());
1753     /// assert_eq!(string, *raw.into_box());
1754     /// ```
1755     #[inline]
1756     #[must_use]
into_box(self) -> Box<RawOsStr>1757     pub fn into_box(self) -> Box<RawOsStr> {
1758         self.0.into_boxed_slice().transmute_box()
1759     }
1760 
1761     if_nightly! {
1762         /// Equivalent to [`OsString::into_encoded_bytes`].
1763         ///
1764         /// The returned string will not use the [unspecified encoding]. It can
1765         /// only be passed to methods accepting the encoding from the standard
1766         /// library, such as [`from_encoded_vec_unchecked`].
1767         ///
1768         /// # Examples
1769         ///
1770         /// ```
1771         /// use os_str_bytes::RawOsString;
1772         ///
1773         /// let string = "foobar".to_owned();
1774         /// let raw = RawOsString::from_string(string.clone());
1775         /// assert_eq!(string.into_bytes(), raw.into_encoded_vec());
1776         /// ```
1777         ///
1778         /// [`from_encoded_vec_unchecked`]: Self::from_encoded_vec_unchecked
1779         /// [unspecified encoding]: super#encoding
1780         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "nightly")))]
1781         #[inline]
1782         #[must_use]
1783         pub fn into_encoded_vec(self) -> Vec<u8> {
1784             self.0
1785         }
1786     }
1787 
1788     /// Converts this representation back to a platform-native string.
1789     ///
1790     /// # Nightly Notes
1791     ///
1792     /// This method does not require copying or encoding conversion.
1793     ///
1794     /// # Examples
1795     ///
1796     /// ```
1797     /// use std::env;
1798     /// # use std::io;
1799     ///
1800     /// use os_str_bytes::RawOsString;
1801     ///
1802     /// let os_string = env::current_exe()?.into_os_string();
1803     /// let raw = RawOsString::new(os_string.clone());
1804     /// assert_eq!(os_string, raw.into_os_string());
1805     /// #
1806     /// # Ok::<_, io::Error>(())
1807     /// ```
1808     #[inline]
1809     #[must_use]
into_os_string(self) -> OsString1810     pub fn into_os_string(self) -> OsString {
1811         if_nightly_return! {{
1812             // SAFETY: This wrapper prevents violating the invariants of the
1813             // encoding used by the standard library.
1814             unsafe { OsString::from_encoded_bytes_unchecked(self.0) }
1815         }}
1816         expect_encoded!(imp::os_string_from_vec(self.0))
1817     }
1818 
1819     deprecated_conversions! {
1820         /// Returns the byte string stored by this container.
1821         ///
1822         /// The returned string will use an [unspecified encoding].
1823         ///
1824         /// # Examples
1825         ///
1826         /// ```
1827         /// use os_str_bytes::RawOsString;
1828         ///
1829         /// let string = "foobar".to_owned();
1830         /// let raw = RawOsString::from_string(string.clone());
1831         /// assert_eq!(string.into_bytes(), raw.into_raw_vec());
1832         /// ```
1833         ///
1834         /// [unspecified encoding]: super#encoding
1835         #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
1836         #[inline]
1837         #[must_use]
1838         pub fn into_raw_vec(self) -> Vec<u8> {
1839             if_nightly_return! {{
1840                 imp::os_string_into_vec(self.into_os_string())
1841             }}
1842             self.0
1843         }
1844     }
1845 
1846     /// Equivalent to [`OsString::into_string`].
1847     ///
1848     /// # Examples
1849     ///
1850     /// ```
1851     /// use os_str_bytes::RawOsString;
1852     ///
1853     /// let string = "foobar".to_owned();
1854     /// let raw = RawOsString::from_string(string.clone());
1855     /// assert_eq!(Ok(string), raw.into_string());
1856     /// ```
1857     #[inline]
into_string(self) -> result::Result<String, Self>1858     pub fn into_string(self) -> result::Result<String, Self> {
1859         String::from_utf8(self.0).map_err(|x| Self(x.into_bytes()))
1860     }
1861 
1862     /// Equivalent to [`String::shrink_to_fit`].
1863     ///
1864     /// # Examples
1865     ///
1866     /// ```
1867     /// use os_str_bytes::RawOsString;
1868     ///
1869     /// let string = "foobar".to_owned();
1870     /// let mut raw = RawOsString::from_string(string.clone());
1871     /// raw.shrink_to_fit();
1872     /// assert_eq!(string, raw);
1873     /// ```
1874     #[inline]
shrink_to_fit(&mut self)1875     pub fn shrink_to_fit(&mut self) {
1876         self.0.shrink_to_fit();
1877     }
1878 
1879     /// Equivalent to [`String::split_off`].
1880     ///
1881     /// # Panics
1882     ///
1883     /// Panics if the index is not a [valid boundary].
1884     ///
1885     /// # Examples
1886     ///
1887     /// ```
1888     /// use os_str_bytes::RawOsString;
1889     ///
1890     /// let mut raw = RawOsString::from_string("foobar".to_owned());
1891     /// assert_eq!("bar", raw.split_off(3));
1892     /// assert_eq!("foo", raw);
1893     /// ```
1894     ///
1895     /// [valid boundary]: RawOsStr#indices
1896     #[inline]
1897     #[must_use]
1898     #[track_caller]
split_off(&mut self, at: usize) -> Self1899     pub fn split_off(&mut self, at: usize) -> Self {
1900         self.check_bound(at);
1901 
1902         Self(self.0.split_off(at))
1903     }
1904 
1905     /// Equivalent to [`String::truncate`].
1906     ///
1907     /// # Panics
1908     ///
1909     /// Panics if the index is not a [valid boundary].
1910     ///
1911     /// # Examples
1912     ///
1913     /// ```
1914     /// use os_str_bytes::RawOsString;
1915     ///
1916     /// let mut raw = RawOsString::from_string("foobar".to_owned());
1917     /// raw.truncate(3);
1918     /// assert_eq!("foo", raw);
1919     /// ```
1920     ///
1921     /// [valid boundary]: RawOsStr#indices
1922     #[inline]
1923     #[track_caller]
truncate(&mut self, new_len: usize)1924     pub fn truncate(&mut self, new_len: usize) {
1925         self.check_bound(new_len);
1926 
1927         self.0.truncate(new_len);
1928     }
1929 }
1930 
1931 if_nightly! {
1932     #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "nightly")))]
1933     impl AsRef<OsStr> for RawOsString {
1934         #[inline]
1935         fn as_ref(&self) -> &OsStr {
1936             (**self).as_ref()
1937         }
1938     }
1939 }
1940 
1941 impl AsRef<RawOsStr> for RawOsString {
1942     #[inline]
as_ref(&self) -> &RawOsStr1943     fn as_ref(&self) -> &RawOsStr {
1944         self
1945     }
1946 }
1947 
1948 impl Borrow<RawOsStr> for RawOsString {
1949     #[inline]
borrow(&self) -> &RawOsStr1950     fn borrow(&self) -> &RawOsStr {
1951         self
1952     }
1953 }
1954 
1955 impl Deref for RawOsString {
1956     type Target = RawOsStr;
1957 
1958     #[inline]
deref(&self) -> &Self::Target1959     fn deref(&self) -> &Self::Target {
1960         RawOsStr::from_inner(&self.0)
1961     }
1962 }
1963 
1964 impl From<RawOsString> for Box<RawOsStr> {
1965     #[inline]
from(value: RawOsString) -> Self1966     fn from(value: RawOsString) -> Self {
1967         value.into_box()
1968     }
1969 }
1970 
1971 impl From<Box<RawOsStr>> for RawOsString {
1972     #[inline]
from(value: Box<RawOsStr>) -> Self1973     fn from(value: Box<RawOsStr>) -> Self {
1974         Self(value.transmute_box::<[_]>().into_vec())
1975     }
1976 }
1977 
1978 impl From<RawOsString> for Cow<'_, RawOsStr> {
1979     #[inline]
from(value: RawOsString) -> Self1980     fn from(value: RawOsString) -> Self {
1981         Cow::Owned(value)
1982     }
1983 }
1984 
1985 if_nightly! {
1986     #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "nightly")))]
1987     impl From<OsString> for RawOsString {
1988         #[inline]
1989         fn from(value: OsString) -> Self {
1990             Self::new(value)
1991         }
1992     }
1993 
1994     #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "nightly")))]
1995     impl From<RawOsString> for OsString {
1996         #[inline]
1997         fn from(value: RawOsString) -> Self {
1998             value.into_os_string()
1999         }
2000     }
2001 }
2002 
2003 impl From<String> for RawOsString {
2004     #[inline]
from(value: String) -> Self2005     fn from(value: String) -> Self {
2006         Self::from_string(value)
2007     }
2008 }
2009 
2010 struct DebugBuffer<'a>(&'a [u8]);
2011 
2012 impl Debug for DebugBuffer<'_> {
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result2013     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2014         f.write_str("\"")?;
2015 
2016         let mut string = self.0;
2017         let mut invalid_length = 0;
2018         while !string.is_empty() {
2019             let (invalid, substring) = string.split_at(invalid_length);
2020 
2021             let valid = match str::from_utf8(substring) {
2022                 Ok(valid) => {
2023                     string = b"";
2024                     valid
2025                 }
2026                 Err(error) => {
2027                     let (valid, substring) =
2028                         substring.split_at(error.valid_up_to());
2029 
2030                     let invalid_char_length =
2031                         error.error_len().unwrap_or_else(|| substring.len());
2032                     if valid.is_empty() {
2033                         invalid_length += invalid_char_length;
2034                         continue;
2035                     }
2036                     string = substring;
2037                     invalid_length = invalid_char_length;
2038 
2039                     // SAFETY: This slice was validated to be UTF-8.
2040                     unsafe { str::from_utf8_unchecked(valid) }
2041                 }
2042             };
2043 
2044             raw::debug(RawOsStr::from_inner(invalid), f)?;
2045             Display::fmt(&valid.escape_debug(), f)?;
2046         }
2047 
2048         f.write_str("\"")
2049     }
2050 }
2051 
2052 macro_rules! r#impl {
2053     ( $type:ty ) => {
2054         impl Debug for $type {
2055             #[inline]
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result2056             fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2057                 f.debug_tuple(stringify!($type))
2058                     .field(&DebugBuffer(&self.0))
2059                     .finish()
2060             }
2061         }
2062     };
2063 }
2064 r#impl!(RawOsStr);
2065 r#impl!(RawOsString);
2066 
2067 macro_rules! r#impl {
2068     ( $index_type:ty $(, $index_var:ident , $($bound:expr),+)? ) => {
2069         impl Index<$index_type> for RawOsStr {
2070             type Output = Self;
2071 
2072             #[inline]
index(&self, idx: $index_type) -> &Self::Output2073             fn index(&self, idx: $index_type) -> &Self::Output {
2074                 $(
2075                     let $index_var = &idx;
2076                     $(self.check_bound($bound);)+
2077                 )?
2078 
2079                 Self::from_inner(&self.0[idx])
2080             }
2081         }
2082 
2083         impl Index<$index_type> for RawOsString {
2084             type Output = RawOsStr;
2085 
2086             #[inline]
index(&self, idx: $index_type) -> &Self::Output2087             fn index(&self, idx: $index_type) -> &Self::Output {
2088                 &(**self)[idx]
2089             }
2090         }
2091     };
2092 }
2093 r#impl!(Range<usize>, x, x.start, x.end);
2094 r#impl!(RangeFrom<usize>, x, x.start);
2095 r#impl!(RangeFull);
2096 // [usize::MAX] will always be a valid inclusive end index.
2097 #[rustfmt::skip]
2098 r#impl!(RangeInclusive<usize>, x, *x.start(), x.end().wrapping_add(1));
2099 r#impl!(RangeTo<usize>, x, x.end);
2100 r#impl!(RangeToInclusive<usize>, x, x.end.wrapping_add(1));
2101 
2102 macro_rules! r#impl {
2103     ( $(#[$attr:meta])* $type:ty , $other_type:ty ) => {
2104         $(#[$attr])*
2105         impl PartialEq<$other_type> for $type {
2106             #[inline]
eq(&self, other: &$other_type) -> bool2107             fn eq(&self, other: &$other_type) -> bool {
2108                 let raw: &RawOsStr = self;
2109                 let other: &RawOsStr = other.as_ref();
2110                 raw == other
2111             }
2112         }
2113 
2114         $(#[$attr])*
2115         impl PartialEq<$type> for $other_type {
2116             #[inline]
eq(&self, other: &$type) -> bool2117             fn eq(&self, other: &$type) -> bool {
2118                 other == self
2119             }
2120         }
2121     };
2122 }
2123 r#impl!(RawOsStr, RawOsString);
2124 r#impl!(RawOsStr, str);
2125 r#impl!(RawOsStr, String);
2126 r#impl!(&RawOsStr, RawOsString);
2127 r#impl!(&RawOsStr, String);
2128 r#impl!(RawOsString, str);
2129 r#impl!(RawOsString, &str);
2130 r#impl!(RawOsString, String);
2131 
2132 if_nightly! {
2133     macro_rules! impl_nightly {
2134         ( $type:ty , $other_type:ty ) => {
2135             r#impl! {
2136                 #[cfg_attr(
2137                     os_str_bytes_docs_rs,
2138                     doc(cfg(feature = "nightly"))
2139                 )]
2140                 $type, $other_type
2141             }
2142         };
2143     }
2144     impl_nightly!(RawOsStr, OsStr);
2145     impl_nightly!(RawOsStr, OsString);
2146     impl_nightly!(&RawOsStr, OsString);
2147     impl_nightly!(RawOsString, OsStr);
2148     impl_nightly!(RawOsString, &OsStr);
2149     impl_nightly!(RawOsString, OsString);
2150 }
2151 
2152 #[cfg(feature = "print_bytes")]
2153 #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "print_bytes")))]
2154 mod print_bytes {
2155     use print_bytes::ByteStr;
2156     use print_bytes::ToBytes;
2157     #[cfg(windows)]
2158     use print_bytes::WideStr;
2159 
2160     #[cfg(windows)]
2161     use crate::imp::raw;
2162 
2163     use super::RawOsStr;
2164     use super::RawOsString;
2165 
2166     impl ToBytes for RawOsStr {
2167         #[inline]
to_bytes(&self) -> ByteStr<'_>2168         fn to_bytes(&self) -> ByteStr<'_> {
2169             self.0.to_bytes()
2170         }
2171 
2172         #[cfg(windows)]
2173         #[inline]
to_wide(&self) -> Option<WideStr>2174         fn to_wide(&self) -> Option<WideStr> {
2175             Some(WideStr::new(raw::encode_wide(self).collect()))
2176         }
2177     }
2178 
2179     impl ToBytes for RawOsString {
2180         #[inline]
to_bytes(&self) -> ByteStr<'_>2181         fn to_bytes(&self) -> ByteStr<'_> {
2182             (**self).to_bytes()
2183         }
2184 
2185         #[cfg(windows)]
2186         #[inline]
to_wide(&self) -> Option<WideStr>2187         fn to_wide(&self) -> Option<WideStr> {
2188             (**self).to_wide()
2189         }
2190     }
2191 }
2192 
2193 #[cfg(feature = "uniquote")]
2194 #[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "uniquote")))]
2195 mod uniquote {
2196     use uniquote::Formatter;
2197     use uniquote::Quote;
2198     use uniquote::Result;
2199 
2200     use crate::imp::raw;
2201 
2202     use super::RawOsStr;
2203     use super::RawOsString;
2204 
2205     impl Quote for RawOsStr {
2206         #[inline]
escape(&self, f: &mut Formatter<'_>) -> Result2207         fn escape(&self, f: &mut Formatter<'_>) -> Result {
2208             raw::uniquote::escape(self, f)
2209         }
2210     }
2211 
2212     impl Quote for RawOsString {
2213         #[inline]
escape(&self, f: &mut Formatter<'_>) -> Result2214         fn escape(&self, f: &mut Formatter<'_>) -> Result {
2215             (**self).escape(f)
2216         }
2217     }
2218 }
2219