Skip to content
Sysadmin

Why I Chose Rust for AI-Built Desktop Tools

When I started building tools, I wasn’t hand-writing the code myself. I know the workflows — systems administration, AD, enterprise infrastructure — and I have a decent grasp of programming concepts and PowerShell. But the application code comes from AI, shaped by the requirements and edge cases I describe.

That made the language choice more important, not less. If I’m not reading every line, I need a compiler that will catch the mistakes I won’t see.

The DiskSleuth problem

DiskSleuth was the first tool that made the language choice obvious. Its job: enumerate every file on a drive and build a size tree. My C# prototype used Directory.EnumerateFiles recursively. It worked, but on large drives it would hit 800 MB of RAM and freeze the UI mid-scan with GC pauses. On a drive with a million files, it took minutes.

The Rust version does two things differently.

Direct MFT access via FSCTL_ENUM_USN_DATA. When elevated, you can walk every file record on an NTFS volume without touching the directory structure at all. DiskSleuth uses a 256 KB IOCTL buffer and reads entries in parallel with rayon. A 500 GB volume enumerates in a few seconds.

Arena-allocated tree. Instead of heap-allocated nodes with pointer chains, the file tree is a Vec<FileNode> with NodeIndex(u32) offsets. Sequential memory, no pointer chasing, no GC. Size aggregation bottom-up is O(n) over a flat array. The same work in under 40 MB with no pauses.

What the compiler actually catches

The borrow checker is Rust’s most talked-about feature, but what surprised me is what it catches that I wouldn’t have thought to test.

DiskSleuth has a real-time scanning mode where the UI thread reads the tree while a background thread is still writing to it. The naive approach is a shared mutex. What the borrow checker nudges you toward is Arc<RwLock<FileTree>> with batched writes — 2,000 entries per lock acquisition — to keep contention low. Without that nudge, you’d write the mutex version and not notice the problem until the tree got large.

In SwatCrypt, #![forbid(unsafe_code)] at the crate root means any unsafe block fails to compile. The crypto is in audited upstream crates with their own unsafe budgets. The application code has none. That’s not something you can express the same way in C# or TypeScript.

Binary size

Every Rust tool I’ve shipped is a single executable. No runtime, no installer, no DLL dependencies. LockSmith is about 4 MB. That’s egui’s overhead — the immediate-mode UI framework bakes into the binary directly, no embedded browser. It starts in half a second.

For tools where binary size actually matters (emergency kit on a USB stick), I use pure C — HandleHunter is 134 KB and has no runtime at all. But for everything else, 4 MB is fine.

Where I don’t use Rust: PSBench hosts a PowerShell runspace, which is already a managed .NET runtime. There’s no point wrapping that in Rust. C# is the right tool when the heavy lifting is already a .NET concern.

The tools are on GitHub, MIT licensed.

← All articles