Skip to content

Commit 2ad765e

Browse files
committed
various: reduce allocations where available
Signed-off-by: NotAShelf <[email protected]> Change-Id: I517d855b14c015569a325deb64948f3b6a6a6964
1 parent 325ec69 commit 2ad765e

File tree

5 files changed

+123
-63
lines changed

5 files changed

+123
-63
lines changed

src/colors.rs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,45 @@ impl Colors {
3737
}
3838

3939
pub static COLORS: LazyLock<Colors> = LazyLock::new(|| {
40-
// check for NO_COLOR once at startup
40+
// Check for NO_COLOR once at startup
4141
let is_no_color = env::var("NO_COLOR").is_ok();
4242
Colors::new(is_no_color)
4343
});
4444

4545
#[must_use]
4646
#[cfg_attr(feature = "hotpath", hotpath::measure)]
4747
pub fn print_dots() -> String {
48-
format!(
49-
"{} {} {} {} {} {} {}",
50-
COLORS.blue,
51-
COLORS.cyan,
52-
COLORS.green,
53-
COLORS.yellow,
54-
COLORS.red,
55-
COLORS.magenta,
56-
COLORS.reset,
57-
)
48+
// Pre-calculate capacity: 6 color codes + " " (glyph + 2 spaces) per color
49+
const GLYPH: &str = "";
50+
let capacity = COLORS.blue.len()
51+
+ COLORS.cyan.len()
52+
+ COLORS.green.len()
53+
+ COLORS.yellow.len()
54+
+ COLORS.red.len()
55+
+ COLORS.magenta.len()
56+
+ COLORS.reset.len()
57+
+ (GLYPH.len() + 2) * 6;
58+
59+
let mut result = String::with_capacity(capacity);
60+
result.push_str(COLORS.blue);
61+
result.push_str(GLYPH);
62+
result.push_str(" ");
63+
result.push_str(COLORS.cyan);
64+
result.push_str(GLYPH);
65+
result.push_str(" ");
66+
result.push_str(COLORS.green);
67+
result.push_str(GLYPH);
68+
result.push_str(" ");
69+
result.push_str(COLORS.yellow);
70+
result.push_str(GLYPH);
71+
result.push_str(" ");
72+
result.push_str(COLORS.red);
73+
result.push_str(GLYPH);
74+
result.push_str(" ");
75+
result.push_str(COLORS.magenta);
76+
result.push_str(GLYPH);
77+
result.push_str(" ");
78+
result.push_str(COLORS.reset);
79+
80+
result
5881
}

src/desktop.rs

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,37 @@
1+
use std::fmt::Write;
2+
13
#[must_use]
24
#[cfg_attr(feature = "hotpath", hotpath::measure)]
35
pub fn get_desktop_info() -> String {
46
// Retrieve the environment variables and handle Result types
57
let desktop_env = std::env::var("XDG_CURRENT_DESKTOP");
6-
let display_backend_result = std::env::var("XDG_SESSION_TYPE");
8+
let display_backend = std::env::var("XDG_SESSION_TYPE");
79

8-
// Capitalize the first letter of the display backend value
9-
let mut display_backend = display_backend_result.unwrap_or_default();
10-
if let Some(c) = display_backend.as_mut_str().get_mut(0..1) {
11-
c.make_ascii_uppercase();
12-
}
10+
let desktop_str = match desktop_env {
11+
Err(_) => "Unknown",
12+
Ok(ref s) if s.starts_with("none+") => &s[5..],
13+
Ok(ref s) => s.as_str(),
14+
};
1315

14-
// Trim "none+" from the start of desktop_env if present
15-
// Use "Unknown" if desktop_env is empty or has an error
16-
let desktop_env = match desktop_env {
17-
Err(_) => "Unknown".to_owned(),
18-
Ok(s) => s.trim_start_matches("none+").to_owned(),
16+
let backend_str = match display_backend {
17+
Err(_) => "Unknown",
18+
Ok(ref s) if s.is_empty() => "Unknown",
19+
Ok(ref s) => s.as_str(),
1920
};
2021

21-
// Handle the case where display_backend might be empty after capitalization
22-
let display_backend = if display_backend.is_empty() {
23-
"Unknown"
24-
} else {
25-
&display_backend
22+
// Pre-calculate capacity: desktop_len + " (" + backend_len + ")"
23+
// Capitalize first char needs temporary allocation only if backend exists
24+
let mut result =
25+
String::with_capacity(desktop_str.len() + backend_str.len() + 3);
26+
result.push_str(desktop_str);
27+
result.push_str(" (");
28+
29+
// Capitalize first character of backend
30+
if let Some(first_char) = backend_str.chars().next() {
31+
let _ = write!(result, "{}", first_char.to_ascii_uppercase());
32+
result.push_str(&backend_str[first_char.len_utf8()..]);
2633
}
27-
.to_owned();
2834

29-
format!("{desktop_env} ({display_backend})")
35+
result.push(')');
36+
result
3037
}

src/release.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,34 @@
11
use std::{
2+
fmt::Write as _,
23
fs::File,
3-
io::{self, BufRead, BufReader},
4+
io::{self, Read},
45
};
56

67
use nix::sys::utsname::UtsName;
78

89
#[must_use]
910
#[cfg_attr(feature = "hotpath", hotpath::measure)]
1011
pub fn get_system_info(utsname: &UtsName) -> String {
11-
format!(
12-
"{} {} ({})",
13-
utsname.sysname().to_str().unwrap_or("Unknown"),
14-
utsname.release().to_str().unwrap_or("Unknown"),
15-
utsname.machine().to_str().unwrap_or("Unknown")
16-
)
12+
let sysname = utsname.sysname().to_str().unwrap_or("Unknown");
13+
let release = utsname.release().to_str().unwrap_or("Unknown");
14+
let machine = utsname.machine().to_str().unwrap_or("Unknown");
15+
16+
// Pre-allocate capacity: sysname + " " + release + " (" + machine + ")"
17+
let capacity = sysname.len() + 1 + release.len() + 2 + machine.len() + 1;
18+
let mut result = String::with_capacity(capacity);
19+
20+
write!(result, "{sysname} {release} ({machine})").unwrap();
21+
result
1722
}
1823

1924
#[cfg_attr(feature = "hotpath", hotpath::measure)]
2025
pub fn get_os_pretty_name() -> Result<String, io::Error> {
21-
let file = File::open("/etc/os-release")?;
22-
let reader = BufReader::new(file);
26+
// We use a stack-allocated buffer here, which seems to perform MUCH better
27+
// than `BufReader`. In hindsight, I should've seen this coming.
28+
let mut buffer = String::with_capacity(1024);
29+
File::open("/etc/os-release")?.read_to_string(&mut buffer)?;
2330

24-
for line in reader.lines() {
25-
let line = line?;
31+
for line in buffer.lines() {
2632
if let Some(pretty_name) = line.strip_prefix("PRETTY_NAME=") {
2733
if let Some(trimmed) = pretty_name
2834
.strip_prefix('"')

src/system.rs

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::{
22
env,
3+
fmt::Write as _,
34
fs::File,
45
io::{self, Read},
56
};
@@ -12,27 +13,40 @@ use crate::colors::COLORS;
1213
#[cfg_attr(feature = "hotpath", hotpath::measure)]
1314
pub fn get_username_and_hostname(utsname: &UtsName) -> String {
1415
let username = env::var("USER").unwrap_or_else(|_| "unknown_user".to_owned());
15-
let hostname = utsname
16-
.nodename()
17-
.to_str()
18-
.unwrap_or("unknown_host")
19-
.to_owned();
20-
format!(
21-
"{yellow}{username}{red}@{green}{hostname}{reset}",
22-
yellow = COLORS.yellow,
23-
red = COLORS.red,
24-
green = COLORS.green,
25-
reset = COLORS.reset,
26-
)
16+
let hostname = utsname.nodename().to_str().unwrap_or("unknown_host");
17+
18+
let capacity = COLORS.yellow.len()
19+
+ username.len()
20+
+ COLORS.red.len()
21+
+ 1
22+
+ COLORS.green.len()
23+
+ hostname.len()
24+
+ COLORS.reset.len();
25+
let mut result = String::with_capacity(capacity);
26+
27+
result.push_str(COLORS.yellow);
28+
result.push_str(&username);
29+
result.push_str(COLORS.red);
30+
result.push('@');
31+
result.push_str(COLORS.green);
32+
result.push_str(hostname);
33+
result.push_str(COLORS.reset);
34+
35+
result
2736
}
2837

2938
#[must_use]
3039
#[cfg_attr(feature = "hotpath", hotpath::measure)]
3140
pub fn get_shell() -> String {
3241
let shell_path =
3342
env::var("SHELL").unwrap_or_else(|_| "unknown_shell".to_owned());
34-
let shell_name = shell_path.rsplit('/').next().unwrap_or("unknown_shell");
35-
shell_name.to_owned()
43+
44+
// Find last '/' and get the part after it, avoiding allocation
45+
shell_path
46+
.rsplit('/')
47+
.next()
48+
.unwrap_or("unknown_shell")
49+
.to_owned()
3650
}
3751

3852
#[cfg_attr(feature = "hotpath", hotpath::measure)]
@@ -49,11 +63,16 @@ pub fn get_root_disk_usage() -> Result<String, io::Error> {
4963
let used_size = used_size as f64 / (1024.0 * 1024.0 * 1024.0);
5064
let usage = (used_size / total_size) * 100.0;
5165

52-
Ok(format!(
66+
let mut result = String::with_capacity(64);
67+
write!(
68+
result,
5369
"{used_size:.2} GiB / {total_size:.2} GiB ({cyan}{usage:.0}%{reset})",
5470
cyan = COLORS.cyan,
5571
reset = COLORS.reset,
56-
))
72+
)
73+
.unwrap();
74+
75+
Ok(result)
5776
}
5877

5978
#[cfg_attr(feature = "hotpath", hotpath::measure)]
@@ -70,7 +89,7 @@ pub fn get_memory_usage() -> Result<String, io::Error> {
7089
let mut split = line.split_whitespace();
7190
match split.next().unwrap_or_default() {
7291
"MemTotal:" => {
73-
total_memory_kb = split.next().unwrap_or("0").parse().unwrap_or(0.0)
92+
total_memory_kb = split.next().unwrap_or("0").parse().unwrap_or(0.0);
7493
},
7594
"MemAvailable:" => {
7695
available_memory_kb =
@@ -92,10 +111,15 @@ pub fn get_memory_usage() -> Result<String, io::Error> {
92111
let (used_memory, total_memory) = parse_memory_info()?;
93112
let percentage_used = (used_memory / total_memory * 100.0).round() as u64;
94113

95-
Ok(format!(
114+
let mut result = String::with_capacity(64);
115+
write!(
116+
result,
96117
"{used_memory:.2} GiB / {total_memory:.2} GiB \
97118
({cyan}{percentage_used}%{reset})",
98119
cyan = COLORS.cyan,
99120
reset = COLORS.reset,
100-
))
121+
)
122+
.unwrap();
123+
124+
Ok(result)
101125
}

src/uptime.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{io, mem::MaybeUninit};
1+
use std::{fmt::Write, io, mem::MaybeUninit};
22

33
#[cfg_attr(feature = "hotpath", hotpath::measure)]
44
pub fn get_current() -> Result<String, io::Error> {
@@ -16,21 +16,21 @@ pub fn get_current() -> Result<String, io::Error> {
1616

1717
let mut result = String::with_capacity(32);
1818
if days > 0 {
19-
result.push_str(&days.to_string());
19+
let _ = write!(result, "{days}");
2020
result.push_str(if days == 1 { " day" } else { " days" });
2121
}
2222
if hours > 0 {
2323
if !result.is_empty() {
2424
result.push_str(", ");
2525
}
26-
result.push_str(&hours.to_string());
26+
let _ = write!(result, "{hours}");
2727
result.push_str(if hours == 1 { " hour" } else { " hours" });
2828
}
2929
if minutes > 0 {
3030
if !result.is_empty() {
3131
result.push_str(", ");
3232
}
33-
result.push_str(&minutes.to_string());
33+
let _ = write!(result, "{minutes}");
3434
result.push_str(if minutes == 1 { " minute" } else { " minutes" });
3535
}
3636
if result.is_empty() {

0 commit comments

Comments
 (0)