scovich commented on code in PR #9689:
URL: https://github.com/apache/arrow-rs/pull/9689#discussion_r3087965547


##########
arrow-cast/src/cast/decimal.rs:
##########
@@ -833,11 +844,11 @@ where
                     if array.is_null(i) {
                         value_builder.append_null();
                     } else {

Review Comment:
   Ah, I totally missed the spurious error allocation pitfall 🤦. Glad your 
benchmarking uncovered it!



##########
arrow-cast/src/cast/decimal.rs:
##########
@@ -833,11 +844,11 @@ where
                     if array.is_null(i) {
                         value_builder.append_null();
                     } else {

Review Comment:
   If you really wanted to unify without the overhead, a helper that returns 
`Result<T, D::Native>` should do the trick: `Ok(v)` is a valid value, and 
`Err(v)` is the out of gamut value. The value would be super cheap, and safe 
path does `.ok()` while unsafe path does `.map(|v| 
ArrowError::CastError(...))`. 
   
   But probably not worth it, especially given that the checked mul/div _also_ 
produce `ArrowError` via `?`.



##########
arrow-cast/src/cast/decimal.rs:
##########
@@ -884,26 +890,66 @@ where
                     if array.is_null(i) {
                         value_builder.append_null();
                     } else {
-                        let v = array.value(i).div_checked(div)?;
-
-                        let value =
-                            <T::Native as 
NumCast>::from::<D::Native>(v).ok_or_else(|| {
-                                ArrowError::CastError(format!(
-                                    "value of {:?} is out of range {}",
-                                    v,
-                                    T::DATA_TYPE
-                                ))
-                            })?;
-
+                        let value = cast_single_decimal_to_integer_result::<D, 
T::Native>(
+                            array.value(i),
+                            div,
+                            false,
+                            T::DATA_TYPE,
+                        )?;
                         value_builder.append_value(value);
                     }
                 }
             }
         }
     }
+
     Ok(Arc::new(value_builder.finish()))
 }
 
+/// Casting a given decimal to an integer based on given div and scale.
+/// The value is scaled by multiplying or dividing with the div based on the 
scale sign.
+/// Returns `None` if the value is overflow or cannot be represented with the 
requested precision.
+#[inline]
+pub fn cast_single_decimal_to_integer_opt<D, T>(
+    value: D::Native,
+    div: D::Native,
+    negative: bool,
+) -> Option<T>
+where
+    T: NumCast + ToPrimitive,
+    D: DecimalType + ArrowPrimitiveType,
+    <D as ArrowPrimitiveType>::Native: ToPrimitive,
+{
+    let v = if negative {
+        value.mul_checked(div).ok()?
+    } else {
+        value.div_checked(div).ok()?
+    };
+    T::from::<D::Native>(v)
+}
+
+#[inline]
+fn cast_single_decimal_to_integer_result<D, T>(
+    value: D::Native,
+    div: D::Native,
+    negative: bool,
+    type_name: DataType,
+) -> Result<T, ArrowError>
+where
+    T: NumCast + ToPrimitive,
+    D: DecimalType + ArrowPrimitiveType,
+    <D as ArrowPrimitiveType>::Native: ToPrimitive,
+{
+    let v = if negative {
+        value.mul_checked(div)?
+    } else {
+        value.div_checked(div)?
+    };
+    T::from::<D::Native>(v).ok_or_else(|| {

Review Comment:
   Ah tricky indeed.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to