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}