1pub use logicaffeine_base::numeric::cmp_i64_f64_exact as logos_cmp_i64_f64;
10
11#[inline]
13pub fn logos_i64_eq_f64(i: i64, f: f64) -> bool {
14 logos_cmp_i64_f64(i, f) == Some(core::cmp::Ordering::Equal)
15}
16
17#[inline]
24pub fn logos_approx_eq(a: f64, b: f64) -> bool {
25 if a == b {
26 return true;
27 }
28 let diff = (a - b).abs();
29 diff <= f64::max(1e-9 * f64::max(a.abs(), b.abs()), 1e-12)
30}
31
32pub trait Truthy {
37 fn truthy(&self) -> bool;
38}
39
40impl Truthy for bool {
41 #[inline]
42 fn truthy(&self) -> bool {
43 *self
44 }
45}
46
47impl Truthy for i64 {
48 #[inline]
49 fn truthy(&self) -> bool {
50 *self != 0
51 }
52}
53
54impl Truthy for f64 {
55 #[inline]
56 fn truthy(&self) -> bool {
57 *self != 0.0
58 }
59}
60
61impl Truthy for char {
62 #[inline]
63 fn truthy(&self) -> bool {
64 true
65 }
66}
67
68impl Truthy for String {
69 #[inline]
70 fn truthy(&self) -> bool {
71 !self.is_empty()
72 }
73}
74
75impl Truthy for &str {
76 #[inline]
77 fn truthy(&self) -> bool {
78 !self.is_empty()
79 }
80}
81
82impl<T> Truthy for crate::types::LogosSeq<T> {
83 #[inline]
84 fn truthy(&self) -> bool {
85 !self.is_empty()
86 }
87}
88
89impl<K: Eq + core::hash::Hash, V> Truthy for crate::types::LogosMap<K, V> {
90 #[inline]
91 fn truthy(&self) -> bool {
92 !self.is_empty()
93 }
94}
95
96impl<T> Truthy for crate::types::FxIndexSet<T> {
97 #[inline]
98 fn truthy(&self) -> bool {
99 !self.is_empty()
100 }
101}
102
103impl<T: Truthy> Truthy for Option<T> {
106 #[inline]
107 fn truthy(&self) -> bool {
108 match self {
109 Some(v) => v.truthy(),
110 None => false,
111 }
112 }
113}
114
115impl Truthy for crate::types::LogosRational {
116 #[inline]
117 fn truthy(&self) -> bool {
118 !self.0.is_zero()
119 }
120}
121
122impl Truthy for crate::types::LogosDecimal {
123 #[inline]
124 fn truthy(&self) -> bool {
125 !self.0.is_zero()
126 }
127}
128
129impl Truthy for crate::types::LogosComplex {
130 #[inline]
131 fn truthy(&self) -> bool {
132 !self.0.is_zero()
133 }
134}
135
136#[inline]
138pub fn logos_truthy<T: Truthy>(v: &T) -> bool {
139 v.truthy()
140}
141
142#[inline(always)]
148pub fn logos_add_exact(a: impl Into<crate::types::LogosInt>, b: impl Into<crate::types::LogosInt>) -> crate::types::LogosInt {
149 a.into().add(&b.into())
150}
151
152#[inline(always)]
153pub fn logos_sub_exact(a: impl Into<crate::types::LogosInt>, b: impl Into<crate::types::LogosInt>) -> crate::types::LogosInt {
154 a.into().sub(&b.into())
155}
156
157#[inline(always)]
158pub fn logos_mul_exact(a: impl Into<crate::types::LogosInt>, b: impl Into<crate::types::LogosInt>) -> crate::types::LogosInt {
159 a.into().mul(&b.into())
160}
161
162#[inline(always)]
165pub fn logos_div_exact(a: impl Into<crate::types::LogosInt>, b: impl Into<crate::types::LogosInt>) -> crate::types::LogosInt {
166 match a.into().div(&b.into()) {
167 Ok(v) => v,
168 Err(e) => panic!("{e}"),
169 }
170}
171
172#[inline(always)]
176pub fn logos_floordiv_exact(a: impl Into<crate::types::LogosInt>, b: impl Into<crate::types::LogosInt>) -> crate::types::LogosInt {
177 match a.into().div_floor(&b.into()) {
178 Ok(v) => v,
179 Err(e) => panic!("{e}"),
180 }
181}
182
183#[inline(always)]
191pub fn logos_add_i64(a: i64, b: i64) -> i64 {
192 match a.checked_add(b) {
193 Some(v) => v,
194 None => narrowed_overflow(logos_add_exact(a, b)),
195 }
196}
197
198#[inline(always)]
199pub fn logos_sub_i64(a: i64, b: i64) -> i64 {
200 match a.checked_sub(b) {
201 Some(v) => v,
202 None => narrowed_overflow(logos_sub_exact(a, b)),
203 }
204}
205
206#[inline(always)]
207pub fn logos_mul_i64(a: i64, b: i64) -> i64 {
208 match a.checked_mul(b) {
209 Some(v) => v,
210 None => narrowed_overflow(logos_mul_exact(a, b)),
211 }
212}
213
214#[inline(always)]
218pub fn logos_div_i64(a: i64, b: i64) -> i64 {
219 match a.checked_div(b) {
220 Some(v) => v,
221 None => logos_div_exact(a, b).expect_i64("Int"),
222 }
223}
224
225#[inline(always)]
229pub fn logos_rem_i64(a: i64, b: i64) -> i64 {
230 match a.checked_rem(b) {
231 Some(v) => v,
232 None => logos_rem_exact(a, b).expect_i64("Int"),
233 }
234}
235
236#[cold]
237#[inline(never)]
238fn narrowed_overflow(v: crate::types::LogosInt) -> ! {
239 panic!("Integer overflow: {v} does not fit a 64-bit Int")
240}
241
242#[inline(always)]
248pub fn logos_narrow_i128(v: i128) -> i64 {
249 match i64::try_from(v) {
250 Ok(x) => x,
251 Err(_) => narrowed_overflow_i128(v),
252 }
253}
254
255#[cold]
256#[inline(never)]
257fn narrowed_overflow_i128(v: i128) -> ! {
258 panic!("Integer overflow: {v} does not fit a 64-bit Int")
259}
260
261#[inline(always)]
265pub fn logos_div_i128(a: i128, b: i128) -> i128 {
266 if b == 0 {
267 panic!("Division by zero");
268 }
269 a / b
270}
271
272#[inline(always)]
275pub fn logos_rem_i128(a: i128, b: i128) -> i128 {
276 if b == 0 {
277 panic!("Modulo by zero");
278 }
279 a % b
280}
281
282#[inline(always)]
285pub fn logos_rem_exact(a: impl Into<crate::types::LogosInt>, b: impl Into<crate::types::LogosInt>) -> crate::types::LogosInt {
286 match a.into().rem(&b.into()) {
287 Ok(v) => v,
288 Err(e) => panic!("{e}"),
289 }
290}
291
292#[inline(always)]
296pub fn logos_pow_exact(a: impl Into<crate::types::LogosInt>, b: impl Into<crate::types::LogosInt>) -> crate::types::LogosInt {
297 match a.into().pow(&b.into()) {
298 Ok(v) => v,
299 Err(e) => panic!("{e}"),
300 }
301}
302
303#[inline(always)]
308pub fn logos_i64_key_of_f64(f: f64) -> Option<i64> {
309 if f.fract() == 0.0 && f >= i64::MIN as f64 && f <= i64::MAX as f64 {
310 Some(f as i64)
311 } else {
312 None
313 }
314}