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.
Author
Joaquín Béjar García jb@taunais.com
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