Skip to content

Commit 6f45cb3

Browse files
authored
Performance Improvements (#147)
* optimized int to string casting; reduced memory allocations for 405; reduced memory allocations on routing * args extraction performance improvements * added unit tests for path args * added query args caching
1 parent 66217cd commit 6f45cb3

File tree

20 files changed

+766
-153
lines changed

20 files changed

+766
-153
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
1313
- Removed unnecessary boxing for `HttpBody::full`, `HttpBody::json` and `HttpBody::form`
1414
- Added additional methods: `HttpBody::text`, `HttpBody::from_static`, `HttpBody::from_static_text`, `HttpBody::from_str` and `HttpBody::from_slice` for better control.
1515
- Improved performance for all producing response macros and `IntoResponse` implementations.
16+
- Improved overall extractors' performance + added additional validation for the cases when mixed Path with NamedPath and positional arguments.
17+
- Added cached query-like path string handling for PathArgs, including into_parts/from_parts, and preserved the cache when cloning to reduce recomputation in extractor/middleware flows.
18+
- Switched route/allow header internals to Arc<str> and cached Allow values on route nodes to avoid recomputing 405 headers, plus simplified HSTS formatting to avoid intermediate allocation.
19+
- Added cached query-arg parsing in HttpRequest/HttpRequestMut to reduce repeated query parsing across extractors.
1620

1721
## 0.8.0
1822

volga-dev-cert/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "volga-dev-cert"
3-
version = "0.8.0"
3+
version = "0.8.1"
44
readme = "README.md"
55
description = "A Rust library for generating self-signed TLS certificates for local development."
66
edition.workspace = true

volga-di/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "volga-di"
3-
version = "0.8.0"
3+
version = "0.8.1"
44
readme = "README.md"
55
description = "Dependency Injection tools for Volga Web Framework"
66
edition.workspace = true

volga-macros/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "volga-macros"
3-
version = "0.8.0"
3+
version = "0.8.1"
44
readme = "README.md"
55
description = "Macros for Volga Web Framework"
66
edition.workspace = true

volga-rate-limiter/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "volga-rate-limiter"
3-
version = "0.8.0"
3+
version = "0.8.1"
44
readme = "README.md"
55
description = "Macros for Volga Web Framework"
66
edition.workspace = true

volga/Cargo.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "volga"
3-
version = "0.8.0"
3+
version = "0.8.1"
44
readme = "../README.md"
55
description = "Easy & Fast Web Framework for Rust"
66
edition.workspace = true
@@ -52,10 +52,10 @@ twox-hash = { version = "2.1.2", optional = true }
5252
uuid = { version = "1.19.0", features = ["v4"], optional = true }
5353

5454
# volga
55-
volga-dev-cert = { path = "../volga-dev-cert", version = "0.8.0", optional = true }
56-
volga-di = { path = "../volga-di", version = "0.8.0", optional = true }
57-
volga-macros = { path = "../volga-macros", version = "0.8.0", optional = true }
58-
volga-rate-limiter = { path = "../volga-rate-limiter", version = "0.8.0", optional = true }
55+
volga-dev-cert = { path = "../volga-dev-cert", version = "0.8.1", optional = true }
56+
volga-di = { path = "../volga-di", version = "0.8.1", optional = true }
57+
volga-macros = { path = "../volga-macros", version = "0.8.1", optional = true }
58+
volga-rate-limiter = { path = "../volga-rate-limiter", version = "0.8.1", optional = true }
5959

6060
[dev-dependencies]
6161
base64 = { version = "0.22.1" }

volga/src/app/scope.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ async fn handle_impl(
177177
) {
178178
FindResult::RouteNotFound => pipeline.fallback(request).await,
179179
FindResult::MethodNotFound(allowed) => status!(405; [
180-
(ALLOW, allowed)
180+
(ALLOW, allowed.as_ref())
181181
]),
182182
FindResult::Ok(endpoint) => {
183183
#[cfg(feature = "middleware")]

volga/src/http/body/into_body.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,17 @@ impl<T: Serialize> TryFrom<Form<T>> for HttpBody {
8484
}
8585
}
8686

87+
macro_rules! impl_int_into_body {
88+
{ $($type:ident),* $(,)? } => {
89+
$(impl From<$type> for HttpBody {
90+
#[inline]
91+
fn from(s: $type) -> Self {
92+
Self::text_ref(itoa::Buffer::new().format(s))
93+
}
94+
})*
95+
};
96+
}
97+
8798
macro_rules! impl_into_body {
8899
{ $($type:ident),* $(,)? } => {
89100
$(impl From<$type> for HttpBody {
@@ -96,13 +107,17 @@ macro_rules! impl_into_body {
96107
}
97108

98109
impl_into_body! {
99-
bool, char,
110+
bool,
111+
char,
112+
f32,
113+
f64
114+
}
115+
116+
impl_int_into_body! {
100117
i8, u8,
101118
i16, u16,
102119
i32, u32,
103-
f32,
104120
i64, u64,
105-
f64,
106121
i128, u128,
107122
isize, usize
108123
}

volga/src/http/cors.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,9 @@ impl CorsConfig {
393393
pub fn max_age(&self) -> Option<HeaderValue> {
394394
match &self.max_age {
395395
None => None,
396-
Some(max_age) => HeaderValue::from_str(&max_age.as_secs().to_string()).ok()
396+
Some(max_age) => HeaderValue::from_str(
397+
itoa::Buffer::new().format(max_age.as_secs())
398+
).ok()
397399
}
398400
}
399401

volga/src/http/endpoints.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//! Endpoints mapping utilities
22
3+
use std::sync::Arc;
34
use hyper::{Method, Uri};
45
use super::endpoints::{
5-
route::{RouteNode, RoutePipeline, PathArgs, make_allowed_str},
6+
route::{RouteNode, RoutePipeline, PathArgs},
67
handlers::RouteHandler
78
};
89

@@ -27,7 +28,7 @@ pub(crate) struct Endpoints {
2728
/// Specifies statuses that could be returned after route matching
2829
pub(crate) enum FindResult {
2930
RouteNotFound,
30-
MethodNotFound(String),
31+
MethodNotFound(Arc<str>),
3132
Ok(Endpoint)
3233
}
3334

@@ -108,7 +109,7 @@ impl Endpoints {
108109
return handlers
109110
.binary_search_by(|h| h.cmp(&target_method))
110111
.map_or_else(
111-
|_| FindResult::MethodNotFound(make_allowed_str(handlers)),
112+
|_| FindResult::MethodNotFound(route_params.route.allowed_methods()),
112113
|i| {
113114
let handler = &handlers[i];
114115
FindResult::Ok(
@@ -126,7 +127,7 @@ impl Endpoints {
126127
handlers
127128
.binary_search_by(|h| h.cmp(method))
128129
.map_or_else(
129-
|_| FindResult::MethodNotFound(make_allowed_str(handlers)),
130+
|_| FindResult::MethodNotFound(route_params.route.allowed_methods()),
130131
|i| {
131132
let handler = &handlers[i];
132133
FindResult::Ok(
@@ -265,7 +266,7 @@ mod tests {
265266
);
266267

267268
match post_handler {
268-
FindResult::MethodNotFound(allow) => assert_eq!(allow, "GET"),
269+
FindResult::MethodNotFound(allow) => assert_eq!(allow.as_ref(), "GET"),
269270
_ => panic!("`post_handler` must be is the `MethodNotFound` state")
270271
}
271272
}

0 commit comments

Comments
 (0)