qubit-budget
qubit-budget helps Rust libraries and services put explicit, finite limits on
work: bytes read, nodes visited, output produced, open resources, or elapsed
time. It keeps the accounting separate from parsing and I/O, so callers can
reject oversized work with structured errors and predictable state changes.
Installation
[]
= "0.5"
The crate has no default features. Enable an integration only when it is needed:
[]
= { = "0.5", = ["json"] }
Available features: json, big-integer, big-decimal (which enables
big-integer), and time. The minimum supported Rust version is 1.94.
Quick Start
Suppose one response may contain no more than eight bytes. Charge each accepted chunk to one budget. A failed charge does not change that budget:
use ResourceBudget;
let mut response = new;
response.try_consume.expect;
let error = response
.try_consume
.expect_err;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
This is the basic pattern: choose a meaningful resource name, configure a limit at the boundary you own, and let the caller decide how to handle a typed error.
Choose the right primitive
| Need | Type | What happens on success | What happens on failure |
|---|---|---|---|
| Check one value, such as nesting depth | ResourceLimit |
No state changes | Reports the observed value and limit |
| Spend an allowance that cannot return | ResourceBudget |
Reduces remaining |
Budget is unchanged |
| Reuse capacity that callers return | ResourcePool |
Acquire or release changes the pool | Pool is unchanged |
| Tie reusable capacity to an owned lifetime | ManagedResourcePool |
Returns an RAII permit | Pool is unchanged |
ResourceBudget is not cloneable: copying it would duplicate a finite
allowance. ResourcePool is only in-memory accounting; it does not wait,
synchronize access, or enforce fairness. ManagedResourcePool is a cloneable,
synchronized handle whose permits return capacity on Drop; it does not wait or
enforce fairness.
What it provides
- Atomic charges for one budget and all-or-nothing charges for a group.
- Checked conversion of native
usizeandu64measurements. - Structured errors for exceeded limits, insufficient budget, conversion, and invalid pool release.
- Reusable structure limits for depth, nodes, container sizes, and key bytes.
- Transactional string rendering: bytes are charged only after a complete, valid UTF-8 string is produced.
- Optional limits for JSON, strings, big integers, big decimals, durations, and clock-backed deadlines.
With json, an attempt distinguishes immediate I/O accounting from
transactional value accounting. Accepted input and writer output remain
charged; staged JSON value usage is published only by commit. The user guide
explains this boundary with a complete decode scenario.
JSON transaction boundary
Use a transaction to stage measurements for one complete value. It publishes them only after the surrounding operation succeeds:
use JsonMeasurement;
use JsonResource;
use JsonValueLimits;
let mut budget = builder
.max_nodes
.max_string_bytes
.build
.budget;
let mut transaction = budget.transaction;
transaction.try_admit?;
transaction.commit?;
# Ok::
Raw and normalized input remain immediate charges. A transaction publishes only
staged value usage, so callers call commit after the complete value succeeds.
A rejected value admission poisons that transaction and prevents publication;
already accepted I/O and output remain accounted. The user guide and design
document define the complete atomicity matrix and recovery boundary.
What it does not do
This crate does not parse JSON, perform I/O, choose application limit values,
wait for pool capacity, or define recovery policy. For JSON
parsing and Serde integration, use an adapter such as
qubit-json.
Learn More
- User guide: a scenario-led explanation of JSON accounting, errors, transactions, and troubleshooting.
- Design document: invariants, state transitions, and feature boundaries.
- API documentation
Testing
# Run tests with the default feature set
# Run tests with all declared features
# Project CI checks
# Check code coverage
License
Copyright (c) 2025 - 2026. Haixing Hu. All rights reserved.
Licensed under the Apache License, Version 2.0. See LICENSE for the full license text.
Contributing
Contributions are welcome. Please follow the Rust API guidelines, keep public
API documentation and tests current, and run ./align-ci.sh to format code and
./ci-check.sh to satisfy CI requirements before submitting a pull request.
Author
Haixing Hu - Qubit Co. Ltd.
Repository: https://github.com/qubit-ltd/rs-budget