Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

tryx explores outcome types that compose with Rust’s ? operator on nightly.

The Question Mark Operator

Rust’s ? operator delegates to Try and FromResidual. tryx uses those nightly traits to model outcomes that are not naturally Result or Option.

The important rule is simple: the success value continues, and the residual short-circuits.

Outcome Types

Cancel

Cancel<T> stops work when cancellation is requested. Use CancelToken when another thread or owner needs to request cancellation.

Run:

cargo run -p tryx --example cancel_basic --features cancel
cargo run -p tryx --example cancel_render_loop --features cancel

Checked

Finite wraps a finite f64. Checked<Finite> is the ?-able outcome used by constructors and arithmetic.

Run:

cargo run -p tryx --example quadratic --features checked

Parsing

Parsing<'a, T> carries parsed values, remaining input, and borrowed failures. ParseError owns the diagnostic data when a parser is absorbed by Result.

Run:

cargo run -p tryx --example kv_parser --features parsing

Stage

Stage<S, T, P> carries the stage marker and partial state when a staged computation stops.

Run:

cargo run -p tryx --example etl_pipeline --features stage

Defining Outcomes

#[derive(Outcome)] supports enums with one success variant and one short-circuit variant.

#![allow(unused)]
#![feature(try_trait_v2)]
fn main() {
use tryx_derive::Outcome;

#[derive(Outcome)]
#[outcome(result_interop = AppError)]
enum Permitted<T> {
    #[outcome(success)]
    Yes(T),
    #[outcome(short_circuit)]
    No(AppError),
}

#[derive(Debug)]
struct AppError;
}

The derive intentionally rejects ambiguous shapes, including multiple success variants and short-circuit variants with multiple fields.

Result Interop

Every shipped residual can be absorbed by a compatible Result.

Use this at boundaries where callers expect normal Rust error handling. Keep the custom outcome internally when its short-circuit semantics matter to the implementation.

When Not To Use This

Do not use a custom outcome type when Result would do. ? already works on Result, and most public Rust APIs should expose ordinary error types.

Do not use outcome types whose short-circuit case is common. ? hides the branch, so frequent control flow deserves an explicit match.

Do not put these types in public APIs of widely used crates unless the semantics are central to the crate. Callers should not have to learn a new meaning for ? just to use a basic function.

Do not compose outcome types when residual semantics conflict. If a function wants to return both parsing failure and cancellation, pick one outcome for the function body and convert at the boundary.

Do not use Stage when a plain state machine is clearer. Stage is useful when partial state and resumption are part of the contract, not when the code only has several helper functions.

Do not use Checked<Finite> as a general numeric tower. It is a narrow tool for making invalid floating-point results visible in ?-driven code.

API Reference

Generate rustdoc locally:

cargo doc --workspace --all-features --no-deps

The generated entry point is target/doc/tryx/index.html.