From c414c20b4486ba83a85d9fc7ab57ddbabf46536e Mon Sep 17 00:00:00 2001 From: subhobhai943 Date: Tue, 25 Aug 2026 20:06:13 +0530 Subject: [PATCH] feat(rust,gui): RLE compression codec + Rust Lab desktop app Rust kernel expansion: - rust/src/compress/mod.rs (new): memory-safe PackBits-style run-length encoding codec (rle_compress / rle_decompress) with C-ABI shims, registered in lib.rs. C fallbacks added to rust_fallback.c so aarch64/armv8i match. - include/kernel/rust.h: FFI declarations for the codec. - LazyBox: new `rle ` applet that compresses, decompresses, prints the ratio and verifies the round-trip is lossless. GUI expansion: - gui/gui_apps.c: "Rust Lab" app -- a live dashboard for the Rust subsystem. Shows CRC-32C/Adler-32 of a sample, measured ChaCha20/SHA3-256/AES-128 throughput as scaled bars plus a composite score (benchmark run once at launch and cached), and a live ChaCha20 CSPRNG byte stream refreshed periodically. Per-window state freed on close. - Registered "Rust Lab" (info icon) in the desktop app table and on the desktop; desktop icon indices updated for the new entry. Verified: clean build on x86_64/aarch64/armv8i; boots through the SUB login to the desktop with the new Rust Lab icon rendering (screenshotted); checksum self-test prints, 0 panics / 0 OOM. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX --- gui/gui_apps.c | 103 +++++++++++++++++++++++++++++++++++++ gui/gui_desktop.c | 6 ++- include/gui/gui_apps.h | 1 + include/kernel/rust.h | 4 ++ rust/rust_fallback.c | 30 +++++++++++ rust/src/compress/mod.rs | 93 +++++++++++++++++++++++++++++++++ rust/src/lib.rs | 1 + userland/lazybox/lazybox.c | 26 ++++++++++ 8 files changed, 262 insertions(+), 2 deletions(-) create mode 100644 rust/src/compress/mod.rs diff --git a/gui/gui_apps.c b/gui/gui_apps.c index d2667c0..0d7b884 100644 --- a/gui/gui_apps.c +++ b/gui/gui_apps.c @@ -546,3 +546,106 @@ void gui_app_life_launch(int x, int y, int w, int h) { win->handle_event = life_event; } } + +// ================================================================= +// 8. Rust Kernel Lab -- showcases the memory-safe Rust subsystem +// ================================================================= +typedef struct { + rust_crypto_bench_result_t bench; // measured once at launch + bool have_bench; + uint32_t frame; + uint8_t entropy[8]; // live CSPRNG sample +} rustlab_data_t; + +static void rustlab_bar(int x, int y, int w, const char* label, uint32_t value, + uint32_t max_value, uint32_t color) { + char buf[48]; + gui_gfx_draw_string(x, y, label, GUI_THEME_TEXT_MAIN); + int bx = x + 96; + int bw = w - 96 - 64; + if (bw < 20) bw = 20; + gui_gfx_fill_rect(bx, y, bw, 10, GUI_THEME_BG_DARK); + uint32_t denom = (max_value > 0) ? max_value : 1; + int fill = (int)(((uint64_t)value * (uint64_t)bw) / denom); + if (fill > bw) fill = bw; + gui_gfx_fill_rect(bx, y, fill, 10, color); + gui_gfx_draw_rect(bx, y, bw, 10, GUI_THEME_BORDER); + snprintf(buf, sizeof(buf), "%u MB/s", value); + gui_gfx_draw_string(bx + bw + 6, y, buf, GUI_THEME_TEXT_MUTED); +} + +static void rustlab_paint(gui_window_t* win) { + rustlab_data_t* rd = (rustlab_data_t*)win->user_data; + if (!rd) return; + + int cx = win->x + 14; + int cy = win->y + GUI_TITLEBAR_HEIGHT + 12; + int w = win->width - 28; + + gui_gfx_draw_string_16_shadow(cx, cy, "Rust Kernel Subsystem (no_std)", GUI_THEME_PRIMARY, GUI_COLOR_BLACK); + cy += 26; + + // Checksum engine (recomputed live -- it is cheap) + static const char sample[] = "SUB-OS"; + uint32_t crc = rust_crc32c((const uint8_t*)sample, 6); + uint32_t adl = rust_adler32((const uint8_t*)sample, 6); + char buf[80]; + gui_gfx_draw_string(cx, cy, "Checksums of \"SUB-OS\":", GUI_THEME_SUCCESS); + cy += 14; + snprintf(buf, sizeof(buf), "CRC-32C 0x%08X Adler-32 0x%08X", crc, adl); + gui_gfx_draw_string(cx + 8, cy, buf, GUI_THEME_TEXT_MUTED); + cy += 22; + + // Crypto benchmark bars (measured once at launch) + gui_gfx_draw_string(cx, cy, "Crypto throughput (measured):", GUI_THEME_SUCCESS); + cy += 16; + if (rd->have_bench) { + uint32_t mx = rd->bench.chacha20_mbs; + if (rd->bench.sha3_256_mbs > mx) mx = rd->bench.sha3_256_mbs; + if (rd->bench.aes128_mbs > mx) mx = rd->bench.aes128_mbs; + rustlab_bar(cx + 4, cy, w, "ChaCha20", rd->bench.chacha20_mbs, mx, GUI_THEME_ACCENT); + cy += 16; + rustlab_bar(cx + 4, cy, w, "SHA3-256", rd->bench.sha3_256_mbs, mx, GUI_THEME_SUCCESS); + cy += 16; + rustlab_bar(cx + 4, cy, w, "AES-128", rd->bench.aes128_mbs, mx, GUI_THEME_WARNING); + cy += 16; + snprintf(buf, sizeof(buf), "Composite score: %u", rd->bench.score); + gui_gfx_draw_string(cx + 4, cy, buf, GUI_THEME_TEXT_DIM); + cy += 22; + } else { + gui_gfx_draw_string(cx + 4, cy, "benchmark unavailable", GUI_THEME_TEXT_DIM); + cy += 22; + } + + // Live CSPRNG entropy, refreshed periodically + if ((rd->frame++ % 20) == 0) { + rust_csprng_get_random(rd->entropy, sizeof(rd->entropy)); + } + gui_gfx_draw_string(cx, cy, "ChaCha20 CSPRNG stream:", GUI_THEME_SUCCESS); + cy += 14; + snprintf(buf, sizeof(buf), "%02X %02X %02X %02X %02X %02X %02X %02X", + rd->entropy[0], rd->entropy[1], rd->entropy[2], rd->entropy[3], + rd->entropy[4], rd->entropy[5], rd->entropy[6], rd->entropy[7]); + gui_gfx_draw_string(cx + 8, cy, buf, GUI_THEME_PRIMARY); +} + +static void rustlab_event(gui_window_t* win, const gui_event_t* ev) { + if (ev->type == GUI_EVENT_CLOSE && win->user_data) { + kfree(win->user_data); + win->user_data = NULL; + } +} + +void gui_app_rustlab_launch(int x, int y, int w, int h) { + gui_window_t* win = gui_wm_create_window("Rust Lab", x, y, (w > 0) ? w : 420, (h > 0) ? h : 300); + if (win) { + rustlab_data_t* rd = (rustlab_data_t*)kzalloc(sizeof(rustlab_data_t)); + if (rd) { + rd->have_bench = (rust_crypto_run_benchmark(&rd->bench) == 0); + rust_csprng_get_random(rd->entropy, sizeof(rd->entropy)); + } + win->user_data = rd; + win->paint = rustlab_paint; + win->handle_event = rustlab_event; + } +} diff --git a/gui/gui_desktop.c b/gui/gui_desktop.c index 0966cf8..ece9e51 100644 --- a/gui/gui_desktop.c +++ b/gui/gui_desktop.c @@ -57,6 +57,7 @@ static const desktop_app_t g_apps[] = { { "Calculator", GUI_ICON_CALC, gui_app_calc_launch, 260, 100, 220, 240 }, { "Paint", GUI_ICON_PAINT, gui_app_paint_launch, 200, 60, 360, 260 }, { "Life", GUI_ICON_FLASK, gui_app_life_launch, 240, 70, 480, 380 }, + { "Rust Lab", GUI_ICON_INFO, gui_app_rustlab_launch, 300, 80, 420, 300 }, { "Clock", GUI_ICON_CLOCK, gui_app_clock_launch, 460, 120, 280, 260 }, { "Settings", GUI_ICON_SETTINGS, gui_app_settings_launch, 160, 60, 400, 320 }, { "About", GUI_ICON_INFO, gui_app_about_launch, 240, 140, 330, 170 }, @@ -64,8 +65,9 @@ static const desktop_app_t g_apps[] = { #define APP_COUNT ((int)(sizeof(g_apps) / sizeof(g_apps[0]))) // Which of the above appear on the desktop itself. -// Indices into g_apps[]: Terminal, Files, Monitor, Kernel Log, KTest, Life, Settings. -static const int g_desktop_icons[] = { 0, 1, 2, 4, 5, 9, 11 }; +// Indices into g_apps[]: Terminal, Files, Monitor, Kernel Log, KTest, Life, +// Rust Lab, Settings. +static const int g_desktop_icons[] = { 0, 1, 2, 4, 5, 9, 10, 12 }; #define DESKTOP_ICON_COUNT ((int)(sizeof(g_desktop_icons) / sizeof(g_desktop_icons[0]))) static bool g_start_menu_open = false; diff --git a/include/gui/gui_apps.h b/include/gui/gui_apps.h index 53500f7..4c99a0e 100644 --- a/include/gui/gui_apps.h +++ b/include/gui/gui_apps.h @@ -10,5 +10,6 @@ void gui_app_calc_launch(int x, int y, int w, int h); void gui_app_paint_launch(int x, int y, int w, int h); void gui_app_about_launch(int x, int y, int w, int h); void gui_app_life_launch(int x, int y, int w, int h); +void gui_app_rustlab_launch(int x, int y, int w, int h); #endif // _GUI_APPS_H diff --git a/include/kernel/rust.h b/include/kernel/rust.h index 489d91d..af32699 100644 --- a/include/kernel/rust.h +++ b/include/kernel/rust.h @@ -76,6 +76,10 @@ uint32_t rust_crc32c(const uint8_t* data, size_t len); uint32_t rust_adler32(const uint8_t* data, size_t len); uint64_t rust_fnv1a64(const uint8_t* data, size_t len); +// Run-Length Encoding Codec (Rust). Return bytes written, or -1. +int rust_rle_compress(const uint8_t* in_buf, size_t in_len, uint8_t* out_buf, size_t max_out); +int rust_rle_decompress(const uint8_t* in_buf, size_t in_len, uint8_t* out_buf, size_t max_out); + // Cryptography int rust_chacha20_crypt(const uint8_t* key, const uint8_t* nonce, uint32_t counter, uint8_t* data, size_t len); int rust_csprng_get_random(uint8_t* buffer, size_t len); diff --git a/rust/rust_fallback.c b/rust/rust_fallback.c index 53af674..ef3ad9a 100644 --- a/rust/rust_fallback.c +++ b/rust/rust_fallback.c @@ -251,3 +251,33 @@ uint64_t rust_fnv1a64(const uint8_t* data, size_t len) { } return hash; } + +// --- RLE codec (C fallback, mirrors rust/src/compress/mod.rs) --- +int rust_rle_compress(const uint8_t* in_buf, size_t in_len, uint8_t* out_buf, size_t max_out) { + if (!in_buf || !out_buf) return -1; + size_t out = 0, i = 0; + while (i < in_len) { + uint8_t value = in_buf[i]; + size_t run = 1; + while (i + run < in_len && in_buf[i + run] == value && run < 255) run++; + if (out + 2 > max_out) return -1; + out_buf[out++] = (uint8_t)run; + out_buf[out++] = value; + i += run; + } + return (int)out; +} + +int rust_rle_decompress(const uint8_t* in_buf, size_t in_len, uint8_t* out_buf, size_t max_out) { + if (!in_buf || !out_buf) return -1; + size_t out = 0, i = 0; + while (i + 1 < in_len) { + size_t run = in_buf[i]; + uint8_t value = in_buf[i + 1]; + if (run == 0) return -1; + if (out + run > max_out) return -1; + for (size_t k = 0; k < run; k++) out_buf[out++] = value; + i += 2; + } + return (int)out; +} diff --git a/rust/src/compress/mod.rs b/rust/src/compress/mod.rs new file mode 100644 index 0000000..3c19d1c --- /dev/null +++ b/rust/src/compress/mod.rs @@ -0,0 +1,93 @@ +//! Memory-safe run-length encoding (RLE) codec for SUB-OS. +//! +//! A compact PackBits-style byte codec: the stream is a sequence of +//! (count, value) pairs where `count` is 1..=255. It is intended for run-heavy +//! data (framebuffer scanlines, zeroed pages, simple bitmaps) and is fully +//! `no_std` with no allocation -- the caller owns both buffers. + +/// Compress `input` into `output` as (count, value) pairs. Returns the number +/// of bytes written, or -1 if `output` is too small. +pub fn rle_compress(input: &[u8], output: &mut [u8]) -> isize { + let mut out = 0usize; + let mut i = 0usize; + let len = input.len(); + + while i < len { + let value = input[i]; + let mut run = 1usize; + while i + run < len && input[i + run] == value && run < 255 { + run += 1; + } + if out + 2 > output.len() { + return -1; + } + output[out] = run as u8; + output[out + 1] = value; + out += 2; + i += run; + } + out as isize +} + +/// Expand a (count, value) stream back into `output`. Returns the number of +/// bytes written, or -1 on a malformed stream or an output overflow. +pub fn rle_decompress(input: &[u8], output: &mut [u8]) -> isize { + let mut out = 0usize; + let mut i = 0usize; + let len = input.len(); + + while i + 1 < len { + let run = input[i] as usize; + let value = input[i + 1]; + if run == 0 { + return -1; // a zero run is never emitted by the compressor + } + if out + run > output.len() { + return -1; + } + for _ in 0..run { + output[out] = value; + out += 1; + } + i += 2; + } + out as isize +} + +// --------------------------------------------------------------------------- +// C ABI shims +// --------------------------------------------------------------------------- + +#[no_mangle] +pub extern "C" fn rust_rle_compress( + in_buf: *const u8, + in_len: usize, + out_buf: *mut u8, + max_out: usize, +) -> i32 { + if in_buf.is_null() || out_buf.is_null() { + return -1; + } + unsafe { + let input = core::slice::from_raw_parts(in_buf, in_len); + let output = core::slice::from_raw_parts_mut(out_buf, max_out); + rle_compress(input, output) as i32 + } +} + +#[no_mangle] +pub extern "C" fn rust_rle_decompress( + in_buf: *const u8, + in_len: usize, + out_buf: *mut u8, + max_out: usize, +) -> i32 { + if in_buf.is_null() || out_buf.is_null() { + return -1; + } + unsafe { + let input = core::slice::from_raw_parts(in_buf, in_len); + let output = core::slice::from_raw_parts_mut(out_buf, max_out); + rle_decompress(input, output) as i32 + } +} diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 3c9ca1a..540f319 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -9,6 +9,7 @@ pub mod printk; pub mod drivers; pub mod crypto; pub mod checksum; +pub mod compress; pub mod fs; pub mod kernel; pub mod storage; diff --git a/userland/lazybox/lazybox.c b/userland/lazybox/lazybox.c index 60b563d..b8fc53f 100644 --- a/userland/lazybox/lazybox.c +++ b/userland/lazybox/lazybox.c @@ -482,6 +482,31 @@ static int applet_cksum(int argc, char** argv) { return 0; } +static int applet_rle(int argc, char** argv) { + const char* str = (argc >= 2) ? argv[1] : "aaaaabbbccccccccd"; + size_t len = strlen(str); + + uint8_t comp[512]; + uint8_t back[512]; + int clen = rust_rle_compress((const uint8_t*)str, len, comp, sizeof(comp)); + if (clen < 0) { + printk(KERN_ERR "rle: input too large for the demo buffer\n"); + return 1; + } + int dlen = rust_rle_decompress(comp, (size_t)clen, back, sizeof(back)); + + bool ok = (dlen == (int)len) && (memcmp(back, str, len) == 0); + int ratio = (len > 0) ? (clen * 100) / (int)len : 0; + + printk(ANSI_BRIGHT_CYAN "Rust RLE codec" ANSI_RESET " (run-length encoding):\n"); + printk(" Input : \"%s\"\n", str); + printk(" Original : %llu bytes\n", (unsigned long long)len); + printk(" Compressed : %d bytes (%d%% of original)\n", clen, ratio); + printk(" Round-trip : %s\n", ok ? ANSI_BRIGHT_GREEN "OK (lossless)" ANSI_RESET + : ANSI_BRIGHT_RED "MISMATCH" ANSI_RESET); + return ok ? 0 : 1; +} + static int applet_rand(int argc, char** argv) { int count = (argc >= 2) ? atoi(argv[1]) : 4; printk("Random Integers: "); @@ -2190,6 +2215,7 @@ static const lazybox_applet_t applets[] = { {"sha256sum", applet_sha256sum, "sha256sum ", "Compute SHA-256 hash", "Crypto"}, {"crc32", applet_crc32, "crc32 ", "Calculate CRC32 checksum", "Crypto"}, {"cksum", applet_cksum, "cksum ", "Rust CRC-32C/Adler-32/FNV", "Crypto"}, + {"rle", applet_rle, "rle ", "Rust RLE compress round-trip","Crypto"}, {"rand", applet_rand, "rand [count]", "Generate random numbers", "Crypto"}, {"certcheck", applet_certcheck, "certcheck", "View X.509 kernel keyring", "Security"}, {"capsh", applet_capsh, "capsh", "View process capabilities", "Security"},