typed_path/common/utf8/pathbuf.rs
1use alloc::borrow::Cow;
2use alloc::collections::TryReserveError;
3use alloc::string::FromUtf8Error;
4use core::borrow::Borrow;
5use core::hash::{Hash, Hasher};
6use core::iter::{Extend, FromIterator};
7use core::marker::PhantomData;
8use core::ops::Deref;
9use core::str::FromStr;
10use core::{cmp, fmt};
11
12use crate::no_std_compat::*;
13use crate::{CheckedPathError, Encoding, PathBuf, Utf8Encoding, Utf8Iter, Utf8Path};
14
15/// An owned, mutable path that mirrors [`std::path::PathBuf`], but operatings using a
16/// [`Utf8Encoding`] to determine how to parse the underlying str.
17///
18/// This type provides methods like [`push`] and [`set_extension`] that mutate
19/// the path in place. It also implements [`Deref`] to [`Utf8Path`], meaning that
20/// all methods on [`Utf8Path`] slices are available on `Utf8PathBuf` values as well.
21///
22/// [`push`]: Utf8PathBuf::push
23/// [`set_extension`]: Utf8PathBuf::set_extension
24///
25/// # Examples
26///
27/// You can use [`push`] to build up a `Utf8PathBuf` from
28/// components:
29///
30/// ```
31/// use typed_path::{Utf8PathBuf, Utf8WindowsEncoding};
32///
33/// // NOTE: A pathbuf cannot be created on its own without a defined encoding
34/// let mut path = Utf8PathBuf::<Utf8WindowsEncoding>::new();
35///
36/// path.push(r"C:\");
37/// path.push("windows");
38/// path.push("system32");
39///
40/// path.set_extension("dll");
41/// ```
42///
43/// However, [`push`] is best used for dynamic situations. This is a better way
44/// to do this when you know all of the components ahead of time:
45///
46/// ```
47/// use typed_path::{Utf8PathBuf, Utf8WindowsEncoding};
48///
49/// let path: Utf8PathBuf<Utf8WindowsEncoding> = [
50/// r"C:\",
51/// "windows",
52/// "system32.dll",
53/// ].iter().collect();
54/// ```
55///
56/// We can still do better than this! Since these are all strings, we can use
57/// `From::from`:
58///
59/// ```
60/// use typed_path::{Utf8PathBuf, Utf8WindowsEncoding};
61///
62/// let path = Utf8PathBuf::<Utf8WindowsEncoding>::from(r"C:\windows\system32.dll");
63/// ```
64///
65/// Which method works best depends on what kind of situation you're in.
66pub struct Utf8PathBuf<T>
67where
68 T: Utf8Encoding,
69{
70 /// Encoding associated with path buf
71 pub(crate) _encoding: PhantomData<T>,
72
73 /// Path as an unparsed string
74 pub(crate) inner: String,
75}
76
77impl<T> Utf8PathBuf<T>
78where
79 T: Utf8Encoding,
80{
81 /// Allocates an empty `Utf8PathBuf`.
82 ///
83 /// # Examples
84 ///
85 /// ```
86 /// use typed_path::{Utf8PathBuf, Utf8UnixEncoding};
87 ///
88 /// // NOTE: A pathbuf cannot be created on its own without a defined encoding
89 /// let path = Utf8PathBuf::<Utf8UnixEncoding>::new();
90 /// ```
91 pub fn new() -> Self {
92 Utf8PathBuf {
93 _encoding: PhantomData,
94 inner: String::new(),
95 }
96 }
97
98 /// Creates a new `PathBuf` with a given capacity used to create the
99 /// internal [`String`]. See [`with_capacity`] defined on [`String`].
100 ///
101 /// # Examples
102 ///
103 /// ```
104 /// use typed_path::{Utf8PathBuf, Utf8UnixEncoding};
105 ///
106 /// // NOTE: A pathbuf cannot be created on its own without a defined encoding
107 /// let mut path = Utf8PathBuf::<Utf8UnixEncoding>::with_capacity(10);
108 /// let capacity = path.capacity();
109 ///
110 /// // This push is done without reallocating
111 /// path.push(r"C:\");
112 ///
113 /// assert_eq!(capacity, path.capacity());
114 /// ```
115 ///
116 /// [`with_capacity`]: String::with_capacity
117 #[inline]
118 pub fn with_capacity(capacity: usize) -> Self {
119 Utf8PathBuf {
120 _encoding: PhantomData,
121 inner: String::with_capacity(capacity),
122 }
123 }
124
125 /// Coerces to a [`Utf8Path`] slice.
126 ///
127 /// # Examples
128 ///
129 /// ```
130 /// use typed_path::{Utf8Path, Utf8PathBuf, Utf8UnixEncoding};
131 ///
132 /// // NOTE: A pathbuf cannot be created on its own without a defined encoding
133 /// let p = Utf8PathBuf::<Utf8UnixEncoding>::from("/test");
134 /// assert_eq!(Utf8Path::new("/test"), p.as_path());
135 /// ```
136 #[inline]
137 pub fn as_path(&self) -> &Utf8Path<T> {
138 self
139 }
140
141 /// Extends `self` with `path`.
142 ///
143 /// If `path` is absolute, it replaces the current path.
144 ///
145 /// With [`Utf8WindowsPathBuf`]:
146 ///
147 /// * if `path` has a root but no prefix (e.g., `\windows`), it
148 /// replaces everything except for the prefix (if any) of `self`.
149 /// * if `path` has a prefix but no root, it replaces `self`.
150 /// * if `self` has a verbatim prefix (e.g. `\\?\C:\windows`)
151 /// and `path` is not empty, the new path is normalized: all references
152 /// to `.` and `..` are removed.
153 ///
154 /// [`Utf8WindowsPathBuf`]: crate::Utf8WindowsPathBuf
155 ///
156 /// # Examples
157 ///
158 /// Pushing a relative path extends the existing path:
159 ///
160 /// ```
161 /// use typed_path::{Utf8PathBuf, Utf8UnixEncoding};
162 ///
163 /// // NOTE: A pathbuf cannot be created on its own without a defined encoding
164 /// let mut path = Utf8PathBuf::<Utf8UnixEncoding>::from("/tmp");
165 /// path.push("file.bk");
166 /// assert_eq!(path, Utf8PathBuf::from("/tmp/file.bk"));
167 /// ```
168 ///
169 /// Pushing an absolute path replaces the existing path:
170 ///
171 /// ```
172 /// use typed_path::{Utf8PathBuf, Utf8UnixEncoding};
173 ///
174 /// // NOTE: A pathbuf cannot be created on its own without a defined encoding
175 /// let mut path = Utf8PathBuf::<Utf8UnixEncoding>::from("/tmp");
176 /// path.push("/etc");
177 /// assert_eq!(path, Utf8PathBuf::from("/etc"));
178 /// ```
179 pub fn push<P: AsRef<Utf8Path<T>>>(&mut self, path: P) {
180 T::push(&mut self.inner, path.as_ref().as_str());
181 }
182
183 /// Like [`Utf8PathBuf::push`], extends `self` with `path`, but also checks to ensure that
184 /// `path` abides by a set of rules.
185 ///
186 /// # Rules
187 ///
188 /// 1. `path` cannot contain a prefix component.
189 /// 2. `path` cannot contain a root component.
190 /// 3. `path` cannot contain invalid filename bytes.
191 /// 4. `path` cannot contain parent components such that the current path would be escaped.
192 ///
193 /// # Examples
194 ///
195 /// Pushing a relative path extends the existing path:
196 ///
197 /// ```
198 /// use typed_path::{Utf8PathBuf, Utf8UnixEncoding};
199 ///
200 /// // NOTE: A pathbuf cannot be created on its own without a defined encoding
201 /// let mut path = Utf8PathBuf::<Utf8UnixEncoding>::from("/tmp");
202 ///
203 /// // Pushing a relative path works like normal
204 /// assert!(path.push_checked("file.bk").is_ok());
205 /// assert_eq!(path, Utf8PathBuf::from("/tmp/file.bk"));
206 /// ```
207 ///
208 /// Pushing a relative path that contains unresolved parent directory references fails
209 /// with an error:
210 ///
211 /// ```
212 /// use typed_path::{CheckedPathError, Utf8PathBuf, Utf8UnixEncoding};
213 ///
214 /// // NOTE: A pathbuf cannot be created on its own without a defined encoding
215 /// let mut path = Utf8PathBuf::<Utf8UnixEncoding>::from("/tmp");
216 ///
217 /// // Pushing a relative path that contains parent directory references that cannot be
218 /// // resolved within the path is considered an error as this is considered a path
219 /// // traversal attack!
220 /// assert_eq!(path.push_checked(".."), Err(CheckedPathError::PathTraversalAttack));
221 /// assert_eq!(path, Utf8PathBuf::from("/tmp"));
222 /// ```
223 ///
224 /// Pushing an absolute path fails with an error:
225 ///
226 /// ```
227 /// use typed_path::{CheckedPathError, Utf8PathBuf, Utf8UnixEncoding};
228 ///
229 /// // NOTE: A pathbuf cannot be created on its own without a defined encoding
230 /// let mut path = Utf8PathBuf::<Utf8UnixEncoding>::from("/tmp");
231 ///
232 /// // Pushing an absolute path will fail with an error
233 /// assert_eq!(path.push_checked("/etc"), Err(CheckedPathError::UnexpectedRoot));
234 /// assert_eq!(path, Utf8PathBuf::from("/tmp"));
235 /// ```
236 pub fn push_checked<P: AsRef<Utf8Path<T>>>(&mut self, path: P) -> Result<(), CheckedPathError> {
237 T::push_checked(&mut self.inner, path.as_ref().as_str())
238 }
239
240 /// Truncates `self` to [`self.parent`].
241 ///
242 /// Returns `false` and does nothing if [`self.parent`] is [`None`].
243 /// Otherwise, returns `true`.
244 ///
245 /// [`self.parent`]: Utf8Path::parent
246 ///
247 /// # Examples
248 ///
249 /// ```
250 /// use typed_path::{Utf8Path, Utf8PathBuf, Utf8UnixEncoding};
251 ///
252 /// // NOTE: A pathbuf cannot be created on its own without a defined encoding
253 /// let mut p = Utf8PathBuf::<Utf8UnixEncoding>::from("/spirited/away.rs");
254 ///
255 /// p.pop();
256 /// assert_eq!(Utf8Path::new("/spirited"), p);
257 /// p.pop();
258 /// assert_eq!(Utf8Path::new("/"), p);
259 /// ```
260 pub fn pop(&mut self) -> bool {
261 match self.parent().map(|p| p.as_str().len()) {
262 Some(len) => {
263 self.inner.truncate(len);
264 true
265 }
266 None => false,
267 }
268 }
269
270 /// Updates [`self.file_name`] to `file_name`.
271 ///
272 /// If [`self.file_name`] was [`None`], this is equivalent to pushing
273 /// `file_name`.
274 ///
275 /// Otherwise it is equivalent to calling [`pop`] and then pushing
276 /// `file_name`. The new path will be a sibling of the original path.
277 /// (That is, it will have the same parent.)
278 ///
279 /// [`self.file_name`]: Utf8Path::file_name
280 /// [`pop`]: Utf8PathBuf::pop
281 ///
282 /// # Examples
283 ///
284 /// ```
285 /// use typed_path::{Utf8PathBuf, Utf8UnixEncoding};
286 ///
287 /// // NOTE: A pathbuf cannot be created on its own without a defined encoding
288 /// let mut buf = Utf8PathBuf::<Utf8UnixEncoding>::from("/");
289 /// assert!(buf.file_name() == None);
290 /// buf.set_file_name("bar");
291 /// assert!(buf == Utf8PathBuf::from("/bar"));
292 /// assert!(buf.file_name().is_some());
293 /// buf.set_file_name("baz.txt");
294 /// assert!(buf == Utf8PathBuf::from("/baz.txt"));
295 /// ```
296 pub fn set_file_name<S: AsRef<str>>(&mut self, file_name: S) {
297 self._set_file_name(file_name.as_ref())
298 }
299
300 fn _set_file_name(&mut self, file_name: &str) {
301 if self.file_name().is_some() {
302 let popped = self.pop();
303 debug_assert!(popped);
304 }
305 self.push(file_name);
306 }
307
308 /// Updates [`self.extension`] to `extension`.
309 ///
310 /// Returns `false` and does nothing if [`self.file_name`] is [`None`],
311 /// returns `true` and updates the extension otherwise.
312 ///
313 /// If [`self.extension`] is [`None`], the extension is added; otherwise
314 /// it is replaced.
315 ///
316 /// [`self.file_name`]: Utf8Path::file_name
317 /// [`self.extension`]: Utf8Path::extension
318 ///
319 /// # Examples
320 ///
321 /// ```
322 /// use typed_path::{Utf8Path, Utf8PathBuf, Utf8UnixEncoding};
323 ///
324 /// let mut p = Utf8PathBuf::<Utf8UnixEncoding>::from("/feel/the");
325 ///
326 /// p.set_extension("force");
327 /// assert_eq!(Utf8Path::new("/feel/the.force"), p.as_path());
328 ///
329 /// p.set_extension("dark_side");
330 /// assert_eq!(Utf8Path::new("/feel/the.dark_side"), p.as_path());
331 /// ```
332 pub fn set_extension<S: AsRef<str>>(&mut self, extension: S) -> bool {
333 self._set_extension(extension.as_ref())
334 }
335
336 fn _set_extension(&mut self, extension: &str) -> bool {
337 if self.file_stem().is_none() {
338 return false;
339 }
340
341 let old_ext_len = self.extension().map(|ext| ext.len()).unwrap_or(0);
342
343 // Truncate to remove the extension
344 if old_ext_len > 0 {
345 self.inner.truncate(self.inner.len() - old_ext_len);
346
347 // If we end with a '.' now from the previous extension, remove that too
348 if self.inner.ends_with('.') {
349 self.inner.pop();
350 }
351 }
352
353 // Add the new extension if it exists
354 if !extension.is_empty() {
355 // Add a '.' at the end prior to adding the extension
356 if !self.inner.ends_with('.') {
357 self.inner.push('.');
358 }
359
360 self.inner.push_str(extension);
361 }
362
363 true
364 }
365
366 /// Consumes the `PathBuf`, yielding its internal [`String`] storage.
367 ///
368 /// # Examples
369 ///
370 /// ```
371 /// use typed_path::{Utf8PathBuf, Utf8UnixEncoding};
372 ///
373 /// let p = Utf8PathBuf::<Utf8UnixEncoding>::from("/the/head");
374 /// let s = p.into_string();
375 /// ```
376 #[inline]
377 pub fn into_string(self) -> String {
378 self.inner
379 }
380
381 /// Converts this [`Utf8PathBuf`] into a [boxed](Box) [`Utf8Path`].
382 #[inline]
383 pub fn into_boxed_path(self) -> Box<Utf8Path<T>> {
384 let rw = Box::into_raw(self.inner.into_boxed_str()) as *mut Utf8Path<T>;
385 unsafe { Box::from_raw(rw) }
386 }
387
388 /// Invokes [`capacity`] on the underlying instance of [`String`].
389 ///
390 /// [`capacity`]: String::capacity
391 #[inline]
392 pub fn capacity(&self) -> usize {
393 self.inner.capacity()
394 }
395
396 /// Invokes [`clear`] on the underlying instance of [`String`].
397 ///
398 /// [`clear`]: String::clear
399 #[inline]
400 pub fn clear(&mut self) {
401 self.inner.clear()
402 }
403
404 /// Invokes [`reserve`] on the underlying instance of [`String`].
405 ///
406 /// [`reserve`]: String::reserve
407 #[inline]
408 pub fn reserve(&mut self, additional: usize) {
409 self.inner.reserve(additional)
410 }
411
412 /// Invokes [`try_reserve`] on the underlying instance of [`String`].
413 ///
414 /// [`try_reserve`]: String::try_reserve
415 #[inline]
416 pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
417 self.inner.try_reserve(additional)
418 }
419
420 /// Invokes [`reserve_exact`] on the underlying instance of [`String`].
421 ///
422 /// [`reserve_exact`]: String::reserve_exact
423 #[inline]
424 pub fn reserve_exact(&mut self, additional: usize) {
425 self.inner.reserve_exact(additional)
426 }
427
428 /// Invokes [`try_reserve_exact`] on the underlying instance of [`String`].
429 ///
430 /// [`try_reserve_exact`]: String::try_reserve_exact
431 #[inline]
432 pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
433 self.inner.try_reserve_exact(additional)
434 }
435
436 /// Invokes [`shrink_to_fit`] on the underlying instance of [`String`].
437 ///
438 /// [`shrink_to_fit`]: String::shrink_to_fit
439 #[inline]
440 pub fn shrink_to_fit(&mut self) {
441 self.inner.shrink_to_fit()
442 }
443
444 /// Invokes [`shrink_to`] on the underlying instance of [`String`].
445 ///
446 /// [`shrink_to`]: String::shrink_to
447 #[inline]
448 pub fn shrink_to(&mut self, min_capacity: usize) {
449 self.inner.shrink_to(min_capacity)
450 }
451
452 /// Consumes [`PathBuf`] and returns a new [`Utf8PathBuf`] by checking that the path contains
453 /// valid UTF-8.
454 ///
455 /// # Errors
456 ///
457 /// Returns `Err` if the path is not UTF-8 with a description as to why the
458 /// provided component is not UTF-8.
459 ///
460 /// # Examples
461 ///
462 /// ```
463 /// use typed_path::{PathBuf, Utf8PathBuf, UnixEncoding, Utf8UnixEncoding};
464 ///
465 /// let path_buf = PathBuf::<UnixEncoding>::from(&[0xf0, 0x9f, 0x92, 0x96]);
466 /// let utf8_path_buf = Utf8PathBuf::<Utf8UnixEncoding>::from_bytes_path_buf(path_buf).unwrap();
467 /// assert_eq!(utf8_path_buf.as_str(), "💖");
468 /// ```
469 pub fn from_bytes_path_buf<U>(path_buf: PathBuf<U>) -> Result<Self, FromUtf8Error>
470 where
471 U: Encoding,
472 {
473 Ok(Self {
474 _encoding: PhantomData,
475 inner: String::from_utf8(path_buf.inner)?,
476 })
477 }
478
479 /// Consumes [`PathBuf`] and returns a new [`Utf8PathBuf`] by checking that the path contains
480 /// valid UTF-8.
481 ///
482 /// # Errors
483 ///
484 /// Returns `Err` if the path is not UTF-8 with a description as to why the
485 /// provided component is not UTF-8.
486 ///
487 /// # Safety
488 ///
489 /// The path passed in must be valid UTF-8.
490 ///
491 /// # Examples
492 ///
493 /// ```
494 /// use typed_path::{PathBuf, Utf8PathBuf, UnixEncoding, Utf8UnixEncoding};
495 ///
496 /// let path_buf = PathBuf::<UnixEncoding>::from(&[0xf0, 0x9f, 0x92, 0x96]);
497 /// let utf8_path_buf = unsafe {
498 /// Utf8PathBuf::<Utf8UnixEncoding>::from_bytes_path_buf_unchecked(path_buf)
499 /// };
500 /// assert_eq!(utf8_path_buf.as_str(), "💖");
501 /// ```
502 pub unsafe fn from_bytes_path_buf_unchecked<U>(path_buf: PathBuf<U>) -> Self
503 where
504 U: Encoding,
505 {
506 Self {
507 _encoding: PhantomData,
508 inner: String::from_utf8_unchecked(path_buf.inner),
509 }
510 }
511
512 /// Consumes [`Utf8PathBuf`] and returns a new [`PathBuf`]
513 ///
514 /// # Examples
515 ///
516 /// ```
517 /// use typed_path::{PathBuf, Utf8PathBuf, UnixEncoding, Utf8UnixEncoding};
518 ///
519 /// let utf8_path_buf = Utf8PathBuf::<Utf8UnixEncoding>::from("💖");
520 /// let path_buf = utf8_path_buf.into_bytes_path_buf::<UnixEncoding>();
521 /// assert_eq!(path_buf.as_bytes(), &[0xf0, 0x9f, 0x92, 0x96]);
522 /// ```
523 pub fn into_bytes_path_buf<U>(self) -> PathBuf<U>
524 where
525 U: Encoding,
526 {
527 PathBuf {
528 _encoding: PhantomData,
529 inner: self.inner.into_bytes(),
530 }
531 }
532}
533
534impl<T> Clone for Utf8PathBuf<T>
535where
536 T: Utf8Encoding,
537{
538 #[inline]
539 fn clone(&self) -> Self {
540 Self {
541 _encoding: self._encoding,
542 inner: self.inner.clone(),
543 }
544 }
545}
546
547impl<T> fmt::Debug for Utf8PathBuf<T>
548where
549 T: Utf8Encoding,
550{
551 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
552 f.debug_struct("Utf8PathBuf")
553 .field("_encoding", &T::label())
554 .field("inner", &self.inner)
555 .finish()
556 }
557}
558
559impl<T> AsRef<[u8]> for Utf8PathBuf<T>
560where
561 T: Utf8Encoding,
562{
563 #[inline]
564 fn as_ref(&self) -> &[u8] {
565 self.as_str().as_bytes()
566 }
567}
568
569impl<T> AsRef<str> for Utf8PathBuf<T>
570where
571 T: Utf8Encoding,
572{
573 #[inline]
574 fn as_ref(&self) -> &str {
575 self.as_str()
576 }
577}
578
579impl<T> AsRef<Utf8Path<T>> for Utf8PathBuf<T>
580where
581 T: Utf8Encoding,
582{
583 #[inline]
584 fn as_ref(&self) -> &Utf8Path<T> {
585 self
586 }
587}
588
589impl<T> Borrow<Utf8Path<T>> for Utf8PathBuf<T>
590where
591 T: Utf8Encoding,
592{
593 #[inline]
594 fn borrow(&self) -> &Utf8Path<T> {
595 self.deref()
596 }
597}
598
599impl<T> Default for Utf8PathBuf<T>
600where
601 T: Utf8Encoding,
602{
603 #[inline]
604 fn default() -> Utf8PathBuf<T> {
605 Utf8PathBuf::new()
606 }
607}
608
609impl<T> fmt::Display for Utf8PathBuf<T>
610where
611 T: Utf8Encoding,
612{
613 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
614 fmt::Display::fmt(&self.inner, f)
615 }
616}
617
618impl<T> Deref for Utf8PathBuf<T>
619where
620 T: Utf8Encoding,
621{
622 type Target = Utf8Path<T>;
623
624 #[inline]
625 fn deref(&self) -> &Utf8Path<T> {
626 Utf8Path::new(&self.inner)
627 }
628}
629
630impl<T> Eq for Utf8PathBuf<T> where T: Utf8Encoding {}
631
632impl<T> PartialEq for Utf8PathBuf<T>
633where
634 T: Utf8Encoding,
635{
636 fn eq(&self, other: &Self) -> bool {
637 self.components() == other.components()
638 }
639}
640
641impl<T, P> Extend<P> for Utf8PathBuf<T>
642where
643 T: Utf8Encoding,
644 P: AsRef<Utf8Path<T>>,
645{
646 fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
647 iter.into_iter().for_each(move |p| self.push(p.as_ref()));
648 }
649}
650
651impl<T> From<Box<Utf8Path<T>>> for Utf8PathBuf<T>
652where
653 T: Utf8Encoding,
654{
655 fn from(boxed: Box<Utf8Path<T>>) -> Self {
656 boxed.into_path_buf()
657 }
658}
659
660impl<T, V> From<&V> for Utf8PathBuf<T>
661where
662 T: Utf8Encoding,
663 V: ?Sized + AsRef<str>,
664{
665 /// Converts a borrowed [`str`] to a [`Utf8PathBuf`].
666 ///
667 /// Allocates a [`Utf8PathBuf`] and copies the data into it.
668 #[inline]
669 fn from(s: &V) -> Self {
670 Utf8PathBuf::from(s.as_ref().to_string())
671 }
672}
673
674impl<T> From<String> for Utf8PathBuf<T>
675where
676 T: Utf8Encoding,
677{
678 /// Converts a [`String`] into a [`Utf8PathBuf`]
679 ///
680 /// This conversion does not allocate or copy memory.
681 #[inline]
682 fn from(inner: String) -> Self {
683 Utf8PathBuf {
684 _encoding: PhantomData,
685 inner,
686 }
687 }
688}
689
690impl<T> From<Utf8PathBuf<T>> for String
691where
692 T: Utf8Encoding,
693{
694 /// Converts a [`Utf8PathBuf`] into a [`String`]
695 ///
696 /// This conversion does not allocate or copy memory.
697 #[inline]
698 fn from(path_buf: Utf8PathBuf<T>) -> Self {
699 path_buf.inner
700 }
701}
702
703impl<T> FromStr for Utf8PathBuf<T>
704where
705 T: Utf8Encoding,
706{
707 type Err = core::convert::Infallible;
708
709 #[inline]
710 fn from_str(s: &str) -> Result<Self, Self::Err> {
711 Ok(Utf8PathBuf::from(s))
712 }
713}
714
715impl<'a, T> From<Cow<'a, Utf8Path<T>>> for Utf8PathBuf<T>
716where
717 T: Utf8Encoding,
718{
719 /// Converts a clone-on-write pointer to an owned path.
720 ///
721 /// Converting from a `Cow::Owned` does not clone or allocate.
722 #[inline]
723 fn from(p: Cow<'a, Utf8Path<T>>) -> Self {
724 p.into_owned()
725 }
726}
727
728impl<T, P> FromIterator<P> for Utf8PathBuf<T>
729where
730 T: Utf8Encoding,
731 P: AsRef<Utf8Path<T>>,
732{
733 fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> Self {
734 let mut buf = Utf8PathBuf::new();
735 buf.extend(iter);
736 buf
737 }
738}
739
740impl<T> Hash for Utf8PathBuf<T>
741where
742 T: Utf8Encoding,
743{
744 fn hash<H: Hasher>(&self, h: &mut H) {
745 self.as_path().hash(h)
746 }
747}
748
749impl<'a, T> IntoIterator for &'a Utf8PathBuf<T>
750where
751 T: Utf8Encoding,
752{
753 type IntoIter = Utf8Iter<'a, T>;
754 type Item = &'a str;
755
756 #[inline]
757 fn into_iter(self) -> Self::IntoIter {
758 self.iter()
759 }
760}
761
762impl<T> cmp::PartialOrd for Utf8PathBuf<T>
763where
764 T: Utf8Encoding,
765{
766 #[inline]
767 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
768 Some(self.cmp(other))
769 }
770}
771
772impl<T> cmp::Ord for Utf8PathBuf<T>
773where
774 T: Utf8Encoding,
775{
776 #[inline]
777 fn cmp(&self, other: &Self) -> cmp::Ordering {
778 self.components().cmp(other.components())
779 }
780}
781
782#[cfg(any(
783 unix,
784 all(target_vendor = "fortanix", target_env = "sgx"),
785 target_os = "solid_asp3",
786 target_os = "hermit",
787 target_os = "wasi"
788))]
789#[cfg(feature = "std")]
790mod std_conversions {
791 use std::ffi::{OsStr, OsString};
792 #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
793 use std::os::fortanix_sgx as os;
794 #[cfg(target_os = "solid_asp3")]
795 use std::os::solid as os;
796 #[cfg(any(target_os = "hermit", unix))]
797 use std::os::unix as os;
798 #[cfg(target_os = "wasi")]
799 use std::os::wasi as os;
800
801 use os::ffi::{OsStrExt, OsStringExt};
802
803 use super::*;
804
805 impl<T> From<Utf8PathBuf<T>> for OsString
806 where
807 T: Utf8Encoding,
808 {
809 #[inline]
810 fn from(path_buf: Utf8PathBuf<T>) -> Self {
811 OsStringExt::from_vec(path_buf.into_string().into_bytes())
812 }
813 }
814
815 impl<T> AsRef<OsStr> for Utf8PathBuf<T>
816 where
817 T: Utf8Encoding,
818 {
819 #[inline]
820 fn as_ref(&self) -> &OsStr {
821 OsStrExt::from_bytes(self.as_str().as_bytes())
822 }
823 }
824}