Skip to content

Commit 50969b2

Browse files
Artem Novikovaskalt
authored andcommitted
feat(Datum): allow to cast from Double to Float
1 parent 53988e3 commit 50969b2

2 files changed

Lines changed: 51 additions & 0 deletions

File tree

crates/iceberg/src/spec/values/datum.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ pub(crate) const INT_MAX: i32 = 2147483647;
4848
pub(crate) const INT_MIN: i32 = -2147483648;
4949
pub(crate) const LONG_MAX: i64 = 9223372036854775807;
5050
pub(crate) const LONG_MIN: i64 = -9223372036854775808;
51+
pub(crate) const FLOAT_MAX: f32 = 3.4028235e38;
52+
pub(crate) const FLOAT_MIN: f32 = -3.4028235e38;
5153

5254
/// Literal associated with its type. The value and type pair is checked when construction, so the type and value is
5355
/// guaranteed to be correct when used.
@@ -1109,6 +1111,16 @@ impl Datum {
11091111
})
11101112
}
11111113

1114+
fn double_to_float<T: Into<f64> + PartialOrd<f64>>(val: T) -> Datum {
1115+
if val > FLOAT_MAX as f64 {
1116+
Datum::new(PrimitiveType::Float, PrimitiveLiteral::AboveMax)
1117+
} else if val < FLOAT_MIN as f64 {
1118+
Datum::new(PrimitiveType::Float, PrimitiveLiteral::BelowMin)
1119+
} else {
1120+
Datum::float(val.into() as f32)
1121+
}
1122+
}
1123+
11121124
/// Convert the datum to `target_type`.
11131125
pub fn to(self, target_type: &Type) -> Result<Datum> {
11141126
match target_type {
@@ -1146,6 +1158,9 @@ impl Datum {
11461158
(PrimitiveLiteral::String(val), _, PrimitiveType::Timestamptz) => {
11471159
Datum::timestamptz_from_str(val)
11481160
}
1161+
(PrimitiveLiteral::Double(val), _, PrimitiveType::Float) => {
1162+
Ok(Datum::double_to_float(**val))
1163+
}
11491164

11501165
// TODO: implement more type conversions
11511166
(_, self_type, target_type) if self_type == target_type => Ok(self),

crates/iceberg/src/spec/values/tests.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,3 +1352,39 @@ fn test_date_from_json_as_number() {
13521352

13531353
// Both formats should produce the same Literal value
13541354
}
1355+
1356+
#[test]
1357+
fn test_iceberg_double_convert_to_float() {
1358+
let float_below_min = Datum::new(PrimitiveType::Float, PrimitiveLiteral::BelowMin);
1359+
let float_above_max = Datum::new(PrimitiveType::Float, PrimitiveLiteral::AboveMax);
1360+
1361+
let test_data = [
1362+
(Datum::double(-f64::NAN), Datum::float(-f32::NAN)),
1363+
(Datum::double(-f64::INFINITY), float_below_min.clone()),
1364+
(Datum::double(f64::MIN), float_below_min),
1365+
(Datum::double(f32::MIN as f64), Datum::float(f32::MIN)),
1366+
(Datum::double(-1.0), Datum::float(-1.0)),
1367+
(Datum::double(-f64::MIN_POSITIVE), Datum::float(-0.0)),
1368+
(
1369+
Datum::double(-f32::MIN_POSITIVE as f64),
1370+
Datum::float(-f32::MIN_POSITIVE),
1371+
),
1372+
(Datum::double(-0.0), Datum::float(-0.0)),
1373+
(Datum::double(0.0), Datum::float(0.0)),
1374+
(Datum::double(f64::MIN_POSITIVE), Datum::float(0.0)),
1375+
(
1376+
Datum::double(f32::MIN_POSITIVE as f64),
1377+
Datum::float(f32::MIN_POSITIVE),
1378+
),
1379+
(Datum::double(1.0), Datum::float(1.0)),
1380+
(Datum::double(f32::MAX as f64), Datum::float(f32::MAX)),
1381+
(Datum::double(f64::MAX), float_above_max.clone()),
1382+
(Datum::double(f64::INFINITY), float_above_max),
1383+
(Datum::double(f64::NAN), Datum::float(f32::NAN)),
1384+
];
1385+
1386+
for (datum, expected) in test_data {
1387+
let result = datum.to(&Primitive(PrimitiveType::Float)).unwrap();
1388+
assert_eq!(result, expected);
1389+
}
1390+
}

0 commit comments

Comments
 (0)