From f800d450b78091835ab7ca67847d76e75d877a24 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 10 Dec 2019 20:48:36 +0100 Subject: [PATCH] Speed up StorePath::to_string() 1.81% -> 0.56% --- nix-rust/src/c.rs | 9 +++++++-- nix-rust/src/store/path.rs | 4 +++- nix-rust/src/util/base32.rs | 19 ++++++++++++++----- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/nix-rust/src/c.rs b/nix-rust/src/c.rs index 4c1724eb3..19e737a88 100644 --- a/nix-rust/src/c.rs +++ b/nix-rust/src/c.rs @@ -1,6 +1,7 @@ use super::{ error, foreign::{self, CBox}, + store::path, store::StorePath, util, }; @@ -53,8 +54,12 @@ pub unsafe extern "C" fn ffi_StorePath_drop(self_: *mut StorePath) { } #[no_mangle] -pub extern "C" fn ffi_StorePath_to_string(self_: &StorePath) -> String { - format!("{}", self_) +pub extern "C" fn ffi_StorePath_to_string(self_: &StorePath) -> Vec { + let mut buf = vec![0; path::STORE_PATH_HASH_CHARS + 1 + self_.name.name().len()]; + util::base32::encode_into(self_.hash.hash(), &mut buf[0..path::STORE_PATH_HASH_CHARS]); + buf[path::STORE_PATH_HASH_CHARS] = b'-'; + buf[path::STORE_PATH_HASH_CHARS + 1..].clone_from_slice(self_.name.name().as_bytes()); + buf } #[no_mangle] diff --git a/nix-rust/src/store/path.rs b/nix-rust/src/store/path.rs index 3ded5c428..2a2232475 100644 --- a/nix-rust/src/store/path.rs +++ b/nix-rust/src/store/path.rs @@ -70,7 +70,9 @@ impl StorePathHash { impl fmt::Display for StorePathHash { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&base32::encode(&self.0)) + let mut buf = vec![0; STORE_PATH_HASH_CHARS]; + base32::encode_into(&self.0, &mut buf); + f.write_str(std::str::from_utf8(&buf).unwrap()) } } diff --git a/nix-rust/src/util/base32.rs b/nix-rust/src/util/base32.rs index 8f6410f16..ba7368933 100644 --- a/nix-rust/src/util/base32.rs +++ b/nix-rust/src/util/base32.rs @@ -25,27 +25,36 @@ lazy_static! { } pub fn encode(input: &[u8]) -> String { - let mut res = String::new(); - res.reserve(encoded_len(input.len())); + let mut buf = vec![0; encoded_len(input.len())]; + encode_into(input, &mut buf); + std::str::from_utf8(&buf).unwrap().to_string() +} + +pub fn encode_into(input: &[u8], output: &mut [u8]) { + let len = encoded_len(input.len()); + assert_eq!(len, output.len()); let mut nr_bits_left: usize = 0; let mut bits_left: u16 = 0; + let mut pos = len; for b in input { bits_left |= (*b as u16) << nr_bits_left; nr_bits_left += 8; while nr_bits_left > 5 { - res.push(BASE32_CHARS[(bits_left & 0x1f) as usize] as char); + output[pos - 1] = BASE32_CHARS[(bits_left & 0x1f) as usize]; + pos -= 1; bits_left >>= 5; nr_bits_left -= 5; } } if nr_bits_left > 0 { - res.push(BASE32_CHARS[(bits_left & 0x1f) as usize] as char); + output[pos - 1] = BASE32_CHARS[(bits_left & 0x1f) as usize]; + pos -= 1; } - res.chars().rev().collect() + assert_eq!(pos, 0); } pub fn decode(input: &str) -> Result, crate::Error> {