use crate::core::{
ProjectionContext, ProjectionIssue, YfError, diagnostics::optional_projected, wire::RawNum,
};
pub fn optional_u32_from_i64(
ctx: &mut ProjectionContext,
path: &'static str,
key: Option<&str>,
field: &'static str,
value: Option<i64>,
) -> Result<Option<u32>, YfError> {
optional_projected(ctx, path, key, value, |value| {
u32::try_from(value).map_err(|_| invalid_u32_count(field, value))
})
}
pub fn optional_u32_from_raw_f64(
ctx: &mut ProjectionContext,
path: &'static str,
key: Option<&str>,
field: &'static str,
value: Option<RawNum<f64>>,
) -> Result<Option<u32>, YfError> {
let Some(value) = value.and_then(|value| value.raw) else {
return Ok(None);
};
if !value.is_finite() || value < 0.0 || value > f64::from(u32::MAX) {
ctx.omitted_present_field(path, key, invalid_u32_count(field, value))?;
return Ok(None);
}
let rounded = value.round();
if value.fract() != 0.0 {
ctx.coerced_present_field(
path,
key,
format!("rounded non-integer count {value} to {rounded}"),
)?;
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
Ok(Some(rounded as u32))
}
fn invalid_u32_count(field: &'static str, value: impl std::fmt::Display) -> ProjectionIssue {
ProjectionIssue::InvalidField {
field,
details: format!(
"expected finite integer count in 0..={}, got {value}",
u32::MAX
),
}
}