float_pigment_css/
length_num.rs1use az::SaturatingCast;
4use fixed::types::extra::*;
5use num_traits::{bounds::Bounded, sign::Signed, NumAssign, Zero};
6
7pub trait LengthNum:
12 NumAssign + Bounded + Signed + PartialEq + PartialOrd + Clone + Copy + core::fmt::Debug + Zero
13{
14 type Hashable: Eq + core::hash::Hash + core::fmt::Debug;
16
17 fn to_hashable(&self) -> Self::Hashable;
19
20 fn is_normal(&self) -> bool;
22
23 fn from_f32(v: f32) -> Self;
25
26 fn to_f32(self) -> f32;
28
29 fn mul_f32(self, v: f32) -> Self {
31 self * Self::from_f32(v)
32 }
33
34 fn div_f32(self, v: f32) -> Self {
36 self / Self::from_f32(v)
37 }
38
39 fn from_i32(v: i32) -> Self;
41
42 fn mul_i32(self, v: i32) -> Self {
44 self * Self::from_i32(v)
45 }
46
47 fn div_i32(self, v: i32) -> Self {
49 self / Self::from_i32(v)
50 }
51
52 fn upper_bound(self, v: Self) -> Self {
54 if self <= v {
55 self
56 } else {
57 v
58 }
59 }
60
61 fn lower_bound(self, v: Self) -> Self {
63 if self >= v {
64 self
65 } else {
66 v
67 }
68 }
69}
70
71pub fn length_sum<L: LengthNum>(iter: impl Iterator<Item = L>) -> L {
73 let mut ret = L::zero();
74 for x in iter {
75 ret += x;
76 }
77 ret
78}
79
80impl LengthNum for f32 {
81 type Hashable = u32;
82
83 fn to_hashable(&self) -> Self::Hashable {
84 if self.is_normal() {
85 self.to_bits()
86 } else {
87 f32::NEG_INFINITY.to_bits()
88 }
89 }
90
91 fn is_normal(&self) -> bool {
92 f32::is_normal(*self)
93 }
94
95 fn from_f32(v: f32) -> Self {
96 v
97 }
98
99 fn to_f32(self) -> f32 {
100 self
101 }
102
103 fn from_i32(v: i32) -> Self {
104 v as f32
105 }
106}
107
108impl LengthNum for f64 {
109 type Hashable = u64;
110
111 fn to_hashable(&self) -> Self::Hashable {
112 if self.is_normal() {
113 self.to_bits()
114 } else {
115 f64::NEG_INFINITY.to_bits()
116 }
117 }
118
119 fn is_normal(&self) -> bool {
120 f64::is_normal(*self)
121 }
122
123 fn from_f32(v: f32) -> Self {
124 v as f64
125 }
126
127 fn to_f32(self) -> f32 {
128 self as f32
129 }
130
131 fn from_i32(v: i32) -> Self {
132 v as f64
133 }
134}
135
136macro_rules! raw_impl {
137 ($base:ty) => {
138 type Hashable = Self;
139
140 fn to_hashable(&self) -> Self::Hashable {
141 *self
142 }
143
144 fn is_normal(&self) -> bool {
145 true
146 }
147 fn from_f32(v: f32) -> Self {
148 let base = Self::from_num(1).to_bits() as f32;
149 Self::from_bits((v * base) as $base)
150 }
151
152 fn to_f32(self) -> f32 {
153 self.saturating_cast()
154 }
155
156 fn from_i32(v: i32) -> Self {
157 v.saturating_cast()
158 }
159 };
160}
161
162impl<Frac> LengthNum for fixed::FixedI32<Frac>
163where
164 Frac: LeEqU32 + IsLessOrEqual<U30, Output = True>,
165{
166 raw_impl!(i32);
167}
168
169impl<Frac> LengthNum for fixed::FixedI64<Frac>
170where
171 Frac: LeEqU64 + IsLessOrEqual<U62, Output = True>,
172{
173 raw_impl!(i64);
174}