retrofire_core/math/
vary.rs1use core::mem;
7
8use super::Lerp;
9
10pub trait ZDiv: Sized {
11 #[must_use]
12 fn z_div(self, _z: f32) -> Self {
13 self
14 }
15}
16
17pub trait Vary: Lerp + ZDiv + Sized + Clone {
24 type Iter: Iterator<Item = Self>;
26 type Diff: Clone;
28
29 fn vary(self, step: Self::Diff, max: Option<u32>) -> Self::Iter;
48
49 #[inline]
66 fn vary_to(self, other: Self, n: u32) -> Self::Iter {
67 let recip_dt = if n <= 1 {
68 1.0
70 } else {
71 1.0 / (n - 1) as f32
73 };
74 let step = self.dv_dt(&other, recip_dt); self.vary(step, Some(n))
76 }
77
78 fn dv_dt(&self, other: &Self, recip_dt: f32) -> Self::Diff;
80
81 #[must_use]
84 fn step(&self, delta: &Self::Diff) -> Self;
85}
86
87#[derive(Copy, Clone, Debug)]
88pub struct Iter<T: Vary> {
89 pub val: T,
90 pub step: T::Diff,
91 pub n: Option<u32>,
92}
93
94impl Vary for () {
95 type Iter = Iter<()>;
96 type Diff = ();
97
98 fn vary(self, _: Self::Diff, n: Option<u32>) -> Self::Iter {
99 Iter { val: (), step: (), n }
100 }
101 fn dv_dt(&self, _: &Self, _: f32) {}
102 fn step(&self, _: &Self::Diff) {}
103}
104impl ZDiv for () {}
105
106impl<T: Vary, U: Vary> Vary for (T, U) {
107 type Iter = Iter<Self>;
108 type Diff = (T::Diff, U::Diff);
109
110 fn vary(self, step: Self::Diff, n: Option<u32>) -> Self::Iter {
111 Iter { val: self, step, n }
112 }
113 fn dv_dt(&self, other: &Self, recip_dt: f32) -> Self::Diff {
114 (
115 self.0.dv_dt(&other.0, recip_dt),
116 self.1.dv_dt(&other.1, recip_dt),
117 )
118 }
119 fn step(&self, (d0, d1): &Self::Diff) -> Self {
120 (self.0.step(d0), self.1.step(d1))
121 }
122}
123impl<T: ZDiv, U: ZDiv> ZDiv for (T, U) {
124 fn z_div(self, z: f32) -> Self {
125 (self.0.z_div(z), self.1.z_div(z))
126 }
127}
128
129impl ZDiv for f32 {
130 fn z_div(self, z: f32) -> Self {
131 self / z
132 }
133}
134
135impl<T: Vary> Iterator for Iter<T> {
136 type Item = T;
137
138 #[inline]
139 fn next(&mut self) -> Option<T> {
140 match &mut self.n {
141 Some(0) => return None,
142 Some(n) => *n -= 1,
143 None => (),
144 }
145 let new = self.val.step(&self.step);
146 Some(mem::replace(&mut self.val, new))
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use crate::assert_approx_eq;
153
154 use super::*;
155
156 #[test]
157 fn vary_f32() {
158 use alloc::vec::Vec;
159 let varying = (-6.0f32).vary(1.2, Some(10));
160 assert_approx_eq!(
161 varying.collect::<Vec<_>>()[..],
162 [-6.0, -4.8, -3.6, -2.4, -1.2, 0.0, 1.2, 2.4, 3.6, 4.8]
163 );
164 }
165
166 #[test]
167 fn vary_to_zero() {
168 assert_eq!(1.0.vary_to(2.0, 0).next(), None);
169 }
170
171 #[test]
172 fn vary_to_one() {
173 let mut v = 1.0.vary_to(2.0, 1);
174 assert_eq!(v.next(), Some(1.0));
175 assert_eq!(v.next(), None);
176 }
177
178 #[test]
179 fn vary_to_two() {
180 let mut v = 1.0.vary_to(2.0, 2);
181 assert_eq!(v.next(), Some(1.0));
182 assert_eq!(v.next(), Some(2.0));
183 assert_eq!(v.next(), None);
184 }
185}