#[derive(Clone, Copy, Debug)]
pub struct Ramp {
value: f32,
max_step: f32,
}
impl Ramp {
pub fn new(start: f32, max_step: f32) -> Self {
Self {
value: start,
max_step: magnitude(max_step),
}
}
pub fn update(&mut self, target: f32) -> f32 {
let delta = target - self.value;
if delta > self.max_step {
self.value += self.max_step;
} else if delta < -self.max_step {
self.value -= self.max_step;
} else {
self.value = target;
}
self.value
}
pub fn value(&self) -> f32 {
self.value
}
pub fn set(&mut self, value: f32) {
self.value = value;
}
}
fn magnitude(value: f32) -> f32 {
if value < 0.0 {
-value
} else {
value
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_climbs_toward_a_higher_target() {
let mut ramp = Ramp::new(0.0, 2.0);
assert_eq!(ramp.update(5.0), 2.0);
assert_eq!(ramp.update(5.0), 4.0);
assert_eq!(ramp.update(5.0), 5.0); assert_eq!(ramp.update(5.0), 5.0); }
#[test]
fn it_falls_toward_a_lower_target() {
let mut ramp = Ramp::new(10.0, 3.0);
assert_eq!(ramp.update(0.0), 7.0);
assert_eq!(ramp.update(0.0), 4.0);
assert_eq!(ramp.update(0.0), 1.0);
assert_eq!(ramp.update(0.0), 0.0);
}
#[test]
fn a_negative_step_is_treated_as_its_magnitude() {
let mut ramp = Ramp::new(0.0, -2.0);
assert_eq!(ramp.update(10.0), 2.0);
}
#[test]
fn set_jumps_past_the_limit() {
let mut ramp = Ramp::new(0.0, 1.0);
ramp.set(100.0);
assert_eq!(ramp.value(), 100.0);
}
}