@@ -18,6 +18,7 @@ use std::fmt;
1818use std:: hash:: { Hash , Hasher } ;
1919use std:: marker:: PhantomData ;
2020use std:: mem;
21+ use std:: num:: NonZeroU64 ;
2122use std:: ops;
2223use std:: slice;
2324use std:: str;
@@ -110,8 +111,7 @@ impl StringCache {
110111 ptr
111112 }
112113
113- fn remove ( & mut self , key : u64 ) {
114- let ptr = key as * mut StringCacheEntry ;
114+ fn remove ( & mut self , ptr : * mut StringCacheEntry ) {
115115 let bucket_index = {
116116 let value: & StringCacheEntry = unsafe { & * ptr } ;
117117 debug_assert ! ( value. ref_count. load( SeqCst ) == 0 ) ;
@@ -236,7 +236,7 @@ pub type DefaultAtom = Atom<EmptyStaticAtomSet>;
236236#[ derive( PartialEq , Eq ) ]
237237// NOTE: Deriving PartialEq requires that a given string must always be interned the same way.
238238pub struct Atom < Static > {
239- unsafe_data : u64 ,
239+ unsafe_data : NonZeroU64 ,
240240 phantom : PhantomData < Static > ,
241241}
242242
@@ -266,7 +266,10 @@ impl<Static> Atom<Static> {
266266 #[ doc( hidden) ]
267267 pub const fn pack_static ( n : u32 ) -> Self {
268268 Self {
269- unsafe_data : ( STATIC_TAG as u64 ) | ( ( n as u64 ) << STATIC_SHIFT_BITS ) ,
269+ unsafe_data : unsafe {
270+ // STATIC_TAG ensure this is non-zero
271+ NonZeroU64 :: new_unchecked ( ( STATIC_TAG as u64 ) | ( ( n as u64 ) << STATIC_SHIFT_BITS ) )
272+ } ,
270273 phantom : PhantomData ,
271274 }
272275 }
@@ -281,7 +284,7 @@ impl<Static: StaticAtomSet> Atom<Static> {
281284 /// Return the internal repersentation. For testing.
282285 #[ doc( hidden) ]
283286 pub fn unsafe_data ( & self ) -> u64 {
284- self . unsafe_data
287+ self . unsafe_data . get ( )
285288 }
286289
287290 /// Return true if this is a static Atom. For testing.
@@ -322,7 +325,7 @@ impl<Static: StaticAtomSet> Atom<Static> {
322325 let entry = entry as * mut StringCacheEntry ;
323326 u64_hash_as_u32 ( unsafe { ( * entry) . hash } )
324327 }
325- Inline ( ..) => u64_hash_as_u32 ( self . unsafe_data ) ,
328+ Inline ( ..) => u64_hash_as_u32 ( self . unsafe_data . get ( ) ) ,
326329 }
327330 }
328331}
@@ -405,7 +408,7 @@ impl<Static: StaticAtomSet> Clone for Atom<Static> {
405408 #[ inline( always) ]
406409 fn clone ( & self ) -> Self {
407410 unsafe {
408- match from_packed_dynamic ( self . unsafe_data ) {
411+ match from_packed_dynamic ( self . unsafe_data . get ( ) ) {
409412 Some ( entry) => {
410413 let entry = entry as * mut StringCacheEntry ;
411414 ( * entry) . ref_count . fetch_add ( 1 , SeqCst ) ;
@@ -425,11 +428,14 @@ impl<Static> Drop for Atom<Static> {
425428 fn drop ( & mut self ) {
426429 // Out of line to guide inlining.
427430 fn drop_slow < Static > ( this : & mut Atom < Static > ) {
428- STRING_CACHE . lock ( ) . unwrap ( ) . remove ( this. unsafe_data ) ;
431+ STRING_CACHE
432+ . lock ( )
433+ . unwrap ( )
434+ . remove ( this. unsafe_data . get ( ) as * mut StringCacheEntry ) ;
429435 }
430436
431437 unsafe {
432- match from_packed_dynamic ( self . unsafe_data ) {
438+ match from_packed_dynamic ( self . unsafe_data . get ( ) ) {
433439 Some ( entry) => {
434440 let entry = entry as * mut StringCacheEntry ;
435441 if ( * entry) . ref_count . fetch_sub ( 1 , SeqCst ) == 1 {
@@ -608,9 +614,9 @@ enum UnpackedAtom {
608614}
609615
610616#[ inline( always) ]
611- fn inline_atom_slice ( x : & u64 ) -> & [ u8 ] {
617+ fn inline_atom_slice ( x : & NonZeroU64 ) -> & [ u8 ] {
612618 unsafe {
613- let x: * const u64 = x;
619+ let x: * const NonZeroU64 = x;
614620 let mut data = x as * const u8 ;
615621 // All except the lowest byte, which is first in little-endian, last in big-endian.
616622 if cfg ! ( target_endian = "little" ) {
@@ -643,22 +649,24 @@ impl UnpackedAtom {
643649 match self {
644650 Static ( n) => Atom :: pack_static ( n) ,
645651 Dynamic ( p) => {
646- let unsafe_data = p as u64 ;
647- debug_assert ! ( 0 == unsafe_data & TAG_MASK ) ;
652+ let data = p as u64 ;
653+ debug_assert ! ( 0 == data & TAG_MASK ) ;
648654 Atom {
649- unsafe_data,
655+ // Callers are responsible for calling this with a valid, non-null pointer
656+ unsafe_data : NonZeroU64 :: new_unchecked ( data) ,
650657 phantom : PhantomData ,
651658 }
652659 }
653660 Inline ( len, buf) => {
654661 debug_assert ! ( ( len as usize ) <= MAX_INLINE_LEN ) ;
655- let mut unsafe_data : u64 = ( INLINE_TAG as u64 ) | ( ( len as u64 ) << 4 ) ;
662+ let mut data : u64 = ( INLINE_TAG as u64 ) | ( ( len as u64 ) << 4 ) ;
656663 {
657- let dest = inline_atom_slice_mut ( & mut unsafe_data ) ;
664+ let dest = inline_atom_slice_mut ( & mut data ) ;
658665 dest. copy_from_slice ( & buf)
659666 }
660667 Atom {
661- unsafe_data,
668+ // INLINE_TAG ensures this is never zero
669+ unsafe_data : NonZeroU64 :: new_unchecked ( data) ,
662670 phantom : PhantomData ,
663671 }
664672 }
@@ -667,14 +675,14 @@ impl UnpackedAtom {
667675
668676 /// Unpack a key, extracting information from a single u64 into useable structs.
669677 #[ inline( always) ]
670- unsafe fn from_packed ( data : u64 ) -> UnpackedAtom {
678+ unsafe fn from_packed ( data : NonZeroU64 ) -> UnpackedAtom {
671679 debug_assert ! ( DYNAMIC_TAG == 0 ) ; // Dynamic is untagged
672680
673- match ( data & TAG_MASK ) as u8 {
674- DYNAMIC_TAG => Dynamic ( data as * mut ( ) ) ,
675- STATIC_TAG => Static ( ( data >> STATIC_SHIFT_BITS ) as u32 ) ,
681+ match ( data. get ( ) & TAG_MASK ) as u8 {
682+ DYNAMIC_TAG => Dynamic ( data. get ( ) as * mut ( ) ) ,
683+ STATIC_TAG => Static ( ( data. get ( ) >> STATIC_SHIFT_BITS ) as u32 ) ,
676684 INLINE_TAG => {
677- let len = ( ( data & 0xf0 ) >> 4 ) as usize ;
685+ let len = ( ( data. get ( ) & 0xf0 ) >> 4 ) as usize ;
678686 debug_assert ! ( len <= MAX_INLINE_LEN ) ;
679687 let mut buf: [ u8 ; 7 ] = [ 0 ; 7 ] ;
680688 let src = inline_atom_slice ( & data) ;
@@ -701,7 +709,7 @@ unsafe fn from_packed_dynamic(data: u64) -> Option<*mut ()> {
701709///
702710/// It's undefined behavior to call this on a non-inline atom!!
703711#[ inline( always) ]
704- unsafe fn inline_orig_bytes < ' a > ( data : & ' a u64 ) -> & ' a [ u8 ] {
712+ unsafe fn inline_orig_bytes < ' a > ( data : & ' a NonZeroU64 ) -> & ' a [ u8 ] {
705713 match UnpackedAtom :: from_packed ( * data) {
706714 Inline ( len, _) => {
707715 let src = inline_atom_slice ( & data) ;
@@ -736,6 +744,10 @@ mod tests {
736744 8
737745 }
738746 ) ;
747+ assert_eq ! (
748+ mem:: size_of:: <Option <DefaultAtom >>( ) ,
749+ mem:: size_of:: <DefaultAtom >( ) ,
750+ ) ;
739751 assert_eq ! (
740752 mem:: size_of:: <super :: StringCacheEntry >( ) ,
741753 8 + 4 * mem:: size_of:: <usize >( )
0 commit comments