1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! Core types and error definitions for the Number type system.
use Arc;
use Decimal;
use crateFloat64;
/// A unified numeric type that provides automatic overflow handling, type
/// promotion, ergonomic primitive operations, and consistent cross-type
/// operations.
///
/// # Type Variants
///
/// **Integer Types:**
/// - `U64(u64)`, `I64(i64)` - 64-bit integers
///
/// **Float Types:**
/// - `F64(Float64)` - 64-bit IEEE 754 float (Ord + Hash)
///
/// **Decimal Type:**
/// - `Decimal(Arc<Decimal>)` - Arbitrary precision decimal (requires "decimal"
/// feature)
///
/// # Ergonomic Operations
///
/// All arithmetic and comparison operations work naturally with primitive
/// types.
///
/// ## **Important**: `&num + 1` vs `num + 1`
///
/// - **`&num + 1`** - Uses a reference, `num` remains available for reuse
/// - **`num + 1`** - Consumes (moves) `num`, making it unavailable afterward
///
/// ```rust
/// # use uninum::Number;
/// let num = Number::from(10i64);
///
/// // Using references - num remains available
/// let result1 = &num + 5; // Uses reference, num still available
/// let result2 = &num * 2; // Can reuse num again
/// let result3 = &num + # // Both are references
///
/// // num is still available here
///
/// // Using owned values - num gets consumed
/// let result4 = num + 1; // num is moved here
/// // println!("{}", num); // ❌ ERROR: num is no longer available
/// ```
///
/// ## All Operation Types
///
/// ```rust
/// # use uninum::Number;
/// let num = Number::from(10i64);
///
/// // Arithmetic operations (all work with references)
/// let add_result = &num + 5; // Number + i64
/// let mul_result = 2.5 * # // f64 * Number
/// let sub_result = &num - 3; // Number - i64
/// let div_result = &num / 2; // Number / i64
///
/// // Comparison operations
/// assert!(&num > 5); // Number > i64
/// assert!(15 > &num); // i64 > Number
/// assert!(&num == 10); // Number == i64
/// ```
///
/// # String Parsing
///
/// String parsing uses optimal type selection:
/// ```rust
/// # use uninum::Number;
/// # use std::convert::TryFrom;
/// // Positive integers parse to U64, negative to I64
/// let positive = Number::try_from("42").unwrap(); // -> U64(42)
/// let negative = Number::try_from("-42").unwrap(); // -> I64(-42)
/// let large = Number::try_from("70_000").unwrap(); // -> U64(70_000)
///
/// // Floats use highest precision (Decimal if enabled, F64 otherwise)
/// let float = Number::try_from("3.14").unwrap(); // -> Decimal(3.14) or F64(3.14)
///
/// // Type suffixes (e.g., `u64`) are rejected to avoid ambiguous parsing
/// assert!(Number::try_from("42u64").is_err());
/// ```
///
/// # Float Precision Note
///
/// Floating-point values are stored as `Float64`, so equality compares the
/// underlying `f64` bits exactly:
/// ```rust
/// # use uninum::Number;
/// let a = Number::from(3.141592653589793_f64);
/// let b = Number::from(3.1415926535897926_f64);
/// assert!(a != b);
/// ```
/// Use `approx_eq()` for precision-tolerant comparisons when a small epsilon is
/// acceptable.