rustapi_core/
path_params.rs1use smallvec::SmallVec;
7use std::collections::HashMap;
8
9pub const STACK_PARAMS_CAPACITY: usize = 4;
13
14#[derive(Debug, Clone, Default)]
19pub struct PathParams {
20 inner: SmallVec<[(String, String); STACK_PARAMS_CAPACITY]>,
21}
22
23impl PathParams {
24 #[inline]
26 pub fn new() -> Self {
27 Self {
28 inner: SmallVec::new(),
29 }
30 }
31
32 #[inline]
34 pub fn with_capacity(capacity: usize) -> Self {
35 Self {
36 inner: SmallVec::with_capacity(capacity),
37 }
38 }
39
40 #[inline]
42 pub fn insert(&mut self, key: String, value: String) {
43 self.inner.push((key, value));
44 }
45
46 #[inline]
48 pub fn get(&self, key: &str) -> Option<&String> {
49 self.inner.iter().find(|(k, _)| k == key).map(|(_, v)| v)
50 }
51
52 #[inline]
54 pub fn contains_key(&self, key: &str) -> bool {
55 self.inner.iter().any(|(k, _)| k == key)
56 }
57
58 #[inline]
60 pub fn is_empty(&self) -> bool {
61 self.inner.is_empty()
62 }
63
64 #[inline]
66 pub fn len(&self) -> usize {
67 self.inner.len()
68 }
69
70 #[inline]
72 pub fn iter(&self) -> impl Iterator<Item = (&String, &String)> {
73 self.inner.iter().map(|(k, v)| (k, v))
74 }
75
76 pub fn to_hashmap(&self) -> HashMap<String, String> {
78 self.inner.iter().cloned().collect()
79 }
80}
81
82impl FromIterator<(String, String)> for PathParams {
83 fn from_iter<I: IntoIterator<Item = (String, String)>>(iter: I) -> Self {
84 Self {
85 inner: iter.into_iter().collect(),
86 }
87 }
88}
89
90impl<'a> FromIterator<(&'a str, &'a str)> for PathParams {
91 fn from_iter<I: IntoIterator<Item = (&'a str, &'a str)>>(iter: I) -> Self {
92 Self {
93 inner: iter
94 .into_iter()
95 .map(|(k, v)| (k.to_string(), v.to_string()))
96 .collect(),
97 }
98 }
99}
100
101impl From<HashMap<String, String>> for PathParams {
102 fn from(map: HashMap<String, String>) -> Self {
103 Self {
104 inner: map.into_iter().collect(),
105 }
106 }
107}
108
109impl From<PathParams> for HashMap<String, String> {
110 fn from(params: PathParams) -> Self {
111 params.inner.into_iter().collect()
112 }
113}
114
115impl<'a> IntoIterator for &'a PathParams {
116 type Item = &'a (String, String);
117 type IntoIter = std::slice::Iter<'a, (String, String)>;
118
119 fn into_iter(self) -> Self::IntoIter {
120 self.inner.iter()
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 #[test]
129 fn test_small_params_on_stack() {
130 let mut params = PathParams::new();
131 params.insert("id".to_string(), "123".to_string());
132 params.insert("name".to_string(), "test".to_string());
133
134 assert_eq!(params.get("id"), Some(&"123".to_string()));
135 assert_eq!(params.get("name"), Some(&"test".to_string()));
136 assert_eq!(params.len(), 2);
137
138 assert!(!params.inner.spilled());
140 }
141
142 #[test]
143 fn test_many_params_spill_to_heap() {
144 let mut params = PathParams::new();
145 for i in 0..10 {
146 params.insert(format!("key{}", i), format!("value{}", i));
147 }
148
149 assert_eq!(params.len(), 10);
150 assert!(params.inner.spilled());
152 }
153
154 #[test]
155 fn test_from_iterator() {
156 let params: PathParams = [("a", "1"), ("b", "2"), ("c", "3")].into_iter().collect();
157
158 assert_eq!(params.get("a"), Some(&"1".to_string()));
159 assert_eq!(params.get("b"), Some(&"2".to_string()));
160 assert_eq!(params.get("c"), Some(&"3".to_string()));
161 }
162
163 #[test]
164 fn test_to_hashmap_conversion() {
165 let mut params = PathParams::new();
166 params.insert("id".to_string(), "42".to_string());
167
168 let map = params.to_hashmap();
169 assert_eq!(map.get("id"), Some(&"42".to_string()));
170 }
171}