55 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
66 */
77
8- use std:: ops:: { Deref , DerefMut } ;
98use std:: sync:: { Mutex , MutexGuard , TryLockError } ;
109
1110/// Ergonomic global variables.
@@ -66,7 +65,6 @@ impl<T> Global<T> {
6665 let guard = Self :: ensure_init ( mutex_guard, true )
6766 . unwrap_or_else ( || panic ! ( "previous Global<T> initialization failed due to panic" ) ) ;
6867
69- debug_assert ! ( matches!( * guard. mutex_guard, InitState :: Initialized ( _) ) ) ;
7068 guard
7169 }
7270
@@ -79,45 +77,31 @@ impl<T> Global<T> {
7977 }
8078 Err ( TryLockError :: Poisoned ( poisoned) ) => {
8179 return Err ( GlobalLockError :: Poisoned {
82- circumvent : GlobalGuard {
83- mutex_guard : poisoned. into_inner ( ) ,
84- } ,
80+ // We can likely use `new_unchecked` here, but verifying that it's safe would need somewhat tricky reasoning.
81+ // Since this error condition isn't very common, it is likely not very important to optimize access to the value here.
82+ // Especially since most users will likely not want to access it anyway.
83+ circumvent : GlobalGuard :: new ( poisoned. into_inner ( ) )
84+ . expect ( "Poisoned global guard should always be initialized" ) ,
8585 } ) ;
8686 }
8787 } ;
8888
89- match guard {
90- None => Err ( GlobalLockError :: InitFailed ) ,
91- Some ( guard) => {
92- debug_assert ! ( matches!( * guard. mutex_guard, InitState :: Initialized ( _) ) ) ;
93- Ok ( guard)
94- }
95- }
89+ guard. ok_or ( GlobalLockError :: InitFailed )
9690 }
9791
9892 fn ensure_init (
9993 mut mutex_guard : MutexGuard < ' _ , InitState < T > > ,
10094 may_panic : bool ,
10195 ) -> Option < GlobalGuard < ' _ , T > > {
102- let pending_state = match & mut * mutex_guard {
96+ let init_fn = match & mut * mutex_guard {
10397 InitState :: Initialized ( _) => {
104- return Some ( GlobalGuard { mutex_guard } ) ;
105- }
106- InitState :: TransientInitializing => {
107- // SAFETY: only set inside this function and all paths (panic + return) leave the enum in a different state.
108- unsafe { std:: hint:: unreachable_unchecked ( ) } ;
98+ // SAFETY: `mutex_guard` is `Initialized`.
99+ return Some ( unsafe { GlobalGuard :: new_unchecked ( mutex_guard) } ) ;
109100 }
110101 InitState :: Failed => {
111102 return None ;
112103 }
113- state @ InitState :: Pending ( _) => {
114- std:: mem:: replace ( state, InitState :: TransientInitializing )
115- }
116- } ;
117-
118- let InitState :: Pending ( init_fn) = pending_state else {
119- // SAFETY: all other paths leave the function, see above.
120- unsafe { std:: hint:: unreachable_unchecked ( ) }
104+ InitState :: Pending ( init_fn) => init_fn,
121105 } ;
122106
123107 // Unwinding should be safe here, as there is no unsafe code relying on it.
@@ -137,32 +121,64 @@ impl<T> Global<T> {
137121 }
138122 } ;
139123
140- Some ( GlobalGuard { mutex_guard } )
124+ // SAFETY: `mutex_guard` was either set to `Initialized` above, or we returned from the function.
125+ Some ( unsafe { GlobalGuard :: new_unchecked ( mutex_guard) } )
141126 }
142127}
143128
144129// ----------------------------------------------------------------------------------------------------------------------------------------------
145130// Guards
146131
147- /// Guard that temporarily gives access to a `Global<T>`'s inner value .
148- pub struct GlobalGuard < ' a , T > {
149- mutex_guard : MutexGuard < ' a , InitState < T > > ,
150- }
132+ // Encapsulate private fields .
133+ mod global_guard {
134+ use std :: ops :: { Deref , DerefMut } ;
135+ use std :: sync :: MutexGuard ;
151136
152- impl < T > Deref for GlobalGuard < ' _ , T > {
153- type Target = T ;
137+ use super :: InitState ;
154138
155- fn deref ( & self ) -> & Self :: Target {
156- self . mutex_guard . unwrap_ref ( )
139+ /// Guard that temporarily gives access to a `Global<T>`'s inner value.
140+ pub struct GlobalGuard < ' a , T > {
141+ // Safety invariant: Is `Initialized`.
142+ mutex_guard : MutexGuard < ' a , InitState < T > > ,
157143 }
158- }
159144
160- impl < T > DerefMut for GlobalGuard < ' _ , T > {
161- fn deref_mut ( & mut self ) -> & mut Self :: Target {
162- self . mutex_guard . unwrap_mut ( )
145+ impl < ' a , T > GlobalGuard < ' a , T > {
146+ pub ( super ) fn new ( mutex_guard : MutexGuard < ' a , InitState < T > > ) -> Option < Self > {
147+ match & * mutex_guard {
148+ InitState :: Initialized ( _) => Some ( Self { mutex_guard } ) ,
149+ _ => None ,
150+ }
151+ }
152+
153+ /// # Safety
154+ ///
155+ /// The value must be `Initialized`.
156+ pub ( super ) unsafe fn new_unchecked ( mutex_guard : MutexGuard < ' a , InitState < T > > ) -> Self {
157+ debug_assert ! ( matches!( * mutex_guard, InitState :: Initialized ( _) ) ) ;
158+
159+ Self :: new ( mutex_guard) . unwrap_unchecked ( )
160+ }
161+ }
162+
163+ impl < T > Deref for GlobalGuard < ' _ , T > {
164+ type Target = T ;
165+
166+ fn deref ( & self ) -> & Self :: Target {
167+ // SAFETY: `self` is `Initialized`.
168+ unsafe { self . mutex_guard . as_initialized ( ) . unwrap_unchecked ( ) }
169+ }
170+ }
171+
172+ impl < T > DerefMut for GlobalGuard < ' _ , T > {
173+ fn deref_mut ( & mut self ) -> & mut Self :: Target {
174+ // SAFETY: `self` is `Initialized`.
175+ unsafe { self . mutex_guard . as_initialized_mut ( ) . unwrap_unchecked ( ) }
176+ }
163177 }
164178}
165179
180+ pub use global_guard:: GlobalGuard ;
181+
166182// ----------------------------------------------------------------------------------------------------------------------------------------------
167183// Errors
168184
@@ -184,28 +200,21 @@ pub enum GlobalLockError<'a, T> {
184200enum InitState < T > {
185201 Initialized ( T ) ,
186202 Pending ( fn ( ) -> T ) ,
187- TransientInitializing ,
188203 Failed ,
189204}
190205
191206impl < T > InitState < T > {
192- fn unwrap_ref ( & self ) -> & T {
207+ fn as_initialized ( & self ) -> Option < & T > {
193208 match self {
194- InitState :: Initialized ( t) => t,
195- _ => {
196- // SAFETY: This method is only called from a guard, which can only be obtained in Initialized state.
197- unsafe { std:: hint:: unreachable_unchecked ( ) }
198- }
209+ InitState :: Initialized ( t) => Some ( t) ,
210+ _ => None ,
199211 }
200212 }
201213
202- fn unwrap_mut ( & mut self ) -> & mut T {
214+ fn as_initialized_mut ( & mut self ) -> Option < & mut T > {
203215 match self {
204- InitState :: Initialized ( t) => t,
205- _ => {
206- // SAFETY: This method is only called from a guard, which can only be obtained in Initialized state.
207- unsafe { std:: hint:: unreachable_unchecked ( ) }
208- }
216+ InitState :: Initialized ( t) => Some ( t) ,
217+ _ => None ,
209218 }
210219 }
211220}
0 commit comments