From 8376e9d32341c44f5bbf07e5020340326093f4b1 Mon Sep 17 00:00:00 2001 From: Uzair Aftab Date: Sun, 30 Nov 2025 18:00:55 +0100 Subject: [PATCH 1/6] perf: use libc to fetch env vars --- src/colors.rs | 6 +++--- src/desktop.rs | 29 +++++++++++++++++------------ src/system.rs | 33 +++++++++++++++++++++------------ 3 files changed, 41 insertions(+), 27 deletions(-) diff --git a/src/colors.rs b/src/colors.rs index 07ab9bd..7c65944 100644 --- a/src/colors.rs +++ b/src/colors.rs @@ -1,4 +1,4 @@ -use std::{env, sync::LazyLock}; +use std::sync::LazyLock; pub struct Colors { pub reset: &'static str, @@ -37,8 +37,8 @@ impl Colors { } pub static COLORS: LazyLock = LazyLock::new(|| { - // Check for NO_COLOR once at startup - let is_no_color = env::var("NO_COLOR").is_ok(); + const NO_COLOR: *const libc::c_char = c"NO_COLOR".as_ptr(); + let is_no_color = unsafe { !libc::getenv(NO_COLOR).is_null() }; Colors::new(is_no_color) }); diff --git a/src/desktop.rs b/src/desktop.rs index 561be03..501e967 100644 --- a/src/desktop.rs +++ b/src/desktop.rs @@ -1,22 +1,27 @@ -use std::fmt::Write; +use std::{ffi::CStr, fmt::Write}; #[must_use] #[cfg_attr(feature = "hotpath", hotpath::measure)] pub fn get_desktop_info() -> String { // Retrieve the environment variables and handle Result types - let desktop_env = std::env::var("XDG_CURRENT_DESKTOP"); - let display_backend = std::env::var("XDG_SESSION_TYPE"); - - let desktop_str = match desktop_env { - Err(_) => "Unknown", - Ok(ref s) if s.starts_with("none+") => &s[5..], - Ok(ref s) => s.as_str(), + let desktop_str = unsafe { + let ptr = libc::getenv(c"XDG_CURRENT_DESKTOP".as_ptr()); + if ptr.is_null() { + "Unknown" + } else { + let s = CStr::from_ptr(ptr).to_str().unwrap_or("Unknown"); + s.strip_prefix("none+").unwrap_or(s) + } }; - let backend_str = match display_backend { - Err(_) => "Unknown", - Ok(ref s) if s.is_empty() => "Unknown", - Ok(ref s) => s.as_str(), + let backend_str = unsafe { + let ptr = libc::getenv(c"XDG_SESSION_TYPE".as_ptr()); + if ptr.is_null() { + "Unknown" + } else { + let s = CStr::from_ptr(ptr).to_str().unwrap_or("Unknown"); + if s.is_empty() { "Unknown" } else { s } + } }; // Pre-calculate capacity: desktop_len + " (" + backend_len + ")" diff --git a/src/system.rs b/src/system.rs index 24406ec..ba8fe79 100644 --- a/src/system.rs +++ b/src/system.rs @@ -1,11 +1,18 @@ -use std::{env, fmt::Write as _, io, mem::MaybeUninit}; +use std::{ffi::CStr, fmt::Write as _, io, mem::MaybeUninit}; use crate::{UtsName, colors::COLORS, syscall::read_file_fast}; #[must_use] #[cfg_attr(feature = "hotpath", hotpath::measure)] pub fn get_username_and_hostname(utsname: &UtsName) -> String { - let username = env::var("USER").unwrap_or_else(|_| "unknown_user".to_owned()); + let username = unsafe { + let ptr = libc::getenv(c"USER".as_ptr()); + if ptr.is_null() { + "unknown_user" + } else { + CStr::from_ptr(ptr).to_str().unwrap_or("unknown_user") + } + }; let hostname = utsname.nodename().to_str().unwrap_or("unknown_host"); let capacity = COLORS.yellow.len() @@ -18,7 +25,7 @@ pub fn get_username_and_hostname(utsname: &UtsName) -> String { let mut result = String::with_capacity(capacity); result.push_str(COLORS.yellow); - result.push_str(&username); + result.push_str(username); result.push_str(COLORS.red); result.push('@'); result.push_str(COLORS.green); @@ -31,15 +38,17 @@ pub fn get_username_and_hostname(utsname: &UtsName) -> String { #[must_use] #[cfg_attr(feature = "hotpath", hotpath::measure)] pub fn get_shell() -> String { - let shell_path = - env::var("SHELL").unwrap_or_else(|_| "unknown_shell".to_owned()); + unsafe { + let ptr = libc::getenv(c"SHELL".as_ptr()); + if ptr.is_null() { + return "unknown_shell".into(); + } - // Find last '/' and get the part after it, avoiding allocation - shell_path - .rsplit('/') - .next() - .unwrap_or("unknown_shell") - .to_owned() + let bytes = CStr::from_ptr(ptr).to_bytes(); + let start = bytes.iter().rposition(|&b| b == b'/').map_or(0, |i| i + 1); + let name = std::str::from_utf8_unchecked(&bytes[start..]); + name.into() + } } /// Gets the root disk usage information. @@ -106,7 +115,7 @@ pub fn get_memory_usage() -> Result { fn parse_memory_info() -> Result<(f64, f64), io::Error> { let mut total_memory_kb = 0u64; let mut available_memory_kb = 0u64; - let mut buffer = [0u8; 2048]; + let mut buffer = [0u8; 1024]; // Use fast syscall-based file reading let bytes_read = read_file_fast("/proc/meminfo", &mut buffer)?; From 9da87b933dd3a5b4d92860aef958e8660d8d2529 Mon Sep 17 00:00:00 2001 From: Uzair Aftab Date: Sun, 30 Nov 2025 19:05:05 +0100 Subject: [PATCH 2/6] perf: use stack buffer and direct write syscall in print_system_info Eliminates ~1KB stdout buffering allocation by using Cursor<&mut [u8]> and libc::write instead of format!() + stdout().write_all() --- src/main.rs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4e664bb..d02f16e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ mod syscall; mod system; mod uptime; -use std::io::{Write, stdout}; +use std::io::{self, Cursor, Write}; pub use microfetch_lib::UtsName; @@ -81,7 +81,13 @@ fn print_system_info( let cyan = COLORS.cyan; let blue = COLORS.blue; let reset = COLORS.reset; - let system_info = format!(" + + let mut buf = [0u8; 2048]; + let mut cursor = Cursor::new(&mut buf[..]); + + write!( + cursor, + " {cyan} ▟█▖ {blue}▝█▙ ▗█▛ {user_info} ~{reset} {cyan} ▗▄▄▟██▄▄▄▄▄{blue}▝█▙█▛ {cyan}▖ {cyan} {blue}System{reset}  {os_name} {cyan} ▀▀▀▀▀▀▀▀▀▀▀▘{blue}▝██ {cyan}▟█▖ {cyan} {blue}Kernel{reset}  {kernel_version} @@ -90,7 +96,16 @@ fn print_system_info( {blue} ▟█▛{cyan}▗█▖ {cyan}▟█▛ {cyan} {blue}Desktop{reset}  {desktop} {blue} ▝█▛ {cyan}██▖{blue}▗▄▄▄▄▄▄▄▄▄▄▄ {cyan} {blue}Memory{reset}  {memory_usage} {blue} ▝ {cyan}▟█▜█▖{blue}▀▀▀▀▀██▛▀▀▘ {cyan}󱥎 {blue}Storage (/){reset}  {storage} - {cyan} ▟█▘ ▜█▖ {blue}▝█▛ {cyan} {blue}Colors{reset}  {colors}\n"); + {cyan} ▟█▘ ▜█▖ {blue}▝█▛ {cyan} {blue}Colors{reset}  {colors}\n" + )?; - Ok(stdout().write_all(system_info.as_bytes())?) + #[allow(clippy::cast_possible_truncation)] + let len = cursor.position() as usize; + + // Direct syscall to avoid stdout buffering allocation + let written = unsafe { libc::write(libc::STDOUT_FILENO, buf.as_ptr().cast(), len) }; + if written < 0 { + return Err(io::Error::last_os_error().into()); + } + Ok(()) } From f0cf18dba708e03d3878d26ced25c00daec4a128 Mon Sep 17 00:00:00 2001 From: Uzair Aftab Date: Tue, 9 Dec 2025 19:36:29 +0100 Subject: [PATCH 3/6] fix: handle partial writes from libc::write --- src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main.rs b/src/main.rs index d02f16e..5e37d85 100644 --- a/src/main.rs +++ b/src/main.rs @@ -107,5 +107,8 @@ fn print_system_info( if written < 0 { return Err(io::Error::last_os_error().into()); } + if written as usize != len { + return Err(io::Error::new(io::ErrorKind::WriteZero, "partial write to stdout").into()); + } Ok(()) } From 7b8e736ff74c4b183a4f129e7f6884e9140aa360 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Wed, 10 Dec 2025 11:06:58 +0300 Subject: [PATCH 4/6] microfetch: update memory icon Fixes #34 Signed-off-by: NotAShelf Change-Id: Iff9da39a11eb4060eb314343efa2674b6a6a6964 --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index c3e7c69..e29d6d1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -94,7 +94,7 @@ fn print_system_info( {blue} ▟█▛ {blue}▝█▘{cyan}▟█▛ {cyan} {blue}Shell{reset}  {shell} {blue}▟█████▛ {cyan}▟█████▛ {cyan} {blue}Uptime{reset}  {uptime} {blue} ▟█▛{cyan}▗█▖ {cyan}▟█▛ {cyan} {blue}Desktop{reset}  {desktop} - {blue} ▝█▛ {cyan}██▖{blue}▗▄▄▄▄▄▄▄▄▄▄▄ {cyan} {blue}Memory{reset}  {memory_usage} + {blue} ▝█▛ {cyan}██▖{blue}▗▄▄▄▄▄▄▄▄▄▄▄ {cyan}󰍛 {blue}Memory{reset}  {memory_usage} {blue} ▝ {cyan}▟█▜█▖{blue}▀▀▀▀▀██▛▀▀▘ {cyan}󱥎 {blue}Storage (/){reset}  {storage} {cyan} ▟█▘ ▜█▖ {blue}▝█▛ {cyan} {blue}Colors{reset}  {colors}\n\n" )?; From cf3321b17ac6e865ef0ee17e930589226caf1610 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Wed, 10 Dec 2025 12:06:13 +0300 Subject: [PATCH 5/6] chore: bump dependencies Signed-off-by: NotAShelf Change-Id: I95094ead2493107a2d4bdd3f797fee246a6a6964 --- Cargo.lock | 12 ++++++------ Cargo.toml | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3a23f75..e2397ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -557,9 +557,9 @@ checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hotpath" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08382b985a19a79d95d35e2e201b02cc4b99efe2f47d82f3fd4301bb0005bb68" +checksum = "4b0a2c66c081fe3684a54a7e5d059c9d9ad6b3ee5ccea14f6e4f056dbd77becf" dependencies = [ "arc-swap", "base64", @@ -586,9 +586,9 @@ dependencies = [ [[package]] name = "hotpath-macros" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d618063f89423ebe079a69f5435a13d4909219d4e359757118b75fd05ae65d0" +checksum = "a38fa43ca80cf906cd05127e490d740a51abb38316db7bce9d95e89724a81761" dependencies = [ "proc-macro2", "quote", @@ -786,9 +786,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.177" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libredox" diff --git a/Cargo.toml b/Cargo.toml index c245c00..9f6cc4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,8 @@ name = "microfetch" path = "src/main.rs" [dependencies] -hotpath = { optional = true, version = "0.7.5" } -libc = "0.2.177" +hotpath = { optional = true, version = "0.8.0" } +libc = "0.2.178" [dev-dependencies] criterion = "0.8.0" From 6640fdd559afebbe4c05fb4d5b054206d30d1d05 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 09:08:02 +0000 Subject: [PATCH 6/6] chore(deps): bump criterion from 0.8.0 to 0.8.1 Bumps [criterion](https://github.com/criterion-rs/criterion.rs) from 0.8.0 to 0.8.1. - [Release notes](https://github.com/criterion-rs/criterion.rs/releases) - [Changelog](https://github.com/criterion-rs/criterion.rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/criterion-rs/criterion.rs/compare/criterion-v0.8.0...criterion-v0.8.1) --- updated-dependencies: - dependency-name: criterion dependency-version: 0.8.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e2397ab..49e7cf4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -280,9 +280,9 @@ dependencies = [ [[package]] name = "criterion" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0dfe5e9e71bdcf4e4954f7d14da74d1cdb92a3a07686452d1509652684b1aab" +checksum = "4d883447757bb0ee46f233e9dc22eb84d93a9508c9b868687b274fc431d886bf" dependencies = [ "alloca", "anes", @@ -305,9 +305,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de36c2bee19fba779808f92bf5d9b0fa5a40095c277aba10c458a12b35d21d6" +checksum = "ed943f81ea2faa8dcecbbfa50164acf95d555afec96a27871663b300e387b2e4" dependencies = [ "cast", "itertools", diff --git a/Cargo.toml b/Cargo.toml index 9f6cc4a..0c70446 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ hotpath = { optional = true, version = "0.8.0" } libc = "0.2.178" [dev-dependencies] -criterion = "0.8.0" +criterion = "0.8.1" [features] hotpath = [ "dep:hotpath", "hotpath/hotpath" ]