qubit-budget

Dependency-light resource limit and budget accounting primitives for Qubit Rust crates

Rust CI Coverage Crates.io Rust License

qubit-budget 用于给 Rust 库和服务中的工作量设定明确、有限的上限:例如读取的字节数、遍历的节点数、已写出的内容、已占用的资源或耗用时间。它只负责记账,不把策略绑定到某个解析器或 I/O 实现,因此超限时可以得到结构化错误,并能明确知道状态是否变化。

安装

[dependencies]
qubit-budget = "0.5"

本 crate 默认不启用 feature。只有需要集成能力时才按需开启:

[dependencies]
qubit-budget = { version = "0.5", features = ["json"] }

可选 feature 为 jsonbig-integerbig-decimal(会同时启用 big-integer)和 time。最低支持 Rust 1.94。

快速开始

假设一次响应最多允许写出 8 字节。每接受一段内容,就向同一份预算记账;如果本次请求超出余额,预算不会变化:

use qubit_budget::ResourceBudget;

let mut response = ResourceBudget::new("response-bytes", 8_u64);
response.try_consume(5).expect("the first chunk fits");

let error = response
    .try_consume(4)
    .expect_err("only three bytes remain");

assert_eq!(error.resource(), &"response-bytes");
assert_eq!(error.limit(), 8);
assert_eq!(error.remaining(), 3);
assert_eq!(error.requested(), 4);
assert_eq!(response.used(), 5);

实际使用时,为资源取一个稳定且有含义的名称,在你负责的边界配置上限;出现类型化错误后,由调用方决定拒绝、重试还是采取其他恢复措施。

先选对原语

需求类型成功后失败后
校验一次独立测量,例如嵌套深度ResourceLimit不修改状态返回测量值和上限
消耗不可归还的额度ResourceBudget扣减 remaining预算保持不变
使用后会显式归还的容量ResourcePool获取或释放会改变资源池资源池保持不变
将可复用容量绑定到所有权生命周期ManagedResourcePool返回 RAII permit资源池保持不变

ResourceBudget 不实现 Clone,避免一份有限额度被复制成两份。 ResourcePool 只是内存中的手工记账对象:它不等待、不提供同步,也不保证公平性。 ManagedResourcePool 是可克隆的同步句柄,permit 会在 Drop 时归还容量;它同样不等待、不保证公平性。

核心能力

启用 json 后,一次处理会区分“立即入账的 I/O”与“可回滚的 value 用量”:已接受的输入和 writer 输出仍会保留;暂存的 JSON value 用量只有调用 commit 才会生效。完整过程见用户手册中的 JSON 解码场景。

JSON transaction 边界

transaction 会暂存一个完整 value 的测量结果,只有外围操作成功才正式发布:

use qubit_budget::json::JsonMeasurement;
use qubit_budget::json::JsonResource;
use qubit_budget::json::JsonValueLimits;

let mut budget = JsonValueLimits::<JsonResource, usize>::builder()
    .max_nodes(8)
    .max_string_bytes(16)
    .build()
    .budget();
let mut transaction = budget.transaction();
transaction.try_admit(JsonMeasurement::String {
    depth: 1,
    bytes: 5,
})?;
transaction.commit()?;
# Ok::<(), qubit_budget::MeasuredBudgetError<qubit_budget::json::JsonResource, usize>>(())

raw input 和 normalized input 仍然立即入账;transaction 只暂存 value 用量,因此应在完整 value 成功后调用 commit。value admission 被拒绝会使该 transaction 进入 poisoned 状态并禁止发布,但已经接受的 I/O 和 output 仍然保留计费。完整原子性矩阵和恢复边界请看用户手册与设计文档。

不负责什么

本 crate 不解析 JSON,不执行 I/O,不替应用选择限额,不等待资源池容量,也不定义错误后的恢复策略。JSON 解析和 Serde 集成应交给 qubit-json 等适配层。

延伸阅读

测试

# 使用默认 feature 集运行测试
cargo test

# 使用项目声明的全部 feature 运行测试
cargo test --all-features

# 运行项目 CI 检查
./ci-check.sh

# 检查代码覆盖率
./coverage.sh

许可证

Copyright (c) 2025 - 2026. Haixing Hu. All rights reserved.

本项目基于 Apache License 2.0 授权。完整许可证文本请参阅 LICENSE

贡献

欢迎贡献。请遵循 Rust API 指南,及时更新公共 API 文档与测试,并在提交 Pull Request 前运行 ./align-ci.sh格式化代码,运行./ci-check.sh对齐CI要求。

作者

Haixing Hu - Qubit Co. Ltd.

仓库地址:https://github.com/qubit-ltd/rs-budget