1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//! Defines helper functions for processing the request path

use crate::helpers::http::PercentDecoded;

const EXCLUDED_SEGMENTS: [&str; 1] = [""];

/// Holder for `Request` URI path segments that have been split into individual segments.
///
/// Used internally by the `Router` when traversing its internal `Tree`.
#[derive(Clone, Debug, PartialEq)]
pub struct RequestPathSegments {
    segments: Vec<PercentDecoded>,
}

pub(crate) fn split_path_segments<'a>(path: &'a str) -> impl Iterator<Item = &'a str> {
    path.split('/').filter(|s| !EXCLUDED_SEGMENTS.contains(s))
}

impl RequestPathSegments {
    /// Creates a new RequestPathSegments instance by splitting a `Request` URI path.
    ///
    /// Empty segments are skipped when generating the `RequestPathSegments` value, and a leading
    /// `/` segment is added to represent the root (and the beginning of traversal). So, a request
    /// path of `/some/path/to//my/handler` will be split into segments:
    ///
    /// ```plain
    /// ["/", "some", "path", "to", "my", "handler"]
    /// ```
    pub(crate) fn new(path: &str) -> Self {
        let segments = split_path_segments(path)
            .filter_map(PercentDecoded::new)
            .collect();

        RequestPathSegments { segments }
    }

    pub(crate) fn subsegments(&self, offset: usize) -> Self {
        RequestPathSegments {
            segments: self.segments.split_at(offset).1.to_vec(),
        }
    }

    /// Provide segments that still need to be processed.
    ///
    /// This will always include a "/" node to represent the root as well as all segments
    /// that remain as of the current offset.
    ///
    /// The offset starts at 0 meaning all segments of the initial Request path will be provided
    /// until the offset is updated.
    pub(crate) fn segments(&self) -> &Vec<PercentDecoded> {
        &self.segments
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn request_path_segments_tests() {
        // Validate the claim made in the doc comment above.
        let rps = RequestPathSegments::new("/some/path/to//my/handler");

        assert_eq!(
            rps.segments.iter().map(AsRef::as_ref).collect::<Vec<_>>(),
            vec!["some", "path", "to", "my", "handler"]
        );
    }
}