Skip to content

Commit cd676cd

Browse files
authored
[Variant] Add as_u* for Variant (#8284)
# Which issue does this PR close? - Closes #8283. # Rationale for this change Add the `Variant::as_u*` functions` # Are these changes tested? Added doc tests # Are there any user-facing changes? No
1 parent bffad59 commit cd676cd

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed

parquet-variant/src/variant.rs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,166 @@ impl<'m, 'v> Variant<'m, 'v> {
805805
}
806806
}
807807

808+
fn generic_convert_unsigned_primitive<T>(&self) -> Option<T>
809+
where
810+
T: TryFrom<i8> + TryFrom<i16> + TryFrom<i32> + TryFrom<i64> + TryFrom<i128>,
811+
{
812+
match *self {
813+
Variant::Int8(i) => i.try_into().ok(),
814+
Variant::Int16(i) => i.try_into().ok(),
815+
Variant::Int32(i) => i.try_into().ok(),
816+
Variant::Int64(i) => i.try_into().ok(),
817+
Variant::Decimal4(d) if d.scale() == 0 => d.integer().try_into().ok(),
818+
Variant::Decimal8(d) if d.scale() == 0 => d.integer().try_into().ok(),
819+
Variant::Decimal16(d) if d.scale() == 0 => d.integer().try_into().ok(),
820+
_ => None,
821+
}
822+
}
823+
824+
/// Converts this variant to a `u8` if possible.
825+
///
826+
/// Returns `Some(u8)` for integer variants that fit in `u8`
827+
/// `None` for non-integer variants or values that would overflow.
828+
///
829+
/// # Examples
830+
///
831+
/// ```
832+
/// use parquet_variant::{Variant, VariantDecimal4};
833+
///
834+
/// // you can read an int64 variant into an u8
835+
/// let v1 = Variant::from(123i64);
836+
/// assert_eq!(v1.as_u8(), Some(123u8));
837+
///
838+
/// // or a Decimal4 with scale 0 into u8
839+
/// let d = VariantDecimal4::try_new(26, 0).unwrap();
840+
/// let v2 = Variant::from(d);
841+
/// assert_eq!(v2.as_u8(), Some(26u8));
842+
///
843+
/// // but not a variant that can't fit into the range
844+
/// let v3 = Variant::from(-1);
845+
/// assert_eq!(v3.as_u8(), None);
846+
///
847+
/// // not a variant that decimal with scale not equal to zero
848+
/// let d = VariantDecimal4::try_new(1, 2).unwrap();
849+
/// let v4 = Variant::from(d);
850+
/// assert_eq!(v4.as_u8(), None);
851+
///
852+
/// // or not a variant that cannot be cast into an integer
853+
/// let v5 = Variant::from("hello!");
854+
/// assert_eq!(v5.as_u8(), None);
855+
/// ```
856+
pub fn as_u8(&self) -> Option<u8> {
857+
self.generic_convert_unsigned_primitive::<u8>()
858+
}
859+
860+
/// Converts this variant to an `u16` if possible.
861+
///
862+
/// Returns `Some(u16)` for integer variants that fit in `u16`
863+
/// `None` for non-integer variants or values that would overflow.
864+
///
865+
/// # Examples
866+
///
867+
/// ```
868+
/// use parquet_variant::{Variant, VariantDecimal4};
869+
///
870+
/// // you can read an int64 variant into an u16
871+
/// let v1 = Variant::from(123i64);
872+
/// assert_eq!(v1.as_u16(), Some(123u16));
873+
///
874+
/// // or a Decimal4 with scale 0 into u8
875+
/// let d = VariantDecimal4::try_new(u16::MAX as i32, 0).unwrap();
876+
/// let v2 = Variant::from(d);
877+
/// assert_eq!(v2.as_u16(), Some(u16::MAX));
878+
///
879+
/// // but not a variant that can't fit into the range
880+
/// let v3 = Variant::from(-1);
881+
/// assert_eq!(v3.as_u16(), None);
882+
///
883+
/// // not a variant that decimal with scale not equal to zero
884+
/// let d = VariantDecimal4::try_new(1, 2).unwrap();
885+
/// let v4 = Variant::from(d);
886+
/// assert_eq!(v4.as_u16(), None);
887+
///
888+
/// // or not a variant that cannot be cast into an integer
889+
/// let v5 = Variant::from("hello!");
890+
/// assert_eq!(v5.as_u16(), None);
891+
/// ```
892+
pub fn as_u16(&self) -> Option<u16> {
893+
self.generic_convert_unsigned_primitive::<u16>()
894+
}
895+
896+
/// Converts this variant to an `u32` if possible.
897+
///
898+
/// Returns `Some(u32)` for integer variants that fit in `u32`
899+
/// `None` for non-integer variants or values that would overflow.
900+
///
901+
/// # Examples
902+
///
903+
/// ```
904+
/// use parquet_variant::{Variant, VariantDecimal8};
905+
///
906+
/// // you can read an int64 variant into an u32
907+
/// let v1 = Variant::from(123i64);
908+
/// assert_eq!(v1.as_u32(), Some(123u32));
909+
///
910+
/// // or a Decimal4 with scale 0 into u8
911+
/// let d = VariantDecimal8::try_new(u32::MAX as i64, 0).unwrap();
912+
/// let v2 = Variant::from(d);
913+
/// assert_eq!(v2.as_u32(), Some(u32::MAX));
914+
///
915+
/// // but not a variant that can't fit into the range
916+
/// let v3 = Variant::from(-1);
917+
/// assert_eq!(v3.as_u32(), None);
918+
///
919+
/// // not a variant that decimal with scale not equal to zero
920+
/// let d = VariantDecimal8::try_new(1, 2).unwrap();
921+
/// let v4 = Variant::from(d);
922+
/// assert_eq!(v4.as_u32(), None);
923+
///
924+
/// // or not a variant that cannot be cast into an integer
925+
/// let v5 = Variant::from("hello!");
926+
/// assert_eq!(v5.as_u32(), None);
927+
/// ```
928+
pub fn as_u32(&self) -> Option<u32> {
929+
self.generic_convert_unsigned_primitive::<u32>()
930+
}
931+
932+
/// Converts this variant to an `u64` if possible.
933+
///
934+
/// Returns `Some(u64)` for integer variants that fit in `u64`
935+
/// `None` for non-integer variants or values that would overflow.
936+
///
937+
/// # Examples
938+
///
939+
/// ```
940+
/// use parquet_variant::{Variant, VariantDecimal16};
941+
///
942+
/// // you can read an int64 variant into an u64
943+
/// let v1 = Variant::from(123i64);
944+
/// assert_eq!(v1.as_u64(), Some(123u64));
945+
///
946+
/// // or a Decimal16 with scale 0 into u8
947+
/// let d = VariantDecimal16::try_new(u64::MAX as i128, 0).unwrap();
948+
/// let v2 = Variant::from(d);
949+
/// assert_eq!(v2.as_u64(), Some(u64::MAX));
950+
///
951+
/// // but not a variant that can't fit into the range
952+
/// let v3 = Variant::from(-1);
953+
/// assert_eq!(v3.as_u64(), None);
954+
///
955+
/// // not a variant that decimal with scale not equal to zero
956+
/// let d = VariantDecimal16::try_new(1, 2).unwrap();
957+
/// let v4 = Variant::from(d);
958+
/// assert_eq!(v4.as_u64(), None);
959+
///
960+
/// // or not a variant that cannot be cast into an integer
961+
/// let v5 = Variant::from("hello!");
962+
/// assert_eq!(v5.as_u64(), None);
963+
/// ```
964+
pub fn as_u64(&self) -> Option<u64> {
965+
self.generic_convert_unsigned_primitive::<u64>()
966+
}
967+
808968
/// Converts this variant to tuple with a 4-byte unscaled value if possible.
809969
///
810970
/// Returns `Some((i32, u8))` for decimal variants where the unscaled value

0 commit comments

Comments
 (0)