sdf-jkl commented on code in PR #10157:
URL: https://github.com/apache/arrow-rs/pull/10157#discussion_r3642049881
##########
parquet-variant/src/variant.rs:
##########
@@ -837,191 +794,213 @@ impl<'m, 'v> Variant<'m, 'v> {
}
}
- fn cast_decimal_to_num<D, T, F>(raw: D::Native, scale: u8, as_float: F) ->
Option<T>
- where
- D: DecimalType,
- D::Native: NumCast + ArrowNativeTypeOp,
- T: DecimalCastTarget,
- F: Fn(D::Native) -> f64,
- {
- let base: D::Native = NumCast::from(10)?;
-
- let div = base.pow_checked(<u32 as From<u8>>::from(scale)).ok()?;
- match T::KIND {
- NumericKind::Integer => raw
- .div_checked(div)
- .ok()
- .and_then(<T as NumCast>::from::<D::Native>),
- NumericKind::Float => T::from(single_decimal_to_float_lossy::<D,
_>(
- &as_float,
- raw,
- <i32 as From<u8>>::from(scale),
- )),
- }
- }
-
- /// Converts a boolean or numeric variant(integers, floating-point, and
decimals)
- /// to the specified numeric type `T`.
- ///
- /// Uses Arrow's casting logic to perform the conversion. Returns
`Some(T)` if
- /// the conversion succeeds, `None` if the variant can't be casted to type
`T`.
- fn as_num<T>(&self) -> Option<T>
- where
- T: DecimalCastTarget,
- {
- match *self {
- Variant::BooleanFalse => single_bool_to_numeric(false),
- Variant::BooleanTrue => single_bool_to_numeric(true),
- Variant::Int8(i) => num_cast(i),
- Variant::Int16(i) => num_cast(i),
- Variant::Int32(i) => num_cast(i),
- Variant::Int64(i) => num_cast(i),
- Variant::Float(f) => num_cast(f),
- Variant::Double(d) => num_cast(d),
- Variant::Decimal4(d) => {
- Self::cast_decimal_to_num::<Decimal32Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- Variant::Decimal8(d) => {
- Self::cast_decimal_to_num::<Decimal64Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- Variant::Decimal16(d) => {
- Self::cast_decimal_to_num::<Decimal128Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- _ => None,
- }
- }
-
/// Converts this variant to an `i8` if possible.
///
- /// Returns `Some(i8)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i8` range,
- /// `None` for other variants or values that would overflow.
- ///
+ /// Returns `Some(i8)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i8` range, `None` for other variants or values that
would overflow.
Review Comment:
Wording polish, same suggestion on the other seven accessors below.
```suggestion
/// Returns `Some(i8)` for int variants and for decimal variants with no
fractional part
/// (scale = 0, or unscaled integer divisible by 10^scale) that fit in
the `i8` range.
/// `None` for other variants or values that would overflow.
```
##########
parquet-variant/src/variant.rs:
##########
@@ -837,191 +794,213 @@ impl<'m, 'v> Variant<'m, 'v> {
}
}
- fn cast_decimal_to_num<D, T, F>(raw: D::Native, scale: u8, as_float: F) ->
Option<T>
- where
- D: DecimalType,
- D::Native: NumCast + ArrowNativeTypeOp,
- T: DecimalCastTarget,
- F: Fn(D::Native) -> f64,
- {
- let base: D::Native = NumCast::from(10)?;
-
- let div = base.pow_checked(<u32 as From<u8>>::from(scale)).ok()?;
- match T::KIND {
- NumericKind::Integer => raw
- .div_checked(div)
- .ok()
- .and_then(<T as NumCast>::from::<D::Native>),
- NumericKind::Float => T::from(single_decimal_to_float_lossy::<D,
_>(
- &as_float,
- raw,
- <i32 as From<u8>>::from(scale),
- )),
- }
- }
-
- /// Converts a boolean or numeric variant(integers, floating-point, and
decimals)
- /// to the specified numeric type `T`.
- ///
- /// Uses Arrow's casting logic to perform the conversion. Returns
`Some(T)` if
- /// the conversion succeeds, `None` if the variant can't be casted to type
`T`.
- fn as_num<T>(&self) -> Option<T>
- where
- T: DecimalCastTarget,
- {
- match *self {
- Variant::BooleanFalse => single_bool_to_numeric(false),
- Variant::BooleanTrue => single_bool_to_numeric(true),
- Variant::Int8(i) => num_cast(i),
- Variant::Int16(i) => num_cast(i),
- Variant::Int32(i) => num_cast(i),
- Variant::Int64(i) => num_cast(i),
- Variant::Float(f) => num_cast(f),
- Variant::Double(d) => num_cast(d),
- Variant::Decimal4(d) => {
- Self::cast_decimal_to_num::<Decimal32Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- Variant::Decimal8(d) => {
- Self::cast_decimal_to_num::<Decimal64Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- Variant::Decimal16(d) => {
- Self::cast_decimal_to_num::<Decimal128Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- _ => None,
- }
- }
-
/// Converts this variant to an `i8` if possible.
///
- /// Returns `Some(i8)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i8` range,
- /// `None` for other variants or values that would overflow.
- ///
+ /// Returns `Some(i8)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i8` range, `None` for other variants or values that
would overflow.
/// # Examples
///
/// ```
- /// use parquet_variant::Variant;
+ /// use parquet_variant::{Variant, VariantDecimal4};
///
/// // you can read an int64 variant into an i8 if it fits
/// let v1 = Variant::from(123i64);
/// assert_eq!(v1.as_int8(), Some(123i8));
///
- /// // or from boolean variant
- /// let v2 = Variant::BooleanFalse;
- /// assert_eq!(v2.as_int8(), Some(0));
+ /// // or from a decimal variant with scale = 0 that fits in i8 range
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v2 = Variant::from(d);
+ /// assert_eq!(v2.as_int8(), Some(123i8));
+ ///
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_int8(), Some(1i8));
///
/// // but not if it would overflow
- /// let v3 = Variant::from(1234i64);
- /// assert_eq!(v3.as_int8(), None);
+ /// let d = VariantDecimal4::try_new(1234i32, 0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_int8(), None);
///
/// // or if the variant cannot be cast into an integer
- /// let v4 = Variant::from("hello!");
- /// assert_eq!(v4.as_int8(), None);
+ /// let v5 = Variant::from("hello");
+ /// assert_eq!(v5.as_int8(), None);
/// ```
pub fn as_int8(&self) -> Option<i8> {
- self.as_num()
+ match *self {
+ Variant::Int8(i) => Some(i),
+ Variant::Int16(i) => i.try_into().ok(),
+ Variant::Int32(i) => i.try_into().ok(),
+ Variant::Int64(i) => i.try_into().ok(),
+ Variant::Decimal4(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal8(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal16(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ _ => None,
+ }
}
/// Converts this variant to an `i16` if possible.
///
- /// Returns `Some(i16)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i16` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(i16)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i16` range, `None` for other variants or values that
would overflow.
///
/// # Examples
///
/// ```
- /// use parquet_variant::Variant;
+ /// use parquet_variant::{Variant, VariantDecimal4};
///
/// // you can read an int64 variant into an i16 if it fits
/// let v1 = Variant::from(123i64);
/// assert_eq!(v1.as_int16(), Some(123i16));
///
- /// // or from boolean variant
- /// let v2 = Variant::BooleanFalse;
- /// assert_eq!(v2.as_int16(), Some(0));
+ /// // or from a decimal variant that scale = 0
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v2 = Variant::from(d);
+ /// assert_eq!(v2.as_int16(), Some(123i16));
+ ///
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_int16(), Some(1i16));
///
/// // but not if it would overflow
- /// let v3 = Variant::from(123456i64);
- /// assert_eq!(v3.as_int16(), None);
+ /// let d = VariantDecimal4::try_new(123456i32, 0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_int16(), None);
///
/// // or if the variant cannot be cast into an integer
- /// let v4 = Variant::from("hello!");
- /// assert_eq!(v4.as_int16(), None);
+ /// let v5 = Variant::from("hello");
+ /// assert_eq!(v5.as_int16(), None);
/// ```
pub fn as_int16(&self) -> Option<i16> {
- self.as_num()
+ match *self {
+ Variant::Int8(i) => Some(i as i16),
+ Variant::Int16(i) => Some(i),
+ Variant::Int32(i) => i.try_into().ok(),
+ Variant::Int64(i) => i.try_into().ok(),
+ Variant::Decimal4(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal8(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal16(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ _ => None,
+ }
}
/// Converts this variant to an `i32` if possible.
///
- /// Returns `Some(i32)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i32` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(i32)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i32` range, `None` for other variants or values that
would overflow.
///
/// # Examples
///
/// ```
- /// use parquet_variant::Variant;
+ /// use parquet_variant::{Variant, VariantDecimal4, VariantDecimal8};
///
- /// // you can read an int64 variant into an i32 if it fits
- /// let v1 = Variant::from(123i64);
+ /// // you can read an int32 variant into an i32
+ /// let v1 = Variant::from(123i32);
/// assert_eq!(v1.as_int32(), Some(123i32));
///
- /// // or from boolean variant
- /// let v2 = Variant::BooleanFalse;
- /// assert_eq!(v2.as_int32(), Some(0));
+ /// // or from an int64 if it fits
+ /// let v2 = Variant::from(1231i64);
+ /// assert_eq!(v2.as_int32(), Some(1231i32));
+ ///
+ /// // or from decimal variant that scale=0
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_int32(), Some(123i32));
+ ///
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_int32(), Some(1i32));
///
/// // but not if it would overflow
- /// let v3 = Variant::from(12345678901i64);
- /// assert_eq!(v3.as_int32(), None);
+ /// let d = VariantDecimal8::try_new(1234567890123, 0).unwrap();
+ /// let v5 = Variant::from(d);
+ /// assert_eq!(v5.as_int32(), None);
///
/// // or if the variant cannot be cast into an integer
- /// let v4 = Variant::from("hello!");
- /// assert_eq!(v4.as_int32(), None);
+ /// let v6 = Variant::from("hello");
+ /// assert_eq!(v6.as_int32(), None)
/// ```
pub fn as_int32(&self) -> Option<i32> {
- self.as_num()
+ match *self {
+ Variant::Int8(i) => Some(i as i32),
+ Variant::Int16(i) => Some(i as i32),
+ Variant::Int32(i) => Some(i),
+ Variant::Int64(i) => i.try_into().ok(),
+ Variant::Decimal4(d) => d.as_integer(),
+ Variant::Decimal8(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal16(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ _ => None,
+ }
}
/// Converts this variant to an `i64` if possible.
///
- /// Returns `Some(i64)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i64` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(i64)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i64` range, `None` for other variants or values that
would overflow.
Review Comment:
```suggestion
/// Returns `Some(i64)` for int variants and for decimal variants with
no fractional part
/// (scale = 0, or unscaled integer divisible by 10^scale) that fit in
the `i64` range.
/// `None` for other variants or values that would overflow.
```
##########
parquet-variant/src/variant.rs:
##########
@@ -837,191 +794,213 @@ impl<'m, 'v> Variant<'m, 'v> {
}
}
- fn cast_decimal_to_num<D, T, F>(raw: D::Native, scale: u8, as_float: F) ->
Option<T>
- where
- D: DecimalType,
- D::Native: NumCast + ArrowNativeTypeOp,
- T: DecimalCastTarget,
- F: Fn(D::Native) -> f64,
- {
- let base: D::Native = NumCast::from(10)?;
-
- let div = base.pow_checked(<u32 as From<u8>>::from(scale)).ok()?;
- match T::KIND {
- NumericKind::Integer => raw
- .div_checked(div)
- .ok()
- .and_then(<T as NumCast>::from::<D::Native>),
- NumericKind::Float => T::from(single_decimal_to_float_lossy::<D,
_>(
- &as_float,
- raw,
- <i32 as From<u8>>::from(scale),
- )),
- }
- }
-
- /// Converts a boolean or numeric variant(integers, floating-point, and
decimals)
- /// to the specified numeric type `T`.
- ///
- /// Uses Arrow's casting logic to perform the conversion. Returns
`Some(T)` if
- /// the conversion succeeds, `None` if the variant can't be casted to type
`T`.
- fn as_num<T>(&self) -> Option<T>
- where
- T: DecimalCastTarget,
- {
- match *self {
- Variant::BooleanFalse => single_bool_to_numeric(false),
- Variant::BooleanTrue => single_bool_to_numeric(true),
- Variant::Int8(i) => num_cast(i),
- Variant::Int16(i) => num_cast(i),
- Variant::Int32(i) => num_cast(i),
- Variant::Int64(i) => num_cast(i),
- Variant::Float(f) => num_cast(f),
- Variant::Double(d) => num_cast(d),
- Variant::Decimal4(d) => {
- Self::cast_decimal_to_num::<Decimal32Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- Variant::Decimal8(d) => {
- Self::cast_decimal_to_num::<Decimal64Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- Variant::Decimal16(d) => {
- Self::cast_decimal_to_num::<Decimal128Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- _ => None,
- }
- }
-
/// Converts this variant to an `i8` if possible.
///
- /// Returns `Some(i8)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i8` range,
- /// `None` for other variants or values that would overflow.
- ///
+ /// Returns `Some(i8)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i8` range, `None` for other variants or values that
would overflow.
/// # Examples
///
/// ```
- /// use parquet_variant::Variant;
+ /// use parquet_variant::{Variant, VariantDecimal4};
///
/// // you can read an int64 variant into an i8 if it fits
/// let v1 = Variant::from(123i64);
/// assert_eq!(v1.as_int8(), Some(123i8));
///
- /// // or from boolean variant
- /// let v2 = Variant::BooleanFalse;
- /// assert_eq!(v2.as_int8(), Some(0));
+ /// // or from a decimal variant with scale = 0 that fits in i8 range
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v2 = Variant::from(d);
+ /// assert_eq!(v2.as_int8(), Some(123i8));
+ ///
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_int8(), Some(1i8));
///
/// // but not if it would overflow
- /// let v3 = Variant::from(1234i64);
- /// assert_eq!(v3.as_int8(), None);
+ /// let d = VariantDecimal4::try_new(1234i32, 0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_int8(), None);
///
/// // or if the variant cannot be cast into an integer
- /// let v4 = Variant::from("hello!");
- /// assert_eq!(v4.as_int8(), None);
+ /// let v5 = Variant::from("hello");
+ /// assert_eq!(v5.as_int8(), None);
/// ```
pub fn as_int8(&self) -> Option<i8> {
- self.as_num()
+ match *self {
+ Variant::Int8(i) => Some(i),
+ Variant::Int16(i) => i.try_into().ok(),
+ Variant::Int32(i) => i.try_into().ok(),
+ Variant::Int64(i) => i.try_into().ok(),
+ Variant::Decimal4(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal8(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal16(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ _ => None,
+ }
}
/// Converts this variant to an `i16` if possible.
///
- /// Returns `Some(i16)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i16` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(i16)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i16` range, `None` for other variants or values that
would overflow.
///
/// # Examples
///
/// ```
- /// use parquet_variant::Variant;
+ /// use parquet_variant::{Variant, VariantDecimal4};
///
/// // you can read an int64 variant into an i16 if it fits
/// let v1 = Variant::from(123i64);
/// assert_eq!(v1.as_int16(), Some(123i16));
///
- /// // or from boolean variant
- /// let v2 = Variant::BooleanFalse;
- /// assert_eq!(v2.as_int16(), Some(0));
+ /// // or from a decimal variant that scale = 0
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v2 = Variant::from(d);
+ /// assert_eq!(v2.as_int16(), Some(123i16));
+ ///
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_int16(), Some(1i16));
///
/// // but not if it would overflow
- /// let v3 = Variant::from(123456i64);
- /// assert_eq!(v3.as_int16(), None);
+ /// let d = VariantDecimal4::try_new(123456i32, 0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_int16(), None);
///
/// // or if the variant cannot be cast into an integer
- /// let v4 = Variant::from("hello!");
- /// assert_eq!(v4.as_int16(), None);
+ /// let v5 = Variant::from("hello");
+ /// assert_eq!(v5.as_int16(), None);
/// ```
pub fn as_int16(&self) -> Option<i16> {
- self.as_num()
+ match *self {
+ Variant::Int8(i) => Some(i as i16),
+ Variant::Int16(i) => Some(i),
+ Variant::Int32(i) => i.try_into().ok(),
+ Variant::Int64(i) => i.try_into().ok(),
+ Variant::Decimal4(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal8(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal16(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ _ => None,
+ }
}
/// Converts this variant to an `i32` if possible.
///
- /// Returns `Some(i32)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i32` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(i32)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i32` range, `None` for other variants or values that
would overflow.
Review Comment:
```suggestion
/// Returns `Some(i32)` for int variants and for decimal variants with
no fractional part
/// (scale = 0, or unscaled integer divisible by 10^scale) that fit in
the `i32` range.
/// `None` for other variants or values that would overflow.
```
##########
parquet-variant/src/variant/decimal.rs:
##########
@@ -141,6 +146,37 @@ macro_rules! impl_variant_decimal {
pub fn scale(&self) -> u8 {
self.scale
}
+
+ #[doc = concat!(
+ "Returns Some(`",
+ stringify!($native),
+ "`) if scale is zero or integer of the decimal is
divisible by 10^scale,\n",
+ "None for other values.\n\n",
+ "",
+ "# Examples\n",
+ "```rust\n",
+ "use parquet_variant::", stringify!($struct_name),
";\n",
+ "//Return the integer if scale is 0\n",
+ "let d1 = ", stringify!($struct_name), "::try_new(123,
0).unwrap();\n",
+ "assert_eq!(d1.as_integer(), Some(123));\n",
+ "// or if the integer is divisible by 10^scale\n",
+ "let d2 = ", stringify!($struct_name), "::try_new(100,
2).unwrap();\n",
+ "assert_eq!(d2.as_integer(), Some(1));\n",
+ "// or if the integer is 0\n",
+ "let d3 = ", stringify!($struct_name), "::try_new(0,
4).unwrap();\n",
+ "assert_eq!(d3.as_integer(), Some(0));\n",
+ "// but not if the integer is not divisible by
10^scale\n",
+ "let d4 = ", stringify!($struct_name), "::try_new(123,
2).unwrap();\n",
+ "assert_eq!(d4.as_integer(), None);\n",
+ "```\n",
+ )]
+ pub fn as_integer(&self) -> Option<$native> {
Review Comment:
The doctest pins the divisibility guard and the zero case. Two cases from
the earlier list are still uncovered:
- negatives: `-100` at scale 2 gives `Some(-1)`, `-1234` at scale 2 gives
`None`
- divisible but overflowing a narrower target:
`Variant::from(VariantDecimal8::try_new(100_000, 2).unwrap()).as_int8()` gives
`None` (1000 does not fit in `i8`)
Both behave correctly today, so this is just pinning the behavior.
##########
parquet-variant-compute/src/type_conversion.rs:
##########
@@ -287,6 +444,269 @@ where
}
}
+/// Return the unscaled integer representation for Arrow decimal type `O` from
a `Variant`.
+///
+/// This function is unlike `variant_to_unscaled_decim`, it would never
rescale the decimal value,
+/// and only return the unscaled integer representation for the specific
decimal variants.
Review Comment:
```suggestion
/// Unlike `variant_to_unscaled_decimal`, this function never rescales the
decimal value.
/// It only returns the unscaled integer representation for the specific
decimal variants.
```
##########
parquet-variant-compute/src/shred_variant.rs:
##########
@@ -2829,4 +3093,237 @@ mod tests {
let shredding_type = ShreddedSchemaBuilder::default().build();
assert_eq!(shredding_type, DataType::Null);
}
+
+ // This test wants to cover that the variant can/can't be shredded to the
given data type.
+ #[test]
+ fn test_variant_type_shredded_correctly() {
+ // array contains all variant types
+ let mut array_builder = VariantArrayBuilder::new(30);
+ array_builder.append_value(Variant::Null);
+ array_builder.append_value(Variant::Int8(1));
+ array_builder.append_value(Variant::Int16(2));
+ array_builder.append_value(Variant::Int32(3));
+ array_builder.append_value(Variant::Int64(4));
+
array_builder.append_value(Variant::Date(NaiveDate::from_epoch_days(12345).unwrap()));
+ array_builder.append_value(Variant::TimestampMicros(
+ DateTime::from_timestamp_micros(123456789).unwrap(),
+ ));
+ array_builder.append_value(Variant::TimestampNtzMicros(
+ DateTime::from_timestamp_micros(123456789)
+ .unwrap()
+ .naive_utc(),
+ ));
+
array_builder.append_value(Variant::TimestampNanos(DateTime::from_timestamp_nanos(
+ 1234567890000,
+ )));
+ array_builder.append_value(Variant::TimestampNtzNanos(
+ DateTime::from_timestamp_nanos(1234567890000).naive_utc(),
+ ));
+ array_builder.append_value(VariantDecimal4::try_new(123, 0).unwrap());
+ array_builder.append_value(VariantDecimal8::try_new(123, 0).unwrap());
+ array_builder.append_value(VariantDecimal16::try_new(123, 0).unwrap());
+ array_builder.append_value(Variant::Float(5.0));
+ array_builder.append_value(Variant::Double(6f64));
+ array_builder.append_value(Variant::BooleanTrue);
+ array_builder.append_value(Variant::BooleanFalse);
+ array_builder.append_value(Variant::Binary("helow".as_bytes()));
+ array_builder.append_value(Variant::String("hello"));
+ array_builder.append_value(Variant::ShortString(
+ ShortString::try_from("world").unwrap(),
+ ));
+ array_builder.append_value(Variant::Time(
+ NaiveTime::from_num_seconds_from_midnight_opt(12345, 123).unwrap(),
+ ));
+
+ let array = array_builder.build();
+
+ fn can_shred_to(v: &Variant, dt: &DataType) -> bool {
+ matches!(
+ (v, dt),
+ (Variant::Int8(_), DataType::Int8)
+ | (Variant::Int8(_), DataType::Int16)
+ | (Variant::Int8(_), DataType::Int32)
+ | (Variant::Int8(_), DataType::Int64)
+ | (Variant::Int8(_), DataType::Decimal32(_, _))
+ | (Variant::Int8(_), DataType::Decimal64(_, _))
+ | (Variant::Int8(_), DataType::Decimal128(_, _))
+ | (Variant::Int16(_), DataType::Int8)
+ | (Variant::Int16(_), DataType::Int16)
+ | (Variant::Int16(_), DataType::Int32)
+ | (Variant::Int16(_), DataType::Int64)
+ | (Variant::Int16(_), DataType::Decimal32(_, _))
+ | (Variant::Int16(_), DataType::Decimal64(_, _))
+ | (Variant::Int16(_), DataType::Decimal128(_, _))
+ | (Variant::Int32(_), DataType::Int8)
+ | (Variant::Int32(_), DataType::Int16)
+ | (Variant::Int32(_), DataType::Int32)
+ | (Variant::Int32(_), DataType::Int64)
+ | (Variant::Int32(_), DataType::Decimal32(_, _))
+ | (Variant::Int32(_), DataType::Decimal64(_, _))
+ | (Variant::Int32(_), DataType::Decimal128(_, _))
+ | (Variant::Int64(_), DataType::Int8)
+ | (Variant::Int64(_), DataType::Int16)
+ | (Variant::Int64(_), DataType::Int32)
+ | (Variant::Int64(_), DataType::Int64)
+ | (Variant::Int64(_), DataType::Decimal32(_, _))
+ | (Variant::Int64(_), DataType::Decimal64(_, _))
+ | (Variant::Int64(_), DataType::Decimal128(_, _))
+ | (Variant::Date(_), DataType::Date32)
+ | (
+ Variant::TimestampMicros(_),
+ DataType::Timestamp(TimeUnit::Microsecond, Some(_)),
+ )
+ | (
+ Variant::TimestampMicros(_),
+ DataType::Timestamp(TimeUnit::Nanosecond, Some(_))
+ )
+ | (
+ Variant::TimestampNtzMicros(_),
+ DataType::Timestamp(TimeUnit::Microsecond, None),
+ )
+ | (
+ Variant::TimestampNtzMicros(_),
+ DataType::Timestamp(TimeUnit::Nanosecond, None)
+ )
+ | (
+ Variant::TimestampNanos(_),
+ DataType::Timestamp(TimeUnit::Microsecond, Some(_))
Review Comment:
The nanos test value (1234567890000) is microsecond aligned, so these rows
only cover the happy path of nanos into a micros column. Worth one shred-level
case with a non-aligned nanos value against a `Timestamp(Microsecond, _)`
column, asserting the row falls back to the `value` column.
##########
parquet-variant/src/variant.rs:
##########
@@ -837,191 +794,213 @@ impl<'m, 'v> Variant<'m, 'v> {
}
}
- fn cast_decimal_to_num<D, T, F>(raw: D::Native, scale: u8, as_float: F) ->
Option<T>
- where
- D: DecimalType,
- D::Native: NumCast + ArrowNativeTypeOp,
- T: DecimalCastTarget,
- F: Fn(D::Native) -> f64,
- {
- let base: D::Native = NumCast::from(10)?;
-
- let div = base.pow_checked(<u32 as From<u8>>::from(scale)).ok()?;
- match T::KIND {
- NumericKind::Integer => raw
- .div_checked(div)
- .ok()
- .and_then(<T as NumCast>::from::<D::Native>),
- NumericKind::Float => T::from(single_decimal_to_float_lossy::<D,
_>(
- &as_float,
- raw,
- <i32 as From<u8>>::from(scale),
- )),
- }
- }
-
- /// Converts a boolean or numeric variant(integers, floating-point, and
decimals)
- /// to the specified numeric type `T`.
- ///
- /// Uses Arrow's casting logic to perform the conversion. Returns
`Some(T)` if
- /// the conversion succeeds, `None` if the variant can't be casted to type
`T`.
- fn as_num<T>(&self) -> Option<T>
- where
- T: DecimalCastTarget,
- {
- match *self {
- Variant::BooleanFalse => single_bool_to_numeric(false),
- Variant::BooleanTrue => single_bool_to_numeric(true),
- Variant::Int8(i) => num_cast(i),
- Variant::Int16(i) => num_cast(i),
- Variant::Int32(i) => num_cast(i),
- Variant::Int64(i) => num_cast(i),
- Variant::Float(f) => num_cast(f),
- Variant::Double(d) => num_cast(d),
- Variant::Decimal4(d) => {
- Self::cast_decimal_to_num::<Decimal32Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- Variant::Decimal8(d) => {
- Self::cast_decimal_to_num::<Decimal64Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- Variant::Decimal16(d) => {
- Self::cast_decimal_to_num::<Decimal128Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- _ => None,
- }
- }
-
/// Converts this variant to an `i8` if possible.
///
- /// Returns `Some(i8)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i8` range,
- /// `None` for other variants or values that would overflow.
- ///
+ /// Returns `Some(i8)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i8` range, `None` for other variants or values that
would overflow.
/// # Examples
///
/// ```
- /// use parquet_variant::Variant;
+ /// use parquet_variant::{Variant, VariantDecimal4};
///
/// // you can read an int64 variant into an i8 if it fits
/// let v1 = Variant::from(123i64);
/// assert_eq!(v1.as_int8(), Some(123i8));
///
- /// // or from boolean variant
- /// let v2 = Variant::BooleanFalse;
- /// assert_eq!(v2.as_int8(), Some(0));
+ /// // or from a decimal variant with scale = 0 that fits in i8 range
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v2 = Variant::from(d);
+ /// assert_eq!(v2.as_int8(), Some(123i8));
+ ///
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_int8(), Some(1i8));
///
/// // but not if it would overflow
- /// let v3 = Variant::from(1234i64);
- /// assert_eq!(v3.as_int8(), None);
+ /// let d = VariantDecimal4::try_new(1234i32, 0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_int8(), None);
///
/// // or if the variant cannot be cast into an integer
- /// let v4 = Variant::from("hello!");
- /// assert_eq!(v4.as_int8(), None);
+ /// let v5 = Variant::from("hello");
+ /// assert_eq!(v5.as_int8(), None);
/// ```
pub fn as_int8(&self) -> Option<i8> {
- self.as_num()
+ match *self {
+ Variant::Int8(i) => Some(i),
+ Variant::Int16(i) => i.try_into().ok(),
+ Variant::Int32(i) => i.try_into().ok(),
+ Variant::Int64(i) => i.try_into().ok(),
+ Variant::Decimal4(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal8(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal16(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ _ => None,
+ }
}
/// Converts this variant to an `i16` if possible.
///
- /// Returns `Some(i16)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i16` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(i16)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i16` range, `None` for other variants or values that
would overflow.
Review Comment:
```suggestion
/// Returns `Some(i16)` for int variants and for decimal variants with
no fractional part
/// (scale = 0, or unscaled integer divisible by 10^scale) that fit in
the `i16` range.
/// `None` for other variants or values that would overflow.
```
##########
parquet-variant/src/variant.rs:
##########
@@ -1032,37 +1011,33 @@ impl<'m, 'v> Variant<'m, 'v> {
/// let v1 = Variant::from(123i64);
/// assert_eq!(v1.as_u8(), Some(123u8));
///
- /// // or a Decimal4 with scale 0 into u8
- /// let d = VariantDecimal4::try_new(26, 0).unwrap();
- /// let v2 = Variant::from(d);
- /// assert_eq!(v2.as_u8(), Some(26u8));
+ /// // or from decimal variant that scale = 0
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v2 = Variant::from(d);
+ /// assert_eq!(v2.as_u8(), Some(123u8));
///
- /// // or a variant that decimal with scale not equal to zero
- /// let d = VariantDecimal4::try_new(123, 2).unwrap();
- /// let v3 = Variant::from(d);
- /// assert_eq!(v3.as_u8(), Some(1));
- ///
- /// // or from boolean variant
- /// let v4 = Variant::BooleanFalse;
- /// assert_eq!(v4.as_u8(), Some(0));
+ /// // or from a decimal variant that unscaled integer is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_u8(), Some(1u8));
///
/// // but not a variant that can't fit into the range
- /// let v5 = Variant::from(-1);
- /// assert_eq!(v5.as_u8(), None);
+ /// let d = VariantDecimal4::try_new(-1, 0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_u8(), None);
///
/// // or not a variant that cannot be cast into an integer
- /// let v6 = Variant::from("hello!");
- /// assert_eq!(v6.as_u8(), None);
+ /// let v5 = Variant::from("hello");
+ /// assert_eq!(v5.as_u8(), None);
/// ```
pub fn as_u8(&self) -> Option<u8> {
- self.as_num()
+ Self::convert_to_unsigned_num(self)
}
/// Converts this variant to an `u16` if possible.
///
- /// Returns `Some(u16)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `u16` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(u16)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `u16`, `None` for other variants or values that would
overflow.
Review Comment:
```suggestion
/// Returns `Some(u16)` for int variants and for decimal variants with
no fractional part
/// (scale = 0, or unscaled integer divisible by 10^scale) that fit in
the `u16` range.
/// `None` for other variants or values that would overflow.
```
##########
parquet-variant/src/variant.rs:
##########
@@ -1073,134 +1048,107 @@ impl<'m, 'v> Variant<'m, 'v> {
/// let v1 = Variant::from(123i64);
/// assert_eq!(v1.as_u16(), Some(123u16));
///
- /// // or a Decimal4 with scale 0 into u8
- /// let d = VariantDecimal4::try_new(u16::MAX as i32, 0).unwrap();
- /// let v2 = Variant::from(d);
- /// assert_eq!(v2.as_u16(), Some(u16::MAX));
- ///
- /// // or a variant that decimal with scale not equal to zero
- /// let d = VariantDecimal4::try_new(123, 2).unwrap();
- /// let v3 = Variant::from(d);
- /// assert_eq!(v3.as_u16(), Some(1));
+ /// // or from decimal variant that scale = 0
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v2 = Variant::from(d);
+ /// assert_eq!(v2.as_u16(), Some(123u16));
///
- /// // or from boolean variant
- /// let v4= Variant::BooleanFalse;
- /// assert_eq!(v4.as_u16(), Some(0));
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_u16(), Some(1u16));
///
/// // but not a variant that can't fit into the range
- /// let v5 = Variant::from(-1);
- /// assert_eq!(v5.as_u16(), None);
+ /// let d = VariantDecimal4::try_new(-1, 0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_u16(), None);
///
/// // or not a variant that cannot be cast into an integer
- /// let v6 = Variant::from("hello!");
- /// assert_eq!(v6.as_u16(), None);
+ /// let v5 = Variant::from("hello");
+ /// assert_eq!(v5.as_u16(), None);
/// ```
pub fn as_u16(&self) -> Option<u16> {
- self.as_num()
+ Self::convert_to_unsigned_num(self)
}
/// Converts this variant to an `u32` if possible.
///
- /// Returns `Some(u32)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `u32` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(u32)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `u32`, `None` for other variants or values that would
overflow.
Review Comment:
```suggestion
/// Returns `Some(u32)` for int variants and for decimal variants with
no fractional part
/// (scale = 0, or unscaled integer divisible by 10^scale) that fit in
the `u32` range.
/// `None` for other variants or values that would overflow.
```
##########
parquet-variant/src/variant/decimal.rs:
##########
@@ -104,6 +104,11 @@ pub trait VariantDecimalType: Into<super::Variant<'static,
'static>> {
/// Returns the scale (number of digits after the decimal point)
fn scale(&self) -> u8;
+
+ /// Converts the decimal as an integer if possible,
+ /// Return Some(integer value) if scale is 0 or the unscaled integer is
divisible by 10^scale.
+ /// None for other values.
Review Comment:
```suggestion
/// Converts the decimal to an integer if possible.
///
/// Returns `Some(integer)` if scale is 0 or the unscaled integer is
divisible by 10^scale,
/// `None` for other values.
```
##########
parquet-variant/src/variant.rs:
##########
@@ -837,191 +794,213 @@ impl<'m, 'v> Variant<'m, 'v> {
}
}
- fn cast_decimal_to_num<D, T, F>(raw: D::Native, scale: u8, as_float: F) ->
Option<T>
- where
- D: DecimalType,
- D::Native: NumCast + ArrowNativeTypeOp,
- T: DecimalCastTarget,
- F: Fn(D::Native) -> f64,
- {
- let base: D::Native = NumCast::from(10)?;
-
- let div = base.pow_checked(<u32 as From<u8>>::from(scale)).ok()?;
- match T::KIND {
- NumericKind::Integer => raw
- .div_checked(div)
- .ok()
- .and_then(<T as NumCast>::from::<D::Native>),
- NumericKind::Float => T::from(single_decimal_to_float_lossy::<D,
_>(
- &as_float,
- raw,
- <i32 as From<u8>>::from(scale),
- )),
- }
- }
-
- /// Converts a boolean or numeric variant(integers, floating-point, and
decimals)
- /// to the specified numeric type `T`.
- ///
- /// Uses Arrow's casting logic to perform the conversion. Returns
`Some(T)` if
- /// the conversion succeeds, `None` if the variant can't be casted to type
`T`.
- fn as_num<T>(&self) -> Option<T>
- where
- T: DecimalCastTarget,
- {
- match *self {
- Variant::BooleanFalse => single_bool_to_numeric(false),
- Variant::BooleanTrue => single_bool_to_numeric(true),
- Variant::Int8(i) => num_cast(i),
- Variant::Int16(i) => num_cast(i),
- Variant::Int32(i) => num_cast(i),
- Variant::Int64(i) => num_cast(i),
- Variant::Float(f) => num_cast(f),
- Variant::Double(d) => num_cast(d),
- Variant::Decimal4(d) => {
- Self::cast_decimal_to_num::<Decimal32Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- Variant::Decimal8(d) => {
- Self::cast_decimal_to_num::<Decimal64Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- Variant::Decimal16(d) => {
- Self::cast_decimal_to_num::<Decimal128Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- _ => None,
- }
- }
-
/// Converts this variant to an `i8` if possible.
///
- /// Returns `Some(i8)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i8` range,
- /// `None` for other variants or values that would overflow.
- ///
+ /// Returns `Some(i8)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i8` range, `None` for other variants or values that
would overflow.
/// # Examples
///
/// ```
- /// use parquet_variant::Variant;
+ /// use parquet_variant::{Variant, VariantDecimal4};
///
/// // you can read an int64 variant into an i8 if it fits
/// let v1 = Variant::from(123i64);
/// assert_eq!(v1.as_int8(), Some(123i8));
///
- /// // or from boolean variant
- /// let v2 = Variant::BooleanFalse;
- /// assert_eq!(v2.as_int8(), Some(0));
+ /// // or from a decimal variant with scale = 0 that fits in i8 range
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v2 = Variant::from(d);
+ /// assert_eq!(v2.as_int8(), Some(123i8));
+ ///
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_int8(), Some(1i8));
///
/// // but not if it would overflow
- /// let v3 = Variant::from(1234i64);
- /// assert_eq!(v3.as_int8(), None);
+ /// let d = VariantDecimal4::try_new(1234i32, 0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_int8(), None);
///
/// // or if the variant cannot be cast into an integer
- /// let v4 = Variant::from("hello!");
- /// assert_eq!(v4.as_int8(), None);
+ /// let v5 = Variant::from("hello");
+ /// assert_eq!(v5.as_int8(), None);
/// ```
pub fn as_int8(&self) -> Option<i8> {
- self.as_num()
+ match *self {
+ Variant::Int8(i) => Some(i),
+ Variant::Int16(i) => i.try_into().ok(),
+ Variant::Int32(i) => i.try_into().ok(),
+ Variant::Int64(i) => i.try_into().ok(),
+ Variant::Decimal4(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal8(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal16(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ _ => None,
+ }
}
/// Converts this variant to an `i16` if possible.
///
- /// Returns `Some(i16)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i16` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(i16)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i16` range, `None` for other variants or values that
would overflow.
///
/// # Examples
///
/// ```
- /// use parquet_variant::Variant;
+ /// use parquet_variant::{Variant, VariantDecimal4};
///
/// // you can read an int64 variant into an i16 if it fits
/// let v1 = Variant::from(123i64);
/// assert_eq!(v1.as_int16(), Some(123i16));
///
- /// // or from boolean variant
- /// let v2 = Variant::BooleanFalse;
- /// assert_eq!(v2.as_int16(), Some(0));
+ /// // or from a decimal variant that scale = 0
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v2 = Variant::from(d);
+ /// assert_eq!(v2.as_int16(), Some(123i16));
+ ///
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_int16(), Some(1i16));
///
/// // but not if it would overflow
- /// let v3 = Variant::from(123456i64);
- /// assert_eq!(v3.as_int16(), None);
+ /// let d = VariantDecimal4::try_new(123456i32, 0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_int16(), None);
///
/// // or if the variant cannot be cast into an integer
- /// let v4 = Variant::from("hello!");
- /// assert_eq!(v4.as_int16(), None);
+ /// let v5 = Variant::from("hello");
+ /// assert_eq!(v5.as_int16(), None);
/// ```
pub fn as_int16(&self) -> Option<i16> {
- self.as_num()
+ match *self {
+ Variant::Int8(i) => Some(i as i16),
+ Variant::Int16(i) => Some(i),
+ Variant::Int32(i) => i.try_into().ok(),
+ Variant::Int64(i) => i.try_into().ok(),
+ Variant::Decimal4(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal8(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal16(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ _ => None,
+ }
}
/// Converts this variant to an `i32` if possible.
///
- /// Returns `Some(i32)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i32` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(i32)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i32` range, `None` for other variants or values that
would overflow.
///
/// # Examples
///
/// ```
- /// use parquet_variant::Variant;
+ /// use parquet_variant::{Variant, VariantDecimal4, VariantDecimal8};
///
- /// // you can read an int64 variant into an i32 if it fits
- /// let v1 = Variant::from(123i64);
+ /// // you can read an int32 variant into an i32
+ /// let v1 = Variant::from(123i32);
/// assert_eq!(v1.as_int32(), Some(123i32));
///
- /// // or from boolean variant
- /// let v2 = Variant::BooleanFalse;
- /// assert_eq!(v2.as_int32(), Some(0));
+ /// // or from an int64 if it fits
+ /// let v2 = Variant::from(1231i64);
+ /// assert_eq!(v2.as_int32(), Some(1231i32));
+ ///
+ /// // or from decimal variant that scale=0
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_int32(), Some(123i32));
+ ///
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_int32(), Some(1i32));
///
/// // but not if it would overflow
- /// let v3 = Variant::from(12345678901i64);
- /// assert_eq!(v3.as_int32(), None);
+ /// let d = VariantDecimal8::try_new(1234567890123, 0).unwrap();
+ /// let v5 = Variant::from(d);
+ /// assert_eq!(v5.as_int32(), None);
///
/// // or if the variant cannot be cast into an integer
- /// let v4 = Variant::from("hello!");
- /// assert_eq!(v4.as_int32(), None);
+ /// let v6 = Variant::from("hello");
+ /// assert_eq!(v6.as_int32(), None)
/// ```
pub fn as_int32(&self) -> Option<i32> {
- self.as_num()
+ match *self {
+ Variant::Int8(i) => Some(i as i32),
+ Variant::Int16(i) => Some(i as i32),
+ Variant::Int32(i) => Some(i),
+ Variant::Int64(i) => i.try_into().ok(),
+ Variant::Decimal4(d) => d.as_integer(),
+ Variant::Decimal8(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal16(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ _ => None,
+ }
}
/// Converts this variant to an `i64` if possible.
///
- /// Returns `Some(i64)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i64` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(i64)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i64` range, `None` for other variants or values that
would overflow.
///
/// # Examples
///
/// ```
- /// use parquet_variant::Variant;
+ /// use parquet_variant::{Variant, VariantDecimal16, VariantDecimal4};
///
/// // you can read an int64 variant into an i64
/// let v1 = Variant::from(123i64);
/// assert_eq!(v1.as_int64(), Some(123i64));
///
- /// // or from boolean variant
- /// let v2 = Variant::BooleanFalse;
- /// assert_eq!(v2.as_int64(), Some(0));
+ /// // or from a decimal variant that scale = 0
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v2 = Variant::from(d);
+ /// assert_eq!(v2.as_int64(), Some(123i64));
///
- /// // but not a variant that cannot be cast into an integer
- /// let v3 = Variant::from("hello!");
- /// assert_eq!(v3.as_int64(), None);
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_int64(), Some(1i64));
+ ///
+ /// // but not if it would overflow
+ /// let d = VariantDecimal16::try_new(i128::from(i64::MAX) + 1,
0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_int64(), None);
+ ///
+ /// // or if the variant cannot be cast into an integer
+ /// let v4 = Variant::from("hello!");
+ /// assert_eq!(v4.as_int64(), None);
/// ```
pub fn as_int64(&self) -> Option<i64> {
- self.as_num()
+ match *self {
+ Variant::Int8(i) => Some(i as i64),
+ Variant::Int16(i) => Some(i as i64),
+ Variant::Int32(i) => Some(i as i64),
+ Variant::Int64(i) => Some(i),
+ Variant::Decimal4(d) => d.as_integer().map(|i| i as i64),
+ Variant::Decimal8(d) => d.as_integer(),
+ Variant::Decimal16(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ _ => None,
+ }
+ }
+
+ fn convert_to_unsigned_num<O>(variant: &Variant) -> Option<O>
+ where
+ O: TryFrom<i8> + TryFrom<i16> + TryFrom<i32> + TryFrom<i64> +
TryFrom<i128>,
+ {
+ match *variant {
+ Variant::Int8(i) => i.try_into().ok(),
+ Variant::Int16(i) => i.try_into().ok(),
+ Variant::Int32(i) => i.try_into().ok(),
+ Variant::Int64(i) => i.try_into().ok(),
+ Variant::Decimal4(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal8(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal16(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ _ => None,
+ }
}
/// Converts this variant to a `u8` if possible.
///
- /// Returns `Some(u8)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `u8` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(u8)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `u8`, `None` for other variants or values that would
overflow.
Review Comment:
```suggestion
/// Returns `Some(u8)` for int variants and for decimal variants with no
fractional part
/// (scale = 0, or unscaled integer divisible by 10^scale) that fit in
the `u8` range.
/// `None` for other variants or values that would overflow.
```
##########
parquet-variant/src/variant.rs:
##########
@@ -1073,134 +1048,107 @@ impl<'m, 'v> Variant<'m, 'v> {
/// let v1 = Variant::from(123i64);
/// assert_eq!(v1.as_u16(), Some(123u16));
///
- /// // or a Decimal4 with scale 0 into u8
- /// let d = VariantDecimal4::try_new(u16::MAX as i32, 0).unwrap();
- /// let v2 = Variant::from(d);
- /// assert_eq!(v2.as_u16(), Some(u16::MAX));
- ///
- /// // or a variant that decimal with scale not equal to zero
- /// let d = VariantDecimal4::try_new(123, 2).unwrap();
- /// let v3 = Variant::from(d);
- /// assert_eq!(v3.as_u16(), Some(1));
+ /// // or from decimal variant that scale = 0
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v2 = Variant::from(d);
+ /// assert_eq!(v2.as_u16(), Some(123u16));
///
- /// // or from boolean variant
- /// let v4= Variant::BooleanFalse;
- /// assert_eq!(v4.as_u16(), Some(0));
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_u16(), Some(1u16));
///
/// // but not a variant that can't fit into the range
- /// let v5 = Variant::from(-1);
- /// assert_eq!(v5.as_u16(), None);
+ /// let d = VariantDecimal4::try_new(-1, 0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_u16(), None);
///
/// // or not a variant that cannot be cast into an integer
- /// let v6 = Variant::from("hello!");
- /// assert_eq!(v6.as_u16(), None);
+ /// let v5 = Variant::from("hello");
+ /// assert_eq!(v5.as_u16(), None);
/// ```
pub fn as_u16(&self) -> Option<u16> {
- self.as_num()
+ Self::convert_to_unsigned_num(self)
}
/// Converts this variant to an `u32` if possible.
///
- /// Returns `Some(u32)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `u32` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(u32)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `u32`, `None` for other variants or values that would
overflow.
///
/// # Examples
///
/// ```
- /// use parquet_variant::{Variant, VariantDecimal8};
+ /// use parquet_variant::{Variant, VariantDecimal4, VariantDecimal8};
///
/// // you can read an int64 variant into an u32
/// let v1 = Variant::from(123i64);
/// assert_eq!(v1.as_u32(), Some(123u32));
///
- /// // or a Decimal4 with scale 0 into u8
- /// let d = VariantDecimal8::try_new(u32::MAX as i64, 0).unwrap();
+ /// // or from decimal variant that scale = 0
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
/// let v2 = Variant::from(d);
- /// assert_eq!(v2.as_u32(), Some(u32::MAX));
- ///
- /// // or a variant that decimal with scale not equal to zero
- /// let d = VariantDecimal8::try_new(123, 2).unwrap();
- /// let v3 = Variant::from(d);
- /// assert_eq!(v3.as_u32(), Some(1));
+ /// assert_eq!(v2.as_u32(), Some(123u32));
///
- /// // or from boolean variant
- /// let v4 = Variant::BooleanFalse;
- /// assert_eq!(v4.as_u32(), Some(0));
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_u32(), Some(1u32));
///
/// // but not a variant that can't fit into the range
- /// let v5 = Variant::from(-1);
- /// assert_eq!(v5.as_u32(), None);
+ /// let d = VariantDecimal4::try_new(-1, 0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_u32(), None);
///
/// // or not a variant that cannot be cast into an integer
- /// let v6 = Variant::from("hello!");
- /// assert_eq!(v6.as_u32(), None);
+ /// let v5 = Variant::from("hello");
+ /// assert_eq!(v5.as_u32(), None);
/// ```
pub fn as_u32(&self) -> Option<u32> {
- self.as_num()
+ Self::convert_to_unsigned_num(self)
}
/// Converts this variant to an `u64` if possible.
///
- /// Returns `Some(u64)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `u64` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(u64)` for integer variant, decimal variant has no
fractional part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `u64`, `None` for other variants or values that would
overflow.
Review Comment:
```suggestion
/// Returns `Some(u64)` for int variants and for decimal variants with
no fractional part
/// (scale = 0, or unscaled integer divisible by 10^scale) that fit in
the `u64` range.
/// `None` for other variants or values that would overflow.
```
##########
parquet-variant/src/variant.rs:
##########
@@ -837,191 +794,213 @@ impl<'m, 'v> Variant<'m, 'v> {
}
}
- fn cast_decimal_to_num<D, T, F>(raw: D::Native, scale: u8, as_float: F) ->
Option<T>
- where
- D: DecimalType,
- D::Native: NumCast + ArrowNativeTypeOp,
- T: DecimalCastTarget,
- F: Fn(D::Native) -> f64,
- {
- let base: D::Native = NumCast::from(10)?;
-
- let div = base.pow_checked(<u32 as From<u8>>::from(scale)).ok()?;
- match T::KIND {
- NumericKind::Integer => raw
- .div_checked(div)
- .ok()
- .and_then(<T as NumCast>::from::<D::Native>),
- NumericKind::Float => T::from(single_decimal_to_float_lossy::<D,
_>(
- &as_float,
- raw,
- <i32 as From<u8>>::from(scale),
- )),
- }
- }
-
- /// Converts a boolean or numeric variant(integers, floating-point, and
decimals)
- /// to the specified numeric type `T`.
- ///
- /// Uses Arrow's casting logic to perform the conversion. Returns
`Some(T)` if
- /// the conversion succeeds, `None` if the variant can't be casted to type
`T`.
- fn as_num<T>(&self) -> Option<T>
- where
- T: DecimalCastTarget,
- {
- match *self {
- Variant::BooleanFalse => single_bool_to_numeric(false),
- Variant::BooleanTrue => single_bool_to_numeric(true),
- Variant::Int8(i) => num_cast(i),
- Variant::Int16(i) => num_cast(i),
- Variant::Int32(i) => num_cast(i),
- Variant::Int64(i) => num_cast(i),
- Variant::Float(f) => num_cast(f),
- Variant::Double(d) => num_cast(d),
- Variant::Decimal4(d) => {
- Self::cast_decimal_to_num::<Decimal32Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- Variant::Decimal8(d) => {
- Self::cast_decimal_to_num::<Decimal64Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- Variant::Decimal16(d) => {
- Self::cast_decimal_to_num::<Decimal128Type, T, _>(d.integer(),
d.scale(), |x| {
- x as f64
- })
- }
- _ => None,
- }
- }
-
/// Converts this variant to an `i8` if possible.
///
- /// Returns `Some(i8)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i8` range,
- /// `None` for other variants or values that would overflow.
- ///
+ /// Returns `Some(i8)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i8` range, `None` for other variants or values that
would overflow.
/// # Examples
///
/// ```
- /// use parquet_variant::Variant;
+ /// use parquet_variant::{Variant, VariantDecimal4};
///
/// // you can read an int64 variant into an i8 if it fits
/// let v1 = Variant::from(123i64);
/// assert_eq!(v1.as_int8(), Some(123i8));
///
- /// // or from boolean variant
- /// let v2 = Variant::BooleanFalse;
- /// assert_eq!(v2.as_int8(), Some(0));
+ /// // or from a decimal variant with scale = 0 that fits in i8 range
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v2 = Variant::from(d);
+ /// assert_eq!(v2.as_int8(), Some(123i8));
+ ///
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_int8(), Some(1i8));
///
/// // but not if it would overflow
- /// let v3 = Variant::from(1234i64);
- /// assert_eq!(v3.as_int8(), None);
+ /// let d = VariantDecimal4::try_new(1234i32, 0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_int8(), None);
///
/// // or if the variant cannot be cast into an integer
- /// let v4 = Variant::from("hello!");
- /// assert_eq!(v4.as_int8(), None);
+ /// let v5 = Variant::from("hello");
+ /// assert_eq!(v5.as_int8(), None);
/// ```
pub fn as_int8(&self) -> Option<i8> {
- self.as_num()
+ match *self {
+ Variant::Int8(i) => Some(i),
+ Variant::Int16(i) => i.try_into().ok(),
+ Variant::Int32(i) => i.try_into().ok(),
+ Variant::Int64(i) => i.try_into().ok(),
+ Variant::Decimal4(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal8(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal16(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ _ => None,
+ }
}
/// Converts this variant to an `i16` if possible.
///
- /// Returns `Some(i16)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i16` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(i16)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i16` range, `None` for other variants or values that
would overflow.
///
/// # Examples
///
/// ```
- /// use parquet_variant::Variant;
+ /// use parquet_variant::{Variant, VariantDecimal4};
///
/// // you can read an int64 variant into an i16 if it fits
/// let v1 = Variant::from(123i64);
/// assert_eq!(v1.as_int16(), Some(123i16));
///
- /// // or from boolean variant
- /// let v2 = Variant::BooleanFalse;
- /// assert_eq!(v2.as_int16(), Some(0));
+ /// // or from a decimal variant that scale = 0
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v2 = Variant::from(d);
+ /// assert_eq!(v2.as_int16(), Some(123i16));
+ ///
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_int16(), Some(1i16));
///
/// // but not if it would overflow
- /// let v3 = Variant::from(123456i64);
- /// assert_eq!(v3.as_int16(), None);
+ /// let d = VariantDecimal4::try_new(123456i32, 0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_int16(), None);
///
/// // or if the variant cannot be cast into an integer
- /// let v4 = Variant::from("hello!");
- /// assert_eq!(v4.as_int16(), None);
+ /// let v5 = Variant::from("hello");
+ /// assert_eq!(v5.as_int16(), None);
/// ```
pub fn as_int16(&self) -> Option<i16> {
- self.as_num()
+ match *self {
+ Variant::Int8(i) => Some(i as i16),
+ Variant::Int16(i) => Some(i),
+ Variant::Int32(i) => i.try_into().ok(),
+ Variant::Int64(i) => i.try_into().ok(),
+ Variant::Decimal4(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal8(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal16(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ _ => None,
+ }
}
/// Converts this variant to an `i32` if possible.
///
- /// Returns `Some(i32)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i32` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(i32)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i32` range, `None` for other variants or values that
would overflow.
///
/// # Examples
///
/// ```
- /// use parquet_variant::Variant;
+ /// use parquet_variant::{Variant, VariantDecimal4, VariantDecimal8};
///
- /// // you can read an int64 variant into an i32 if it fits
- /// let v1 = Variant::from(123i64);
+ /// // you can read an int32 variant into an i32
+ /// let v1 = Variant::from(123i32);
/// assert_eq!(v1.as_int32(), Some(123i32));
///
- /// // or from boolean variant
- /// let v2 = Variant::BooleanFalse;
- /// assert_eq!(v2.as_int32(), Some(0));
+ /// // or from an int64 if it fits
+ /// let v2 = Variant::from(1231i64);
+ /// assert_eq!(v2.as_int32(), Some(1231i32));
+ ///
+ /// // or from decimal variant that scale=0
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_int32(), Some(123i32));
+ ///
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_int32(), Some(1i32));
///
/// // but not if it would overflow
- /// let v3 = Variant::from(12345678901i64);
- /// assert_eq!(v3.as_int32(), None);
+ /// let d = VariantDecimal8::try_new(1234567890123, 0).unwrap();
+ /// let v5 = Variant::from(d);
+ /// assert_eq!(v5.as_int32(), None);
///
/// // or if the variant cannot be cast into an integer
- /// let v4 = Variant::from("hello!");
- /// assert_eq!(v4.as_int32(), None);
+ /// let v6 = Variant::from("hello");
+ /// assert_eq!(v6.as_int32(), None)
/// ```
pub fn as_int32(&self) -> Option<i32> {
- self.as_num()
+ match *self {
+ Variant::Int8(i) => Some(i as i32),
+ Variant::Int16(i) => Some(i as i32),
+ Variant::Int32(i) => Some(i),
+ Variant::Int64(i) => i.try_into().ok(),
+ Variant::Decimal4(d) => d.as_integer(),
+ Variant::Decimal8(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ Variant::Decimal16(d) => d.as_integer().and_then(|i|
i.try_into().ok()),
+ _ => None,
+ }
}
/// Converts this variant to an `i64` if possible.
///
- /// Returns `Some(i64)` for boolean and numeric variants(integers,
floating-point,
- /// and decimals with scale 0) that fit in `i64` range
- /// `None` for other variants or values that would overflow.
+ /// Returns `Some(i64)` for int variant, decimal variant has no fractional
part(scale=0 or unscaled integer is divisible by 10^scale)
+ /// that fits in `i64` range, `None` for other variants or values that
would overflow.
///
/// # Examples
///
/// ```
- /// use parquet_variant::Variant;
+ /// use parquet_variant::{Variant, VariantDecimal16, VariantDecimal4};
///
/// // you can read an int64 variant into an i64
/// let v1 = Variant::from(123i64);
/// assert_eq!(v1.as_int64(), Some(123i64));
///
- /// // or from boolean variant
- /// let v2 = Variant::BooleanFalse;
- /// assert_eq!(v2.as_int64(), Some(0));
+ /// // or from a decimal variant that scale = 0
+ /// let d = VariantDecimal4::try_new(123, 0).unwrap();
+ /// let v2 = Variant::from(d);
+ /// assert_eq!(v2.as_int64(), Some(123i64));
///
- /// // but not a variant that cannot be cast into an integer
- /// let v3 = Variant::from("hello!");
- /// assert_eq!(v3.as_int64(), None);
+ /// // or from a decimal variant that unscaled value is divisible by
10^scale
+ /// let d = VariantDecimal4::try_new(100, 2).unwrap();
+ /// let v3 = Variant::from(d);
+ /// assert_eq!(v3.as_int64(), Some(1i64));
+ ///
+ /// // but not if it would overflow
+ /// let d = VariantDecimal16::try_new(i128::from(i64::MAX) + 1,
0).unwrap();
+ /// let v4 = Variant::from(d);
+ /// assert_eq!(v4.as_int64(), None);
+ ///
+ /// // or if the variant cannot be cast into an integer
+ /// let v4 = Variant::from("hello!");
+ /// assert_eq!(v4.as_int64(), None);
Review Comment:
Nit: reuses `v4`.
```suggestion
/// let v5 = Variant::from("hello!");
/// assert_eq!(v5.as_int64(), None);
```
--
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]