iref_core/uri/
path.rs

1use static_regular_grammar::RegularGrammar;
2
3mod segment;
4
5pub use segment::*;
6
7use crate::common::path::{NormalizedSegmentsImpl, PathBufImpl, PathImpl, SegmentsImpl};
8
9use super::PathMut;
10
11/// IRI path.
12#[derive(RegularGrammar)]
13#[grammar(
14	file = "src/uri/grammar.abnf",
15	entry_point = "path",
16	name = "URI path",
17	ascii,
18	cache = "automata/uri/path.aut.cbor"
19)]
20#[grammar(sized(PathBuf, derive(Debug, Display)))]
21#[cfg_attr(feature = "serde", grammar(serde))]
22#[cfg_attr(feature = "ignore-grammars", grammar(disable))]
23pub struct Path([u8]);
24
25impl PathImpl for Path {
26	const EMPTY: &'static Self = Self::EMPTY;
27
28	const EMPTY_ABSOLUTE: &'static Self = Self::EMPTY_ABSOLUTE;
29
30	type Segment = Segment;
31
32	type Owned = PathBuf;
33
34	unsafe fn new_unchecked(bytes: &[u8]) -> &Self {
35		Self::new_unchecked(bytes)
36	}
37
38	#[inline(always)]
39	fn as_bytes(&self) -> &[u8] {
40		self.as_bytes()
41	}
42
43	fn to_path_buf(&self) -> Self::Owned {
44		unsafe { PathBuf::new_unchecked(self.as_bytes().to_vec()) }
45	}
46}
47
48impl PathBufImpl for PathBuf {
49	type Borrowed = Path;
50
51	unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
52		&mut self.0
53	}
54
55	fn as_bytes(&self) -> &[u8] {
56		&self.0
57	}
58}
59
60impl Path {
61	/// The empty absolute path `/`.
62	pub const EMPTY_ABSOLUTE: &'static Self = unsafe { Self::new_unchecked(b"/") };
63
64	/// Returns the number of segments in the path.
65	///
66	/// This computes in linear time w.r.t the number of segments. It is
67	/// equivalent to `path.segments().count()`.
68	#[inline]
69	pub fn segment_count(&self) -> usize {
70		self.segments().count()
71	}
72
73	/// Checks if the path is empty.
74	///
75	/// Returns `true` if the path has no segments.
76	/// The absolute path `/` is empty.
77	#[inline]
78	pub fn is_empty(&self) -> bool {
79		PathImpl::is_empty(self)
80	}
81
82	/// Checks if the path is absolute.
83	///
84	/// A path is absolute if it starts with a `/`.
85	#[inline]
86	pub fn is_absolute(&self) -> bool {
87		PathImpl::is_absolute(self)
88	}
89
90	/// Checks if the path is relative.
91	///
92	/// A path is relative if it does not start with a `/`.
93	#[inline]
94	pub fn is_relative(&self) -> bool {
95		PathImpl::is_relative(self)
96	}
97
98	pub fn first(&self) -> Option<&Segment> {
99		PathImpl::first(self)
100	}
101
102	pub fn last(&self) -> Option<&Segment> {
103		PathImpl::last(self)
104	}
105
106	/// Produces an iterator over the segments of the IRI path.
107	///
108	/// Empty segments are preserved: the path `a//b` will raise the three
109	/// segments `a`, `` and `b`. The absolute path `/` has no segments, but
110	/// the path `/a/` has two segments, `a` and ``.
111	///
112	/// No normalization occurs with `.` and `..` segments. See the
113	/// [`Self::normalized_segments`] to iterate over the normalized segments
114	/// of a path.
115	#[inline]
116	pub fn segments(&self) -> Segments {
117		Segments(PathImpl::segments(self))
118	}
119
120	/// Iterate over the normalized segments of the path.
121	///
122	/// Remove the special dot segments `..` and `.` from the iteration using
123	/// the usual path semantics for dot segments. This may be expensive for
124	/// large paths since it will need to internally normalize the path first.
125	#[inline]
126	pub fn normalized_segments(&self) -> NormalizedSegments {
127		NormalizedSegments(PathImpl::normalized_segments(self))
128	}
129
130	#[inline]
131	pub fn normalized(&self) -> PathBuf {
132		PathImpl::normalized(self)
133	}
134
135	/// Returns the last segment of the path, if there is one, unless it is
136	/// empty.
137	///
138	/// This does not consider the normalized version of the path, dot segments
139	/// are preserved.
140	#[inline]
141	pub fn file_name(&self) -> Option<&Segment> {
142		PathImpl::file_name(self)
143	}
144
145	/// Returns the directory path, which is the path without the file name.
146	///
147	/// # Example
148	///
149	/// ```
150	/// # use iref_core::uri::Path;
151	/// assert_eq!(Path::new(b"/foo/bar").unwrap().directory(), b"/foo/");
152	/// assert_eq!(Path::new(b"/foo").unwrap().directory(), b"/");
153	/// assert_eq!(Path::new(b"//foo").unwrap().directory(), b"//");
154	/// assert_eq!(Path::new(b"/").unwrap().directory(), b"/");
155	/// ```
156	pub fn directory(&self) -> &Self {
157		PathImpl::directory(self)
158	}
159
160	/// Returns the path without its final segment, if there is one.
161	///
162	/// ```
163	/// # use iref_core::uri::Path;
164	/// assert_eq!(Path::new(b"/foo/bar").unwrap().parent().unwrap(), b"/foo");
165	/// assert_eq!(Path::new(b"/foo").unwrap().parent().unwrap(), b"/");
166	/// assert_eq!(Path::new(b"//foo").unwrap().parent().unwrap(), b"/./");
167	/// assert_eq!(Path::new(b"/").unwrap().parent(), None);
168	/// ```
169	#[inline]
170	pub fn parent(&self) -> Option<&Self> {
171		PathImpl::parent(self)
172	}
173
174	/// Returns the path without its final segment, if there is one.
175	///
176	/// ```
177	/// # use iref_core::uri::Path;
178	/// assert_eq!(Path::new(b"/foo/bar").unwrap().parent_or_empty(), b"/foo");
179	/// assert_eq!(Path::new(b"/foo").unwrap().parent_or_empty(), b"/");
180	/// assert_eq!(Path::new(b"//foo").unwrap().parent_or_empty(), b"/./");
181	/// assert_eq!(Path::new(b"/").unwrap().parent_or_empty(), b"/");
182	/// assert_eq!(Path::new(b"").unwrap().parent_or_empty(), b"");
183	/// ```
184	#[inline]
185	pub fn parent_or_empty(&self) -> &Self {
186		PathImpl::parent_or_empty(self)
187	}
188
189	/// Get the suffix part of this path, if any, with regard to the given prefix path.
190	///
191	/// Returns `Some(suffix)` if this path is of the form `prefix/suffix` where `prefix` is given
192	/// as parameter. Returns `None` otherwise.
193	///
194	/// Both paths are normalized during the process.
195	/// The result is a normalized suffix path.
196	///
197	/// # Example
198	/// ```
199	/// # use std::convert::TryFrom;
200	/// # use iref_core as iref;
201	/// use iref::iri::{Path, PathBuf};
202	///
203	/// let prefix = Path::new("/foo/bar").unwrap();
204	/// let path = Path::new("/foo/bar/baz").unwrap();
205	/// let suffix: PathBuf = path.suffix(prefix).unwrap();
206	///
207	/// assert_eq!(suffix.as_str(), "baz");
208	/// ```
209	#[inline]
210	pub fn suffix(&self, prefix: &Self) -> Option<PathBuf> {
211		PathImpl::suffix(self, prefix)
212	}
213}
214
215impl<'a> IntoIterator for &'a Path {
216	type Item = &'a Segment;
217	type IntoIter = Segments<'a>;
218
219	#[inline]
220	fn into_iter(self) -> Segments<'a> {
221		self.segments()
222	}
223}
224
225impl PartialEq for Path {
226	#[inline]
227	fn eq(&self, other: &Path) -> bool {
228		if self.is_absolute() == other.is_absolute() {
229			let self_segments = self.normalized_segments();
230			let other_segments = other.normalized_segments();
231			self_segments.len() == other_segments.len()
232				&& self_segments.zip(other_segments).all(|(a, b)| a == b)
233		} else {
234			false
235		}
236	}
237}
238
239impl PartialEq<[u8]> for Path {
240	fn eq(&self, other: &[u8]) -> bool {
241		self.as_bytes() == other
242	}
243}
244
245impl<'a> PartialEq<&'a [u8]> for Path {
246	fn eq(&self, other: &&'a [u8]) -> bool {
247		self.as_bytes() == *other
248	}
249}
250
251impl<const N: usize> PartialEq<[u8; N]> for Path {
252	fn eq(&self, other: &[u8; N]) -> bool {
253		self.as_bytes() == other
254	}
255}
256
257impl<'a, const N: usize> PartialEq<&'a [u8; N]> for Path {
258	fn eq(&self, other: &&'a [u8; N]) -> bool {
259		self.as_bytes() == *other
260	}
261}
262
263impl PartialEq<str> for Path {
264	fn eq(&self, other: &str) -> bool {
265		self.as_str() == other
266	}
267}
268
269impl<'a> PartialEq<&'a str> for Path {
270	fn eq(&self, other: &&'a str) -> bool {
271		self.as_str() == *other
272	}
273}
274
275impl PartialEq<String> for Path {
276	fn eq(&self, other: &String) -> bool {
277		self.as_str() == other.as_str()
278	}
279}
280
281impl Eq for Path {}
282
283impl PartialOrd for Path {
284	#[inline]
285	fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
286		Some(self.cmp(other))
287	}
288}
289
290impl Ord for Path {
291	#[inline]
292	fn cmp(&self, other: &Self) -> std::cmp::Ordering {
293		use std::cmp::Ordering;
294		if self.is_absolute() == other.is_absolute() {
295			let mut self_segments = self.normalized_segments();
296			let mut other_segments = other.normalized_segments();
297
298			loop {
299				match (self_segments.next(), other_segments.next()) {
300					(None, None) => return Ordering::Equal,
301					(Some(_), None) => return Ordering::Greater,
302					(None, Some(_)) => return Ordering::Less,
303					(Some(a), Some(b)) => match a.cmp(b) {
304						Ordering::Greater => return Ordering::Greater,
305						Ordering::Less => return Ordering::Less,
306						Ordering::Equal => (),
307					},
308				}
309			}
310		} else if self.is_absolute() {
311			Ordering::Greater
312		} else {
313			Ordering::Less
314		}
315	}
316}
317
318impl std::hash::Hash for Path {
319	#[inline]
320	fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
321		self.is_absolute().hash(hasher);
322		self.normalized_segments().for_each(move |s| s.hash(hasher))
323	}
324}
325
326pub struct Segments<'a>(SegmentsImpl<'a, Path>);
327
328impl<'a> Iterator for Segments<'a> {
329	type Item = &'a Segment;
330
331	fn next(&mut self) -> Option<Self::Item> {
332		self.0.next()
333	}
334}
335
336impl<'a> DoubleEndedIterator for Segments<'a> {
337	fn next_back(&mut self) -> Option<Self::Item> {
338		self.0.next_back()
339	}
340}
341
342pub struct NormalizedSegments<'a>(NormalizedSegmentsImpl<'a, Path>);
343
344impl<'a> Iterator for NormalizedSegments<'a> {
345	type Item = &'a Segment;
346
347	fn size_hint(&self) -> (usize, Option<usize>) {
348		self.0.size_hint()
349	}
350
351	#[inline]
352	fn next(&mut self) -> Option<&'a Segment> {
353		self.0.next()
354	}
355}
356
357impl<'a> DoubleEndedIterator for NormalizedSegments<'a> {
358	#[inline]
359	fn next_back(&mut self) -> Option<Self::Item> {
360		self.0.next_back()
361	}
362}
363
364impl<'a> ExactSizeIterator for NormalizedSegments<'a> {}
365
366impl PathBuf {
367	/// Returns a mutable reference to the interior bytes.
368	///
369	/// # Safety
370	///
371	/// This function is unsafe because the returned `&mut Vec` allows writing
372	/// bytes which are not valid in a path. If this constraint is violated,
373	/// using the original `PathBuf` after dropping the `&mut Vec` may violate
374	/// memory safety, as the rest of the library assumes that `PathBuf` are
375	/// valid paths.
376	pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
377		PathBufImpl::as_mut_vec(self)
378	}
379
380	pub fn as_path_mut(&mut self) -> PathMut {
381		PathMut::from_path(self)
382	}
383
384	pub fn push(&mut self, segment: &Segment) {
385		self.as_path_mut().push(segment)
386	}
387
388	/// Pop the last non-`..` segment of the path.
389	///
390	/// If the path is empty or ends in `..`, then a `..` segment
391	/// will be added instead.
392	pub fn pop(&mut self) {
393		self.as_path_mut().pop()
394	}
395
396	pub fn clear(&mut self) {
397		self.as_path_mut().clear()
398	}
399
400	/// Push the given segment to this path using the `.` and `..` segments semantics.
401	#[inline]
402	pub fn symbolic_push(&mut self, segment: &Segment) {
403		self.as_path_mut().symbolic_push(segment)
404	}
405
406	/// Append the given path to this path using the `.` and `..` segments semantics.
407	///
408	/// Note that this does not normalize the segments already in the path.
409	/// For instance `'/a/b/.'.symbolc_append('../')` will return `/a/b/` and not
410	/// `a/` because the semantics of `..` is applied on the last `.` in the path.
411	#[inline]
412	pub fn symbolic_append<'s, P: IntoIterator<Item = &'s Segment>>(&mut self, path: P) {
413		self.as_path_mut().symbolic_append(path)
414	}
415
416	#[inline]
417	pub fn normalize(&mut self) {
418		self.as_path_mut().normalize()
419	}
420}
421
422#[cfg(test)]
423mod tests {
424	use super::*;
425
426	#[test]
427	fn empty() {
428		let path = Path::EMPTY;
429		assert!(path.is_empty());
430		assert!(!path.is_absolute());
431		assert!(path.segments().next().is_none());
432	}
433
434	#[test]
435	fn empty_absolute() {
436		let path = Path::EMPTY_ABSOLUTE;
437		assert!(path.is_empty());
438		assert!(path.is_absolute());
439		assert!(path.segments().next().is_none());
440	}
441
442	#[test]
443	fn non_empty() {
444		let path = Path::new(b"a/b").unwrap();
445
446		assert!(!path.is_empty());
447		assert!(!path.is_absolute());
448
449		let mut segments = path.segments();
450		assert!(segments.next().unwrap().as_str() == "a");
451		assert!(segments.next().unwrap().as_str() == "b");
452		assert!(segments.next().is_none());
453	}
454
455	#[test]
456	fn non_empty_absolute() {
457		let path = Path::new(b"/foo/bar").unwrap();
458		assert!(!path.is_empty());
459		assert!(path.is_absolute());
460
461		let mut segments = path.segments();
462		assert!(segments.next().unwrap().as_bytes() == b"foo");
463		assert!(segments.next().unwrap().as_bytes() == b"bar");
464		assert!(segments.next().is_none());
465	}
466
467	#[test]
468	fn next_segment() {
469		let vectors: [(&[u8], usize, Option<(&[u8], usize)>); 6] = [
470			(b"foo/bar", 0, Some((b"foo", 4))),
471			(b"foo/bar", 4, Some((b"bar", 8))),
472			(b"foo/bar", 8, None),
473			(b"foo/bar/", 8, Some((b"", 9))),
474			(b"foo/bar/", 9, None),
475			(b"//foo", 1, Some((b"", 2))),
476		];
477
478		for (input, offset, expected) in vectors {
479			unsafe {
480				assert_eq!(
481					Path::new(input).unwrap().next_segment_from(offset),
482					expected.map(|(e, i)| (Segment::new(e).unwrap(), i))
483				)
484			}
485		}
486	}
487
488	#[test]
489	fn previous_segment() {
490		let vectors: [(&[u8], usize, Option<(&[u8], usize)>); 7] = [
491			(b"/foo/bar", 1, None),
492			(b"foo/bar", 0, None),
493			(b"foo/bar", 4, Some((b"foo", 0))),
494			(b"foo/bar", 8, Some((b"bar", 4))),
495			(b"foo/bar/", 8, Some((b"bar", 4))),
496			(b"foo/bar/", 9, Some((b"", 8))),
497			(b"//a/b", 4, Some((b"a", 2))),
498		];
499
500		for (input, offset, expected) in vectors {
501			unsafe {
502				assert_eq!(
503					Path::new(input).unwrap().previous_segment_from(offset),
504					expected.map(|(e, i)| (Segment::new(e).unwrap(), i))
505				)
506			}
507		}
508	}
509
510	#[test]
511	fn first_segment() {
512		let vectors: [(&[u8], Option<&[u8]>); 4] = [
513			(b"", None),
514			(b"/", None),
515			(b"//", Some(b"")),
516			(b"/foo/bar", Some(b"foo")),
517		];
518
519		for (input, expected) in vectors {
520			assert_eq!(
521				Path::new(input).unwrap().first(),
522				expected.map(|e| Segment::new(e).unwrap())
523			)
524		}
525	}
526
527	#[test]
528	fn segments() {
529		let vectors: [(&[u8], &[&[u8]]); 8] = [
530			(b"", &[]),
531			(b"foo", &[b"foo"]),
532			(b"/foo", &[b"foo"]),
533			(b"foo/", &[b"foo", b""]),
534			(b"/foo/", &[b"foo", b""]),
535			(b"a/b/c/d", &[b"a", b"b", b"c", b"d"]),
536			(b"a/b//c/d", &[b"a", b"b", b"", b"c", b"d"]),
537			(
538				b"//a/b/foo//bar/",
539				&[b"", b"a", b"b", b"foo", b"", b"bar", b""],
540			),
541		];
542
543		for (input, expected) in vectors {
544			let path = Path::new(input).unwrap();
545			let segments: Vec<_> = path.segments().collect();
546			assert_eq!(segments.len(), expected.len());
547			assert!(segments
548				.into_iter()
549				.zip(expected)
550				.all(|(a, b)| a.as_bytes() == *b))
551		}
552	}
553
554	#[test]
555	fn segments_rev() {
556		let vectors: [(&[u8], &[&[u8]]); 8] = [
557			(b"", &[]),
558			(b"foo", &[b"foo"]),
559			(b"/foo", &[b"foo"]),
560			(b"foo/", &[b"foo", b""]),
561			(b"/foo/", &[b"foo", b""]),
562			(b"a/b/c/d", &[b"a", b"b", b"c", b"d"]),
563			(b"a/b//c/d", &[b"a", b"b", b"", b"c", b"d"]),
564			(
565				b"//a/b/foo//bar/",
566				&[b"", b"a", b"b", b"foo", b"", b"bar", b""],
567			),
568		];
569
570		for (input, expected) in vectors {
571			let path = Path::new(input).unwrap();
572			let segments: Vec<_> = path.segments().rev().collect();
573			assert_eq!(segments.len(), expected.len());
574			assert!(segments
575				.into_iter()
576				.zip(expected.into_iter().rev())
577				.all(|(a, b)| a.as_bytes() == *b))
578		}
579	}
580
581	#[test]
582	fn normalized() {
583		let vectors: [(&[u8], &[u8]); 9] = [
584			(b"", b""),
585			(b"a/b/c", b"a/b/c"),
586			(b"a/..", b""),
587			(b"a/b/..", b"a/"),
588			(b"a/b/../", b"a/"),
589			(b"a/b/c/..", b"a/b/"),
590			(b"a/b/c/.", b"a/b/c/"),
591			(b"a/../..", b"../"),
592			(b"/a/../..", b"/"),
593		];
594
595		for (input, expected) in vectors {
596			let path = Path::new(input).unwrap();
597			let output = path.normalized();
598			assert_eq!(output.as_bytes(), expected);
599		}
600	}
601
602	#[test]
603	fn eq() {
604		let vectors: [(&[u8], &[u8]); 11] = [
605			(b"a/b/c", b"a/b/c"),
606			(b"a/b/c", b"a/b/c/."),
607			(b"a/b/c/", b"a/b/c/./"),
608			(b"a/b/c", b"a/b/../b/c"),
609			(b"a/b/c/..", b"a/b"),
610			(b"a/..", b""),
611			(b"/a/..", b"/"),
612			(b"a/../..", b".."),
613			(b"/a/../..", b"/.."),
614			(b"a/b/c/./", b"a/b/c/"),
615			(b"a/b/c/../", b"a/b/"),
616		];
617
618		for (a, b) in vectors {
619			let a = Path::new(a).unwrap();
620			let b = Path::new(b).unwrap();
621			assert_eq!(a, b)
622		}
623	}
624
625	#[test]
626	fn ne() {
627		let vectors: [(&[u8], &[u8]); 3] = [
628			(b"a/b/c", b"a/b/c/"),
629			(b"a/b/c/", b"a/b/c/."),
630			(b"a/b/c/../", b"a/b"),
631		];
632
633		for (a, b) in vectors {
634			let a = Path::new(a).unwrap();
635			let b = Path::new(b).unwrap();
636			assert_ne!(a, b)
637		}
638	}
639
640	#[test]
641	fn file_name() {
642		let vectors: [(&[u8], Option<&[u8]>); 2] = [
643			(b"//a/b/foo//bar/", None),
644			(b"//a/b/foo//bar", Some(b"bar")),
645		];
646
647		for (input, expected) in vectors {
648			let input = Path::new(input).unwrap();
649			assert_eq!(input.file_name().map(Segment::as_bytes), expected)
650		}
651	}
652
653	#[test]
654	fn parent() {
655		let vectors: [(&[u8], Option<&[u8]>); 11] = [
656			(b"", None),
657			(b"/", None),
658			(b".", None),
659			(b"//a/b/foo//bar", Some(b"//a/b/foo/")),
660			(b"//a/b/foo//", Some(b"//a/b/foo/")),
661			(b"//a/b/foo/", Some(b"//a/b/foo")),
662			(b"//a/b/foo", Some(b"//a/b")),
663			(b"//a/b", Some(b"//a")),
664			(b"//a", Some(b"/./")),
665			(b"/./", Some(b"/.")),
666			(b"/.", Some(b"/")),
667		];
668
669		for (input, expected) in vectors {
670			let input = Path::new(input).unwrap();
671			assert_eq!(input.parent().map(Path::as_bytes), expected)
672		}
673	}
674
675	#[test]
676	fn suffix() {
677		let vectors: [(&[u8], &[u8], Option<&[u8]>); 3] = [
678			(b"/foo/bar/baz", b"/foo/bar", Some(b"baz")),
679			(b"//foo", b"/", Some(b".//foo")),
680			(b"/a/b/baz", b"/foo/bar", None),
681		];
682
683		for (path, prefix, expected_suffix) in vectors {
684			let path = Path::new(path).unwrap();
685			let suffix = path.suffix(Path::new(prefix).unwrap());
686			assert_eq!(suffix.as_deref().map(Path::as_bytes), expected_suffix)
687		}
688	}
689}