33
44use std:: fmt:: Display ;
55use std:: fmt:: Formatter ;
6+ use std:: hash:: Hash ;
7+ use std:: hash:: Hasher ;
68use std:: sync:: Arc ;
79
810use DType :: * ;
@@ -120,21 +122,9 @@ impl DType {
120122 lhs_size == rhs_size && lhs_dtype. eq_ignore_nullability ( rhs_dtype)
121123 }
122124 ( Struct ( lhs_dtype, _) , Struct ( rhs_dtype, _) ) => {
123- ( lhs_dtype. names ( ) == rhs_dtype. names ( ) )
124- && ( lhs_dtype
125- . fields ( )
126- . zip_eq ( rhs_dtype. fields ( ) )
127- . all ( |( l, r) | l. eq_ignore_nullability ( & r) ) )
128- }
129- ( Union ( lhs, _) , Union ( rhs, _) ) => {
130- // Equal `names` implies equal length by FieldNames equality.
131- lhs. names ( ) == rhs. names ( )
132- && lhs. type_ids ( ) == rhs. type_ids ( )
133- && lhs
134- . variants ( )
135- . zip_eq ( rhs. variants ( ) )
136- . all ( |( l, r) | l. eq_ignore_nullability ( & r) )
125+ lhs_dtype. eq_ignore_nullability ( rhs_dtype)
137126 }
127+ ( Union ( lhs, _) , Union ( rhs, _) ) => lhs. eq_ignore_nullability ( rhs) ,
138128 ( Variant ( _) , Variant ( _) ) => true ,
139129 ( Extension ( lhs_extdtype) , Extension ( rhs_extdtype) ) => {
140130 lhs_extdtype. eq_ignore_nullability ( rhs_extdtype)
@@ -143,6 +133,25 @@ impl DType {
143133 }
144134 }
145135
136+ /// Hash this dtype using the same equivalence relation as [`Self::eq_ignore_nullability`].
137+ pub ( crate ) fn hash_ignore_nullability < H : Hasher > ( & self , state : & mut H ) {
138+ std:: mem:: discriminant ( self ) . hash ( state) ;
139+
140+ match self {
141+ Null | Bool ( _) | Utf8 ( _) | Binary ( _) | Variant ( _) => { }
142+ Primitive ( ptype, _) => ptype. hash ( state) ,
143+ Decimal ( decimal, _) => decimal. hash ( state) ,
144+ List ( element, _) => element. hash_ignore_nullability ( state) ,
145+ FixedSizeList ( element, size, _) => {
146+ element. hash_ignore_nullability ( state) ;
147+ size. hash ( state) ;
148+ }
149+ Struct ( fields, _) => fields. hash_ignore_nullability ( state) ,
150+ Union ( variants, _) => variants. hash_ignore_nullability ( state) ,
151+ Extension ( ext) => ext. hash_ignore_nullability ( state) ,
152+ }
153+ }
154+
146155 /// Returns `true` if `self` is a subset type of `other, otherwise `false`.
147156 ///
148157 /// If `self` is nullable, this means that the other `DType` must also be nullable (since a
@@ -514,18 +523,29 @@ impl Display for DType {
514523
515524#[ cfg( test) ]
516525mod tests {
526+ use std:: collections:: hash_map:: DefaultHasher ;
527+ use std:: hash:: Hasher ;
517528 use std:: sync:: Arc ;
518529
530+ use vortex_error:: VortexResult ;
531+
519532 use crate :: dtype:: DType ;
520533 use crate :: dtype:: Nullability :: NonNullable ;
521534 use crate :: dtype:: Nullability :: Nullable ;
522535 use crate :: dtype:: PType ;
536+ use crate :: dtype:: UnionVariants ;
523537 use crate :: dtype:: decimal:: DecimalDType ;
524538 use crate :: extension:: datetime:: Date ;
525539 use crate :: extension:: datetime:: Time ;
526540 use crate :: extension:: datetime:: TimeUnit ;
527541 use crate :: extension:: datetime:: Timestamp ;
528542
543+ fn hash_ignore_nullability ( dtype : & DType ) -> u64 {
544+ let mut hasher = DefaultHasher :: new ( ) ;
545+ dtype. hash_ignore_nullability ( & mut hasher) ;
546+ hasher. finish ( )
547+ }
548+
529549 #[ test]
530550 fn test_ext_dtype_eq_ignore_nullability ( ) {
531551 let d1 = DType :: Extension ( Time :: new ( TimeUnit :: Seconds , Nullable ) . erased ( ) ) ;
@@ -541,6 +561,37 @@ mod tests {
541561 assert ! ( !t1. eq_ignore_nullability( & t2) ) ;
542562 }
543563
564+ #[ test]
565+ fn test_union_dtype_hash_ignores_variant_nullability ( ) -> VortexResult < ( ) > {
566+ let lhs = DType :: Union (
567+ UnionVariants :: try_new (
568+ [ "int" , "string" ] . into ( ) ,
569+ vec ! [
570+ DType :: Primitive ( PType :: I32 , Nullable ) ,
571+ DType :: Utf8 ( NonNullable ) ,
572+ ] ,
573+ vec ! [ 5 , 9 ] ,
574+ ) ?,
575+ NonNullable ,
576+ ) ;
577+ let rhs = DType :: Union (
578+ UnionVariants :: try_new (
579+ [ "int" , "string" ] . into ( ) ,
580+ vec ! [
581+ DType :: Primitive ( PType :: I32 , NonNullable ) ,
582+ DType :: Utf8 ( Nullable ) ,
583+ ] ,
584+ vec ! [ 5 , 9 ] ,
585+ ) ?,
586+ NonNullable ,
587+ ) ;
588+
589+ assert ! ( lhs. eq_ignore_nullability( & rhs) ) ;
590+ assert_eq ! ( hash_ignore_nullability( & lhs) , hash_ignore_nullability( & rhs) ) ;
591+
592+ Ok ( ( ) )
593+ }
594+
544595 #[ test]
545596 fn element_size_null ( ) {
546597 assert_eq ! ( DType :: Null . element_size( ) , Some ( 0 ) ) ;
0 commit comments