7070extern crate lazy_static;
7171
7272mod cached;
73+ mod maybe_uninit;
7374mod thread_id;
7475mod unreachable;
7576
7677#[ allow( deprecated) ]
7778pub use cached:: { CachedIntoIter , CachedIterMut , CachedThreadLocal } ;
7879
80+ use maybe_uninit:: MaybeUninit ;
7981use std:: cell:: UnsafeCell ;
8082use std:: fmt;
8183use std:: iter:: FusedIterator ;
@@ -86,7 +88,7 @@ use std::ptr;
8688use std:: sync:: atomic:: { AtomicBool , AtomicPtr , AtomicUsize , Ordering } ;
8789use std:: sync:: Mutex ;
8890use thread_id:: Thread ;
89- use unreachable:: { UncheckedOptionExt , UncheckedResultExt } ;
91+ use unreachable:: UncheckedResultExt ;
9092
9193// Use usize::BITS once it has stabilized and the MSRV has been bumped.
9294#[ cfg( target_pointer_width = "16" ) ]
@@ -119,8 +121,7 @@ pub struct ThreadLocal<T: Send> {
119121
120122struct Entry < T > {
121123 present : AtomicBool ,
122- // Use MaybeUninit once the MSRV has been bumped.
123- value : UnsafeCell < Option < T > > ,
124+ value : UnsafeCell < MaybeUninit < T > > ,
124125}
125126
126127// ThreadLocal is always Sync, even if T isn't
@@ -226,7 +227,15 @@ impl<T: Send> ThreadLocal<T> {
226227 if bucket_ptr. is_null ( ) {
227228 return None ;
228229 }
229- unsafe { ( & * ( * bucket_ptr. add ( thread. index ) ) . value . get ( ) ) . as_ref ( ) }
230+ unsafe {
231+ let entry = & * bucket_ptr. add ( thread. index ) ;
232+ // Read without atomic operations as only this thread can set the value.
233+ if ( & entry. present as * const _ as * const bool ) . read ( ) {
234+ Some ( & * ( & * entry. value . get ( ) ) . as_ptr ( ) )
235+ } else {
236+ None
237+ }
238+ }
230239 }
231240
232241 #[ cold]
@@ -251,12 +260,12 @@ impl<T: Send> ThreadLocal<T> {
251260 // Insert the new element into the bucket
252261 let entry = unsafe { & * bucket_ptr. add ( thread. index ) } ;
253262 let value_ptr = entry. value . get ( ) ;
254- unsafe { value_ptr. write ( Some ( data) ) } ;
263+ unsafe { value_ptr. write ( MaybeUninit :: new ( data) ) } ;
255264 entry. present . store ( true , Ordering :: Release ) ;
256265
257266 self . values . fetch_add ( 1 , Ordering :: Release ) ;
258267
259- unsafe { ( & * value_ptr) . as_ref ( ) . unchecked_unwrap ( ) }
268+ unsafe { & * ( & * value_ptr) . as_ptr ( ) }
260269 }
261270
262271 /// Returns an iterator over the local values of all threads in unspecified
@@ -370,7 +379,7 @@ impl<'a, T: Send + Sync> Iterator for Iter<'a, T> {
370379 self . index += 1 ;
371380 if entry. present . load ( Ordering :: Acquire ) {
372381 self . yielded += 1 ;
373- return Some ( unsafe { ( & * entry. value . get ( ) ) . as_ref ( ) . unchecked_unwrap ( ) } ) ;
382+ return Some ( unsafe { & * ( & * entry. value . get ( ) ) . as_ptr ( ) } ) ;
374383 }
375384 }
376385 }
@@ -401,7 +410,7 @@ struct RawIterMut<T: Send> {
401410}
402411
403412impl < T : Send > Iterator for RawIterMut < T > {
404- type Item = * mut Option < T > ;
413+ type Item = * mut MaybeUninit < T > ;
405414
406415 fn next ( & mut self ) -> Option < Self :: Item > {
407416 if self . remaining == 0 {
@@ -448,7 +457,7 @@ impl<'a, T: Send + 'a> Iterator for IterMut<'a, T> {
448457 fn next ( & mut self ) -> Option < & ' a mut T > {
449458 self . raw
450459 . next ( )
451- . map ( |x| unsafe { & mut * ( * x) . as_mut ( ) . unchecked_unwrap ( ) } )
460+ . map ( |x| unsafe { & mut * ( & mut * x) . as_mut_ptr ( ) } )
452461 }
453462
454463 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
@@ -470,7 +479,7 @@ impl<T: Send> Iterator for IntoIter<T> {
470479 fn next ( & mut self ) -> Option < T > {
471480 self . raw
472481 . next ( )
473- . map ( |x| unsafe { ( * x ) . take ( ) . unchecked_unwrap ( ) } )
482+ . map ( |x| unsafe { std :: mem :: replace ( & mut * x , MaybeUninit :: uninit ( ) ) . assume_init ( ) } )
474483 }
475484
476485 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
@@ -485,7 +494,7 @@ fn allocate_bucket<T>(size: usize) -> *mut Entry<T> {
485494 ( 0 ..size)
486495 . map ( |_| Entry :: < T > {
487496 present : AtomicBool :: new ( false ) ,
488- value : UnsafeCell :: new ( None ) ,
497+ value : UnsafeCell :: new ( MaybeUninit :: uninit ( ) ) ,
489498 } )
490499 . collect :: < Vec < _ > > ( )
491500 . into_boxed_slice ( ) ,
0 commit comments