From f94c52da7781459d3f4edeadc109788938ef3c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Frosteg=C3=A5rd?= Date: Sat, 18 Jul 2020 03:03:39 +0200 Subject: [PATCH] aquatic_http: send_response: use itoa and Vec::with_capacity This leads to fewer allocations and possibly better performance. --- Cargo.lock | 1 + aquatic_http/Cargo.toml | 1 + aquatic_http/src/lib/network/connection.rs | 46 ++++++++++++++++++++-- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 27f36f5..9d40191 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,6 +81,7 @@ dependencies = [ "hashbrown", "httparse", "indexmap", + "itoa", "log", "mimalloc", "mio", diff --git a/aquatic_http/Cargo.toml b/aquatic_http/Cargo.toml index 15171ef..9c1262a 100644 --- a/aquatic_http/Cargo.toml +++ b/aquatic_http/Cargo.toml @@ -24,6 +24,7 @@ flume = "0.7" hashbrown = { version = "0.7", features = ["serde"] } httparse = "1" indexmap = "1" +itoa = "0.4" log = "0.4" mimalloc = { version = "0.1", default-features = false } mio = { version = "0.7", features = ["tcp", "os-poll", "os-util"] } diff --git a/aquatic_http/src/lib/network/connection.rs b/aquatic_http/src/lib/network/connection.rs index 5be0cae..12d3f7c 100644 --- a/aquatic_http/src/lib/network/connection.rs +++ b/aquatic_http/src/lib/network/connection.rs @@ -100,17 +100,22 @@ impl EstablishedConnection { } pub fn send_response(&mut self, body: &[u8]) -> ::std::io::Result<()> { - let mut response = Vec::new(); + let content_len = body.len() + 2; // 2 is for newlines at end + let content_len_num_digits = Self::num_digits_in_usize(content_len); + + let mut response = Vec::with_capacity( + 39 + content_len_num_digits + body.len() + ); response.extend_from_slice(b"HTTP/1.1 200 OK\r\nContent-Length: "); - response.extend_from_slice(format!("{}", body.len() + 2).as_bytes()); + ::itoa::write(&mut response, content_len)?; response.extend_from_slice(b"\r\n\r\n"); response.extend_from_slice(body); response.extend_from_slice(b"\r\n"); let bytes_written = self.stream.write(&response)?; - if bytes_written != response.len(){ + if bytes_written != response.len() { ::log::error!( "send_response: only {} out of {} bytes written", bytes_written, @@ -123,6 +128,18 @@ impl EstablishedConnection { Ok(()) } + fn num_digits_in_usize(mut number: usize) -> usize { + let mut num_digits = 1usize; + + while number >= 10 { + num_digits += 1; + + number /= 10; + } + + num_digits + } + #[inline] pub fn clear_buffer(&mut self){ self.bytes_read = 0; @@ -284,4 +301,25 @@ impl Connection { } -pub type ConnectionMap = HashMap; \ No newline at end of file +pub type ConnectionMap = HashMap; + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_num_digits_in_usize(){ + let f = EstablishedConnection::num_digits_in_usize; + + assert_eq!(f(0), 1); + assert_eq!(f(1), 1); + assert_eq!(f(9), 1); + assert_eq!(f(10), 2); + assert_eq!(f(11), 2); + assert_eq!(f(99), 2); + assert_eq!(f(100), 3); + assert_eq!(f(101), 3); + assert_eq!(f(1000), 4); + } +} \ No newline at end of file