From 01db028c5883b89dfa2cf303d9f1ee1f7bf84c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o-Tinkeam?= Date: Sun, 23 Aug 2026 15:44:45 +0200 Subject: [PATCH] Rust: Use faster varint library --- lib/rs/Cargo.toml | 2 +- lib/rs/src/protocol/compact.rs | 59 ++++++++++++++++++++++++++-------- 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/lib/rs/Cargo.toml b/lib/rs/Cargo.toml index 460ab693a18..a098f16d1b3 100644 --- a/lib/rs/Cargo.toml +++ b/lib/rs/Cargo.toml @@ -14,12 +14,12 @@ keywords = ["thrift"] [dependencies] byteorder = "1.3" -integer-encoding = "3.0.3" uuid = "1" log = {version = "0.4", optional = true} ordered-float = "3.0" threadpool = {version = "1.7", optional = true} rustls = { version = "0.23.42", default-features = false, features = ["std", "tls12"], optional = true } +varint-rs = "2.2.1" [features] default = ["server"] diff --git a/lib/rs/src/protocol/compact.rs b/lib/rs/src/protocol/compact.rs index a1c4930d42d..fb31a0acb0e 100644 --- a/lib/rs/src/protocol/compact.rs +++ b/lib/rs/src/protocol/compact.rs @@ -16,9 +16,9 @@ // under the License. use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use integer_encoding::VarIntWriter; +use varint_rs::VarintWriter; use std::convert::{From, TryFrom}; -use std::io; +use std::io::{self, Cursor}; use super::{ TFieldIdentifier, TInputProtocol, TInputProtocolFactory, TListIdentifier, TMapIdentifier, @@ -31,6 +31,7 @@ use crate::{ProtocolError, ProtocolErrorKind, TConfiguration}; const COMPACT_PROTOCOL_ID: u8 = 0x82; const COMPACT_VERSION: u8 = 0x01; const COMPACT_VERSION_MASK: u8 = 0x1F; +const MAX_VARINT16_BYTES: usize = 3; // ceil(16/7); matches protobuf wire format const MAX_VARINT32_BYTES: usize = 5; // ceil(32/7); matches protobuf wire format const MAX_VARINT64_BYTES: usize = 10; // ceil(64/7); matches protobuf wire format @@ -562,12 +563,16 @@ where } else { let header = 0xF0 | elem_identifier; self.write_byte(header)?; + let mut buf = [0 as u8; MAX_VARINT32_BYTES]; + let mut writer = Cursor::new(&mut buf[..]); // element count is strictly positive as per the spec, so // cast i32 as u32 so that varint writing won't use zigzag encoding + writer + .write_u32_varint(element_count as u32)?; + let len = writer.position() as usize; self.transport - .write_varint(element_count as u32) + .write_all(&buf[..len]) .map_err(From::from) - .map(|_| ()) } } @@ -585,9 +590,14 @@ where fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> crate::Result<()> { self.write_byte(COMPACT_PROTOCOL_ID)?; self.write_byte((u8::from(identifier.message_type) << 5) | COMPACT_VERSION)?; + let mut buf = [0 as u8; MAX_VARINT32_BYTES]; + let mut writer = Cursor::new(&mut buf[..]); // cast i32 as u32 so that varint writing won't use zigzag encoding + writer + .write_u32_varint(identifier.sequence_number as u32)?; + let len = writer.position() as usize; self.transport - .write_varint(identifier.sequence_number as u32)?; + .write_all(&buf[..len])?; self.write_string(&identifier.name)?; Ok(()) } @@ -664,9 +674,14 @@ where } fn write_bytes(&mut self, b: &[u8]) -> crate::Result<()> { + let mut buf = [0 as u8; MAX_VARINT32_BYTES]; + let mut writer = Cursor::new(&mut buf[..]); // length is strictly positive as per the spec, so // cast i32 as u32 so that varint writing won't use zigzag encoding - self.transport.write_varint(b.len() as u32)?; + writer + .write_u32_varint(b.len() as u32)?; + let len = writer.position() as usize; + self.transport.write_all(&buf[..len])?; self.transport.write_all(b).map_err(From::from) } @@ -675,24 +690,36 @@ where } fn write_i16(&mut self, i: i16) -> crate::Result<()> { + let mut buf = [0 as u8; MAX_VARINT16_BYTES]; + let mut writer = Cursor::new(&mut buf[..]); + writer + .write_i16_varint(i)?; + let len = writer.position() as usize; self.transport - .write_varint(i) + .write_all(&buf[..len]) .map_err(From::from) - .map(|_| ()) } fn write_i32(&mut self, i: i32) -> crate::Result<()> { + let mut buf = [0 as u8; MAX_VARINT32_BYTES]; + let mut writer = Cursor::new(&mut buf[..]); + writer + .write_i32_varint(i)?; + let len = writer.position() as usize; self.transport - .write_varint(i) + .write_all(&buf[..len]) .map_err(From::from) - .map(|_| ()) } fn write_i64(&mut self, i: i64) -> crate::Result<()> { + let mut buf = [0 as u8; MAX_VARINT64_BYTES]; + let mut writer = Cursor::new(&mut buf[..]); + writer + .write_i64_varint(i)?; + let len = writer.position() as usize; self.transport - .write_varint(i) + .write_all(&buf[..len]) .map_err(From::from) - .map(|_| ()) } fn write_double(&mut self, d: f64) -> crate::Result<()> { @@ -731,9 +758,15 @@ where if identifier.size == 0 { self.write_byte(0) } else { + let mut buf = [0 as u8; MAX_VARINT32_BYTES]; + let mut writer = Cursor::new(&mut buf[..]); // element count is strictly positive as per the spec, so // cast i32 as u32 so that varint writing won't use zigzag encoding - self.transport.write_varint(identifier.size as u32)?; + writer + .write_u32_varint(identifier.size as u32)?; + let len = writer.position() as usize; + self.transport + .write_all(&buf[..len])?; let key_type = identifier .key_type