Auto merge of #117107 - zachs18:mapped-mutex-guard, r=Amanieu · rust-lang/rust@a2f3c0c (original) (raw)

`@@ -3,7 +3,10 @@ mod tests;

`

3

3

``

4

4

`use crate::cell::UnsafeCell;

`

5

5

`use crate::fmt;

`

``

6

`+

use crate:📑:PhantomData;

`

``

7

`+

use crate::mem::ManuallyDrop;

`

6

8

`use crate::ops::{Deref, DerefMut};

`

``

9

`+

use crate::ptr::NonNull;

`

7

10

`use crate::sync::{poison, LockResult, TryLockError, TryLockResult};

`

8

11

`use crate::sys::locks as sys;

`

9

12

``

`@@ -213,6 +216,47 @@ impl<T: ?Sized> !Send for MutexGuard<'_, T> {}

`

213

216

`#[stable(feature = "mutexguard", since = "1.19.0")]

`

214

217

`unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {}

`

215

218

``

``

219

`` +

/// An RAII mutex guard returned by MutexGuard::map, which can point to a

``

``

220

`+

/// subfield of the protected data. When this structure is dropped (falls out

`

``

221

`+

/// of scope), the lock will be unlocked.

`

``

222

`+

///

`

``

223

`` +

/// The main difference between MappedMutexGuard and [MutexGuard] is that the

``

``

224

`` +

/// former cannot be used with [Condvar], since that

``

``

225

`+

/// could introduce soundness issues if the locked object is modified by another

`

``

226

`` +

/// thread while the Mutex is unlocked.

``

``

227

`+

///

`

``

228

`+

/// The data protected by the mutex can be accessed through this guard via its

`

``

229

`` +

/// [Deref] and [DerefMut] implementations.

``

``

230

`+

///

`

``

231

`` +

/// This structure is created by the [map] and [try_map] methods on

``

``

232

`` +

/// [MutexGuard].

``

``

233

`+

///

`

``

234

`` +

/// [map]: MutexGuard::map

``

``

235

`` +

/// [try_map]: MutexGuard::try_map

``

``

236

`` +

/// [Condvar]: crate::sync::Condvar

``

``

237

`+

#[must_use = "if unused the Mutex will immediately unlock"]

`

``

238

`+

#[must_not_suspend = "holding a MappedMutexGuard across suspend \

`

``

239

`+

points can cause deadlocks, delays, \

`

``

240

`` +

and cause Futures to not implement Send"]

``

``

241

`+

#[unstable(feature = "mapped_lock_guards", issue = "117108")]

`

``

242

`+

#[clippy::has_significant_drop]

`

``

243

`+

pub struct MappedMutexGuard<'a, T: ?Sized + 'a> {

`

``

244

`` +

// NB: we use a pointer instead of &'a mut T to avoid noalias violations, because a

``

``

245

`` +

// MappedMutexGuard argument doesn't hold uniqueness for its whole scope, only until it drops.

``

``

246

`` +

// NonNull is covariant over T, so we add a PhantomData<&'a mut T> field

``

``

247

`` +

// below for the correct variance over T (invariance).

``

``

248

`+

data: NonNull,

`

``

249

`+

inner: &'a sys::Mutex,

`

``

250

`+

poison_flag: &'a poison::Flag,

`

``

251

`+

poison: poison::Guard,

`

``

252

`+

_variance: PhantomData<&'a mut T>,

`

``

253

`+

}

`

``

254

+

``

255

`+

#[unstable(feature = "mapped_lock_guards", issue = "117108")]

`

``

256

`+

impl<T: ?Sized> !Send for MappedMutexGuard<'_, T> {}

`

``

257

`+

#[unstable(feature = "mapped_lock_guards", issue = "117108")]

`

``

258

`+

unsafe impl<T: ?Sized + Sync> Sync for MappedMutexGuard<'_, T> {}

`

``

259

+

216

260

`impl Mutex {

`

217

261

`/// Creates a new mutex in an unlocked state ready for use.

`

218

262

`///

`

`@@ -550,3 +594,178 @@ pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {

`

550

594

`pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {

`

551

595

`&guard.lock.poison

`

552

596

`}

`

``

597

+

``

598

`+

impl<'a, T: ?Sized> MutexGuard<'a, T> {

`

``

599

`` +

/// Makes a [MappedMutexGuard] for a component of the borrowed data, e.g.

``

``

600

`+

/// an enum variant.

`

``

601

`+

///

`

``

602

`` +

/// The Mutex is already locked, so this cannot fail.

``

``

603

`+

///

`

``

604

`+

/// This is an associated function that needs to be used as

`

``

605

`` +

/// MutexGuard::map(...). A method would interfere with methods of the

``

``

606

`` +

/// same name on the contents of the MutexGuard used through Deref.

``

``

607

`+

#[unstable(feature = "mapped_lock_guards", issue = "117108")]

`

``

608

`+

pub fn map<U, F>(orig: Self, f: F) -> MappedMutexGuard<'a, U>

`

``

609

`+

where

`

``

610

`+

F: FnOnce(&mut T) -> &mut U,

`

``

611

`+

U: ?Sized,

`

``

612

`+

{

`

``

613

`` +

// SAFETY: the conditions of MutexGuard::new were satisfied when the original guard

``

``

614

`` +

// was created, and have been upheld throughout map and/or try_map.

``

``

615

`+

// The signature of the closure guarantees that it will not "leak" the lifetime of the reference

`

``

616

`+

// passed to it. If the closure panics, the guard will be dropped.

`

``

617

`+

let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() }));

`

``

618

`+

let orig = ManuallyDrop::new(orig);

`

``

619

`+

MappedMutexGuard {

`

``

620

`+

data,

`

``

621

`+

inner: &orig.lock.inner,

`

``

622

`+

poison_flag: &orig.lock.poison,

`

``

623

`+

poison: orig.poison.clone(),

`

``

624

`+

_variance: PhantomData,

`

``

625

`+

}

`

``

626

`+

}

`

``

627

+

``

628

`` +

/// Makes a [MappedMutexGuard] for a component of the borrowed data. The

``

``

629

`` +

/// original guard is returned as an Err(...) if the closure returns

``

``

630

`` +

/// None.

``

``

631

`+

///

`

``

632

`` +

/// The Mutex is already locked, so this cannot fail.

``

``

633

`+

///

`

``

634

`+

/// This is an associated function that needs to be used as

`

``

635

`` +

/// MutexGuard::try_map(...). A method would interfere with methods of the

``

``

636

`` +

/// same name on the contents of the MutexGuard used through Deref.

``

``

637

`+

#[doc(alias = "filter_map")]

`

``

638

`+

#[unstable(feature = "mapped_lock_guards", issue = "117108")]

`

``

639

`+

pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>

`

``

640

`+

where

`

``

641

`+

F: FnOnce(&mut T) -> Option<&mut U>,

`

``

642

`+

U: ?Sized,

`

``

643

`+

{

`

``

644

`` +

// SAFETY: the conditions of MutexGuard::new were satisfied when the original guard

``

``

645

`` +

// was created, and have been upheld throughout map and/or try_map.

``

``

646

`+

// The signature of the closure guarantees that it will not "leak" the lifetime of the reference

`

``

647

`+

// passed to it. If the closure panics, the guard will be dropped.

`

``

648

`+

match f(unsafe { &mut *orig.lock.data.get() }) {

`

``

649

`+

Some(data) => {

`

``

650

`+

let data = NonNull::from(data);

`

``

651

`+

let orig = ManuallyDrop::new(orig);

`

``

652

`+

Ok(MappedMutexGuard {

`

``

653

`+

data,

`

``

654

`+

inner: &orig.lock.inner,

`

``

655

`+

poison_flag: &orig.lock.poison,

`

``

656

`+

poison: orig.poison.clone(),

`

``

657

`+

_variance: PhantomData,

`

``

658

`+

})

`

``

659

`+

}

`

``

660

`+

None => Err(orig),

`

``

661

`+

}

`

``

662

`+

}

`

``

663

`+

}

`

``

664

+

``

665

`+

#[unstable(feature = "mapped_lock_guards", issue = "117108")]

`

``

666

`+

impl<T: ?Sized> Deref for MappedMutexGuard<'_, T> {

`

``

667

`+

type Target = T;

`

``

668

+

``

669

`+

fn deref(&self) -> &T {

`

``

670

`+

unsafe { self.data.as_ref() }

`

``

671

`+

}

`

``

672

`+

}

`

``

673

+

``

674

`+

#[unstable(feature = "mapped_lock_guards", issue = "117108")]

`

``

675

`+

impl<T: ?Sized> DerefMut for MappedMutexGuard<'_, T> {

`

``

676

`+

fn deref_mut(&mut self) -> &mut T {

`

``

677

`+

unsafe { self.data.as_mut() }

`

``

678

`+

}

`

``

679

`+

}

`

``

680

+

``

681

`+

#[unstable(feature = "mapped_lock_guards", issue = "117108")]

`

``

682

`+

impl<T: ?Sized> Drop for MappedMutexGuard<'_, T> {

`

``

683

`+

#[inline]

`

``

684

`+

fn drop(&mut self) {

`

``

685

`+

unsafe {

`

``

686

`+

self.poison_flag.done(&self.poison);

`

``

687

`+

self.inner.unlock();

`

``

688

`+

}

`

``

689

`+

}

`

``

690

`+

}

`

``

691

+

``

692

`+

#[unstable(feature = "mapped_lock_guards", issue = "117108")]

`

``

693

`+

impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedMutexGuard<'_, T> {

`

``

694

`+

fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

`

``

695

`+

fmt::Debug::fmt(&**self, f)

`

``

696

`+

}

`

``

697

`+

}

`

``

698

+

``

699

`+

#[unstable(feature = "mapped_lock_guards", issue = "117108")]

`

``

700

`+

impl<T: ?Sized + fmt::Display> fmt::Display for MappedMutexGuard<'_, T> {

`

``

701

`+

fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

`

``

702

`+

(**self).fmt(f)

`

``

703

`+

}

`

``

704

`+

}

`

``

705

+

``

706

`+

impl<'a, T: ?Sized> MappedMutexGuard<'a, T> {

`

``

707

`` +

/// Makes a [MappedMutexGuard] for a component of the borrowed data, e.g.

``

``

708

`+

/// an enum variant.

`

``

709

`+

///

`

``

710

`` +

/// The Mutex is already locked, so this cannot fail.

``

``

711

`+

///

`

``

712

`+

/// This is an associated function that needs to be used as

`

``

713

`` +

/// MappedMutexGuard::map(...). A method would interfere with methods of the

``

``

714

`` +

/// same name on the contents of the MutexGuard used through Deref.

``

``

715

`+

#[unstable(feature = "mapped_lock_guards", issue = "117108")]

`

``

716

`+

pub fn map<U, F>(mut orig: Self, f: F) -> MappedMutexGuard<'a, U>

`

``

717

`+

where

`

``

718

`+

F: FnOnce(&mut T) -> &mut U,

`

``

719

`+

U: ?Sized,

`

``

720

`+

{

`

``

721

`` +

// SAFETY: the conditions of MutexGuard::new were satisfied when the original guard

``

``

722

`` +

// was created, and have been upheld throughout map and/or try_map.

``

``

723

`+

// The signature of the closure guarantees that it will not "leak" the lifetime of the reference

`

``

724

`+

// passed to it. If the closure panics, the guard will be dropped.

`

``

725

`+

let data = NonNull::from(f(unsafe { orig.data.as_mut() }));

`

``

726

`+

let orig = ManuallyDrop::new(orig);

`

``

727

`+

MappedMutexGuard {

`

``

728

`+

data,

`

``

729

`+

inner: orig.inner,

`

``

730

`+

poison_flag: orig.poison_flag,

`

``

731

`+

poison: orig.poison.clone(),

`

``

732

`+

_variance: PhantomData,

`

``

733

`+

}

`

``

734

`+

}

`

``

735

+

``

736

`` +

/// Makes a [MappedMutexGuard] for a component of the borrowed data. The

``

``

737

`` +

/// original guard is returned as an Err(...) if the closure returns

``

``

738

`` +

/// None.

``

``

739

`+

///

`

``

740

`` +

/// The Mutex is already locked, so this cannot fail.

``

``

741

`+

///

`

``

742

`+

/// This is an associated function that needs to be used as

`

``

743

`` +

/// MappedMutexGuard::try_map(...). A method would interfere with methods of the

``

``

744

`` +

/// same name on the contents of the MutexGuard used through Deref.

``

``

745

`+

#[doc(alias = "filter_map")]

`

``

746

`+

#[unstable(feature = "mapped_lock_guards", issue = "117108")]

`

``

747

`+

pub fn try_map<U, F>(mut orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>

`

``

748

`+

where

`

``

749

`+

F: FnOnce(&mut T) -> Option<&mut U>,

`

``

750

`+

U: ?Sized,

`

``

751

`+

{

`

``

752

`` +

// SAFETY: the conditions of MutexGuard::new were satisfied when the original guard

``

``

753

`` +

// was created, and have been upheld throughout map and/or try_map.

``

``

754

`+

// The signature of the closure guarantees that it will not "leak" the lifetime of the reference

`

``

755

`+

// passed to it. If the closure panics, the guard will be dropped.

`

``

756

`+

match f(unsafe { orig.data.as_mut() }) {

`

``

757

`+

Some(data) => {

`

``

758

`+

let data = NonNull::from(data);

`

``

759

`+

let orig = ManuallyDrop::new(orig);

`

``

760

`+

Ok(MappedMutexGuard {

`

``

761

`+

data,

`

``

762

`+

inner: orig.inner,

`

``

763

`+

poison_flag: orig.poison_flag,

`

``

764

`+

poison: orig.poison.clone(),

`

``

765

`+

_variance: PhantomData,

`

``

766

`+

})

`

``

767

`+

}

`

``

768

`+

None => Err(orig),

`

``

769

`+

}

`

``

770

`+

}

`

``

771

`+

}

`