Repository navigation
Add StrictlyPositive type and deprecate non-zero (#124) - #125
Merged
Merged
Conversation
Add an always-available StrictlyPositive (> 0) type that can be used next to Positive (>= 0) regardless of features. It wraps a private Positive, delegates every operation and re-validates > 0, so the existing Positive API is untouched. - constructors, conversions, serde, approx and utoipa support - arithmetic: S+S, S+P, S*S, S/S -> S; S-S and mixed ops -> Positive; checked_* counterparts for every operator - math helpers (sqrt, exp, pow*, rounding, clamp) with checked variants - strict_pos! and strict_pos_or_panic! macros, prelude exports - crate docs: StrictlyPositive section, non-zero marked deprecated (non-additive under Cargo feature unification) Closes #124
Codecov Report❌ Patch coverage is
... and 1 file with indirect coverage changes 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
An oversized usize literal prevents the new integration test from compiling on 32-bit targets.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Adds StrictlyPositive alongside Positive, allowing strict and non-negative decimals in the same build.
Changes:
- Adds checked arithmetic, conversions, serialization, schemas, and constructor macros.
- Adds tests and a mixed-type usage example.
- Documents migration from
non-zeroand bumps the version to 0.7.1.
| File | Description |
|---|---|
| tests/utoipa_schema.rs | Tests schema generation and composition. |
| tests/strictly_positive_tests.rs | Tests strict invariants and public APIs. |
| src/strictly_positive.rs | Implements the new decimal type. |
| src/prelude.rs | Exports the type and macros. |
| src/macros.rs | Adds strict constructor macros. |
| src/lib.rs | Exports and documents the new API. |
| README.md | Explains usage and migration. |
| examples/strictly_positive.rs | Demonstrates both types together. |
| CHANGELOG.md | Records additions and deprecation. |
| Cargo.toml | Bumps version and documents feature deprecation. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
15 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
Users could not have strictly positive (> 0) and non-negative (>= 0) decimals in the same build: the only option was the
non-zerofeature, which changes whatPositivemeans crate-wide and, through Cargo feature unification, for every crate in the dependency tree (#122). This PR adds an always-availableStrictlyPositivetype next toPositive, deprecatesnon-zeroand releases it as v0.7.1.Changes
StrictlyPositivetype (src/strictly_positive.rs):#[repr(transparent)]over a privatePositive. Every operation delegates to the existingPositivemethod and re-validates> 0, soPositiveitself is untouched.new,new_decimal),FromStr,TryFrom<Positive | Decimal | &Decimal | f64 | i64 | u64 | usize>,From<StrictlyPositive>forPositive/Decimal/f64, comparisons withPositive/Decimal/f64in both directions.S+S,S+P,P+S,S*S,S/S→StrictlyPositive;S-S,S*P,P*S,S/P,P/S→Positive. Each operator has achecked_*counterpart; rounding underflow to zero (e.g.MIN * MIN) returnsErr/ panics with a clear message.sqrt,exp,powi,powu,pow,floor,ceiling,round,round_to,clamp, plusln/log10,min/max,checked_sum(empty iterator →Err, so nostd::iter::Sum).MIN(1e-28),MAX,ONE..TEN,HUNDRED,THOUSAND,PI,E.approx, and autoipaschema behind the feature.strict_pos!/strict_pos_or_panic!; type and macros in the prelude.StrictlyPositivesection with the how to use both positive and strictly positive in a crate #122 example;non-zeromarked deprecated with a migration note (also commented inCargo.toml).Design notes (deviations from the issue text): delegation instead of extracting a shared macro (no churn in the 3.5k-line
positive.rs, zero semver risk onPositive); no newPositiveErrorvariant because the enum is not#[non_exhaustive], so zero is reported asOutOfBounds { min: 1e-28 }.Public API impact
Additive only (patch/minor release 0.7.1).
cargo semver-checks check-releasereports no semver update required. The prelude gainsStrictlyPositive,strict_pos!andstrict_pos_or_panic!.Feature-flag behavior
StrictlyPositivebehaves identically underdefaultandnon-zero. Ops returningPositive(e.g.S - S) followPositive's rules for the active mode.non-zero: deprecated in docs only; behavior unchanged. Removal will be a separate breaking change.utoipa:StrictlyPositiveimplementsToSchema(string schema, likePositive).Testing
tests/strictly_positive_tests.rs,tests/utoipa_schema.rs,examples/strictly_positive.rs)default,non-zero, and--all-features(624 / 601 / 607 passed, 0 failed)-D warnings, fmt, release build,cargo doc -D warnings,make readme-check,make scan-banned)Checklist
rules/global_rules.mdPositiveinvariant preserved at every constructor / arithmetic pathpubitems have///documentation (including# Errors/# Panics/# Exampleswhere applicable).unwrap()/.expect()/ unchecked indexing insrc/outside#[cfg(test)]Decimal— nosaturating_*/wrapping_*rust_decimal::Decimalstorage only — nof64as the inner typeprintln!/eprintln!/dbg!/loginsrc/src/lib.rsupdated;README.mdregenerated viamake readmeif public surface changedCloses #124