Skip to content

Commit 1750bc6

Browse files
committed
implement feature lock_value_accessors and mutex_data_ptr
1 parent ebe9ca0 commit 1750bc6

File tree

2 files changed

+131
-47
lines changed

2 files changed

+131
-47
lines changed

library/std/src/sync/nonpoison/mutex.rs

Lines changed: 85 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
use crate::cell::UnsafeCell;
22
use crate::fmt;
33
use crate::marker::PhantomData;
4-
use crate::mem::ManuallyDrop;
4+
use crate::mem::{self, ManuallyDrop};
55
use crate::ops::{Deref, DerefMut};
66
use crate::ptr::NonNull;
77
use crate::sync::nonpoison::{TryLockResult, WouldBlock};
88
use crate::sys::sync as sys;
99

10-
/// A mutual exclusion primitive useful for protecting shared data.
10+
/// A mutual exclusion primitive useful for protecting shared data that does not keep track of
11+
/// lock poisoning.
1112
///
1213
/// For more information about mutexes, check out the documentation for the poisoning variant of
13-
/// this lock (which can be found at [`poison::Mutex`])
14+
/// this lock (which can be found at [`poison::Mutex`]).
1415
///
1516
/// # Examples
1617
///
@@ -259,6 +260,7 @@ impl<T> Mutex<T> {
259260
///
260261
/// ```
261262
/// #![feature(nonpoison_mutex)]
263+
///
262264
/// use std::sync::nonpoison::Mutex;
263265
///
264266
/// let mutex = Mutex::new(0);
@@ -269,7 +271,72 @@ impl<T> Mutex<T> {
269271
Mutex { inner: sys::Mutex::new(), data: UnsafeCell::new(t) }
270272
}
271273

272-
// FIXME: Add `lock_value_accessors` feature methods.
274+
/// Returns the contained value by cloning it.
275+
///
276+
/// # Examples
277+
///
278+
/// ```
279+
/// #![feature(nonpoison_mutex)]
280+
/// #![feature(lock_value_accessors)]
281+
///
282+
/// use std::sync::nonpoison::Mutex;
283+
///
284+
/// let mut mutex = Mutex::new(7);
285+
///
286+
/// assert_eq!(mutex.get_cloned(), 7);
287+
/// ```
288+
#[unstable(feature = "lock_value_accessors", issue = "133407")]
289+
pub fn get_cloned(&self) -> T
290+
where
291+
T: Clone,
292+
{
293+
self.lock().clone()
294+
}
295+
296+
/// Sets the contained value.
297+
///
298+
/// # Examples
299+
///
300+
/// ```
301+
/// #![feature(nonpoison_mutex)]
302+
/// #![feature(lock_value_accessors)]
303+
///
304+
/// use std::sync::nonpoison::Mutex;
305+
///
306+
/// let mut mutex = Mutex::new(7);
307+
///
308+
/// assert_eq!(mutex.get_cloned(), 7);
309+
/// mutex.set(11);
310+
/// assert_eq!(mutex.get_cloned(), 11);
311+
/// ```
312+
#[unstable(feature = "lock_value_accessors", issue = "133407")]
313+
pub fn set(&self, value: T) {
314+
let old = self.replace(value);
315+
if mem::needs_drop::<T>() {
316+
drop(old)
317+
}
318+
}
319+
320+
/// Replaces the contained value with `value`, and returns the old contained value.
321+
///
322+
/// # Examples
323+
///
324+
/// ```
325+
/// #![feature(nonpoison_mutex)]
326+
/// #![feature(lock_value_accessors)]
327+
///
328+
/// use std::sync::nonpoison::Mutex;
329+
///
330+
/// let mut mutex = Mutex::new(7);
331+
///
332+
/// assert_eq!(mutex.replace(11), 7);
333+
/// assert_eq!(mutex.get_cloned(), 11);
334+
/// ```
335+
#[unstable(feature = "lock_value_accessors", issue = "133407")]
336+
pub fn replace(&self, value: T) -> T {
337+
let mut guard = self.lock();
338+
mem::replace(&mut *guard, value)
339+
}
273340
}
274341

275342
impl<T: ?Sized> Mutex<T> {
@@ -293,6 +360,7 @@ impl<T: ?Sized> Mutex<T> {
293360
///
294361
/// ```
295362
/// #![feature(nonpoison_mutex)]
363+
///
296364
/// use std::sync::{Arc, nonpoison::Mutex};
297365
/// use std::thread;
298366
///
@@ -329,6 +397,7 @@ impl<T: ?Sized> Mutex<T> {
329397
///
330398
/// ```
331399
/// #![feature(nonpoison_mutex)]
400+
///
332401
/// use std::sync::{Arc, nonpoison::Mutex};
333402
/// use std::thread;
334403
///
@@ -356,6 +425,7 @@ impl<T: ?Sized> Mutex<T> {
356425
///
357426
/// ```
358427
/// #![feature(nonpoison_mutex)]
428+
///
359429
/// use std::sync::nonpoison::Mutex;
360430
///
361431
/// let mutex = Mutex::new(0);
@@ -378,6 +448,7 @@ impl<T: ?Sized> Mutex<T> {
378448
///
379449
/// ```
380450
/// #![feature(nonpoison_mutex)]
451+
///
381452
/// use std::sync::nonpoison::Mutex;
382453
///
383454
/// let mut mutex = Mutex::new(0);
@@ -389,7 +460,16 @@ impl<T: ?Sized> Mutex<T> {
389460
self.data.get_mut()
390461
}
391462

392-
// FIXME: Add `mutex_data_ptr` feature method.
463+
/// Returns a raw pointer to the underlying data.
464+
///
465+
/// The returned pointer is always non-null and properly aligned, but it is
466+
/// the user's responsibility to ensure that any reads and writes through it
467+
/// are properly synchronized to avoid data races, and that it is not read
468+
/// or written through after the mutex is dropped.
469+
#[unstable(feature = "mutex_data_ptr", issue = "140368")]
470+
pub fn data_ptr(&self) -> *mut T {
471+
self.data.get()
472+
}
393473
}
394474

395475
#[unstable(feature = "nonpoison_mutex", issue = "134645")]

library/std/tests/sync/mutex.rs

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ use std::{hint, mem, thread};
1010
//
1111
// To write a test that uses both `poison::Mutex` and `nonpoison::Mutex`, simply call the macro
1212
// `maybe_unwrap!(...)` on the result of `mutex.lock()`. For the `poison::Mutex`, it will unwrap the
13-
// `LockResult`, but for the `nonpoison::Mutex` it will do nothing.
13+
// `Result` (usually `LockResult`, but it could be other kinds of results), but for the
14+
// `nonpoison::Mutex` it will do nothing.
1415
//
1516
// The `poison` test will have the same name, but with a suffix of `_unwrap_poisoned`.
1617
//
@@ -38,11 +39,11 @@ macro_rules! nonpoison_and_poison_unwrap_test {
3839
#[test]
3940
fn ${concat($name, _unwrap_poisoned)}() {
4041
#[allow(unused_imports)]
41-
use ::std::sync::{Mutex, MappedMutexGuard, MutexGuard, LockResult};
42+
use ::std::sync::{Mutex, MappedMutexGuard, MutexGuard};
4243

4344
#[allow(unused_macros)]
4445
macro_rules! maybe_unwrap {
45-
($e:expr) => { LockResult::unwrap($e) };
46+
($e:expr) => { Result::unwrap($e) };
4647
}
4748

4849
$($test_body)*
@@ -151,17 +152,6 @@ nonpoison_and_poison_unwrap_test!(
151152
}
152153
);
153154

154-
// TODO(connor): make this a double test after implementing `lock_value_accessors` on `nonpoison`.
155-
#[test]
156-
fn test_get_cloned() {
157-
#[derive(Clone, Eq, PartialEq, Debug)]
158-
struct Cloneable(i32);
159-
160-
let m = Mutex::new(Cloneable(10));
161-
162-
assert_eq!(m.get_cloned().unwrap(), Cloneable(10));
163-
}
164-
165155
nonpoison_and_poison_unwrap_test!(
166156
name: test_get_mut,
167157
test_body: {
@@ -171,41 +161,55 @@ nonpoison_and_poison_unwrap_test!(
171161
}
172162
);
173163

174-
// TODO(connor): make this a double test after implementing `lock_value_accessors` on `nonpoison`.
175-
#[test]
176-
fn test_set() {
177-
fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
178-
where
179-
T: Debug + Eq,
180-
{
181-
let m = Mutex::new(init());
164+
nonpoison_and_poison_unwrap_test!(
165+
name: test_get_cloned,
166+
test_body: {
167+
#[derive(Clone, Eq, PartialEq, Debug)]
168+
struct Cloneable(i32);
169+
170+
let m = Mutex::new(Cloneable(10));
182171

183-
assert_eq!(*m.lock().unwrap(), init());
184-
m.set(value()).unwrap();
185-
assert_eq!(*m.lock().unwrap(), value());
172+
assert_eq!(maybe_unwrap!(m.get_cloned()), Cloneable(10));
186173
}
174+
);
187175

188-
inner(|| NonCopy(10), || NonCopy(20));
189-
inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
190-
}
176+
nonpoison_and_poison_unwrap_test!(
177+
name: test_set,
178+
test_body: {
179+
fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
180+
where
181+
T: Debug + Eq,
182+
{
183+
let m = Mutex::new(init());
191184

192-
// TODO(connor): make this a double test after implementing `lock_value_accessors` on `nonpoison`.
193-
#[test]
194-
fn test_replace() {
195-
fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
196-
where
197-
T: Debug + Eq,
198-
{
199-
let m = Mutex::new(init());
185+
assert_eq!(*maybe_unwrap!(m.lock()), init());
186+
maybe_unwrap!(m.set(value()));
187+
assert_eq!(*maybe_unwrap!(m.lock()), value());
188+
}
200189

201-
assert_eq!(*m.lock().unwrap(), init());
202-
assert_eq!(m.replace(value()).unwrap(), init());
203-
assert_eq!(*m.lock().unwrap(), value());
190+
inner(|| NonCopy(10), || NonCopy(20));
191+
inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
204192
}
193+
);
205194

206-
inner(|| NonCopy(10), || NonCopy(20));
207-
inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
208-
}
195+
nonpoison_and_poison_unwrap_test!(
196+
name: test_replace,
197+
test_body: {
198+
fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
199+
where
200+
T: Debug + Eq,
201+
{
202+
let m = Mutex::new(init());
203+
204+
assert_eq!(*maybe_unwrap!(m.lock()), init());
205+
assert_eq!(maybe_unwrap!(m.replace(value())), init());
206+
assert_eq!(*maybe_unwrap!(m.lock()), value());
207+
}
208+
209+
inner(|| NonCopy(10), || NonCopy(20));
210+
inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
211+
}
212+
);
209213

210214
#[test]
211215
fn test_mutex_arc_condvar() {

0 commit comments

Comments
 (0)