use crate::error::{OptimError, Result};
use scirs2_core::numeric::{Float, NumCast};
pub(crate) fn count_as<T: Float>(count: usize, context: &str) -> Result<T> {
NumCast::from(count as f64).ok_or_else(|| {
OptimError::InvalidParameter(format!(
"cannot represent {} ({}) in the optimizer's element type",
context, count
))
})
}
pub(crate) fn scalar_as<T: Float>(value: f64, context: &str) -> Result<T> {
NumCast::from(value).ok_or_else(|| {
OptimError::InvalidParameter(format!(
"cannot represent {} ({}) in the optimizer's element type",
context, value
))
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn counts_and_scalars_convert() {
assert_eq!(
count_as::<f64>(7, "sample count").expect("convertible"),
7.0
);
assert_eq!(
count_as::<f32>(7, "sample count").expect("convertible"),
7.0
);
assert_eq!(
scalar_as::<f64>(1.96, "z score").expect("convertible"),
1.96
);
}
#[test]
fn the_built_in_floats_saturate_rather_than_failing() {
assert!(scalar_as::<f32>(f64::MAX, "huge")
.expect("f64::MAX saturates to f32::INFINITY")
.is_infinite());
assert!(scalar_as::<f32>(f64::NAN, "nan")
.expect("NaN is representable")
.is_nan());
assert!(scalar_as::<f32>(f64::INFINITY, "inf")
.expect("infinity is representable")
.is_infinite());
assert!(count_as::<f32>(usize::MAX, "max count")
.expect("usize::MAX is far inside f32's range")
.is_finite());
}
#[test]
fn a_failed_conversion_names_its_context() {
let message = OptimError::InvalidParameter(format!(
"cannot represent {} ({}) in the optimizer's element type",
"sample count", 3
))
.to_string();
assert!(message.contains("sample count"));
assert!(message.contains("Invalid parameter"));
}
}