@@ -121,7 +121,7 @@ pub const RW_LOCK_INIT: StaticRwLock = StaticRwLock::new();
121121#[ stable( feature = "rust1" , since = "1.0.0" ) ]
122122pub struct RwLockReadGuard < ' a , T : ?Sized + ' a > {
123123 __lock : & ' a StaticRwLock ,
124- __data : & ' a UnsafeCell < T > ,
124+ __data : & ' a T ,
125125}
126126
127127#[ stable( feature = "rust1" , since = "1.0.0" ) ]
@@ -417,10 +417,37 @@ impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> {
417417 poison:: map_result ( lock. poison . borrow ( ) , |_| {
418418 RwLockReadGuard {
419419 __lock : lock,
420- __data : data,
420+ __data : unsafe { & * data. get ( ) } ,
421421 }
422422 } )
423423 }
424+
425+ /// Transform this guard to hold a sub-borrow of the original data.
426+ ///
427+ /// Applies the supplied closure to the data, returning a new lock
428+ /// guard referencing the borrow returned by the closure.
429+ ///
430+ /// ```rust
431+ /// # use std::sync::{RwLockReadGuard, RwLock};
432+ /// let x = RwLock::new(vec![1, 2]);
433+ ///
434+ /// let y = RwLockReadGuard::map(x.read().unwrap(), |v| &v[0]);
435+ /// assert_eq!(*y, 1);
436+ /// ```
437+ #[ unstable( feature = "guard_map" ,
438+ reason = "recently added, needs RFC for stabilization" ,
439+ issue = "0" ) ]
440+ pub fn map < U : ?Sized , F > ( this : Self , cb : F ) -> RwLockReadGuard < ' rwlock , U >
441+ where F : FnOnce ( & ' rwlock T ) -> & ' rwlock U {
442+ let new = RwLockReadGuard {
443+ __lock : this. __lock ,
444+ __data : cb ( this. __data )
445+ } ;
446+
447+ mem:: forget ( this) ;
448+
449+ new
450+ }
424451}
425452
426453impl < ' rwlock , T : ?Sized > RwLockWriteGuard < ' rwlock , T > {
@@ -434,13 +461,52 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> {
434461 }
435462 } )
436463 }
464+
465+ /// Transform this guard to hold a sub-borrow of the original data.
466+ ///
467+ /// Applies the supplied closure to the data, returning a new lock
468+ /// guard referencing the borrow returned by the closure.
469+ ///
470+ /// ```rust
471+ /// # use std::sync::{RwLockWriteGuard, RwLock};
472+ /// let x = RwLock::new(vec![1, 2]);
473+ ///
474+ /// {
475+ /// let y = RwLockWriteGuard::map(x.write().unwrap(), |v| &mut v[0]);
476+ /// assert_eq!(*y, 1);
477+ ///
478+ /// *y = 10;
479+ /// }
480+ ///
481+ /// assert_eq!(&**x.read().unwrap(), &[10, 2]);
482+ /// ```
483+ #[ unstable( feature = "guard_map" ,
484+ reason = "recently added, needs RFC for stabilization" ,
485+ issue = "0" ) ]
486+ pub fn map < U : ?Sized , F > ( this : Self , cb : F ) -> RwLockWriteGuard < ' rwlock , U >
487+ where F : FnOnce ( & ' rwlock mut T ) -> & ' rwlock mut U {
488+ let new_data = unsafe {
489+ let data: & ' rwlock mut T = & mut * this. __data . get ( ) ;
490+ mem:: transmute :: < & ' rwlock mut U , & ' rwlock UnsafeCell < U > > ( cb ( data) )
491+ } ;
492+
493+ let poison = unsafe { ptr:: read ( & this. __poison ) } ;
494+ let lock = unsafe { ptr:: read ( & this. __lock ) } ;
495+ mem:: forget ( this) ;
496+
497+ RwLockWriteGuard {
498+ __lock : lock,
499+ __data : new_data,
500+ __poison : poison
501+ }
502+ }
437503}
438504
439505#[ stable( feature = "rust1" , since = "1.0.0" ) ]
440506impl < ' rwlock , T : ?Sized > Deref for RwLockReadGuard < ' rwlock , T > {
441507 type Target = T ;
442508
443- fn deref ( & self ) -> & T { unsafe { & * self . __data . get ( ) } }
509+ fn deref ( & self ) -> & T { self . __data }
444510}
445511
446512#[ stable( feature = "rust1" , since = "1.0.0" ) ]
@@ -481,7 +547,7 @@ mod tests {
481547 use rand:: { self , Rng } ;
482548 use sync:: mpsc:: channel;
483549 use thread;
484- use sync:: { Arc , RwLock , StaticRwLock , TryLockError } ;
550+ use sync:: { Arc , RwLock , StaticRwLock , TryLockError , RwLockWriteGuard } ;
485551 use sync:: atomic:: { AtomicUsize , Ordering } ;
486552
487553 #[ derive( Eq , PartialEq , Debug ) ]
@@ -729,4 +795,20 @@ mod tests {
729795 Ok ( x) => panic ! ( "get_mut of poisoned RwLock is Ok: {:?}" , x) ,
730796 }
731797 }
798+
799+ #[ test]
800+ fn test_rwlock_write_map_poison ( ) {
801+ let rwlock = Arc :: new ( RwLock :: new ( vec ! [ 1 , 2 ] ) ) ;
802+ let rwlock2 = rwlock. clone ( ) ;
803+
804+ thread:: spawn ( move || {
805+ let _ = RwLockWriteGuard :: map :: < usize , _ > ( rwlock2. write ( ) . unwrap ( ) , |_| panic ! ( ) ) ;
806+ } ) . join ( ) . unwrap_err ( ) ;
807+
808+ match rwlock. read ( ) {
809+ Ok ( r) => panic ! ( "Read lock on poisioned RwLock is Ok: {:?}" , & * r) ,
810+ Err ( _) => { }
811+ } ;
812+ }
732813}
814+
0 commit comments