@@ -145,27 +145,6 @@ impl DecimalCast for i256 {
145145 }
146146}
147147
148- fn cast_decimal_to_decimal_error < I , O > (
149- output_precision : u8 ,
150- output_scale : i8 ,
151- ) -> impl Fn ( <I as ArrowPrimitiveType >:: Native ) -> ArrowError
152- where
153- I : DecimalType ,
154- O : DecimalType ,
155- I :: Native : DecimalCast + ArrowNativeTypeOp ,
156- O :: Native : DecimalCast + ArrowNativeTypeOp ,
157- {
158- move |x : I :: Native | {
159- ArrowError :: CastError ( format ! (
160- "Cannot cast to {}({}, {}). Overflowing on {:?}" ,
161- O :: PREFIX ,
162- output_precision,
163- output_scale,
164- x
165- ) )
166- }
167- }
168-
169148/// Construct closures to upscale decimals from `(input_precision, input_scale)` to
170149/// `(output_precision, output_scale)`.
171150///
@@ -174,7 +153,7 @@ where
174153/// In that case, the caller should treat this as an overflow for the output scale
175154/// and handle it accordingly (e.g., return a cast error).
176155#[ allow( clippy:: type_complexity) ]
177- pub fn make_upscaler < I : DecimalType , O : DecimalType > (
156+ fn make_upscaler < I : DecimalType , O : DecimalType > (
178157 input_precision : u8 ,
179158 input_scale : i8 ,
180159 output_precision : u8 ,
@@ -218,7 +197,7 @@ where
218197/// available precision). Callers should therefore produce zero values (preserving nulls) rather
219198/// than returning an error.
220199#[ allow( clippy:: type_complexity) ]
221- pub fn make_downscaler < I : DecimalType , O : DecimalType > (
200+ fn make_downscaler < I : DecimalType , O : DecimalType > (
222201 input_precision : u8 ,
223202 input_scale : i8 ,
224203 output_precision : u8 ,
@@ -274,6 +253,76 @@ where
274253 Some ( ( f, f_infallible) )
275254}
276255
256+ /// Apply the rescaler function to the value.
257+ /// If the rescaler is infallible, use the infallible function.
258+ /// Otherwise, use the fallible function and validate the precision.
259+ fn apply_rescaler < I : DecimalType , O : DecimalType > (
260+ value : I :: Native ,
261+ output_precision : u8 ,
262+ f : impl Fn ( I :: Native ) -> Option < O :: Native > ,
263+ f_infallible : Option < impl Fn ( I :: Native ) -> O :: Native > ,
264+ ) -> Option < O :: Native >
265+ where
266+ I :: Native : DecimalCast ,
267+ O :: Native : DecimalCast ,
268+ {
269+ if let Some ( f_infallible) = f_infallible {
270+ Some ( f_infallible ( value) )
271+ } else {
272+ f ( value) . filter ( |v| O :: is_valid_decimal_precision ( * v, output_precision) )
273+ }
274+ }
275+
276+ /// Rescale a decimal from (input_precision, input_scale) to (output_precision, output_scale)
277+ /// and return the scaled value if it fits the output precision. Similar to the implementation in
278+ /// decimal.rs in arrow-cast.
279+ pub fn rescale_decimal < I : DecimalType , O : DecimalType > (
280+ value : I :: Native ,
281+ input_precision : u8 ,
282+ input_scale : i8 ,
283+ output_precision : u8 ,
284+ output_scale : i8 ,
285+ ) -> Option < O :: Native >
286+ where
287+ I :: Native : DecimalCast + ArrowNativeTypeOp ,
288+ O :: Native : DecimalCast + ArrowNativeTypeOp ,
289+ {
290+ if input_scale <= output_scale {
291+ let ( f, f_infallible) =
292+ make_upscaler :: < I , O > ( input_precision, input_scale, output_precision, output_scale) ?;
293+ apply_rescaler :: < I , O > ( value, output_precision, f, f_infallible)
294+ } else {
295+ let Some ( ( f, f_infallible) ) =
296+ make_downscaler :: < I , O > ( input_precision, input_scale, output_precision, output_scale)
297+ else {
298+ // Scale reduction exceeds supported precision; result mathematically rounds to zero
299+ return Some ( O :: Native :: ZERO ) ;
300+ } ;
301+ apply_rescaler :: < I , O > ( value, output_precision, f, f_infallible)
302+ }
303+ }
304+
305+ fn cast_decimal_to_decimal_error < I , O > (
306+ output_precision : u8 ,
307+ output_scale : i8 ,
308+ ) -> impl Fn ( <I as ArrowPrimitiveType >:: Native ) -> ArrowError
309+ where
310+ I : DecimalType ,
311+ O : DecimalType ,
312+ I :: Native : DecimalCast + ArrowNativeTypeOp ,
313+ O :: Native : DecimalCast + ArrowNativeTypeOp ,
314+ {
315+ move |x : I :: Native | {
316+ ArrowError :: CastError ( format ! (
317+ "Cannot cast to {}({}, {}). Overflowing on {:?}" ,
318+ O :: PREFIX ,
319+ output_precision,
320+ output_scale,
321+ x
322+ ) )
323+ }
324+ }
325+
277326fn apply_decimal_cast < I : DecimalType , O : DecimalType > (
278327 array : & PrimitiveArray < I > ,
279328 output_precision : u8 ,
0 commit comments