scanstate 0.2.0

Generic scan checkpoint, journal, and progress primitives for pause/resume workflows
Documentation

scanstate

Checkpoint a scan so you can resume it later. If the process crashes, pick up where you left off. Tracks which targets are done, writes a journal for crash recovery, and calculates ETA.

use scanstate::ScanCheckpoint;

let mut checkpoint = ScanCheckpoint::new("my-scan");
checkpoint.mark_complete("https://target-1.com");
checkpoint.mark_complete("https://target-2.com");
checkpoint.save("checkpoint.json").unwrap();

// Later, or after a crash:
let resumed = ScanCheckpoint::load("checkpoint.json").unwrap();
if resumed.is_complete("https://target-1.com") {
    // skip it
}

Write-ahead journal

For crash recovery, append events to a journal. If the process dies mid-scan, replay the journal to rebuild state:

use scanstate::{WriteAheadJournal, Entry};

let journal = WriteAheadJournal::new("scan.journal");
journal.append(&Entry {
    target_id: "https://target-1.com".into(),
    status: "completed".into(),
    timestamp: 1234567890,
    findings_count: 3,
}).unwrap();

// After crash, replay:
let entries = journal.replay().unwrap();
// Or lenient replay (skips corrupt entries):
let (entries, corrupt_count) = journal.replay_lenient().unwrap();

Progress tracking

use scanstate::ScanProgress;

let mut progress = ScanProgress::new(1000); // 1000 total targets
progress.record_completed();
progress.record_completed();
println!("ETA: {:?}", progress.eta());
println!("Rate: {:.1}/sec", progress.rate());

Contributing

Pull requests are welcome. There is no such thing as a perfect crate. If you find a bug, a better API, or just a rough edge, open a PR. We review quickly.

License

MIT. Copyright 2026 CORUM COLLECTIVE LLC.

crates.io docs.rs