Skip to main content

sark_core/http/request/
mod.rs

1use std::ops::Range;
2
3const INLINE_PATH_PARAM_CAP: usize = 2;
4
5type PathParam = (Box<str>, Range<usize>);
6
7#[derive(Clone)]
8enum PathParamStorage {
9    Inline {
10        items: [Option<PathParam>; INLINE_PATH_PARAM_CAP],
11        len: u8,
12    },
13    Heap(Vec<PathParam>),
14}
15
16#[derive(Clone)]
17pub struct PathParamRanges(PathParamStorage);
18
19impl Default for PathParamRanges {
20    fn default() -> Self {
21        Self::new()
22    }
23}
24
25impl PathParamRanges {
26    pub fn new() -> Self {
27        Self(PathParamStorage::Inline {
28            items: [const { None }; INLINE_PATH_PARAM_CAP],
29            len: 0,
30        })
31    }
32
33    pub fn with_capacity(cap: usize) -> Self {
34        if cap > INLINE_PATH_PARAM_CAP {
35            Self(PathParamStorage::Heap(Vec::with_capacity(cap)))
36        } else {
37            Self::new()
38        }
39    }
40
41    pub fn push(&mut self, key: Box<str>, range: Range<usize>) {
42        match &mut self.0 {
43            PathParamStorage::Heap(heap) => heap.push((key, range)),
44            PathParamStorage::Inline { items, len }
45                if usize::from(*len) < INLINE_PATH_PARAM_CAP =>
46            {
47                items[usize::from(*len)] = Some((key, range));
48                *len += 1;
49            }
50            PathParamStorage::Inline { items, len } => {
51                let mut heap = Vec::with_capacity(usize::from(*len).saturating_add(1));
52                for slot in items.iter_mut().take(usize::from(*len)) {
53                    if let Some(item) = slot.take() {
54                        heap.push(item);
55                    }
56                }
57                heap.push((key, range));
58                self.0 = PathParamStorage::Heap(heap);
59            }
60        }
61    }
62
63    pub fn find_last(&self, key: &str) -> Option<&Range<usize>> {
64        match &self.0 {
65            PathParamStorage::Heap(heap) => heap
66                .iter()
67                .rev()
68                .find(|(k, _)| k.as_ref() == key)
69                .map(|(_, r)| r),
70            PathParamStorage::Inline { items, len } => items
71                .iter()
72                .take(usize::from(*len))
73                .rev()
74                .find_map(|slot| slot.as_ref().filter(|(k, _)| k.as_ref() == key))
75                .map(|(_, r)| r),
76        }
77    }
78}