sark_core/http/request/
mod.rs1use 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}