use crate::records::{JsonValue, ParamSpec, ParamType};
impl ParamSpec {
pub fn int_range(&self) -> Option<(i64, i64)> {
let [lower, upper] = self.range.as_deref()? else {
return None;
};
let lower = int_scalar(lower)?;
let upper = int_scalar(upper)?;
(lower <= upper).then_some((lower, upper))
}
pub fn double_range(&self) -> Option<(f64, f64)> {
let [lower, upper] = self.range.as_deref()? else {
return None;
};
let lower = double_scalar(lower)?;
let upper = double_scalar(upper)?;
(lower <= upper).then_some((lower, upper))
}
pub fn normalized(&self, value: &JsonValue) -> Option<JsonValue> {
match self.param_type {
ParamType::Int => {
let raw = int_scalar(value)?;
let clamped = match self.int_range() {
Some((lower, upper)) => raw.clamp(lower, upper),
None => raw,
};
Some(JsonValue::Int(clamped))
}
ParamType::Float => {
let raw = double_scalar(value)?;
let clamped = match self.double_range() {
Some((lower, upper)) => raw.max(lower).min(upper),
None => raw,
};
Some(JsonValue::Double(clamped))
}
ParamType::Enum => match value {
JsonValue::String(raw)
if self
.values
.as_ref()
.is_some_and(|allowed| allowed.contains(raw)) =>
{
Some(JsonValue::String(raw.clone()))
}
_ => None,
},
ParamType::Bool => match value {
JsonValue::Bool(raw) => Some(JsonValue::Bool(*raw)),
_ => None,
},
ParamType::String => match value {
JsonValue::String(raw) => Some(JsonValue::String(raw.clone())),
_ => None,
},
}
}
}
fn int_scalar(value: &JsonValue) -> Option<i64> {
match value {
JsonValue::Int(raw) => Some(*raw),
JsonValue::Double(raw) => Some(raw.round() as i64),
_ => None,
}
}
fn double_scalar(value: &JsonValue) -> Option<f64> {
match value {
JsonValue::Int(raw) => Some(*raw as f64),
JsonValue::Double(raw) => Some(*raw),
_ => None,
}
}