relative_path/
relative_path_buf.rs1use core::cmp;
2use core::fmt;
3use core::hash::{Hash, Hasher};
4use core::iter::FromIterator;
5use core::ops;
6use core::str;
7
8use alloc::borrow::{Borrow, Cow, ToOwned};
9use alloc::boxed::Box;
10use alloc::string::String;
11
12#[cfg(feature = "std")]
13use std::path;
14
15use super::{Component, RelativePath, PARENT_STR, SEP, STEM_SEP};
16
17#[cfg(feature = "std")]
18use super::{FromPathError, FromPathErrorKind};
19
20#[inline(always)]
25pub(super) fn relative_traversal<'a, C>(buf: &mut RelativePathBuf, components: C)
26where
27 C: IntoIterator<Item = Component<'a>>,
28{
29 use self::Component::{CurDir, Normal, ParentDir};
30
31 for c in components {
32 match c {
33 CurDir => (),
34 ParentDir => match buf.components().next_back() {
35 Some(Component::ParentDir) | None => {
36 buf.push(PARENT_STR);
37 }
38 _ => {
39 buf.pop();
40 }
41 },
42 Normal(name) => {
43 buf.push(name);
44 }
45 }
46 }
47}
48
49#[derive(Clone)]
53pub struct RelativePathBuf {
54 inner: String,
55}
56
57impl RelativePathBuf {
58 #[must_use]
60 #[inline]
61 pub fn new() -> RelativePathBuf {
62 RelativePathBuf {
63 inner: String::new(),
64 }
65 }
66
67 #[inline]
69 pub(super) fn with_capacity(cap: usize) -> RelativePathBuf {
70 RelativePathBuf {
71 inner: String::with_capacity(cap),
72 }
73 }
74
75 #[inline]
77 pub(super) fn len(&self) -> usize {
78 self.inner.len()
79 }
80
81 #[cfg(feature = "std")]
105 #[cfg_attr(relative_path_docsrs, doc(cfg(feature = "std")))]
106 #[inline]
107 pub fn from_path<P>(path: P) -> Result<RelativePathBuf, FromPathError>
108 where
109 P: AsRef<path::Path>,
110 {
111 use std::path::Component::{CurDir, Normal, ParentDir, Prefix, RootDir};
112
113 let mut buffer = RelativePathBuf::new();
114
115 for c in path.as_ref().components() {
116 match c {
117 Prefix(_) | RootDir => return Err(FromPathErrorKind::NonRelative.into()),
118 CurDir => continue,
119 ParentDir => buffer.push(PARENT_STR),
120 Normal(s) => buffer.push(s.to_str().ok_or(FromPathErrorKind::NonUtf8)?),
121 }
122 }
123
124 Ok(buffer)
125 }
126
127 pub fn push<P>(&mut self, path: P)
147 where
148 P: AsRef<RelativePath>,
149 {
150 let other = path.as_ref();
151
152 let other = if other.starts_with_sep() {
153 &other.inner[1..]
154 } else {
155 &other.inner[..]
156 };
157
158 if !self.inner.is_empty() && !self.ends_with_sep() {
159 self.inner.push(SEP);
160 }
161
162 self.inner.push_str(other);
163 }
164
165 pub fn set_file_name<S>(&mut self, file_name: S)
198 where
199 S: AsRef<str>,
200 {
201 if self.file_name().is_some() {
202 let popped = self.pop();
203 debug_assert!(popped);
204 }
205
206 self.push(file_name.as_ref());
207 }
208
209 pub fn set_extension<S>(&mut self, extension: S) -> bool
238 where
239 S: AsRef<str>,
240 {
241 let file_stem = match self.file_stem() {
242 Some(stem) => stem,
243 None => return false,
244 };
245
246 let end_file_stem = file_stem[file_stem.len()..].as_ptr() as usize;
247 let start = self.inner.as_ptr() as usize;
248 self.inner.truncate(end_file_stem.wrapping_sub(start));
249
250 let extension = extension.as_ref();
251
252 if !extension.is_empty() {
253 self.inner.push(STEM_SEP);
254 self.inner.push_str(extension);
255 }
256
257 true
258 }
259
260 pub fn pop(&mut self) -> bool {
277 match self.parent().map(|p| p.inner.len()) {
278 Some(len) => {
279 self.inner.truncate(len);
280 true
281 }
282 None => false,
283 }
284 }
285
286 #[must_use]
288 #[inline]
289 pub fn as_relative_path(&self) -> &RelativePath {
290 self
291 }
292
293 #[must_use]
305 #[inline]
306 pub fn into_string(self) -> String {
307 self.inner
308 }
309
310 #[must_use]
313 #[inline]
314 pub fn into_boxed_relative_path(self) -> Box<RelativePath> {
315 let rw = Box::into_raw(self.inner.into_boxed_str()) as *mut RelativePath;
316 unsafe { Box::from_raw(rw) }
317 }
318}
319
320impl Default for RelativePathBuf {
321 #[inline]
322 fn default() -> Self {
323 RelativePathBuf::new()
324 }
325}
326
327impl<'a> From<&'a RelativePath> for Cow<'a, RelativePath> {
328 #[inline]
329 fn from(s: &'a RelativePath) -> Cow<'a, RelativePath> {
330 Cow::Borrowed(s)
331 }
332}
333
334impl<'a> From<RelativePathBuf> for Cow<'a, RelativePath> {
335 #[inline]
336 fn from(s: RelativePathBuf) -> Cow<'a, RelativePath> {
337 Cow::Owned(s)
338 }
339}
340
341impl fmt::Debug for RelativePathBuf {
342 #[inline]
343 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
344 write!(fmt, "{:?}", &self.inner)
345 }
346}
347
348impl AsRef<RelativePath> for RelativePathBuf {
349 #[inline]
350 fn as_ref(&self) -> &RelativePath {
351 RelativePath::new(&self.inner)
352 }
353}
354
355impl AsRef<str> for RelativePath {
356 #[inline]
357 fn as_ref(&self) -> &str {
358 &self.inner
359 }
360}
361
362impl Borrow<RelativePath> for RelativePathBuf {
363 #[inline]
364 fn borrow(&self) -> &RelativePath {
365 self
366 }
367}
368
369impl<'a, T: ?Sized + AsRef<str>> From<&'a T> for RelativePathBuf {
370 #[inline]
371 fn from(path: &'a T) -> RelativePathBuf {
372 RelativePathBuf {
373 inner: path.as_ref().to_owned(),
374 }
375 }
376}
377
378impl From<String> for RelativePathBuf {
379 #[inline]
380 fn from(path: String) -> RelativePathBuf {
381 RelativePathBuf { inner: path }
382 }
383}
384
385impl From<RelativePathBuf> for String {
386 #[inline]
387 fn from(path: RelativePathBuf) -> String {
388 path.into_string()
389 }
390}
391
392impl ops::Deref for RelativePathBuf {
393 type Target = RelativePath;
394
395 #[inline]
396 fn deref(&self) -> &RelativePath {
397 RelativePath::new(&self.inner)
398 }
399}
400
401impl cmp::PartialEq for RelativePathBuf {
402 #[inline]
403 fn eq(&self, other: &RelativePathBuf) -> bool {
404 self.components() == other.components()
405 }
406}
407
408impl cmp::Eq for RelativePathBuf {}
409
410impl cmp::PartialOrd for RelativePathBuf {
411 #[inline]
412 fn partial_cmp(&self, other: &RelativePathBuf) -> Option<cmp::Ordering> {
413 Some(self.cmp(other))
414 }
415}
416
417impl cmp::Ord for RelativePathBuf {
418 #[inline]
419 fn cmp(&self, other: &RelativePathBuf) -> cmp::Ordering {
420 self.components().cmp(other.components())
421 }
422}
423
424impl Hash for RelativePathBuf {
425 #[inline]
426 fn hash<H>(&self, h: &mut H)
427 where
428 H: Hasher,
429 {
430 self.as_relative_path().hash(h);
431 }
432}
433
434impl<P> Extend<P> for RelativePathBuf
435where
436 P: AsRef<RelativePath>,
437{
438 #[inline]
439 fn extend<I>(&mut self, iter: I)
440 where
441 I: IntoIterator<Item = P>,
442 {
443 iter.into_iter().for_each(move |p| self.push(p.as_ref()));
444 }
445}
446
447impl<P> FromIterator<P> for RelativePathBuf
448where
449 P: AsRef<RelativePath>,
450{
451 #[inline]
452 fn from_iter<I>(iter: I) -> RelativePathBuf
453 where
454 I: IntoIterator<Item = P>,
455 {
456 let mut buf = RelativePathBuf::new();
457 buf.extend(iter);
458 buf
459 }
460}
461
462impl fmt::Display for RelativePathBuf {
463 #[inline]
464 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
465 fmt::Display::fmt(&self.inner, f)
466 }
467}
468
469impl AsRef<str> for RelativePathBuf {
481 #[inline]
482 fn as_ref(&self) -> &str {
483 &self.inner
484 }
485}
486
487#[cfg(feature = "serde")]
499#[cfg_attr(relative_path_docsrs, doc(cfg(feature = "serde")))]
500impl serde::ser::Serialize for RelativePathBuf {
501 #[inline]
502 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
503 where
504 S: serde::ser::Serializer,
505 {
506 serializer.serialize_str(&self.inner)
507 }
508}
509
510#[cfg(feature = "serde")]
522#[cfg_attr(relative_path_docsrs, doc(cfg(feature = "serde")))]
523impl<'de> serde::de::Deserialize<'de> for RelativePathBuf {
524 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
525 where
526 D: serde::de::Deserializer<'de>,
527 {
528 struct Visitor;
529
530 impl serde::de::Visitor<'_> for Visitor {
531 type Value = RelativePathBuf;
532
533 #[inline]
534 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
535 formatter.write_str("a relative path")
536 }
537
538 #[inline]
539 fn visit_string<E>(self, input: String) -> Result<Self::Value, E>
540 where
541 E: serde::de::Error,
542 {
543 Ok(RelativePathBuf::from(input))
544 }
545
546 #[inline]
547 fn visit_str<E>(self, input: &str) -> Result<Self::Value, E>
548 where
549 E: serde::de::Error,
550 {
551 Ok(RelativePathBuf::from(input.to_owned()))
552 }
553 }
554
555 deserializer.deserialize_str(Visitor)
556 }
557}