1use std::fmt;
4
5pub fn safe_div(a: f64, b: f64) -> Option<f64> {
7 if b == 0.0 || b.is_nan() {
8 None
9 } else {
10 let result = a / b;
11 if result.is_nan() || result.is_infinite() {
12 None
13 } else {
14 Some(result)
15 }
16 }
17}
18
19pub fn checked_add_u64(a: u64, b: u64) -> Option<u64> {
21 a.checked_add(b)
22}
23
24pub fn checked_mul_u64(a: u64, b: u64) -> Option<u64> {
26 a.checked_mul(b)
27}
28
29pub fn bound_value(value: f64, min: f64, max: f64) -> f64 {
31 if value.is_nan() {
32 (min + max) / 2.0
33 } else {
34 value.clamp(min, max)
35 }
36}
37
38pub fn sanitize_float(value: f64) -> f64 {
40 if value.is_nan() {
41 0.0
42 } else if value.is_infinite() {
43 if value > 0.0 {
44 f64::MAX
45 } else {
46 f64::MIN
47 }
48 } else {
49 value
50 }
51}
52
53pub fn test_float_edge_cases<F, T>(f: F) -> Vec<(f64, Result<T, String>)>
55where
56 F: Fn(f64) -> T,
57 T: fmt::Debug,
58{
59 let edge_cases = [
60 0.0,
61 -0.0,
62 1.0,
63 -1.0,
64 f64::MIN,
65 f64::MAX,
66 f64::MIN_POSITIVE,
67 f64::EPSILON,
68 f64::NAN,
69 f64::INFINITY,
70 f64::NEG_INFINITY,
71 1e15,
72 -1e15,
73 1e-15,
74 -1e-15,
75 ];
76
77 edge_cases
78 .iter()
79 .map(|&x| {
80 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(x)));
81 match result {
82 Ok(v) => (x, Ok(v)),
83 Err(e) => {
84 let msg = if let Some(s) = e.downcast_ref::<&str>() {
85 s.to_string()
86 } else if let Some(s) = e.downcast_ref::<String>() {
87 s.clone()
88 } else {
89 "Unknown panic".to_string()
90 };
91 (x, Err(msg))
92 }
93 }
94 })
95 .collect()
96}
97
98pub fn test_u64_edge_cases<F, T>(f: F) -> Vec<(u64, Result<T, String>)>
100where
101 F: Fn(u64) -> T,
102 T: fmt::Debug,
103{
104 let edge_cases = [
105 0u64,
106 1,
107 u64::MAX,
108 u64::MAX - 1,
109 u64::MAX / 2,
110 1000,
111 1_000_000,
112 1_000_000_000,
113 ];
114
115 edge_cases
116 .iter()
117 .map(|&x| {
118 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(x)));
119 match result {
120 Ok(v) => (x, Ok(v)),
121 Err(e) => {
122 let msg = if let Some(s) = e.downcast_ref::<&str>() {
123 s.to_string()
124 } else if let Some(s) = e.downcast_ref::<String>() {
125 s.clone()
126 } else {
127 "Unknown panic".to_string()
128 };
129 (x, Err(msg))
130 }
131 }
132 })
133 .collect()
134}