requisite carries data-handling requirements in types. A function can require
trusted input, a high-confidence authorization token, or a value that is still
within its TTL.
cargo add requisiteThe crate supports Rust 1.70 and later.
Most applications can start with the prelude:
use requisite::prelude::*;Import from individual modules when a narrower import list is preferable:
use requisite::confidence::{Confident, Gate};
use requisite::fresh::Fresh;
use requisite::trust::{try_sanitize, Tainted, Trusted, Untrusted};This example parses an external customer ID, checks a cached balance, and gates an action on a confidence score.
use requisite::prelude::*;
use std::time::Duration;
fn load_customer(id: Tainted<u64, Trusted>) -> String {
format!("customer-{}", id.into_inner())
}
fn approve(_proof: Certain, customer: &str) {
println!("approved for {customer}");
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let input = Tainted::<_, Untrusted>::from_input("42".to_owned());
let id = try_sanitize(input, |value| value.parse::<u64>())?;
let customer = load_customer(id);
let balance = Fresh::fetch(125_00_u64, Duration::from_secs(30));
println!("balance: {}", balance.get()?);
let decision = Confident::new(true, 0.98)?;
match decision.gate() {
Gate::HighConfidence(proof, true) => approve(proof, &customer),
Gate::HighConfidence(_, false) | Gate::Likely(_) | Gate::Unsure(_) => {}
}
Ok(())
}The function signatures hold the requirements:
load_customeraccepts a parsed, trusted ID.Fresh::getperforms the TTL check at the read.approverequires the token issued by the high-confidence gate.
Create wrappers where data enters a subsystem:
- HTTP handlers and message consumers create
Tainted<_, Untrusted>. - Forecasts and classifiers create
Confident<T>. - Cache clients and remote fetches create
Fresh<T>.
Keep the wrappers in function signatures until the receiving operation has performed or required the relevant check. See Integration patterns for larger application layouts.