http_handle/optimized.rs
1// SPDX-License-Identifier: AGPL-3.0-only
2// Copyright (c) 2026 Sebastien Rousseau
3
4//! Zero-allocation lookup helpers for hot-path operations.
5
6use crate::language::Language;
7
8/// Small stack-backed language set.
9///
10/// # Examples
11///
12/// ```rust
13/// use http_handle::optimized::LanguageSet;
14/// let set = LanguageSet::new();
15/// assert!(set.as_slice().is_empty());
16/// ```
17///
18/// # Panics
19///
20/// This type does not panic.
21#[derive(Clone, Copy, Debug, Eq, PartialEq)]
22pub struct LanguageSet {
23 data: [Language; 8],
24 len: usize,
25}
26
27impl LanguageSet {
28 /// Creates an empty set.
29 ///
30 /// # Examples
31 ///
32 /// ```rust
33 /// use http_handle::optimized::LanguageSet;
34 /// let set = LanguageSet::new();
35 /// assert_eq!(set.as_slice().len(), 0);
36 /// ```
37 ///
38 /// # Panics
39 ///
40 /// This function does not panic.
41 pub const fn new() -> Self {
42 Self {
43 data: [Language::Unknown; 8],
44 len: 0,
45 }
46 }
47
48 /// Inserts a language if absent and capacity allows.
49 ///
50 /// # Examples
51 ///
52 /// ```rust
53 /// use http_handle::language::Language;
54 /// use http_handle::optimized::LanguageSet;
55 /// let mut set = LanguageSet::new();
56 /// set.insert(Language::Rust);
57 /// assert!(set.contains(Language::Rust));
58 /// ```
59 ///
60 /// # Panics
61 ///
62 /// This function does not panic.
63 pub fn insert(&mut self, language: Language) {
64 if self.contains(language) || self.len >= self.data.len() {
65 return;
66 }
67 self.data[self.len] = language;
68 self.len += 1;
69 }
70
71 /// Returns true if language is present.
72 ///
73 /// # Examples
74 ///
75 /// ```rust
76 /// use http_handle::language::Language;
77 /// use http_handle::optimized::LanguageSet;
78 /// let mut set = LanguageSet::new();
79 /// set.insert(Language::Go);
80 /// assert!(set.contains(Language::Go));
81 /// ```
82 ///
83 /// # Panics
84 ///
85 /// This function does not panic.
86 pub fn contains(&self, language: Language) -> bool {
87 self.data[..self.len].contains(&language)
88 }
89
90 /// Returns slice view over inserted languages.
91 ///
92 /// # Examples
93 ///
94 /// ```rust
95 /// use http_handle::language::Language;
96 /// use http_handle::optimized::LanguageSet;
97 /// let mut set = LanguageSet::new();
98 /// set.insert(Language::Python);
99 /// assert_eq!(set.as_slice(), &[Language::Python]);
100 /// ```
101 ///
102 /// # Panics
103 ///
104 /// This function does not panic.
105 pub fn as_slice(&self) -> &[Language] {
106 &self.data[..self.len]
107 }
108}
109
110impl Default for LanguageSet {
111 fn default() -> Self {
112 Self::new()
113 }
114}
115
116/// Branch-optimized extension to content type lookup for hot paths.
117///
118/// # Examples
119///
120/// ```rust
121/// use http_handle::optimized::const_content_type_from_ext;
122/// assert_eq!(const_content_type_from_ext("wasm"), "application/wasm");
123/// ```
124///
125/// # Panics
126///
127/// This function does not panic.
128pub fn const_content_type_from_ext(ext: &str) -> &'static str {
129 match ext {
130 "html" | "htm" => "text/html",
131 "css" => "text/css",
132 "js" | "mjs" => "application/javascript",
133 "json" => "application/json",
134 "wasm" => "application/wasm",
135 "webp" => "image/webp",
136 "avif" => "image/avif",
137 _ => "application/octet-stream",
138 }
139}
140
141/// Fast no-allocation language hinting using substring checks only.
142///
143/// # Examples
144///
145/// ```rust
146/// use http_handle::language::Language;
147/// use http_handle::optimized::detect_language_fast;
148/// assert_eq!(detect_language_fast("fn main() {}"), Language::Rust);
149/// ```
150///
151/// # Panics
152///
153/// This function does not panic.
154pub fn detect_language_fast(input: &str) -> Language {
155 if input.contains("fn ")
156 || input.contains("impl ")
157 || input.contains("let ")
158 {
159 return Language::Rust;
160 }
161 if input.contains("def ") || input.contains("import ") {
162 return Language::Python;
163 }
164 if input.contains("function ")
165 || input.contains("const ")
166 || input.contains("=>")
167 {
168 return Language::JavaScript;
169 }
170 if input.contains("package ") || input.contains("func ") {
171 return Language::Go;
172 }
173 Language::Unknown
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179
180 #[test]
181 fn set_is_stack_based_and_deduplicated() {
182 let mut set = LanguageSet::new();
183 set.insert(Language::Rust);
184 set.insert(Language::Rust);
185 set.insert(Language::Python);
186 assert_eq!(set.as_slice(), &[Language::Rust, Language::Python]);
187 }
188
189 #[test]
190 fn detects_const_content_types() {
191 assert_eq!(
192 const_content_type_from_ext("wasm"),
193 "application/wasm"
194 );
195 assert_eq!(
196 const_content_type_from_ext("unknown"),
197 "application/octet-stream"
198 );
199 }
200
201 #[test]
202 fn detects_fast_language_paths() {
203 assert_eq!(
204 detect_language_fast("fn main() {}"),
205 Language::Rust
206 );
207 assert_eq!(
208 detect_language_fast("def main(): pass"),
209 Language::Python
210 );
211 assert_eq!(
212 detect_language_fast("const x = () => 1;"),
213 Language::JavaScript
214 );
215 assert_eq!(
216 detect_language_fast("package main\nfunc main() {}"),
217 Language::Go
218 );
219 assert_eq!(
220 detect_language_fast("plain text"),
221 Language::Unknown
222 );
223 }
224
225 #[test]
226 fn set_capacity_is_bounded() {
227 let mut set = LanguageSet::new();
228 for _ in 0..16 {
229 set.insert(Language::Rust);
230 set.insert(Language::Python);
231 set.insert(Language::JavaScript);
232 set.insert(Language::Go);
233 set.insert(Language::Unknown);
234 }
235 assert!(set.as_slice().len() <= 8);
236 }
237
238 #[test]
239 fn default_matches_new_set() {
240 let via_default = LanguageSet::default();
241 let via_new = LanguageSet::new();
242 assert_eq!(via_default.as_slice(), via_new.as_slice());
243 }
244}