1use crate::{
2 BackgroundExecutor, Clock, Instant, LocalExecutor, Priority, RunnableMeta, Scheduler,
3 SessionId, Task, TestClock, Timer,
4};
5use async_task::Runnable;
6use backtrace::{Backtrace, BacktraceFrame};
7use futures::channel::oneshot;
8use parking_lot::{Mutex, MutexGuard};
9use rand::{
10 distr::{StandardUniform, uniform::SampleRange, uniform::SampleUniform},
11 prelude::*,
12};
13use std::any::Any;
14use std::{
15 any::type_name_of_val,
16 collections::{BTreeMap, HashSet, VecDeque},
17 env,
18 fmt::Write,
19 future::Future,
20 mem,
21 ops::RangeInclusive,
22 pin::Pin,
23 sync::{
24 Arc, Weak,
25 atomic::{AtomicBool, Ordering::SeqCst},
26 },
27 task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
28 thread::{self, Thread},
29 time::Duration,
30};
31
32const PENDING_TRACES_VAR_NAME: &str = "PENDING_TRACES";
33
34pub struct TestScheduler {
35 clock: Arc<TestClock>,
36 rng: Arc<Mutex<StdRng>>,
37 state: Arc<Mutex<SchedulerState>>,
38 thread: Thread,
39}
40
41impl TestScheduler {
42 pub fn once<R>(f: impl AsyncFnOnce(Arc<TestScheduler>) -> R) -> R {
44 Self::with_seed(0, f)
45 }
46
47 pub fn many<R>(
49 default_iterations: usize,
50 mut f: impl AsyncFnMut(Arc<TestScheduler>) -> R,
51 ) -> Vec<R> {
52 let num_iterations = std::env::var("ITERATIONS")
53 .map(|iterations| iterations.parse().unwrap())
54 .unwrap_or(default_iterations);
55
56 let seed = std::env::var("SEED")
57 .map(|seed| seed.parse().unwrap())
58 .unwrap_or(0);
59
60 let interactive = !std::env::var("SCHEDULER_NONINTERACTIVE").is_ok();
61
62 (seed..seed + num_iterations as u64)
63 .map(|seed| {
64 let mut unwind_safe_f = std::panic::AssertUnwindSafe(&mut f);
65 if interactive {
66 eprintln!("Running seed: {seed}");
67 }
68 match std::panic::catch_unwind(move || Self::with_seed(seed, &mut *unwind_safe_f)) {
69 Ok(result) => result,
70 Err(error) => {
71 eprintln!("\x1b[31mFailing Seed: {seed}\x1b[0m");
72 std::panic::resume_unwind(error);
73 }
74 }
75 })
76 .collect()
77 }
78
79 fn with_seed<R>(seed: u64, f: impl AsyncFnOnce(Arc<TestScheduler>) -> R) -> R {
80 let scheduler = Arc::new(TestScheduler::new(TestSchedulerConfig::with_seed(seed)));
81 let output = std::cell::Cell::new(None);
82 let future = f(scheduler.clone());
83 let future = async {
84 output.set(Some(future.await));
85 };
86 let mut future = std::pin::pin!(future);
87 scheduler.block_until(None, future.as_mut(), None);
88 let result = output.take().expect("test future did not complete");
89 scheduler.run(); result
91 }
92
93 fn block_until(
94 &self,
95 session_id: Option<SessionId>,
96 mut future: Pin<&mut dyn Future<Output = ()>>,
97 timeout: Option<Duration>,
98 ) -> bool {
99 if let Some(session_id) = session_id {
100 self.state.lock().blocked_sessions.push(session_id);
101 }
102
103 let deadline = timeout.map(|timeout| Instant::now() + timeout);
104 let awoken = Arc::new(AtomicBool::new(false));
105 let waker = Box::new(TracingWaker {
106 id: None,
107 awoken: awoken.clone(),
108 thread: self.thread.clone(),
109 state: self.state.clone(),
110 });
111 let waker = unsafe { Waker::new(Box::into_raw(waker) as *const (), &WAKER_VTABLE) };
112 let max_ticks = if timeout.is_some() {
113 self.rng
114 .lock()
115 .random_range(self.state.lock().timeout_ticks.clone())
116 } else {
117 usize::MAX
118 };
119 let mut cx = Context::from_waker(&waker);
120
121 let mut completed = false;
122 for _ in 0..max_ticks {
123 match future.as_mut().poll(&mut cx) {
124 Poll::Ready(()) => {
125 completed = true;
126 break;
127 }
128 Poll::Pending => {}
129 }
130
131 let mut stepped = None;
132 while self.rng.lock().random() {
133 let stepped = stepped.get_or_insert(false);
134 if self.step() {
135 *stepped = true;
136 } else {
137 break;
138 }
139 }
140
141 let stepped = stepped.unwrap_or(true);
142 let awoken = awoken.swap(false, SeqCst);
143 if !stepped && !awoken {
144 let parking_allowed = self.state.lock().allow_parking;
145 let advanced_to_timer = !parking_allowed && self.advance_clock_to_next_timer();
148 if !advanced_to_timer && !self.park(deadline) {
149 break;
150 }
151 }
152 }
153
154 if session_id.is_some() {
155 self.state.lock().blocked_sessions.pop();
156 }
157
158 completed
159 }
160
161 pub fn new(config: TestSchedulerConfig) -> Self {
162 crate::TEST_SCHEDULER_CREATED.store(true, std::sync::atomic::Ordering::Relaxed);
163 Self {
164 rng: Arc::new(Mutex::new(StdRng::seed_from_u64(config.seed))),
165 state: Arc::new(Mutex::new(SchedulerState {
166 runnables: VecDeque::new(),
167 timers: Vec::new(),
168 blocked_sessions: Vec::new(),
169 randomize_order: config.randomize_order,
170 allow_parking: config.allow_parking,
171 timeout_ticks: config.timeout_ticks,
172 next_session_id: SessionId(0),
173 capture_pending_traces: config.capture_pending_traces,
174 pending_traces: BTreeMap::new(),
175 next_trace_id: TraceId(0),
176 is_main_thread: true,
177 non_determinism_error: None,
178 finished: false,
179 parking_allowed_once: false,
180 unparked: false,
181 })),
182 clock: Arc::new(TestClock::new()),
183 thread: thread::current(),
184 }
185 }
186
187 pub fn end_test(&self) {
188 let mut state = self.state.lock();
189 if let Some((message, backtrace)) = &state.non_determinism_error {
190 if cfg!(miri) {
191 panic!("{}", message)
193 } else {
194 panic!("{}\n{:?}", message, backtrace)
195 }
196 }
197 state.finished = true;
198 }
199
200 pub fn clock(&self) -> Arc<TestClock> {
201 self.clock.clone()
202 }
203
204 pub fn rng(&self) -> SharedRng {
205 SharedRng(self.rng.clone())
206 }
207
208 pub fn set_timeout_ticks(&self, timeout_ticks: RangeInclusive<usize>) {
209 self.state.lock().timeout_ticks = timeout_ticks;
210 }
211
212 pub fn allow_parking(&self) {
213 let mut state = self.state.lock();
214 state.allow_parking = true;
215 state.parking_allowed_once = true;
216 }
217
218 pub fn forbid_parking(&self) {
219 self.state.lock().allow_parking = false;
220 }
221
222 pub fn parking_allowed(&self) -> bool {
223 self.state.lock().allow_parking
224 }
225
226 pub fn is_main_thread(&self) -> bool {
227 self.state.lock().is_main_thread
228 }
229
230 pub fn allocate_session_id(&self) -> SessionId {
231 let mut state = self.state.lock();
232 state.next_session_id.0 += 1;
233 state.next_session_id
234 }
235
236 pub fn foreground(self: &Arc<Self>) -> LocalExecutor {
238 let session_id = self.allocate_session_id();
239 LocalExecutor::new(
240 session_id,
241 self.clone(),
242 schedule_local_dispatch(Arc::downgrade(self), session_id),
243 )
244 }
245
246 pub fn background(self: &Arc<Self>) -> BackgroundExecutor {
248 BackgroundExecutor::new(self.clone())
249 }
250
251 pub fn yield_random(&self) -> Yield {
252 let rng = &mut *self.rng.lock();
253 if rng.random_bool(0.1) {
254 Yield(rng.random_range(10..20))
255 } else {
256 Yield(rng.random_range(0..2))
257 }
258 }
259
260 pub fn run(&self) {
261 while self.step() {
262 }
264 }
265
266 pub fn run_with_clock_advancement(&self) {
267 while self.step() || self.advance_clock_to_next_timer() {
268 }
270 }
271
272 pub fn tick(&self) -> bool {
277 self.step_filtered(false)
278 }
279
280 pub fn tick_background_only(&self) -> bool {
283 self.step_filtered(true)
284 }
285
286 pub fn has_pending_tasks(&self) -> bool {
288 let state = self.state.lock();
289 !state.runnables.is_empty() || !state.timers.is_empty()
290 }
291
292 pub fn pending_task_counts(&self) -> (usize, usize) {
295 let state = self.state.lock();
296 let foreground = state
297 .runnables
298 .iter()
299 .filter(|r| r.session_id.is_some())
300 .count();
301 let background = state
302 .runnables
303 .iter()
304 .filter(|r| r.session_id.is_none())
305 .count();
306 (foreground, background)
307 }
308
309 fn step(&self) -> bool {
310 self.step_filtered(false)
311 }
312
313 fn step_filtered(&self, background_only: bool) -> bool {
314 let (elapsed_count, runnables_before) = {
315 let mut state = self.state.lock();
316 let end_ix = state
317 .timers
318 .partition_point(|timer| timer.expiration <= self.clock.now());
319 let elapsed: Vec<_> = state.timers.drain(..end_ix).collect();
320 let count = elapsed.len();
321 let runnables = state.runnables.len();
322 drop(state);
323 drop(elapsed);
325 (count, runnables)
326 };
327
328 if elapsed_count > 0 {
329 let runnables_after = self.state.lock().runnables.len();
330 if std::env::var("DEBUG_SCHEDULER").is_ok() {
331 eprintln!(
332 "[scheduler] Expired {} timers at {:?}, runnables: {} -> {}",
333 elapsed_count,
334 self.clock.now(),
335 runnables_before,
336 runnables_after
337 );
338 }
339 return true;
340 }
341
342 let runnable = {
343 let state = &mut *self.state.lock();
344
345 let mut seen_sessions = HashSet::new();
352 let candidate_indices: Vec<usize> = state
353 .runnables
354 .iter()
355 .enumerate()
356 .filter(|(_, runnable)| {
357 if let Some(session_id) = runnable.session_id {
358 if background_only {
360 return false;
361 }
362 if state.blocked_sessions.contains(&session_id) {
364 return false;
365 }
366 seen_sessions.insert(session_id)
368 } else {
369 true
371 }
372 })
373 .map(|(ix, _)| ix)
374 .collect();
375
376 if candidate_indices.is_empty() {
377 None
378 } else if state.randomize_order {
379 let weights: Vec<u32> = candidate_indices
381 .iter()
382 .map(|&ix| state.runnables[ix].priority.weight())
383 .collect();
384 let total_weight: u32 = weights.iter().sum();
385
386 if total_weight == 0 {
387 let choice = self.rng.lock().random_range(0..candidate_indices.len());
389 state.runnables.remove(candidate_indices[choice])
390 } else {
391 let mut target = self.rng.lock().random_range(0..total_weight);
392 let mut selected_idx = 0;
393 for (i, &weight) in weights.iter().enumerate() {
394 if target < weight {
395 selected_idx = i;
396 break;
397 }
398 target -= weight;
399 }
400 state.runnables.remove(candidate_indices[selected_idx])
401 }
402 } else {
403 state.runnables.remove(candidate_indices[0])
405 }
406 };
407
408 if let Some(runnable) = runnable {
409 let is_foreground = runnable.session_id.is_some();
410 let was_main_thread = self.state.lock().is_main_thread;
411 self.state.lock().is_main_thread = is_foreground;
412 runnable.run();
413 self.state.lock().is_main_thread = was_main_thread;
414 return true;
415 }
416
417 false
418 }
419
420 pub fn drain_tasks(&self) {
426 loop {
430 let mut state = self.state.lock();
431 if state.runnables.is_empty() && state.timers.is_empty() {
432 break;
433 }
434 let runnables = std::mem::take(&mut state.runnables);
435 let timers = std::mem::take(&mut state.timers);
436 drop(state);
437 drop(timers);
438 drop(runnables);
439 }
440 }
441
442 pub fn advance_clock_to_next_timer(&self) -> bool {
443 if let Some(timer) = self.state.lock().timers.first() {
444 self.clock.advance(timer.expiration - self.clock.now());
445 true
446 } else {
447 false
448 }
449 }
450
451 pub fn advance_clock(&self, duration: Duration) {
452 let debug = std::env::var("DEBUG_SCHEDULER").is_ok();
453 let start = self.clock.now();
454 let next_now = start + duration;
455 if debug {
456 let timer_count = self.state.lock().timers.len();
457 eprintln!(
458 "[scheduler] advance_clock({:?}) from {:?}, {} pending timers",
459 duration, start, timer_count
460 );
461 }
462 loop {
463 self.run();
464 if let Some(timer) = self.state.lock().timers.first()
465 && timer.expiration <= next_now
466 {
467 let advance_to = timer.expiration;
468 if debug {
469 eprintln!(
470 "[scheduler] Advancing clock {:?} -> {:?} for timer",
471 self.clock.now(),
472 advance_to
473 );
474 }
475 self.clock.advance(advance_to - self.clock.now());
476 } else {
477 break;
478 }
479 }
480 self.clock.advance(next_now - self.clock.now());
481 if debug {
482 eprintln!(
483 "[scheduler] advance_clock done, now at {:?}",
484 self.clock.now()
485 );
486 }
487 }
488
489 fn park(&self, deadline: Option<Instant>) -> bool {
490 if self.state.lock().allow_parking {
491 let start = Instant::now();
492 let hard_deadline = start + Duration::from_secs(15);
494
495 let effective_deadline = deadline
497 .map(|d| d.min(hard_deadline))
498 .unwrap_or(hard_deadline);
499
500 const PARK_INTERVAL: Duration = Duration::from_millis(100);
502 loop {
503 let now = Instant::now();
504 if now >= effective_deadline {
505 if now >= hard_deadline {
507 panic!(
508 "Test timed out after 15 seconds while parking. \
509 This may indicate a deadlock or missing waker.",
510 );
511 }
512 return false;
514 }
515
516 let remaining = effective_deadline.saturating_duration_since(now);
517 let park_duration = remaining.min(PARK_INTERVAL);
518 let before_park = Instant::now();
519 thread::park_timeout(park_duration);
520 let elapsed = before_park.elapsed();
521
522 self.clock.advance(elapsed);
524
525 if self
528 .state
529 .lock()
530 .timers
531 .first()
532 .map_or(false, |t| t.expiration <= self.clock.now())
533 {
534 return true;
535 }
536
537 if std::mem::take(&mut self.state.lock().unparked) {
542 return true;
543 }
544 }
545 } else if deadline.is_some() {
546 false
547 } else if cfg!(miri) {
548 panic!("Parking forbidden.");
550 } else if self.state.lock().capture_pending_traces {
551 let mut pending_traces = String::new();
552 for (_, trace) in mem::take(&mut self.state.lock().pending_traces) {
553 writeln!(pending_traces, "{:?}", exclude_wakers_from_trace(trace)).unwrap();
554 }
555 panic!("Parking forbidden. Pending traces:\n{}", pending_traces);
556 } else {
557 panic!(
558 "Parking forbidden. Re-run with {PENDING_TRACES_VAR_NAME}=1 to show pending traces"
559 );
560 }
561 }
562}
563
564fn assert_correct_thread(expected: &Thread, state: &Arc<Mutex<SchedulerState>>) {
565 let current_thread = thread::current();
566 let mut state = state.lock();
567 if state.parking_allowed_once {
568 return;
569 }
570 if current_thread.id() == expected.id() {
571 return;
572 }
573
574 let message = format!(
575 "Detected activity on thread {:?} {:?}, but test scheduler is running on {:?} {:?}. Your test is not deterministic.",
576 current_thread.name(),
577 current_thread.id(),
578 expected.name(),
579 expected.id(),
580 );
581 let backtrace = Backtrace::new();
582 if state.finished {
583 panic!("{}", message);
584 } else {
585 state.non_determinism_error = Some((message, backtrace))
586 }
587}
588
589impl Scheduler for TestScheduler {
590 #[cfg(not(target_family = "wasm"))]
598 fn block(
599 &self,
600 session_id: Option<SessionId>,
601 future: Pin<&mut dyn Future<Output = ()>>,
602 timeout: Option<Duration>,
603 ) -> bool {
604 self.block_until(session_id, future, timeout)
605 }
606
607 fn schedule_local(&self, session_id: SessionId, runnable: Runnable<RunnableMeta>) {
608 assert_correct_thread(&self.thread, &self.state);
609 let mut state = self.state.lock();
610 let ix = if state.randomize_order {
611 let start_ix = state
612 .runnables
613 .iter()
614 .rposition(|task| task.session_id == Some(session_id))
615 .map_or(0, |ix| ix + 1);
616 self.rng
617 .lock()
618 .random_range(start_ix..=state.runnables.len())
619 } else {
620 state.runnables.len()
621 };
622 state.runnables.insert(
623 ix,
624 ScheduledRunnable {
625 session_id: Some(session_id),
626 priority: Priority::default(),
627 runnable,
628 },
629 );
630 state.unparked = true;
631 drop(state);
632 self.thread.unpark();
633 }
634
635 fn schedule_background_with_priority(
636 &self,
637 runnable: Runnable<RunnableMeta>,
638 priority: Priority,
639 ) {
640 assert_correct_thread(&self.thread, &self.state);
641 let mut state = self.state.lock();
642 let ix = if state.randomize_order {
643 self.rng.lock().random_range(0..=state.runnables.len())
644 } else {
645 state.runnables.len()
646 };
647 state.runnables.insert(
648 ix,
649 ScheduledRunnable {
650 session_id: None,
651 priority,
652 runnable,
653 },
654 );
655 state.unparked = true;
656 drop(state);
657 self.thread.unpark();
658 }
659
660 fn spawn_realtime(&self, f: Box<dyn FnOnce() + Send>) {
661 std::thread::spawn(move || {
662 f();
663 });
664 }
665
666 #[track_caller]
667 fn timer(&self, duration: Duration) -> Timer {
668 let (tx, rx) = oneshot::channel();
669 let state = &mut *self.state.lock();
670 state.timers.push(ScheduledTimer {
671 expiration: self.clock.now() + duration,
672 _notify: tx,
673 });
674 state.timers.sort_by_key(|timer| timer.expiration);
675 Timer(rx)
676 }
677
678 fn clock(&self) -> Arc<dyn Clock> {
679 self.clock.clone()
680 }
681
682 fn spawn_dedicated(
687 self: Arc<Self>,
688 f: Box<
689 dyn FnOnce(
690 LocalExecutor,
691 )
692 -> Pin<Box<dyn Future<Output = Box<dyn Any + Send + Sync>> + 'static>>
693 + Send
694 + 'static,
695 >,
696 ) -> Task<Box<dyn Any + Send + Sync>> {
697 let session_id = self.allocate_session_id();
698 let weak_scheduler = Arc::downgrade(&self);
699 let spawner = LocalExecutor::new(
700 session_id,
701 self,
702 schedule_local_dispatch(weak_scheduler.clone(), session_id),
703 );
704 spawner.spawn(async move {
712 let scheduler = weak_scheduler
713 .upgrade()
714 .expect("dedicated tasks are only polled by their scheduler, which is still alive when polled");
715 let executor = LocalExecutor::new(
716 session_id,
717 scheduler,
718 schedule_local_dispatch(weak_scheduler, session_id),
719 );
720 f(executor).await
721 })
722 }
723
724 fn as_test(&self) -> Option<&TestScheduler> {
725 Some(self)
726 }
727}
728
729fn schedule_local_dispatch(
732 scheduler: Weak<TestScheduler>,
733 session_id: SessionId,
734) -> impl Fn(Runnable<RunnableMeta>) + Send + Sync + 'static {
735 move |runnable| {
736 if let Some(scheduler) = scheduler.upgrade() {
737 scheduler.schedule_local(session_id, runnable);
738 }
739 }
740}
741
742#[derive(Clone, Debug)]
743pub struct TestSchedulerConfig {
744 pub seed: u64,
745 pub randomize_order: bool,
746 pub allow_parking: bool,
747 pub capture_pending_traces: bool,
748 pub timeout_ticks: RangeInclusive<usize>,
749}
750
751impl TestSchedulerConfig {
752 pub fn with_seed(seed: u64) -> Self {
753 Self {
754 seed,
755 ..Default::default()
756 }
757 }
758}
759
760impl Default for TestSchedulerConfig {
761 fn default() -> Self {
762 Self {
763 seed: 0,
764 randomize_order: true,
765 allow_parking: false,
766 capture_pending_traces: env::var(PENDING_TRACES_VAR_NAME)
767 .map_or(false, |var| var == "1" || var == "true"),
768 timeout_ticks: 1..=1000,
769 }
770 }
771}
772
773struct ScheduledRunnable {
774 session_id: Option<SessionId>,
775 priority: Priority,
776 runnable: Runnable<RunnableMeta>,
777}
778
779impl ScheduledRunnable {
780 fn run(self) {
781 self.runnable.run();
782 }
783}
784
785struct ScheduledTimer {
786 expiration: Instant,
787 _notify: oneshot::Sender<()>,
788}
789
790struct SchedulerState {
791 runnables: VecDeque<ScheduledRunnable>,
792 timers: Vec<ScheduledTimer>,
793 blocked_sessions: Vec<SessionId>,
794 randomize_order: bool,
795 allow_parking: bool,
796 timeout_ticks: RangeInclusive<usize>,
797 next_session_id: SessionId,
798 capture_pending_traces: bool,
799 next_trace_id: TraceId,
800 pending_traces: BTreeMap<TraceId, Backtrace>,
801 is_main_thread: bool,
802 non_determinism_error: Option<(String, Backtrace)>,
803 parking_allowed_once: bool,
804 finished: bool,
805 unparked: bool,
806}
807
808const WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
809 TracingWaker::clone_raw,
810 TracingWaker::wake_raw,
811 TracingWaker::wake_by_ref_raw,
812 TracingWaker::drop_raw,
813);
814
815#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
816struct TraceId(usize);
817
818struct TracingWaker {
819 id: Option<TraceId>,
820 awoken: Arc<AtomicBool>,
821 thread: Thread,
822 state: Arc<Mutex<SchedulerState>>,
823}
824
825impl Clone for TracingWaker {
826 fn clone(&self) -> Self {
827 let mut state = self.state.lock();
828 let id = if state.capture_pending_traces {
829 let id = state.next_trace_id;
830 state.next_trace_id.0 += 1;
831 state.pending_traces.insert(id, Backtrace::new_unresolved());
832 Some(id)
833 } else {
834 None
835 };
836 Self {
837 id,
838 awoken: self.awoken.clone(),
839 thread: self.thread.clone(),
840 state: self.state.clone(),
841 }
842 }
843}
844
845impl Drop for TracingWaker {
846 fn drop(&mut self) {
847 assert_correct_thread(&self.thread, &self.state);
848
849 if let Some(id) = self.id {
850 self.state.lock().pending_traces.remove(&id);
851 }
852 }
853}
854
855impl TracingWaker {
856 fn wake(self) {
857 self.wake_by_ref();
858 }
859
860 fn wake_by_ref(&self) {
861 assert_correct_thread(&self.thread, &self.state);
862
863 let mut state = self.state.lock();
864 if let Some(id) = self.id {
865 state.pending_traces.remove(&id);
866 }
867 state.unparked = true;
868 drop(state);
869 self.awoken.store(true, SeqCst);
870 self.thread.unpark();
871 }
872
873 fn clone_raw(waker: *const ()) -> RawWaker {
874 let waker = waker as *const TracingWaker;
875 let waker = unsafe { &*waker };
876 RawWaker::new(
877 Box::into_raw(Box::new(waker.clone())) as *const (),
878 &WAKER_VTABLE,
879 )
880 }
881
882 fn wake_raw(waker: *const ()) {
883 let waker = unsafe { Box::from_raw(waker as *mut TracingWaker) };
884 waker.wake();
885 }
886
887 fn wake_by_ref_raw(waker: *const ()) {
888 let waker = waker as *const TracingWaker;
889 let waker = unsafe { &*waker };
890 waker.wake_by_ref();
891 }
892
893 fn drop_raw(waker: *const ()) {
894 let waker = unsafe { Box::from_raw(waker as *mut TracingWaker) };
895 drop(waker);
896 }
897}
898
899pub struct Yield(usize);
900
901#[derive(Clone)]
904pub struct SharedRng(Arc<Mutex<StdRng>>);
905
906impl SharedRng {
907 pub fn lock(&self) -> MutexGuard<'_, StdRng> {
910 self.0.lock()
911 }
912
913 pub fn random_range<T, R>(&self, range: R) -> T
915 where
916 T: SampleUniform,
917 R: SampleRange<T>,
918 {
919 self.0.lock().random_range(range)
920 }
921
922 pub fn random_bool(&self, p: f64) -> bool {
924 self.0.lock().random_bool(p)
925 }
926
927 pub fn random<T>(&self) -> T
929 where
930 StandardUniform: Distribution<T>,
931 {
932 self.0.lock().random()
933 }
934
935 pub fn random_ratio(&self, numerator: u32, denominator: u32) -> bool {
937 self.0.lock().random_ratio(numerator, denominator)
938 }
939}
940
941impl Future for Yield {
942 type Output = ();
943
944 fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
945 if self.0 == 0 {
946 Poll::Ready(())
947 } else {
948 self.0 -= 1;
949 cx.waker().wake_by_ref();
950 Poll::Pending
951 }
952 }
953}
954
955fn exclude_wakers_from_trace(mut trace: Backtrace) -> Backtrace {
956 trace.resolve();
957 let mut frames: Vec<BacktraceFrame> = trace.into();
958 let waker_clone_frame_ix = frames.iter().position(|frame| {
959 frame.symbols().iter().any(|symbol| {
960 symbol
961 .name()
962 .is_some_and(|name| format!("{name:#?}") == type_name_of_val(&Waker::clone))
963 })
964 });
965
966 if let Some(waker_clone_frame_ix) = waker_clone_frame_ix {
967 frames.drain(..waker_clone_frame_ix + 1);
968 }
969
970 Backtrace::from(frames)
971}