Skip to content

Repository files navigation

requisite

requisite makes data-handling requirements part of Rust function signatures. Values carry the state required by the next operation, and APIs state that requirement in their parameter types.

use requisite::prelude::*;fndb_lookup(id:Tainted<u64,Trusted>) -> String{/* ... */}let body = Tainted::<_,Untrusted>::from_input(request_body);let customer_id = sanitize(body, clean_customer_id);db_lookup(customer_id);

The receiving function states its requirement in its parameter type. The compiler then verifies that callers perform the required transition.

modulerole
trustroutes external input through a named sanitizer before trusted use
confidenceconverts a probability into an action tier and issues proof for the highest tier
freshchecks TTLs at read time and binds scoped values to their use site

Installation

cargo add requisite

requisite supports Rust 1.70 and later.

Guides

guideuse it to
Getting startedadd requisite and build an end-to-end flow
Trust transitionsroute external input through infallible or fallible policies
Confidence gatesvalidate probabilities and authorize high-confidence actions
Freshnessenforce TTLs, recover stale values, and scope live data
Integration patternsplace wrappers at application boundaries and design typed APIs

Trust

use requisite::prelude::*;fndb_lookup(id:Tainted<u64,Trusted>) -> String{/* ... */}let raw = Tainted::<_,Untrusted>::from_input("42; DROP TABLE customers".into());println!("{:?}", raw.as_ref());let clean = try_sanitize(raw, |s| {
s.chars().filter(char::is_ascii_digit).collect::<String>().parse::<u64>()})?;db_lookup(clean);

Tainted<T, Untrusted> marks data at an input boundary. sanitize handles infallible transformations, while try_sanitize returns validation errors to the caller. Successful transitions produce Tainted<U, Trusted>, which trusted sinks accept directly.

The sanitizer closure defines what “trusted” means for a specific sink. Keep the destination's cleaning policy in that closure. widen() supports APIs that accept a lower trust requirement.

See Trust transitions for validation, type-changing policies, and sink design.

Confidence

Confident<T> carries a value and a validated probability. gate() applies the default thresholds, and gate_with() accepts application-defined thresholds.

let aurora = Confident::new(forecast(kp_index),0.97)?;let plan = match aurora.gate(){Gate::HighConfidence(proof, _) => {wake_slepp(proof);"woke him up"}Gate::Likely(_) => {buzz_phone();"sent a buzz"}Gate::Unsure(_) => "logged it",};

The highest tier includes a Certain token. Functions such as wake_slepp can require that token, making a successful confidence check part of their call contract. Lower tiers remain available for proportionate actions such as a notification or log entry.

let forecast = Confident::new(predicted_event,0.99)?;let thresholds = Thresholds::new(0.70,0.98)?;match forecast.gate_with(thresholds){Gate::HighConfidence(proof, value) => act(proof, value),Gate::Likely(value) => notify(value),Gate::Unsure(value) => record(value),}

Custom thresholds may raise the Certain boundary above 0.95. The lower bound keeps every Certain token consistent for functions that require one.

See Confidence gates for threshold configuration and typed action authorization.

Freshness

let quote = Fresh::fetch(price,Duration::from_secs(30));match quote.get(){Ok(price) => charge(customer,*price),Err(stale) => println!("price is {} old, refetching", stale.age.as_secs()),}

Fresh::get compares the value's age with its TTL and returns either the value or a Stale error containing both durations. into_inner performs the same check while consuming the wrapper, allowing ownership of a fresh non-Clone value to move into the next operation. A stale result returns the value in StaleValue<T>. fetched_at supports deterministic tests and rejects timestamps ahead of the current monotonic clock.

with_live handles values whose validity is tied to one operation:

with_live(price, |live| {let total = live.get().cents + tax;
total
});

The branded Live value stays within the closure while derived owned values can be returned. The closure’s return type is independent of the private lifetime brand, so retaining Live produces a lifetime error at the return site.

See Freshness for cache access, stale-value recovery, and deterministic tests.

Enforcement model

requirementenforcement
trusted sink argumentsTainted<T, Trusted> parameter types
confidence-based action tiersConfident::gate(), gate_with(), and Gate<T>
high-confidence action authorizationprivate Certain construction
operation-scoped valuesbranded Live<'id, T> lifetimes
TTL validityFresh::get() or into_inner() at read time
sanitization policythe closure passed to sanitize or try_sanitize

Runtime checks produce types that carry their result into the next operation. For example, gate() converts a probability into a Gate<T>, and the highest tier carries the Certain token required by sensitive actions.

Compile-time guarantees

tests/ui/ contains compile-fail cases for each type-level contract. trybuild compares the compiler output with checked-in snapshots, so CI detects changes that weaken a contract.

testcontract
untrusted_to_sink.rstrusted sinks require sanitized input
widen_upward.rstrust promotion goes through sanitize
confidence_as_bool.rsconfidence values go through gate
forge_certain.rsCertain originates from the highest gate tier
escape_live.rsscoped values remain inside their closure

Regenerate snapshots after an intentional compiler diagnostic change:

TRYBUILD=overwrite cargo test --test compile_fail

Review the resulting diff to confirm that each failure still exercises its documented contract.

Try it

cargo run --example payment_flow
cargo test

Layout

src/trust.rs Tainted<T, Tr>, sanitize, widen
src/confidence.rs Confident<T>, gate() -> Gate, Certain
src/fresh.rs Fresh<T> with a TTL; scoped::with_live
examples/payment_flow.rs payment and alerting example
tests/runtime.rs behavior tests
tests/ui/*.rs + .stderr compile-fail tests
docs/ user guides

License

Licensed under either of

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

About

Typed validated values, explicit trust transitions, exhaustive confidence levels, and per-value TTL freshness for Rust.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages