proptest_arbitrary/_std/
sync.rs

1//! Arbitrary implementations for `std::sync`.
2
3use super::*;
4use std::sync::*;
5use std::sync::atomic::*;
6use std::sync::mpsc::*;
7use std::thread;
8use std::time::Duration;
9
10// OnceState can not escape Once::call_once_force.
11// PoisonError depends implicitly on the lifetime on MutexGuard, etc.
12// This transitively applies to TryLockError.
13
14wrap_from!(Arc);
15
16#[cfg(not(MIN_VER_1_24_0))]
17wrap_ctor!(Mutex);
18#[cfg(MIN_VER_1_24_0)]
19wrap_from!(Mutex);
20
21#[cfg(not(MIN_VER_1_24_0))]
22wrap_ctor!(RwLock);
23#[cfg(MIN_VER_1_24_0)]
24wrap_from!(RwLock);
25
26arbitrary!(Barrier, SMapped<'a, u16, Self>;  // usize would be extreme!
27    static_map(any::<u16>(), |n| Barrier::new(n as usize))
28);
29
30arbitrary!(BarrierWaitResult,
31    TupleUnion<(W<FnGenerator<Self>>, W<FnGenerator<Self>>)>;
32    prop_oneof![FnGenerator::new(bwr_true), FnGenerator::new(bwr_false)]
33);
34
35generator!(
36    Condvar, default;
37    Once, Once::new
38);
39
40arbitrary!(WaitTimeoutResult, TupleUnion<(W<Just<Self>>, W<Just<Self>>)>;
41    prop_oneof![Just(wtr_true()), Just(wtr_false())]
42);
43
44fn bwr_true() -> BarrierWaitResult {
45    Barrier::new(1).wait()
46}
47
48fn bwr_false() -> BarrierWaitResult {
49    let barrier = Arc::new(Barrier::new(2));
50    let b2 = barrier.clone();
51    let jh = thread::spawn(move|| { b2.wait() });
52    let bwr1 = barrier.wait();
53    let bwr2 = jh.join().unwrap();
54    if bwr1.is_leader() { bwr2 } else { bwr1 }
55}
56
57fn wtr_false() -> WaitTimeoutResult {
58    let cvar = Arc::new(Condvar::new());
59    let cvar2 = cvar.clone();
60    thread::spawn(move|| { cvar2.notify_one(); });
61    let lock = Mutex::new(());
62    let wt = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(1));
63    let (_, wtr) = wt.unwrap();
64    wtr
65}
66
67fn wtr_true() -> WaitTimeoutResult {
68    let cvar = Condvar::new();
69    let lock = Mutex::new(());
70    let wt = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(0));
71    let (_, wtr) = wt.unwrap();
72    wtr
73}
74
75macro_rules! atomic {
76    ($($type: ident, $base: ty);+) => {
77        $(arbitrary!($type, SMapped<'a, $base, Self>;
78            any_with_smap((), $type::new)
79        );)+
80    };
81}
82
83// impl_wrap_gen!(AtomicPtr); // We don't have impl Arbitrary for *mut T yet.
84atomic!(AtomicBool, bool; AtomicIsize, isize; AtomicUsize, usize);
85
86#[cfg(feature = "unstable")]
87atomic!(AtomicI8, i8; AtomicI16, i16; AtomicI32, i32; AtomicI64, i64;
88        AtomicU8, u8; AtomicU16, u16; AtomicU32, u32; AtomicU64, u64);
89
90arbitrary!(Ordering,
91    TupleUnion<(W<Just<Self>>, W<Just<Self>>, W<Just<Self>>,
92                W<Just<Self>>, W<Just<Self>>)>;
93    prop_oneof![
94        Just(Ordering::Relaxed),
95        Just(Ordering::Release),
96        Just(Ordering::Acquire),
97        Just(Ordering::AcqRel),
98        Just(Ordering::SeqCst)
99    ]
100);
101
102arbitrary!(RecvError; RecvError);
103
104arbitrary!([T: Arbitrary<'a>] SendError<T>, SMapped<'a, T, Self>, T::Parameters;
105    args => any_with_smap(args, SendError)
106);
107
108arbitrary!(RecvTimeoutError, TupleUnion<(W<Just<Self>>, W<Just<Self>>)>;
109    prop_oneof![
110        Just(RecvTimeoutError::Disconnected),
111        Just(RecvTimeoutError::Timeout)
112    ]
113);
114
115arbitrary!(TryRecvError, TupleUnion<(W<Just<Self>>, W<Just<Self>>)>;
116    prop_oneof![
117        Just(TryRecvError::Disconnected),
118        Just(TryRecvError::Empty)
119    ]
120);
121
122arbitrary!(
123    [P: Clone + Default, T: Arbitrary<'a, Parameters = P>] TrySendError<T>,
124    TupleUnion<(W<SMapped<'a, T, Self>>, W<SMapped<'a, T, Self>>)>, P;
125    args => prop_oneof![
126        any_with_smap(args.clone(), TrySendError::Disconnected),
127        any_with_smap(args, TrySendError::Full),
128    ]
129);
130
131#[cfg(feature = "unstable")]
132generator!(Select, Select::new);
133
134// If only half of a pair is generated then you will get a hang-up.
135// Thus the only meaningful impls are in pairs.
136arbitrary!([A] (Sender<A>, Receiver<A>), FnGenerator<Self>;
137    FnGenerator::new(channel)
138);
139
140arbitrary!([A: Debug] (Sender<A>, IntoIter<A>), FnGenerator<Self>;
141    FnGenerator::new(|| {
142        let (rx, tx) = channel();
143        (rx, tx.into_iter())
144    })
145);
146
147arbitrary!([A] (SyncSender<A>, Receiver<A>), SMapped<'a, u16, Self>;
148    static_map(any::<u16>(), |size| sync_channel(size as usize))
149);
150
151arbitrary!([A: Debug] (SyncSender<A>, IntoIter<A>), SMapped<'a, u16, Self>;
152    static_map(any::<u16>(), |size| {
153        let (rx, tx) = sync_channel(size as usize);
154        (rx, tx.into_iter())
155    })
156);
157
158#[cfg(test)]
159mod test {
160    no_panic_test!(
161        arc => Arc<u8>,
162        mutex => Mutex<u8>,
163        rw_lock => RwLock<u8>,
164        barrier => Barrier,
165        barrier_wait_result => BarrierWaitResult,
166        condvar => Condvar,
167        once => Once,
168        wait_timeout_result => WaitTimeoutResult,
169        atomic_bool => AtomicBool,
170        atomic_isize => AtomicIsize,
171        atomic_usize => AtomicUsize,
172        ordering => Ordering,
173        recv_error => RecvError,
174        send_error => SendError<u8>,
175        recv_timeout_error => RecvTimeoutError,
176        try_recv_error => TryRecvError,
177        try_send_error => TrySendError<u8>,
178        rx_tx => (Sender<u8>, Receiver<u8>),
179        rx_txiter => (Sender<u8>, IntoIter<u8>),
180        syncrx_tx => (SyncSender<u8>, Receiver<u8>),
181        syncrx_txiter => (SyncSender<u8>, IntoIter<u8>)
182    );
183
184    #[cfg(feature = "unstable")]
185    no_panic_test!(
186        select => Select,
187        atomic_i8  => AtomicI8,
188        atomic_i16 => AtomicI16,
189        atomic_i32 => AtomicI32,
190        atomic_i64 => AtomicI64,
191        atomic_u8  => AtomicU8,
192        atomic_u16 => AtomicU16,
193        atomic_u32 => AtomicU32,
194        atomic_u64 => AtomicU64
195    );
196}