@@ -172,7 +172,7 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> {
172172 // funny underscores due to how Deref/DerefMut currently work (they
173173 // disregard field privacy).
174174 __lock : & ' a StaticMutex ,
175- __data : & ' a UnsafeCell < T > ,
175+ __data : & ' a mut T ,
176176 __poison : poison:: Guard ,
177177}
178178
@@ -211,8 +211,10 @@ impl<T: ?Sized> Mutex<T> {
211211 /// this call will return an error once the mutex is acquired.
212212 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
213213 pub fn lock ( & self ) -> LockResult < MutexGuard < T > > {
214- unsafe { self . inner . lock . lock ( ) }
215- MutexGuard :: new ( & * self . inner , & self . data )
214+ unsafe {
215+ self . inner . lock . lock ( ) ;
216+ MutexGuard :: new ( & * self . inner , & self . data )
217+ }
216218 }
217219
218220 /// Attempts to acquire this lock.
@@ -230,10 +232,12 @@ impl<T: ?Sized> Mutex<T> {
230232 /// acquired.
231233 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
232234 pub fn try_lock ( & self ) -> TryLockResult < MutexGuard < T > > {
233- if unsafe { self . inner . lock . try_lock ( ) } {
234- Ok ( try!( MutexGuard :: new ( & * self . inner , & self . data ) ) )
235- } else {
236- Err ( TryLockError :: WouldBlock )
235+ unsafe {
236+ if self . inner . lock . try_lock ( ) {
237+ Ok ( try!( MutexGuard :: new ( & * self . inner , & self . data ) ) )
238+ } else {
239+ Err ( TryLockError :: WouldBlock )
240+ }
237241 }
238242 }
239243
@@ -338,17 +342,21 @@ impl StaticMutex {
338342 /// Acquires this lock, see `Mutex::lock`
339343 #[ inline]
340344 pub fn lock ( & ' static self ) -> LockResult < MutexGuard < ( ) > > {
341- unsafe { self . lock . lock ( ) }
342- MutexGuard :: new ( self , & DUMMY . 0 )
345+ unsafe {
346+ self . lock . lock ( ) ;
347+ MutexGuard :: new ( self , & DUMMY . 0 )
348+ }
343349 }
344350
345351 /// Attempts to grab this lock, see `Mutex::try_lock`
346352 #[ inline]
347353 pub fn try_lock ( & ' static self ) -> TryLockResult < MutexGuard < ( ) > > {
348- if unsafe { self . lock . try_lock ( ) } {
349- Ok ( try!( MutexGuard :: new ( self , & DUMMY . 0 ) ) )
350- } else {
351- Err ( TryLockError :: WouldBlock )
354+ unsafe {
355+ if self . lock . try_lock ( ) {
356+ Ok ( try!( MutexGuard :: new ( self , & DUMMY . 0 ) ) )
357+ } else {
358+ Err ( TryLockError :: WouldBlock )
359+ }
352360 }
353361 }
354362
@@ -369,32 +377,72 @@ impl StaticMutex {
369377
370378impl < ' mutex , T : ?Sized > MutexGuard < ' mutex , T > {
371379
372- fn new ( lock : & ' mutex StaticMutex , data : & ' mutex UnsafeCell < T > )
380+ unsafe fn new ( lock : & ' mutex StaticMutex , data : & ' mutex UnsafeCell < T > )
373381 -> LockResult < MutexGuard < ' mutex , T > > {
374382 poison:: map_result ( lock. poison . borrow ( ) , |guard| {
375383 MutexGuard {
376384 __lock : lock,
377- __data : data,
385+ __data : & mut * data. get ( ) ,
378386 __poison : guard,
379387 }
380388 } )
381389 }
390+
391+ /// Transform this guard to hold a sub-borrow of the original data.
392+ ///
393+ /// Applies the supplied closure to the data, returning a new lock
394+ /// guard referencing the borrow returned by the closure.
395+ ///
396+ /// # Examples
397+ ///
398+ /// ```rust
399+ /// # #![feature(guard_map)]
400+ /// # use std::sync::{Mutex, MutexGuard};
401+ /// let x = Mutex::new(vec![1, 2]);
402+ ///
403+ /// {
404+ /// let mut y = MutexGuard::map(x.lock().unwrap(), |v| &mut v[0]);
405+ /// *y = 3;
406+ /// }
407+ ///
408+ /// assert_eq!(&*x.lock().unwrap(), &[3, 2]);
409+ /// ```
410+ #[ unstable( feature = "guard_map" ,
411+ reason = "recently added, needs RFC for stabilization" ,
412+ issue = "27746" ) ]
413+ pub fn map < U : ?Sized , F > ( this : Self , cb : F ) -> MutexGuard < ' mutex , U >
414+ where F : FnOnce ( & ' mutex mut T ) -> & ' mutex mut U
415+ {
416+ // Compute the new data while still owning the original lock
417+ // in order to correctly poison if the callback panics.
418+ let data = unsafe { ptr:: read ( & this. __data ) } ;
419+ let new_data = cb ( data) ;
420+
421+ // We don't want to unlock the lock by running the destructor of the
422+ // original lock, so just read the fields we need and forget it.
423+ let ( poison, lock) = unsafe {
424+ ( ptr:: read ( & this. __poison ) , ptr:: read ( & this. __lock ) )
425+ } ;
426+ mem:: forget ( this) ;
427+
428+ MutexGuard {
429+ __lock : lock,
430+ __data : new_data,
431+ __poison : poison
432+ }
433+ }
382434}
383435
384436#[ stable( feature = "rust1" , since = "1.0.0" ) ]
385437impl < ' mutex , T : ?Sized > Deref for MutexGuard < ' mutex , T > {
386438 type Target = T ;
387439
388- fn deref ( & self ) -> & T {
389- unsafe { & * self . __data . get ( ) }
390- }
440+ fn deref ( & self ) -> & T { self . __data }
391441}
392442
393443#[ stable( feature = "rust1" , since = "1.0.0" ) ]
394444impl < ' mutex , T : ?Sized > DerefMut for MutexGuard < ' mutex , T > {
395- fn deref_mut ( & mut self ) -> & mut T {
396- unsafe { & mut * self . __data . get ( ) }
397- }
445+ fn deref_mut ( & mut self ) -> & mut T { self . __data }
398446}
399447
400448#[ stable( feature = "rust1" , since = "1.0.0" ) ]
@@ -421,7 +469,7 @@ mod tests {
421469 use prelude:: v1:: * ;
422470
423471 use sync:: mpsc:: channel;
424- use sync:: { Arc , Mutex , StaticMutex , Condvar } ;
472+ use sync:: { Arc , Mutex , StaticMutex , Condvar , MutexGuard } ;
425473 use sync:: atomic:: { AtomicUsize , Ordering } ;
426474 use thread;
427475
@@ -665,4 +713,19 @@ mod tests {
665713 let comp: & [ i32 ] = & [ 4 , 2 , 5 ] ;
666714 assert_eq ! ( & * mutex. lock( ) . unwrap( ) , comp) ;
667715 }
716+
717+ #[ test]
718+ fn test_mutex_guard_map_panic ( ) {
719+ let mutex = Arc :: new ( Mutex :: new ( vec ! [ 1 , 2 ] ) ) ;
720+ let mutex2 = mutex. clone ( ) ;
721+
722+ thread:: spawn ( move || {
723+ let _ = MutexGuard :: map :: < usize , _ > ( mutex2. lock ( ) . unwrap ( ) , |_| panic ! ( ) ) ;
724+ } ) . join ( ) . unwrap_err ( ) ;
725+
726+ match mutex. lock ( ) {
727+ Ok ( r) => panic ! ( "Lock on poisioned Mutex is Ok: {:?}" , & * r) ,
728+ Err ( _) => { }
729+ } ;
730+ }
668731}
0 commit comments