use super::CreepStrategy;
pub fn creep_shift_mm(strategy: CreepStrategy, i: usize, thickness_mm: f32) -> f32 {
match strategy {
CreepStrategy::None => 0.0,
CreepStrategy::Shingle | CreepStrategy::Pushout => {
i.saturating_sub(1) as f32 * thickness_mm.max(0.0)
}
}
}
pub fn max_creep_mm(strategy: CreepStrategy, sheets: usize, thickness_mm: f32) -> f32 {
creep_shift_mm(strategy, sheets, thickness_mm)
}
#[cfg(test)]
mod tests {
use super::*;
fn approx(a: f32, b: f32) {
assert!((a - b).abs() < 1e-4, "{a} !≈ {b}");
}
#[test]
fn none_strategy_is_zero() {
approx(creep_shift_mm(CreepStrategy::None, 4, 0.1), 0.0);
}
#[test]
fn outermost_sheet_has_no_creep() {
approx(creep_shift_mm(CreepStrategy::Shingle, 1, 0.1), 0.0);
}
#[test]
fn grows_inward_proportional_to_caliper() {
approx(creep_shift_mm(CreepStrategy::Shingle, 2, 0.1), 0.1);
approx(creep_shift_mm(CreepStrategy::Shingle, 4, 0.1), 0.3);
approx(creep_shift_mm(CreepStrategy::Pushout, 4, 0.1), 0.3);
approx(creep_shift_mm(CreepStrategy::Shingle, 4, 0.2), 0.6);
}
#[test]
fn monotonic_non_decreasing_toward_the_inside() {
let mut prev = -1.0;
for i in 1..=8 {
let s = creep_shift_mm(CreepStrategy::Shingle, i, 0.12);
assert!(s >= prev, "creep must not decrease inward");
prev = s;
}
}
#[test]
fn max_is_at_the_innermost_sheet() {
approx(max_creep_mm(CreepStrategy::Shingle, 4, 0.1), 0.3);
approx(max_creep_mm(CreepStrategy::None, 4, 0.1), 0.0);
}
#[test]
fn negative_caliper_clamped() {
approx(creep_shift_mm(CreepStrategy::Shingle, 4, -1.0), 0.0);
}
}