1use std::ops::Range;
2
3use num_traits::{float::FloatCore, Bounded, Num};
4pub trait NumPercent<N>
5{
6 fn percent_in<U: Num + From<N> + Clone>(self, range: Range<U>) -> U;
9 fn try_percent_in<U: Num + TryFrom<N> + Clone>(
12 self, range: Range<U>,
13 ) -> Result<U, U::Error>;
14}
15pub trait NumLerp<N: FloatCore>
16{
17 fn lerp_in(self, range: Range<N>) -> N;
18 fn lerp(range: Range<N>, alpha: N) -> N;
19}
20pub trait NumRemap<N>
21{
22 fn remap<U: FloatCore + NumLerp<U> + From<N>>(
23 self, from: Range<U>, to: Range<U>,
24 ) -> U;
25 fn try_remap<U: FloatCore + NumLerp<U> + TryFrom<N>>(
26 self, from: Range<U>, to: Range<U>,
27 ) -> Result<U, U::Error>;
28 fn remap01<U: FloatCore + NumLerp<U> + From<N>>(self) -> U
29 where
30 N: Bounded,
31 Self: Sized,
32 {
33 self
34 .remap(N::min_value().into()..N::max_value().into(), U::zero()..U::one())
35 }
36 fn try_remap01<U: FloatCore + NumLerp<U> + TryFrom<N>>(
37 self,
38 ) -> Result<U, U::Error>
39 where
40 N: Bounded,
41 Self: Sized,
42 {
43 Ok(self.try_remap(
44 N::min_value().try_into()?..N::max_value().try_into()?,
45 U::zero()..U::one(),
46 ))?
47 }
48}
49pub trait NumsRemap<N, const L: usize>
50{
51 fn remap<U: FloatCore + NumRemap<U> + From<N>>(
52 self, from: Range<U>, to: Range<U>,
53 ) -> [U; L];
54 fn try_remap<U: FloatCore + NumRemap<U> + TryFrom<N>>(
55 self, from: Range<U>, to: Range<U>,
56 ) -> Result<[U; L], U::Error>;
57 fn remap01<U: FloatCore + NumLerp<U> + From<N>>(self) -> [U; L]
58 where
59 N: Bounded,
60 Self: Sized,
61 {
62 self
63 .remap(N::min_value().into()..N::max_value().into(), U::zero()..U::one())
64 }
65 fn try_remap01<U: FloatCore + NumLerp<U> + TryFrom<N>>(
66 self,
67 ) -> Result<[U; L], U::Error>
68 where
69 N: Bounded,
70 Self: Sized,
71 {
72 Ok(self.try_remap(
73 N::min_value().try_into()?..N::max_value().try_into()?,
74 U::zero()..U::one(),
75 ))?
76 }
77}
78impl<N: Num> NumPercent<N> for N
79{
80 fn percent_in<U: Num + From<N> + Clone>(self, range: Range<U>) -> U
81 {
82 (<U as From<N>>::from(self) - range.start.clone())
83 / (range.end - range.start)
84 }
85
86 fn try_percent_in<U: Num + TryFrom<N> + Clone>(
87 self, range: Range<U>,
88 ) -> Result<U, U::Error>
89 {
90 Ok(
91 (<U as TryFrom<N>>::try_from(self)? - range.start.clone())
92 / (range.end - range.start),
93 )
94 }
95}
96impl<N: FloatCore> NumLerp<N> for N
97{
98 fn lerp_in(self, range: Range<N>) -> N
99 {
100 Self::lerp(range, self)
101 }
102
103 fn lerp(range: Range<N>, alpha: N) -> N
104 {
105 ((N::one() - alpha) * range.start) + (alpha * range.end)
106 }
107}
108impl<N: Num + NumPercent<N>> NumRemap<N> for N
109{
110 fn remap<U: FloatCore + NumLerp<U> + From<N>>(
111 self, from: Range<U>, to: Range<U>,
112 ) -> U
113 {
114 if from.start == from.end
115 {
116 to.start
117 }
118 else
119 {
120 let percent = self.percent_in::<U>(from);
121 percent.lerp_in(to)
122 }
123 }
124
125 fn try_remap<U: FloatCore + NumLerp<U> + TryFrom<N>>(
126 self, from: Range<U>, to: Range<U>,
127 ) -> Result<U, U::Error>
128 {
129 Ok(
130 if from.start == from.end
131 {
132 to.start
133 }
134 else
135 {
136 let percent = self.try_percent_in::<U>(from)?;
137 percent.lerp_in(to)
138 },
139 )
140 }
141}
142impl<N: Num, const L: usize> NumsRemap<N, L> for [N; L]
143{
144 fn remap<U: FloatCore + NumRemap<U> + From<N>>(
145 self, from: Range<U>, to: Range<U>,
146 ) -> [U; L]
147 {
148 let mut arr: [std::mem::MaybeUninit<U>; L] =
149 unsafe { std::mem::MaybeUninit::uninit().assume_init() };
150 for (elem, n) in arr.iter_mut().zip(self.into_iter())
151 {
152 *elem = std::mem::MaybeUninit::new(
153 <U as From<N>>::from(n).remap(from.clone(), to.clone()),
154 );
155 }
156 unsafe { std::mem::transmute_copy::<_, [U; L]>(&arr) }
157 }
158
159 fn try_remap<U: FloatCore + NumRemap<U> + TryFrom<N>>(
160 self, from: Range<U>, to: Range<U>,
161 ) -> Result<[U; L], U::Error>
162 {
163 let mut arr: [std::mem::MaybeUninit<U>; L] =
164 unsafe { std::mem::MaybeUninit::uninit().assume_init() };
165 for (elem, n) in arr.iter_mut().zip(self.into_iter())
166 {
167 *elem = std::mem::MaybeUninit::new(
168 <U as TryFrom<N>>::try_from(n)?.remap(from.clone(), to.clone()),
169 );
170 }
171 Ok(unsafe { std::mem::transmute_copy::<_, [U; L]>(&arr) })
172 }
173}