@@ -76,14 +76,14 @@ pub struct UtcOffset {
7676impl Hash for UtcOffset {
7777 #[ inline]
7878 fn hash < H : Hasher > ( & self , state : & mut H ) {
79- state. write_u32 ( self . as_u32 ( ) ) ;
79+ state. write_u32 ( self . as_u32_for_equality ( ) ) ;
8080 }
8181}
8282
8383impl PartialEq for UtcOffset {
8484 #[ inline]
8585 fn eq ( & self , other : & Self ) -> bool {
86- self . as_u32 ( ) . eq ( & other. as_u32 ( ) )
86+ self . as_u32_for_equality ( ) . eq ( & other. as_u32_for_equality ( ) )
8787 }
8888}
8989
@@ -97,30 +97,45 @@ impl PartialOrd for UtcOffset {
9797impl Ord for UtcOffset {
9898 #[ inline]
9999 fn cmp ( & self , other : & Self ) -> Ordering {
100- self . as_u32 ( ) . cmp ( & other. as_u32 ( ) )
100+ self . as_i32_for_comparison ( )
101+ . cmp ( & other. as_i32_for_comparison ( ) )
101102 }
102103}
103104
104105impl UtcOffset {
105- /// Provide a representation of the `UtcOffset` as a `u32`. This value can be used for equality,
106- /// hashing, and ordering.
107- #[ inline]
108- pub ( crate ) const fn as_u32 ( self ) -> u32 {
109- #[ cfg( target_endian = "big" ) ]
110- return u32:: from_be_bytes ( [
111- self . seconds . get ( ) . cast_unsigned ( ) ,
112- self . minutes . get ( ) . cast_unsigned ( ) ,
113- self . hours . get ( ) . cast_unsigned ( ) ,
114- 0 ,
115- ] ) ;
116-
117- #[ cfg( target_endian = "little" ) ]
118- return u32:: from_le_bytes ( [
119- self . seconds . get ( ) . cast_unsigned ( ) ,
120- self . minutes . get ( ) . cast_unsigned ( ) ,
121- self . hours . get ( ) . cast_unsigned ( ) ,
122- 0 ,
123- ] ) ;
106+ /// Provide a representation of the `UtcOffset` as a `i32`. This value can be used for equality,
107+ /// and hashing. This value is not suitable for ordering; use `as_i32_for_comparison` instead.
108+ #[ inline]
109+ pub ( crate ) const fn as_u32_for_equality ( self ) -> u32 {
110+ // Safety: Size and alignment are handled by the compiler. Both the source and destination
111+ // types are plain old data (POD) types.
112+ unsafe {
113+ if const { cfg ! ( target_endian = "little" ) } {
114+ core:: mem:: transmute :: < [ i8 ; 4 ] , u32 > ( [
115+ self . seconds . get ( ) ,
116+ self . minutes . get ( ) ,
117+ self . hours . get ( ) ,
118+ 0 ,
119+ ] )
120+ } else {
121+ core:: mem:: transmute :: < [ i8 ; 4 ] , u32 > ( [
122+ self . hours . get ( ) ,
123+ self . minutes . get ( ) ,
124+ self . seconds . get ( ) ,
125+ 0 ,
126+ ] )
127+ }
128+ }
129+ }
130+
131+ /// Provide a representation of the `UtcOffset` as a `i32`. This value can be used for ordering.
132+ /// While it is suitable for equality, `as_u32_for_equality` is preferred for performance
133+ /// reasons.
134+ #[ inline]
135+ const fn as_i32_for_comparison ( self ) -> i32 {
136+ ( self . hours . get ( ) as i32 ) << 16
137+ | ( self . minutes . get ( ) as i32 ) << 8
138+ | ( self . seconds . get ( ) as i32 )
124139 }
125140
126141 /// A `UtcOffset` that is UTC.
@@ -381,7 +396,7 @@ impl UtcOffset {
381396 /// ```
382397 #[ inline]
383398 pub const fn is_utc ( self ) -> bool {
384- self . hours . get ( ) == 0 && self . minutes . get ( ) == 0 && self . seconds . get ( ) == 0
399+ self . as_u32_for_equality ( ) == Self :: UTC . as_u32_for_equality ( )
385400 }
386401
387402 /// Check if the offset is positive, or east of UTC.
@@ -394,7 +409,7 @@ impl UtcOffset {
394409 /// ```
395410 #[ inline]
396411 pub const fn is_positive ( self ) -> bool {
397- self . hours . get ( ) > 0 || self . minutes . get ( ) > 0 || self . seconds . get ( ) > 0
412+ self . as_i32_for_comparison ( ) > Self :: UTC . as_i32_for_comparison ( )
398413 }
399414
400415 /// Check if the offset is negative, or west of UTC.
@@ -407,7 +422,7 @@ impl UtcOffset {
407422 /// ```
408423 #[ inline]
409424 pub const fn is_negative ( self ) -> bool {
410- self . hours . get ( ) < 0 || self . minutes . get ( ) < 0 || self . seconds . get ( ) < 0
425+ self . as_i32_for_comparison ( ) < Self :: UTC . as_i32_for_comparison ( )
411426 }
412427
413428 /// Attempt to obtain the system's UTC offset at a known moment in time. If the offset cannot be
0 commit comments