Positive
A type-safe wrapper for guaranteed positive decimal values in Rust.
Overview
Positive is a Rust library that provides a type-safe wrapper around Decimal values,
ensuring that the contained value is always non-negative (>= 0). This is particularly
useful in financial applications where negative values would be invalid or meaningless,
such as prices, quantities, volatilities, and other strictly positive metrics.
Features
- Type Safety: Compile-time and runtime guarantees that values are non-negative
- Decimal Precision: Built on
rust_decimalfor accurate financial calculations - Rich API: Comprehensive arithmetic operations, conversions, and mathematical utilities
- Serde Support: Full serialization/deserialization support for JSON and other formats
- Approx Support: Approximate equality comparisons for floating-point tolerance
- Checked Operations: Safe arithmetic operations that return
Resultinstead of panicking - Optional utoipa Integration: OpenAPI schema generation support via feature flag
Installation
Add this to your Cargo.toml:
[]
= "0.1"
To enable OpenAPI schema support:
[]
= { = "0.1", = ["utoipa"] }
Quick Start
use ;
// Create a positive value using the macro (returns Result)
let price = pos!.unwrap;
// Or use pos_or_panic! for direct value (panics on invalid input)
let price = pos_or_panic!;
// Create using the constructor
let quantity = new.unwrap;
// Arithmetic operations
let total = price * quantity;
// Safe operations that return Result
let discount = pos_or_panic!;
let final_price = price.checked_sub.unwrap;
// Saturating subtraction (returns ZERO instead of negative)
let result = pos_or_panic!.saturating_sub;
assert_eq!;
API Overview
Creation
use ;
use Decimal;
// From f64
let p = new.unwrap;
// From Decimal
let p = new_decimal.unwrap;
// Using macros
let p = pos!; // Returns Result<Positive, PositiveError>
let p = pos_or_panic!; // Panics on invalid input
let p = spos!; // Returns Option<Positive>
Constants
use Positive;
let zero = ZERO; // 0
let one = ONE; // 1
let two = TWO; // 2
let ten = TEN; // 10
let hundred = HUNDRED; // 100
let thousand = THOUSAND; // 1000
let pi = PI; // π
let inf = INFINITY; // Maximum value
Conversions
use pos_or_panic;
let p = pos_or_panic!;
let f: f64 = p.to_f64; // Panics on failure
let f: = p.to_f64_checked; // Returns None on failure
let f: f64 = p.to_f64_lossy; // Returns 0.0 on failure
let i: i64 = p.to_i64; // To signed integer
let u: u64 = p.to_u64; // To unsigned integer
let d = p.to_dec; // To Decimal
Arithmetic Operations
use pos_or_panic;
let a = pos_or_panic!;
let b = pos_or_panic!;
// Standard operations
let sum = a + b; // Addition
let diff = a - b; // Subtraction (panics if result < 0)
let prod = a * b; // Multiplication
let quot = a / b; // Division
// Safe operations
let safe_diff = a.checked_sub; // Returns Result
let sat_diff = a.saturating_sub; // Returns ZERO if result < 0
let safe_quot = a.checked_div; // Returns Result (handles div by zero)
Mathematical Functions
use pos_or_panic;
let p = pos_or_panic!;
let sqrt = p.sqrt; // Square root
let ln = p.ln; // Natural logarithm
let log10 = p.log10; // Base-10 logarithm
let exp = p.exp; // Exponential (e^x)
let pow = p.pow; // Power with Positive exponent
let powi = p.powi; // Integer power
let floor = p.floor; // Floor
let ceil = p.ceiling; // Ceiling
let round = p.round; // Round to nearest integer
let round2 = p.round_to; // Round to 2 decimal places
Utility Methods
use pos_or_panic;
let p = pos_or_panic!;
let is_zero = p.is_zero; // Check if zero
let is_mult = p.is_multiple; // Check if multiple of value
let clamped = p.clamp; // Clamp between bounds
let min_val = p.min; // Minimum of two values
let max_val = p.max; // Maximum of two values
let formatted = p.format_fixed_places; // Format with fixed decimals
Error Handling
The library provides PositiveError for comprehensive error handling:
use ;
Error variants include:
InvalidValue- Value cannot be represented as a valid positive decimalArithmeticError- Error during mathematical operationsConversionError- Error when converting between typesOutOfBounds- Value exceeds defined limitsInvalidPrecision- Invalid decimal precision settings
Serialization
Positive implements Serialize and Deserialize:
use pos_or_panic;
let p = pos_or_panic!;
let json = to_string.unwrap; // "42.5"
let parsed: Positive = from_str.unwrap;
Use Cases
- Financial Applications: Prices, quantities, fees, rates
- Scientific Computing: Physical quantities that cannot be negative
- Game Development: Health points, distances, timers
- Data Validation: Ensuring input values meet positivity constraints
License
This project is licensed under the MIT License.
Contribution and Contact
We welcome contributions to this project! If you would like to contribute, please follow these steps:
- Fork the repository.
- Create a new branch for your feature or bug fix.
- Make your changes and ensure that the project still builds and all tests pass.
- Commit your changes and push your branch to your forked repository.
- Submit a pull request to the main repository.
If you have any questions, issues, or would like to provide feedback, please feel free to contact the project maintainer:
Contact Information
- Author: Joaquín Béjar García
- Email: jb@taunais.com
- Telegram: @joaquin_bejar
- Repository: https://github.com/joaquinbejar/positive
- Documentation: https://docs.rs/positive
We appreciate your interest and look forward to your contributions!
✍️ License
Licensed under MIT license