gotham/helpers/http/request/path.rs
1//! Defines helper functions for processing the request path
2
3use crate::helpers::http::PercentDecoded;
4
5const EXCLUDED_SEGMENTS: [&str; 1] = [""];
6
7/// Holder for `Request` URI path segments that have been split into individual segments.
8///
9/// Used internally by the `Router` when traversing its internal `Tree`.
10#[derive(Clone, Debug, Eq, PartialEq)]
11pub struct RequestPathSegments {
12 segments: Vec<PercentDecoded>,
13}
14
15pub(crate) fn split_path_segments<'a>(path: &'a str) -> impl Iterator<Item = &'a str> {
16 path.split('/').filter(|s| !EXCLUDED_SEGMENTS.contains(s))
17}
18
19impl RequestPathSegments {
20 /// Creates a new RequestPathSegments instance by splitting a `Request` URI path.
21 ///
22 /// Empty segments are skipped when generating the `RequestPathSegments` value, and a leading
23 /// `/` segment is added to represent the root (and the beginning of traversal). So, a request
24 /// path of `/some/path/to//my/handler` will be split into segments:
25 ///
26 /// ```plain
27 /// ["/", "some", "path", "to", "my", "handler"]
28 /// ```
29 pub(crate) fn new(path: &str) -> Self {
30 let segments = split_path_segments(path)
31 .filter_map(PercentDecoded::new)
32 .collect();
33
34 RequestPathSegments { segments }
35 }
36
37 pub(crate) fn subsegments(&self, offset: usize) -> Self {
38 RequestPathSegments {
39 segments: self.segments.split_at(offset).1.to_vec(),
40 }
41 }
42
43 /// Provide segments that still need to be processed.
44 ///
45 /// This will always include a "/" node to represent the root as well as all segments
46 /// that remain as of the current offset.
47 ///
48 /// The offset starts at 0 meaning all segments of the initial Request path will be provided
49 /// until the offset is updated.
50 pub(crate) fn segments(&self) -> &Vec<PercentDecoded> {
51 &self.segments
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58
59 #[test]
60 fn request_path_segments_tests() {
61 // Validate the claim made in the doc comment above.
62 let rps = RequestPathSegments::new("/some/path/to//my/handler");
63
64 assert_eq!(
65 rps.segments.iter().map(AsRef::as_ref).collect::<Vec<_>>(),
66 vec!["some", "path", "to", "my", "handler"]
67 );
68 }
69}