Compare commits

...

8 commits

Author SHA1 Message Date
dependabot[bot]
6640fdd559
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] <support@github.com>
2025-12-10 09:08:02 +00:00
cf3321b17a
chore: bump dependencies
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I95094ead2493107a2d4bdd3f797fee246a6a6964
2025-12-10 12:06:46 +03:00
7b8e736ff7
microfetch: update memory icon
Fixes #34

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Iff9da39a11eb4060eb314343efa2674b6a6a6964
2025-12-10 11:10:49 +03:00
raf
927dce4127
Merge pull request #29 from Uzaaft/main
Some checks are pending
Rust / Test on aarch64-unknown-linux-gnu (push) Waiting to run
Rust / Test on x86_64-unknown-linux-gnu (push) Waiting to run
Gotta go small
2025-12-09 21:42:02 +03:00
Uzair Aftab
f883723608
Merge branch 'main' into main 2025-12-09 19:38:21 +01:00
Uzair Aftab
f0cf18dba7
fix: handle partial writes from libc::write 2025-12-09 19:36:29 +01:00
Uzair Aftab
9da87b933d
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()
2025-11-30 19:05:05 +01:00
Uzair Aftab
8376e9d323
perf: use libc to fetch env vars 2025-11-30 18:01:11 +01:00
6 changed files with 76 additions and 46 deletions

20
Cargo.lock generated
View file

@ -280,9 +280,9 @@ dependencies = [
[[package]] [[package]]
name = "criterion" name = "criterion"
version = "0.8.0" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0dfe5e9e71bdcf4e4954f7d14da74d1cdb92a3a07686452d1509652684b1aab" checksum = "4d883447757bb0ee46f233e9dc22eb84d93a9508c9b868687b274fc431d886bf"
dependencies = [ dependencies = [
"alloca", "alloca",
"anes", "anes",
@ -305,9 +305,9 @@ dependencies = [
[[package]] [[package]]
name = "criterion-plot" name = "criterion-plot"
version = "0.8.0" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5de36c2bee19fba779808f92bf5d9b0fa5a40095c277aba10c458a12b35d21d6" checksum = "ed943f81ea2faa8dcecbbfa50164acf95d555afec96a27871663b300e387b2e4"
dependencies = [ dependencies = [
"cast", "cast",
"itertools", "itertools",
@ -557,9 +557,9 @@ checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
[[package]] [[package]]
name = "hotpath" name = "hotpath"
version = "0.7.5" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08382b985a19a79d95d35e2e201b02cc4b99efe2f47d82f3fd4301bb0005bb68" checksum = "4b0a2c66c081fe3684a54a7e5d059c9d9ad6b3ee5ccea14f6e4f056dbd77becf"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"base64", "base64",
@ -586,9 +586,9 @@ dependencies = [
[[package]] [[package]]
name = "hotpath-macros" name = "hotpath-macros"
version = "0.7.5" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d618063f89423ebe079a69f5435a13d4909219d4e359757118b75fd05ae65d0" checksum = "a38fa43ca80cf906cd05127e490d740a51abb38316db7bce9d95e89724a81761"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -786,9 +786,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.177" version = "0.2.178"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
[[package]] [[package]]
name = "libredox" name = "libredox"

View file

@ -12,11 +12,11 @@ name = "microfetch"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
hotpath = { optional = true, version = "0.7.5" } hotpath = { optional = true, version = "0.8.0" }
libc = "0.2.177" libc = "0.2.178"
[dev-dependencies] [dev-dependencies]
criterion = "0.8.0" criterion = "0.8.1"
[features] [features]
hotpath = [ "dep:hotpath", "hotpath/hotpath" ] hotpath = [ "dep:hotpath", "hotpath/hotpath" ]

View file

@ -1,4 +1,4 @@
use std::{env, sync::LazyLock}; use std::sync::LazyLock;
pub struct Colors { pub struct Colors {
pub reset: &'static str, pub reset: &'static str,
@ -37,8 +37,8 @@ impl Colors {
} }
pub static COLORS: LazyLock<Colors> = LazyLock::new(|| { pub static COLORS: LazyLock<Colors> = LazyLock::new(|| {
// Check for NO_COLOR once at startup const NO_COLOR: *const libc::c_char = c"NO_COLOR".as_ptr();
let is_no_color = env::var("NO_COLOR").is_ok(); let is_no_color = unsafe { !libc::getenv(NO_COLOR).is_null() };
Colors::new(is_no_color) Colors::new(is_no_color)
}); });

View file

@ -1,22 +1,27 @@
use std::fmt::Write; use std::{ffi::CStr, fmt::Write};
#[must_use] #[must_use]
#[cfg_attr(feature = "hotpath", hotpath::measure)] #[cfg_attr(feature = "hotpath", hotpath::measure)]
pub fn get_desktop_info() -> String { pub fn get_desktop_info() -> String {
// Retrieve the environment variables and handle Result types // Retrieve the environment variables and handle Result types
let desktop_env = std::env::var("XDG_CURRENT_DESKTOP"); let desktop_str = unsafe {
let display_backend = std::env::var("XDG_SESSION_TYPE"); let ptr = libc::getenv(c"XDG_CURRENT_DESKTOP".as_ptr());
if ptr.is_null() {
let desktop_str = match desktop_env { "Unknown"
Err(_) => "Unknown", } else {
Ok(ref s) if s.starts_with("none+") => &s[5..], let s = CStr::from_ptr(ptr).to_str().unwrap_or("Unknown");
Ok(ref s) => s.as_str(), s.strip_prefix("none+").unwrap_or(s)
}
}; };
let backend_str = match display_backend { let backend_str = unsafe {
Err(_) => "Unknown", let ptr = libc::getenv(c"XDG_SESSION_TYPE".as_ptr());
Ok(ref s) if s.is_empty() => "Unknown", if ptr.is_null() {
Ok(ref s) => s.as_str(), "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 + ")" // Pre-calculate capacity: desktop_len + " (" + backend_len + ")"

View file

@ -5,7 +5,7 @@ mod syscall;
mod system; mod system;
mod uptime; mod uptime;
use std::io::{Write, stdout}; use std::io::{self, Cursor, Write};
pub use microfetch_lib::UtsName; pub use microfetch_lib::UtsName;
@ -81,16 +81,32 @@ fn print_system_info(
let cyan = COLORS.cyan; let cyan = COLORS.cyan;
let blue = COLORS.blue; let blue = COLORS.blue;
let reset = COLORS.reset; 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} {user_info} ~{reset}
{cyan} {blue} {cyan} {cyan} {blue}System{reset} {os_name} {cyan} {blue} {cyan} {cyan} {blue}System{reset} {os_name}
{cyan} {blue} {cyan} {cyan} {blue}Kernel{reset} {kernel_version} {cyan} {blue} {cyan} {cyan} {blue}Kernel{reset} {kernel_version}
{blue} {blue}{cyan} {cyan} {blue}Shell{reset} {shell} {blue} {blue}{cyan} {cyan} {blue}Shell{reset} {shell}
{blue} {cyan} {cyan} {blue}Uptime{reset} {uptime} {blue} {cyan} {cyan} {blue}Uptime{reset} {uptime}
{blue} {cyan} {cyan} {cyan} {blue}Desktop{reset} {desktop} {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} {blue} {cyan}{blue} {cyan}󱥎 {blue}Storage (/){reset} {storage}
{cyan} {blue} {cyan} {blue}Colors{reset} {colors}\n\n"); {cyan} {blue} {cyan} {blue}Colors{reset} {colors}\n\n"
)?;
Ok(stdout().write_all(system_info.as_bytes())?) 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());
}
if written as usize != len {
return Err(io::Error::new(io::ErrorKind::WriteZero, "partial write to stdout").into());
}
Ok(())
} }

View file

@ -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}; use crate::{UtsName, colors::COLORS, syscall::read_file_fast};
#[must_use] #[must_use]
#[cfg_attr(feature = "hotpath", hotpath::measure)] #[cfg_attr(feature = "hotpath", hotpath::measure)]
pub fn get_username_and_hostname(utsname: &UtsName) -> String { 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 hostname = utsname.nodename().to_str().unwrap_or("unknown_host");
let capacity = COLORS.yellow.len() 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); let mut result = String::with_capacity(capacity);
result.push_str(COLORS.yellow); result.push_str(COLORS.yellow);
result.push_str(&username); result.push_str(username);
result.push_str(COLORS.red); result.push_str(COLORS.red);
result.push('@'); result.push('@');
result.push_str(COLORS.green); result.push_str(COLORS.green);
@ -31,15 +38,17 @@ pub fn get_username_and_hostname(utsname: &UtsName) -> String {
#[must_use] #[must_use]
#[cfg_attr(feature = "hotpath", hotpath::measure)] #[cfg_attr(feature = "hotpath", hotpath::measure)]
pub fn get_shell() -> String { pub fn get_shell() -> String {
let shell_path = unsafe {
env::var("SHELL").unwrap_or_else(|_| "unknown_shell".to_owned()); 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 let bytes = CStr::from_ptr(ptr).to_bytes();
shell_path let start = bytes.iter().rposition(|&b| b == b'/').map_or(0, |i| i + 1);
.rsplit('/') let name = std::str::from_utf8_unchecked(&bytes[start..]);
.next() name.into()
.unwrap_or("unknown_shell") }
.to_owned()
} }
/// Gets the root disk usage information. /// Gets the root disk usage information.
@ -106,7 +115,7 @@ pub fn get_memory_usage() -> Result<String, io::Error> {
fn parse_memory_info() -> Result<(f64, f64), io::Error> { fn parse_memory_info() -> Result<(f64, f64), io::Error> {
let mut total_memory_kb = 0u64; let mut total_memory_kb = 0u64;
let mut available_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 // Use fast syscall-based file reading
let bytes_read = read_file_fast("/proc/meminfo", &mut buffer)?; let bytes_read = read_file_fast("/proc/meminfo", &mut buffer)?;