Skip to content

Rust SDK for Hardware Test Data

April 2, 2026

Rust SDK for TofuPilot hardware test data

Not every test station runs Python. Some teams need bare-metal performance, memory safety, or just prefer cargo test over openhtf or pytest. TofuPilot now has an official Rust client.

Create a run

The SDK uses async builders. Required fields are enforced at compile time, optional ones chain before .send().

rust
use tofupilot::TofuPilot;use tofupilot::types::*;let client = TofuPilot::new(std::env::var("TOFUPILOT_API_KEY").unwrap());let run = client.runs().create()    .procedure_id("FVT-001")    .serial_number("SN-042")    .part_number("PCB-V2")    .outcome(Outcome::Pass)    .started_at(chrono::Utc::now() - chrono::TimeDelta::minutes(5))    .ended_at(chrono::Utc::now())    .send()    .await?;

Phases and measurements

You can push structured test data in one call. Builders keep the nested types readable.

rust
let run = client.runs().create()    .procedure_id("FVT-001")    .serial_number("SN-042")    .part_number("PCB-V2")    .outcome(Outcome::Pass)    .started_at(now - chrono::TimeDelta::minutes(5))    .ended_at(now)    .phases(vec![RunCreatePhases::builder()        .name("voltage_check")        .outcome(PhasesOutcome::Pass)        .started_at(now - chrono::TimeDelta::minutes(5))        .ended_at(now - chrono::TimeDelta::minutes(3))        .measurements(vec![RunCreateMeasurements::builder()            .name("output_voltage")            .outcome(ValidatorsOutcome::Pass)            .measured_value(serde_json::json!(3.3))            .units("V")            .build()            .unwrap()        ])        .build()        .unwrap()    ])    .send()    .await?;

Upload files in one call

Attach files directly to runs or units through the attachments() sub-resource.

rust
// Upload a file to a runlet id = client.runs().attachments().upload(&run.id, "report.pdf").await?;// Upload a file to a unitlet id = client.units().attachments().upload("SN-0001", "calibration.pdf").await?;// Download an attachmentclient.runs().attachments().download(&url, "local-report.pdf").await?;// Delete a unit attachmentclient.units().attachments().delete("SN-0001", vec![id]).await?;

Typed errors

Every API error maps to a Rust enum. No string matching.

rust
use tofupilot::Error;match client.runs().get().id("nonexistent").send().await {    Ok(run) => println!("Found: {}", run.id),    Err(Error::NotFound(e)) => println!("Not found: {}", e.message),    Err(Error::Unauthorized(e)) => println!("Bad key: {}", e.message),    Err(e) => println!("Other: {e}"),}

Retries built in

The client retries on 429 and 5xx with exponential backoff and jitter. You can tune it or leave the defaults.

Every V2 endpoint

Runs, units, parts, revisions, procedures, batches, stations, versions, users. 132 integration tests run on every deployment.

The SDK is open source under MIT. Source on GitHub, package on crates.io.

cargo add tofupilot

See what's new in action