Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion benches/benchmark.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use criterion::{Criterion, criterion_group, criterion_main};
use microfetch_lib::{
UtsName,
colors::print_dots,
desktop::get_desktop_info,
dots::print_dots,
release::{get_os_pretty_name, get_system_info},
system::{
get_memory_usage,
Expand Down
78 changes: 29 additions & 49 deletions src/colors.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
use std::sync::LazyLock;

// All this because concat!() doesn't accept const parameters
// See https://github.com/rust-lang/rust/issues/31383
#[macro_export]
macro_rules! RESET {() => {"\x1b[0m"}}
#[macro_export]
macro_rules! BLUE {() => {"\x1b[34m"}}
#[macro_export]
macro_rules! CYAN {() => {"\x1b[34m"}}
#[macro_export]
macro_rules! GREEN {() => {"\x1b[32m"}}
#[macro_export]
macro_rules! YELLOW {() => {"\x1b[33m"}}
#[macro_export]
macro_rules! RED {() => {"\x1b[31m"}}
#[macro_export]
macro_rules! MAGENTA {() => {"\x1b[35m"}}

pub struct Colors {
pub reset: &'static str,
pub blue: &'static str,
pub cyan: &'static str,
pub green: &'static str,
pub yellow: &'static str,
pub red: &'static str,
pub magenta: &'static str,
}

impl Colors {
Expand All @@ -20,62 +36,26 @@ impl Colors {
green: "",
yellow: "",
red: "",
magenta: "",
}
} else {
Self {
reset: "\x1b[0m",
blue: "\x1b[34m",
cyan: "\x1b[36m",
green: "\x1b[32m",
yellow: "\x1b[33m",
red: "\x1b[31m",
magenta: "\x1b[35m",
reset: RESET!(),
blue: BLUE!(),
cyan: CYAN!(),
green: GREEN!(),
yellow: YELLOW!(),
red: RED!(),
}
}
}
}

pub static COLORS: LazyLock<Colors> = LazyLock::new(|| {
pub static IS_NO_COLOR: LazyLock<bool> = 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 = unsafe { !libc::getenv(NO_COLOR).is_null() };
Colors::new(is_no_color)
unsafe { !libc::getenv(NO_COLOR).is_null() }
});

#[must_use]
#[cfg_attr(feature = "hotpath", hotpath::measure)]
pub fn print_dots() -> String {
// Pre-calculate capacity: 6 color codes + " " (glyph + 2 spaces) per color
const GLYPH: &str = "";
let capacity = COLORS.blue.len()
+ COLORS.cyan.len()
+ COLORS.green.len()
+ COLORS.yellow.len()
+ COLORS.red.len()
+ COLORS.magenta.len()
+ COLORS.reset.len()
+ (GLYPH.len() + 2) * 6;

let mut result = String::with_capacity(capacity);
result.push_str(COLORS.blue);
result.push_str(GLYPH);
result.push_str(" ");
result.push_str(COLORS.cyan);
result.push_str(GLYPH);
result.push_str(" ");
result.push_str(COLORS.green);
result.push_str(GLYPH);
result.push_str(" ");
result.push_str(COLORS.yellow);
result.push_str(GLYPH);
result.push_str(" ");
result.push_str(COLORS.red);
result.push_str(GLYPH);
result.push_str(" ");
result.push_str(COLORS.magenta);
result.push_str(GLYPH);
result.push_str(" ");
result.push_str(COLORS.reset);

result
}
pub static COLORS: LazyLock<Colors> = LazyLock::new(|| {
Colors::new(*IS_NO_COLOR)
});
19 changes: 11 additions & 8 deletions src/desktop.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::{ffi::CStr, fmt::Write};
use std::ffi::CStr;

use crate::unknown;

#[must_use]
#[cfg_attr(feature = "hotpath", hotpath::measure)]
Expand All @@ -7,20 +9,20 @@ pub fn get_desktop_info() -> String {
let desktop_str = unsafe {
let ptr = libc::getenv(c"XDG_CURRENT_DESKTOP".as_ptr());
if ptr.is_null() {
"Unknown"
unknown()
} else {
let s = CStr::from_ptr(ptr).to_str().unwrap_or("Unknown");
let s = CStr::from_ptr(ptr).to_str().unwrap_or_else(|_| unknown());
s.strip_prefix("none+").unwrap_or(s)
}
};

let backend_str = unsafe {
let ptr = libc::getenv(c"XDG_SESSION_TYPE".as_ptr());
if ptr.is_null() {
"Unknown"
unknown()
} else {
let s = CStr::from_ptr(ptr).to_str().unwrap_or("Unknown");
if s.is_empty() { "Unknown" } else { s }
let s = CStr::from_ptr(ptr).to_str().unwrap_or_else(|_| unknown());
if s.is_empty() { unknown() } else { s }
}
};

Expand All @@ -29,11 +31,12 @@ pub fn get_desktop_info() -> String {
let mut result =
String::with_capacity(desktop_str.len() + backend_str.len() + 3);
result.push_str(desktop_str);
result.push_str(" (");
result.push(' ');
result.push('(');

// Capitalize first character of backend
if let Some(first_char) = backend_str.chars().next() {
let _ = write!(result, "{}", first_char.to_ascii_uppercase());
result.push(first_char.to_ascii_uppercase());
result.push_str(&backend_str[first_char.len_utf8()..]);
}

Expand Down
33 changes: 33 additions & 0 deletions src/dots.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use crate::{colors::IS_NO_COLOR, BLUE, CYAN, GREEN, MAGENTA, RED, RESET, YELLOW};

macro_rules! GLYPH {() => {""}}

macro_rules! GAP {() => {" "}}

const NO_COLORS_STR: &str = concat!(
GLYPH!(), GAP!(),
GLYPH!(), GAP!(),
GLYPH!(), GAP!(),
GLYPH!(), GAP!(),
GLYPH!(), GAP!(),
GLYPH!(),
);

const COLORS_STR: &str = concat!(
BLUE!(), GLYPH!(), GAP!(),
CYAN!(), GLYPH!(), GAP!(),
GREEN!(), GLYPH!(), GAP!(),
YELLOW!(), GLYPH!(), GAP!(),
RED!(), GLYPH!(), GAP!(),
MAGENTA!(), GLYPH!(), RESET!(),
);

#[must_use]
#[cfg_attr(feature = "hotpath", hotpath::measure)]
pub fn print_dots() -> &'static str {
if *IS_NO_COLOR {
NO_COLORS_STR
} else {
COLORS_STR
}
}
15 changes: 13 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
pub mod colors;
pub mod desktop;
pub mod dots;
pub mod release;
pub mod syscall;
pub mod system;
pub mod uptime;

use std::mem::MaybeUninit;
use std::{io, mem::MaybeUninit};

#[inline]
#[cold]
pub const fn unknown() -> &'static str { "Unknown" }

#[inline]
#[cold]
pub fn last_os_error<T>() -> io::Result<T> {
Err(io::Error::last_os_error())
}

/// Wrapper for `libc::utsname` with safe accessor methods
pub struct UtsName(libc::utsname);
Expand All @@ -19,7 +30,7 @@ impl UtsName {
pub fn uname() -> Result<Self, std::io::Error> {
let mut uts = MaybeUninit::uninit();
if unsafe { libc::uname(uts.as_mut_ptr()) } != 0 {
return Err(std::io::Error::last_os_error());
return last_os_error();
}
Ok(Self(unsafe { uts.assume_init() }))
}
Expand Down
13 changes: 7 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
mod colors;
mod desktop;
mod dots;
mod release;
mod syscall;
mod system;
mod uptime;

use std::io::{self, Cursor, Write};

pub use microfetch_lib::UtsName;
pub use microfetch_lib::{UtsName, last_os_error, unknown};

use crate::{
colors::print_dots,
desktop::get_desktop_info,
dots::print_dots,
release::{get_os_pretty_name, get_system_info},
system::{
get_memory_usage,
Expand All @@ -37,7 +38,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
uptime: get_current()?,
memory_usage: get_memory_usage()?,
storage: get_root_disk_usage()?,
colors: print_dots(),
dots: print_dots(),
};
print_system_info(&fields)?;
}
Expand All @@ -57,7 +58,7 @@ struct Fields {
desktop: String,
memory_usage: String,
storage: String,
colors: String,
dots: &'static str,
}

#[cfg_attr(feature = "hotpath", hotpath::measure)]
Expand All @@ -75,7 +76,7 @@ fn print_system_info(
desktop,
memory_usage,
storage,
colors,
dots,
} = fields;

let cyan = COLORS.cyan;
Expand All @@ -96,7 +97,7 @@ 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\n"
{cyan} ▟█▘ ▜█▖ {blue}▝█▛ {cyan} {blue}Colors{reset}  {dots}\n\n"
)?;

let len = cursor.position() as usize;
Expand Down
20 changes: 13 additions & 7 deletions src/release.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
use std::{fmt::Write as _, io};
use std::io;

use crate::{UtsName, syscall::read_file_fast};
use crate::{syscall::read_file_fast, unknown, UtsName};

#[must_use]
#[cfg_attr(feature = "hotpath", hotpath::measure)]
pub fn get_system_info(utsname: &UtsName) -> String {
let sysname = utsname.sysname().to_str().unwrap_or("Unknown");
let release = utsname.release().to_str().unwrap_or("Unknown");
let machine = utsname.machine().to_str().unwrap_or("Unknown");
let sysname = utsname.sysname().to_str().unwrap_or_else(|_| unknown());
let release = utsname.release().to_str().unwrap_or_else(|_| unknown());
let machine = utsname.machine().to_str().unwrap_or_else(|_| unknown());

// Pre-allocate capacity: sysname + " " + release + " (" + machine + ")"
let capacity = sysname.len() + 1 + release.len() + 2 + machine.len() + 1;
let mut result = String::with_capacity(capacity);

write!(result, "{sysname} {release} ({machine})").unwrap();
result.push_str(sysname);
result.push(' ');
result.push_str(release);
result.push(' ');
result.push('(');
result.push_str(machine);
result.push(')');
result
}

Expand Down Expand Up @@ -65,5 +71,5 @@ pub fn get_os_pretty_name() -> Result<String, io::Error> {
offset += line_end + 1;
}

Ok("Unknown".to_owned())
Ok(unknown().to_owned())
}
14 changes: 11 additions & 3 deletions src/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

use std::io;

use crate::last_os_error;

/// Direct syscall to open a file
///
/// # Returns
Expand Down Expand Up @@ -169,6 +171,12 @@ pub unsafe fn sys_close(fd: i32) -> i32 {
}
}

#[inline]
#[cold]
fn path_too_long() -> io::Result<usize> {
Err(io::Error::new(io::ErrorKind::InvalidInput, "Path too long"))
}

/// Read entire file using direct syscalls. This avoids libc overhead and can be
/// significantly faster for small files.
///
Expand All @@ -182,7 +190,7 @@ pub fn read_file_fast(path: &str, buffer: &mut [u8]) -> io::Result<usize> {
// Use stack-allocated buffer for null-terminated path (max 256 bytes)
let path_bytes = path.as_bytes();
if path_bytes.len() >= 256 {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "Path too long"));
return path_too_long();
}

let mut path_buf = [0u8; 256];
Expand All @@ -192,14 +200,14 @@ pub fn read_file_fast(path: &str, buffer: &mut [u8]) -> io::Result<usize> {
unsafe {
let fd = sys_open(path_buf.as_ptr(), O_RDONLY);
if fd < 0 {
return Err(io::Error::last_os_error());
return last_os_error();
}

let bytes_read = sys_read(fd, buffer.as_mut_ptr(), buffer.len());
let _ = sys_close(fd);

if bytes_read < 0 {
return Err(io::Error::last_os_error());
return last_os_error();
}

#[allow(clippy::cast_sign_loss)]
Expand Down
Loading