Skip to content

Commit d6fa078

Browse files
authored
Expose min/max values for Decimal128/256 and improve docs (#6992)
* Expose min/max values for Decimal128/256 and improve docs * fix test
1 parent 6340d46 commit d6fa078

File tree

1 file changed

+108
-34
lines changed

1 file changed

+108
-34
lines changed

arrow-data/src/decimal.rs

Lines changed: 108 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18-
//! Defines maximum and minimum values for `decimal256` and `decimal128` types for varying precisions.
18+
//! Maximum and minimum values for [`Decimal256`] and [`Decimal128`].
1919
//!
20-
//! Also provides functions to validate if a given decimal value is within the valid range of the decimal type.
21-
20+
//! Also provides functions to validate if a given decimal value is within
21+
//! the valid range of the decimal type.
22+
//!
23+
//! [`Decimal128`]: arrow_schema::DataType::Decimal128
24+
//! [`Decimal256`]: arrow_schema::DataType::Decimal256
2225
use arrow_buffer::i256;
2326
use arrow_schema::ArrowError;
2427

@@ -27,12 +30,27 @@ pub use arrow_schema::{
2730
DECIMAL_DEFAULT_SCALE,
2831
};
2932

30-
/// MAX decimal256 value of little-endian format for each precision.
31-
/// Each element is the max value of signed 256-bit integer for the specified precision which
32-
/// is encoded to the 32-byte width format of little-endian.
33+
/// `MAX_DECIMAL256_FOR_EACH_PRECISION[p]` holds the maximum [`i256`] value that can
34+
/// be stored in a [`Decimal256`] value of precision `p`.
35+
///
36+
/// # Notes
37+
///
38+
/// Each element is the max value of signed 256-bit integer for the specified
39+
/// precision which is encoded to the 32-byte width format of little-endian.
40+
///
3341
/// The first element is unused and is inserted so that we can look up using
3442
/// precision as the index without the need to subtract 1 first.
35-
pub(crate) const MAX_DECIMAL_BYTES_FOR_LARGER_EACH_PRECISION: [i256; 77] = [
43+
///
44+
/// # Example
45+
/// ```
46+
/// # use arrow_buffer::i256;
47+
/// # use arrow_data::decimal::MAX_DECIMAL256_FOR_EACH_PRECISION;
48+
/// assert_eq!(MAX_DECIMAL256_FOR_EACH_PRECISION[3], i256::from(999));
49+
/// ```
50+
///
51+
/// [`Decimal256`]: arrow_schema::DataType::Decimal256
52+
/// [`i256`]: arrow_buffer::i256
53+
pub const MAX_DECIMAL256_FOR_EACH_PRECISION: [i256; 77] = [
3654
i256::from_i128(0_i128), // unused first element
3755
i256::from_le_bytes([
3856
9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -340,12 +358,26 @@ pub(crate) const MAX_DECIMAL_BYTES_FOR_LARGER_EACH_PRECISION: [i256; 77] = [
340358
]),
341359
];
342360

343-
/// MIN decimal256 value of little-endian format for each precision.
361+
/// `MIN_DECIMAL256_FOR_EACH_PRECISION[p]` holds the minimum [`i256`] value that can
362+
/// be stored in a [`Decimal256`] value of precision `p`.
363+
///
364+
/// # Notes
365+
///
344366
/// Each element is the min value of signed 256-bit integer for the specified precision which
345367
/// is encoded to the 76-byte width format of little-endian.
368+
///
346369
/// The first element is unused and is inserted so that we can look up using
347370
/// precision as the index without the need to subtract 1 first.
348-
pub(crate) const MIN_DECIMAL_BYTES_FOR_LARGER_EACH_PRECISION: [i256; 77] = [
371+
/// # Example
372+
/// ```
373+
/// # use arrow_buffer::i256;
374+
/// # use arrow_data::decimal::MIN_DECIMAL256_FOR_EACH_PRECISION;
375+
/// assert_eq!(MIN_DECIMAL256_FOR_EACH_PRECISION[3], i256::from(-999));
376+
/// ```
377+
///
378+
/// [`i256`]: arrow_buffer::i256
379+
/// [`Decimal256`]: arrow_schema::DataType::Decimal256
380+
pub const MIN_DECIMAL256_FOR_EACH_PRECISION: [i256; 77] = [
349381
i256::from_i128(0_i128), // unused first element
350382
i256::from_le_bytes([
351383
247, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
@@ -654,7 +686,13 @@ pub(crate) const MIN_DECIMAL_BYTES_FOR_LARGER_EACH_PRECISION: [i256; 77] = [
654686
];
655687

656688
/// `MAX_DECIMAL_FOR_EACH_PRECISION[p-1]` holds the maximum `i128` value that can
657-
/// be stored in [arrow_schema::DataType::Decimal128] value of precision `p`
689+
/// be stored in a [`Decimal128`] value of precision `p`
690+
///
691+
/// [`Decimal128`]: arrow_schema::DataType::Decimal128
692+
#[deprecated(
693+
since = "54.1.0",
694+
note = "Use MAX_DECIMAL128_FOR_EACH_PRECISION (note indexes are different)"
695+
)]
658696
#[allow(dead_code)] // no longer used but is part of our public API
659697
pub const MAX_DECIMAL_FOR_EACH_PRECISION: [i128; 38] = [
660698
9,
@@ -698,8 +736,14 @@ pub const MAX_DECIMAL_FOR_EACH_PRECISION: [i128; 38] = [
698736
];
699737

700738
/// `MIN_DECIMAL_FOR_EACH_PRECISION[p-1]` holds the minimum `i128` value that can
701-
/// be stored in a [arrow_schema::DataType::Decimal128] value of precision `p`
739+
/// be stored in a [`Decimal128`] value of precision `p`
740+
///
741+
/// [`Decimal128`]: arrow_schema::DataType::Decimal128
702742
#[allow(dead_code)] // no longer used but is part of our public API
743+
#[deprecated(
744+
since = "54.1.0",
745+
note = "Use MIN_DECIMAL_FOR_EACH_PRECISION (note indexes are different)"
746+
)]
703747
pub const MIN_DECIMAL_FOR_EACH_PRECISION: [i128; 38] = [
704748
-9,
705749
-99,
@@ -741,11 +785,22 @@ pub const MIN_DECIMAL_FOR_EACH_PRECISION: [i128; 38] = [
741785
-99999999999999999999999999999999999999,
742786
];
743787

744-
/// `MAX_DECIMAL_FOR_EACH_PRECISION_ONE_BASED[p]` holds the maximum `i128` value that can
745-
/// be stored in [arrow_schema::DataType::Decimal128] value of precision `p`.
788+
/// `MAX_DECIMAL128_FOR_EACH_PRECISION[p]` holds the maximum `i128` value that can
789+
/// be stored in [`Decimal128`] value of precision `p`.
790+
///
791+
/// # Notes
792+
///
746793
/// The first element is unused and is inserted so that we can look up using
747794
/// precision as the index without the need to subtract 1 first.
748-
pub(crate) const MAX_DECIMAL_FOR_EACH_PRECISION_ONE_BASED: [i128; 39] = [
795+
///
796+
/// # Example
797+
/// ```
798+
/// # use arrow_data::decimal::MAX_DECIMAL128_FOR_EACH_PRECISION;
799+
/// assert_eq!(MAX_DECIMAL128_FOR_EACH_PRECISION[3], 999);
800+
/// ```
801+
///
802+
/// [`Decimal128`]: arrow_schema::DataType::Decimal128
803+
pub const MAX_DECIMAL128_FOR_EACH_PRECISION: [i128; 39] = [
749804
0, // unused first element
750805
9,
751806
99,
@@ -788,10 +843,21 @@ pub(crate) const MAX_DECIMAL_FOR_EACH_PRECISION_ONE_BASED: [i128; 39] = [
788843
];
789844

790845
/// `MIN_DECIMAL_FOR_EACH_PRECISION[p]` holds the minimum `i128` value that can
791-
/// be stored in a [arrow_schema::DataType::Decimal128] value of precision `p`.
846+
/// be stored in a [`Decimal128`] value of precision `p`.
847+
///
848+
/// # Notes
849+
///
792850
/// The first element is unused and is inserted so that we can look up using
793851
/// precision as the index without the need to subtract 1 first.
794-
pub(crate) const MIN_DECIMAL_FOR_EACH_PRECISION_ONE_BASED: [i128; 39] = [
852+
///
853+
/// # Example
854+
/// ```
855+
/// # use arrow_data::decimal::MIN_DECIMAL128_FOR_EACH_PRECISION;
856+
/// assert_eq!(MIN_DECIMAL128_FOR_EACH_PRECISION[3], -999);
857+
/// ```
858+
///
859+
/// [`Decimal128`]: arrow_schema::DataType::Decimal128
860+
pub const MIN_DECIMAL128_FOR_EACH_PRECISION: [i128; 39] = [
795861
0, // unused first element
796862
-9,
797863
-99,
@@ -834,67 +900,75 @@ pub(crate) const MIN_DECIMAL_FOR_EACH_PRECISION_ONE_BASED: [i128; 39] = [
834900
];
835901

836902
/// Validates that the specified `i128` value can be properly
837-
/// interpreted as a Decimal number with precision `precision`
903+
/// interpreted as a [`Decimal128`] number with precision `precision`
904+
///
905+
/// [`Decimal128`]: arrow_schema::DataType::Decimal128
838906
#[inline]
839907
pub fn validate_decimal_precision(value: i128, precision: u8) -> Result<(), ArrowError> {
840908
if precision > DECIMAL128_MAX_PRECISION {
841909
return Err(ArrowError::InvalidArgumentError(format!(
842910
"Max precision of a Decimal128 is {DECIMAL128_MAX_PRECISION}, but got {precision}",
843911
)));
844912
}
845-
if value > MAX_DECIMAL_FOR_EACH_PRECISION_ONE_BASED[precision as usize] {
913+
if value > MAX_DECIMAL128_FOR_EACH_PRECISION[precision as usize] {
846914
Err(ArrowError::InvalidArgumentError(format!(
847915
"{value} is too large to store in a Decimal128 of precision {precision}. Max is {}",
848-
MAX_DECIMAL_FOR_EACH_PRECISION_ONE_BASED[precision as usize]
916+
MAX_DECIMAL128_FOR_EACH_PRECISION[precision as usize]
849917
)))
850-
} else if value < MIN_DECIMAL_FOR_EACH_PRECISION_ONE_BASED[precision as usize] {
918+
} else if value < MIN_DECIMAL128_FOR_EACH_PRECISION[precision as usize] {
851919
Err(ArrowError::InvalidArgumentError(format!(
852920
"{value} is too small to store in a Decimal128 of precision {precision}. Min is {}",
853-
MIN_DECIMAL_FOR_EACH_PRECISION_ONE_BASED[precision as usize]
921+
MIN_DECIMAL128_FOR_EACH_PRECISION[precision as usize]
854922
)))
855923
} else {
856924
Ok(())
857925
}
858926
}
859927

860-
/// Determines whether the specified `i128` value can be properly
861-
/// interpreted as a Decimal number with precision `precision`
928+
/// Returns true if the specified `i128` value can be properly
929+
/// interpreted as a [`Decimal128`] number with precision `precision`
930+
///
931+
/// [`Decimal128`]: arrow_schema::DataType::Decimal128
862932
#[inline]
863933
pub fn is_validate_decimal_precision(value: i128, precision: u8) -> bool {
864934
precision <= DECIMAL128_MAX_PRECISION
865-
&& value >= MIN_DECIMAL_FOR_EACH_PRECISION_ONE_BASED[precision as usize]
866-
&& value <= MAX_DECIMAL_FOR_EACH_PRECISION_ONE_BASED[precision as usize]
935+
&& value >= MIN_DECIMAL128_FOR_EACH_PRECISION[precision as usize]
936+
&& value <= MAX_DECIMAL128_FOR_EACH_PRECISION[precision as usize]
867937
}
868938

869939
/// Validates that the specified `i256` of value can be properly
870-
/// interpreted as a Decimal256 number with precision `precision`
940+
/// interpreted as a [`Decimal256`] number with precision `precision`
941+
///
942+
/// [`Decimal256`]: arrow_schema::DataType::Decimal256
871943
#[inline]
872944
pub fn validate_decimal256_precision(value: i256, precision: u8) -> Result<(), ArrowError> {
873945
if precision > DECIMAL256_MAX_PRECISION {
874946
return Err(ArrowError::InvalidArgumentError(format!(
875947
"Max precision of a Decimal256 is {DECIMAL256_MAX_PRECISION}, but got {precision}",
876948
)));
877949
}
878-
if value > MAX_DECIMAL_BYTES_FOR_LARGER_EACH_PRECISION[precision as usize] {
950+
if value > MAX_DECIMAL256_FOR_EACH_PRECISION[precision as usize] {
879951
Err(ArrowError::InvalidArgumentError(format!(
880952
"{value:?} is too large to store in a Decimal256 of precision {precision}. Max is {:?}",
881-
MAX_DECIMAL_BYTES_FOR_LARGER_EACH_PRECISION[precision as usize]
953+
MAX_DECIMAL256_FOR_EACH_PRECISION[precision as usize]
882954
)))
883-
} else if value < MIN_DECIMAL_BYTES_FOR_LARGER_EACH_PRECISION[precision as usize] {
955+
} else if value < MIN_DECIMAL256_FOR_EACH_PRECISION[precision as usize] {
884956
Err(ArrowError::InvalidArgumentError(format!(
885957
"{value:?} is too small to store in a Decimal256 of precision {precision}. Min is {:?}",
886-
MIN_DECIMAL_BYTES_FOR_LARGER_EACH_PRECISION[precision as usize]
958+
MIN_DECIMAL256_FOR_EACH_PRECISION[precision as usize]
887959
)))
888960
} else {
889961
Ok(())
890962
}
891963
}
892964

893-
/// Determines whether the specified `i256` value can be properly
894-
/// interpreted as a Decimal256 number with precision `precision`
965+
/// Return true if the specified `i256` value can be properly
966+
/// interpreted as a [`Decimal256`] number with precision `precision`
967+
///
968+
/// [`Decimal256`]: arrow_schema::DataType::Decimal256
895969
#[inline]
896970
pub fn is_validate_decimal256_precision(value: i256, precision: u8) -> bool {
897971
precision <= DECIMAL256_MAX_PRECISION
898-
&& value >= MIN_DECIMAL_BYTES_FOR_LARGER_EACH_PRECISION[precision as usize]
899-
&& value <= MAX_DECIMAL_BYTES_FOR_LARGER_EACH_PRECISION[precision as usize]
972+
&& value >= MIN_DECIMAL256_FOR_EACH_PRECISION[precision as usize]
973+
&& value <= MAX_DECIMAL256_FOR_EACH_PRECISION[precision as usize]
900974
}

0 commit comments

Comments
 (0)