boa_engine/value/
integer.rs1use num_traits::{AsPrimitive, FromPrimitive};
2use std::cmp::Ordering;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
6pub enum IntegerOrInfinity {
7 PositiveInfinity,
9
10 Integer(i64),
12
13 NegativeInfinity,
15}
16
17impl IntegerOrInfinity {
18 #[must_use]
25 pub fn clamp_finite<I: Ord + AsPrimitive<i64> + FromPrimitive>(self, min: I, max: I) -> I {
26 assert!(min <= max);
27 match self {
28 Self::Integer(i) => {
29 I::from_i64(i.clamp(min.as_(), max.as_())).expect("`i` should already be clamped")
30 }
31 Self::PositiveInfinity => max,
32 Self::NegativeInfinity => min,
33 }
34 }
35
36 #[must_use]
38 pub const fn as_integer(self) -> Option<i64> {
39 match self {
40 Self::Integer(i) => Some(i),
41 _ => None,
42 }
43 }
44}
45
46impl From<f64> for IntegerOrInfinity {
47 fn from(number: f64) -> Self {
48 if number.is_nan() || number == 0.0 {
50 Self::Integer(0)
52 } else if number == f64::INFINITY {
53 Self::PositiveInfinity
55 } else if number == f64::NEG_INFINITY {
56 Self::NegativeInfinity
58 } else {
59 let integer = number.abs().floor().copysign(number) as i64;
62
63 Self::Integer(integer)
65 }
66 }
67}
68
69impl PartialEq<i64> for IntegerOrInfinity {
70 fn eq(&self, other: &i64) -> bool {
71 match self {
72 Self::Integer(i) => i == other,
73 _ => false,
74 }
75 }
76}
77
78impl PartialEq<IntegerOrInfinity> for i64 {
79 fn eq(&self, other: &IntegerOrInfinity) -> bool {
80 other.eq(self)
81 }
82}
83
84impl PartialOrd<i64> for IntegerOrInfinity {
85 fn partial_cmp(&self, other: &i64) -> Option<Ordering> {
86 match self {
87 Self::PositiveInfinity => Some(Ordering::Greater),
88 Self::Integer(i) => i.partial_cmp(other),
89 Self::NegativeInfinity => Some(Ordering::Less),
90 }
91 }
92}
93
94impl PartialOrd<IntegerOrInfinity> for i64 {
95 fn partial_cmp(&self, other: &IntegerOrInfinity) -> Option<Ordering> {
96 other.partial_cmp(self).map(Ordering::reverse)
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn test_eq() {
106 let int: i64 = 42;
107 let int_or_inf = IntegerOrInfinity::Integer(10);
108 assert!(int != int_or_inf);
109 assert!(int_or_inf != int);
110
111 let int: i64 = 10;
112 assert!(int == int_or_inf);
113 assert!(int_or_inf == int);
114 }
115
116 #[test]
117 fn test_ord() {
118 let int: i64 = 42;
119
120 let int_or_inf = IntegerOrInfinity::Integer(10);
121 assert!(int_or_inf < int);
122 assert!(int > int_or_inf);
123
124 let int_or_inf = IntegerOrInfinity::Integer(100);
125 assert!(int_or_inf > int);
126 assert!(int < int_or_inf);
127
128 let int_or_inf = IntegerOrInfinity::PositiveInfinity;
129 assert!(int_or_inf > int);
130 assert!(int < int_or_inf);
131
132 let int_or_inf = IntegerOrInfinity::NegativeInfinity;
133 assert!(int_or_inf < int);
134 assert!(int > int_or_inf);
135 }
136}