Skip to content

Add StrictlyPositive type and deprecate non-zero (#124) - #125

Merged
joaquinbejar merged 3 commits into
mainfrom
issue-124-strictly-positive
Oct 5, 2026
Merged

joaquinbejar merged 3 commits into
mainfrom
issue-124-strictly-positive

Conversation

@joaquinbejar

Copy link
Copy Markdown
Owner

Summary

Users could not have strictly positive (> 0) and non-negative (>= 0) decimals in the same build: the only option was the non-zero feature, which changes what Positive means crate-wide and, through Cargo feature unification, for every crate in the dependency tree (#122). This PR adds an always-available StrictlyPositive type next to Positive, deprecates non-zero and releases it as v0.7.1.

Changes

  • New StrictlyPositive type (src/strictly_positive.rs): #[repr(transparent)] over a private Positive. Every operation delegates to the existing Positive method and re-validates > 0, so Positive itself is untouched.
  • Constructors (new, new_decimal), FromStr, TryFrom<Positive | Decimal | &Decimal | f64 | i64 | u64 | usize>, From<StrictlyPositive> for Positive/Decimal/f64, comparisons with Positive/Decimal/f64 in both directions.
  • Arithmetic: 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 a checked_* counterpart; rounding underflow to zero (e.g. MIN * MIN) returns Err / panics with a clear message.
  • Math helpers with checked variants: sqrt, exp, powi, powu, pow, floor, ceiling, round, round_to, clamp, plus ln/log10, min/max, checked_sum (empty iterator → Err, so no std::iter::Sum).
  • Constants: MIN (1e-28), MAX, ONE..TEN, HUNDRED, THOUSAND, PI, E.
  • Serde (exact decimal string, legacy numbers accepted, zero rejected), approx, and a utoipa schema behind the feature.
  • Macros strict_pos! / strict_pos_or_panic!; type and macros in the prelude.
  • Crate docs/README: new StrictlyPositive section with the how to use both positive and strictly positive in a crate #122 example; non-zero marked deprecated with a migration note (also commented in Cargo.toml).
  • Version bumped to 0.7.1 with CHANGELOG entry.

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 on Positive); no new PositiveError variant because the enum is not #[non_exhaustive], so zero is reported as OutOfBounds { min: 1e-28 }.

Public API impact

Additive only (patch/minor release 0.7.1). cargo semver-checks check-release reports no semver update required. The prelude gains StrictlyPositive, strict_pos! and strict_pos_or_panic!.

Feature-flag behavior

  • StrictlyPositive behaves identically under default and non-zero. Ops returning Positive (e.g. S - S) follow Positive's rules for the active mode.
  • non-zero: deprecated in docs only; behavior unchanged. Removal will be a separate breaking change.
  • utoipa: StrictlyPositive implements ToSchema (string schema, like Positive).

Testing

  • Unit tests added or updated
  • Integration tests added or updated (tests/strictly_positive_tests.rs, tests/utoipa_schema.rs, examples/strictly_positive.rs)
  • Tested under default, non-zero, and --all-features (624 / 601 / 607 passed, 0 failed)
  • Full pre-submission checklist run locally and clean (clippy -D warnings, fmt, release build, cargo doc -D warnings, make readme-check, make scan-banned)

Checklist

  • Code follows rules/global_rules.md
  • Positive invariant preserved at every constructor / arithmetic path
  • All pub items have /// documentation (including # Errors / # Panics / # Examples where applicable)
  • No .unwrap() / .expect() / unchecked indexing in src/ outside #[cfg(test)]
  • Checked arithmetic only on the inner Decimal — no saturating_* / wrapping_*
  • rust_decimal::Decimal storage only — no f64 as the inner type
  • No new dependencies added without explicit approval
  • No println! / eprintln! / dbg! / log in src/
  • Crate docs in src/lib.rs updated; README.md regenerated via make readme if public surface changed
  • Semver respected (no renames / removals / signature changes without a major version bump)

Closes #124

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
@joaquinbejar joaquinbejar added the enhancement New feature or request label Oct 5, 2026
@joaquinbejar joaquinbejar self-assigned this Oct 5, 2026
@joaquinbejar
joaquinbejar requested a balanced review from Copilot October 5, 2026 10:56
@codecov-commenter

codecov-commenter commented Oct 5, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.28326% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/strictly_positive.rs 98.28% 4 Missing ⚠️
Files with missing lines Coverage Δ
src/strictly_positive.rs 98.28% <98.28%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 High severity

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-zero and 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.

Comment thread tests/strictly_positive_tests.rs Resolved
@joaquinbejar
joaquinbejar merged commit b547fa6 into main Oct 5, 2026
18 checks passed
@joaquinbejar
joaquinbejar deleted the issue-124-strictly-positive branch October 5, 2026 11:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add StrictlyPositive type and deprecate the non-zero feature

3 participants