p9.rs

a terse utility -- raw interface, low ceremony, written in Rust

/* this page rejects polish on purpose */

// intro

What this is

p9.rs is a tiny command-line utility -- it reads files, splits them on byte boundaries, and emits a deterministic stream. No flags, no config. Pipe in, pipe out.

It exists because every "simple" tool eventually grows TOML config and a plugin system. This one will not.

// install
cargo install p9

that's it -- if it errors you probably need rustup update first.

// core idea

Boundary splitting

The trick is page-9 framing -- 4096 byte windows aligned on file offsets that are multiples of nine. Sounds arbitrary. Is arbitrary. Works anyway.

// usage
$ cat input.bin | p9
0000  4d 5a 90 00 03 00 00 00
0008  04 00 00 00 ff ff 00 00
0010  b8 00 00 00 00 00 00 00
...

Output is stable across runs -- same input, same bytes, every time. No timestamps, no machine IDs, nothing leaky.

// performance

Roughly 1.4 GB/sec on a warm SSD with a single thread. Adding threads helps below the disk ceiling.

// philosophy

Why so plain

Every option you add is a promise. Promises break. p9.rs has no options, so there is nothing to deprecate, nothing to migrate, nothing to read in a changelog at 2am.

// internals

The actual loop

loop {
  let n = reader.read(&mut buf)?;
  if n == 0 { break; }
  emit(&buf[..n]);
}

That is most of the program. The rest is argument parsing (there are no arguments) and a Ctrl-C handler.

// dependency

Three crates total -- std, libc, memmap2. The whole thing audits in a coffee break.

// quirk

The "9" really is just nine

People keep asking. It is not a magic number, not a port, not a Plan 9 reference (although the vibes overlap). Nine fit. Nine stayed.

// stability

Versioning

Semver, but major bumps are forbidden. The output format is the public API. If a future version emits different bytes for the same input, that is a bug, not a release.

Currently 0.4.2. Will probably stay there.

// tests

200 fuzz inputs, 12 hand-written goldens, one property test for determinism. Runs in 0.3 seconds.

// coffee note

If you got this far -- the README is shorter than this page, and the source is shorter than the README. Read it. Tell me what is wrong with it.