From 277dd54cc53977e1476eaf7517e004c7719784eb Mon Sep 17 00:00:00 2001 From: dualfroz Date: Fri, 4 Sep 2026 09:45:03 +0200 Subject: [PATCH] fix: avoid no_std panic in ceil helpers on non-finite input Byte::from_f64/from_f32 let +inf past the size >= 0.0 guard and then called the no_std ceil helpers, which used Decimal::from_f64(v).unwrap(). Decimal conversion returns None for non-finite values, so this panicked in no_std builds while std returned None. Fall back to the input value for non-finite input so no_std matches std and the documented None contract is upheld. --- src/common.rs | 14 ++++++++++++-- tests/byte.rs | 9 +++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/common.rs b/src/common.rs index ee94712..1987356 100644 --- a/src/common.rs +++ b/src/common.rs @@ -36,7 +36,12 @@ pub(crate) fn ceil_f64(v: f64) -> f64 { pub(crate) fn ceil_f64(v: f64) -> f64 { debug_assert!(v >= 0.0); - Decimal::from_f64(v).unwrap().ceil().to_f64().unwrap() + // `Decimal::from_f64` returns `None` for non-finite values, so fall back to + // the input and mirror `f64::ceil` instead of panicking. + match Decimal::from_f64(v) { + Some(d) => d.ceil().to_f64().unwrap_or(v), + None => v, + } } #[cfg(any(feature = "byte", feature = "bit"))] @@ -54,7 +59,12 @@ pub(crate) fn ceil_f32(v: f32) -> f32 { pub(crate) fn ceil_f32(v: f32) -> f32 { debug_assert!(v >= 0.0); - Decimal::from_f32(v).unwrap().ceil().to_f32().unwrap() + // `Decimal::from_f32` returns `None` for non-finite values, so fall back to + // the input and mirror `f32::ceil` instead of panicking. + match Decimal::from_f32(v) { + Some(d) => d.ceil().to_f32().unwrap_or(v), + None => v, + } } #[cfg(any(feature = "byte", feature = "bit"))] diff --git a/tests/byte.rs b/tests/byte.rs index 8687ce1..d0502c9 100644 --- a/tests/byte.rs +++ b/tests/byte.rs @@ -170,3 +170,12 @@ fn tests() { assert_eq!(byte, serde_json::from_str::(case.0).unwrap(), "{i}"); } } + +#[test] +fn from_non_finite_returns_none() { + // Non-finite inputs must return None instead of panicking, in both builds. + assert_eq!(Byte::from_f64(f64::INFINITY), None); + assert_eq!(Byte::from_f64(f64::NAN), None); + assert_eq!(Byte::from_f32(f32::INFINITY), None); + assert_eq!(Byte::from_f32(f32::NAN), None); +}