@@ -4,16 +4,15 @@ use crate::{
keymap::{self, Keystroke},
platform::{self, CursorStyle, Platform, PromptLevel, WindowOptions},
presenter::Presenter,
- util::{post_inc, timeout, CwdBacktrace},
+ util::post_inc,
AssetCache, AssetSource, ClipboardItem, FontCache, PathPromptOptions, TextLayoutCache,
};
use anyhow::{anyhow, Result};
-use backtrace::Backtrace;
use keymap::MatchResult;
use lazy_static::lazy_static;
use parking_lot::Mutex;
use platform::Event;
-use postage::{mpsc, oneshot, sink::Sink as _, stream::Stream as _};
+use postage::oneshot;
use smol::prelude::*;
use std::{
any::{self, type_name, Any, TypeId},
@@ -237,6 +236,7 @@ pub struct App(Rc<RefCell<MutableAppContext>>);
#[derive(Clone)]
pub struct AsyncAppContext(Rc<RefCell<MutableAppContext>>);
+#[cfg(any(test, feature = "test-support"))]
pub struct TestAppContext {
cx: Rc<RefCell<MutableAppContext>>,
foreground_platform: Rc<platform::test::ForegroundPlatform>,
@@ -384,6 +384,7 @@ impl App {
}
}
+#[cfg(any(test, feature = "test-support"))]
impl TestAppContext {
pub fn new(
foreground_platform: Rc<platform::test::ForegroundPlatform>,
@@ -401,7 +402,7 @@ impl TestAppContext {
foreground_platform.clone(),
font_cache,
RefCounts {
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
leak_detector,
..Default::default()
},
@@ -544,6 +545,8 @@ impl TestAppContext {
}
pub fn simulate_prompt_answer(&self, window_id: usize, answer: usize) {
+ use postage::prelude::Sink as _;
+
let mut state = self.cx.borrow_mut();
let (_, window) = state
.presenters_and_platform_windows
@@ -560,18 +563,12 @@ impl TestAppContext {
let _ = done_tx.try_send(answer);
}
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
pub fn leak_detector(&self) -> Arc<Mutex<LeakDetector>> {
self.cx.borrow().leak_detector()
}
}
-impl Drop for TestAppContext {
- fn drop(&mut self) {
- self.cx.borrow_mut().remove_all_windows();
- }
-}
-
impl AsyncAppContext {
pub fn spawn<F, Fut, T>(&self, f: F) -> Task<T>
where
@@ -684,6 +681,7 @@ impl ReadViewWith for AsyncAppContext {
}
}
+#[cfg(any(test, feature = "test-support"))]
impl UpdateModel for TestAppContext {
fn update_model<T: Entity, O>(
&mut self,
@@ -694,6 +692,7 @@ impl UpdateModel for TestAppContext {
}
}
+#[cfg(any(test, feature = "test-support"))]
impl ReadModelWith for TestAppContext {
fn read_model_with<E: Entity, T>(
&self,
@@ -706,6 +705,7 @@ impl ReadModelWith for TestAppContext {
}
}
+#[cfg(any(test, feature = "test-support"))]
impl UpdateView for TestAppContext {
fn update_view<T, S>(
&mut self,
@@ -719,6 +719,7 @@ impl UpdateView for TestAppContext {
}
}
+#[cfg(any(test, feature = "test-support"))]
impl ReadViewWith for TestAppContext {
fn read_view_with<V, T>(
&self,
@@ -848,7 +849,7 @@ impl MutableAppContext {
}
}
- fn remove_all_windows(&mut self) {
+ pub fn remove_all_windows(&mut self) {
for (window_id, _) in self.cx.windows.drain() {
self.presenters_and_platform_windows.remove(&window_id);
}
@@ -1827,7 +1828,7 @@ impl MutableAppContext {
self.cx.platform.read_from_clipboard()
}
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
pub fn leak_detector(&self) -> Arc<Mutex<LeakDetector>> {
self.cx.ref_counts.lock().leak_detector.clone()
}
@@ -2841,7 +2842,7 @@ pub struct ModelHandle<T: Entity> {
model_type: PhantomData<T>,
ref_counts: Arc<Mutex<RefCounts>>,
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
handle_id: usize,
}
@@ -2849,7 +2850,7 @@ impl<T: Entity> ModelHandle<T> {
fn new(model_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
ref_counts.lock().inc_model(model_id);
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
let handle_id = ref_counts
.lock()
.leak_detector
@@ -2861,7 +2862,7 @@ impl<T: Entity> ModelHandle<T> {
model_type: PhantomData,
ref_counts: ref_counts.clone(),
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
handle_id,
}
}
@@ -2902,8 +2903,11 @@ impl<T: Entity> ModelHandle<T> {
})
}
+ #[cfg(any(test, feature = "test-support"))]
pub fn next_notification(&self, cx: &TestAppContext) -> impl Future<Output = ()> {
- let (mut tx, mut rx) = mpsc::channel(1);
+ use postage::prelude::{Sink as _, Stream as _};
+
+ let (mut tx, mut rx) = postage::mpsc::channel(1);
let mut cx = cx.cx.borrow_mut();
let subscription = cx.observe(self, move |_, _| {
tx.try_send(()).ok();
@@ -2916,7 +2920,7 @@ impl<T: Entity> ModelHandle<T> {
};
async move {
- let notification = timeout(duration, rx.recv())
+ let notification = crate::util::timeout(duration, rx.recv())
.await
.expect("next notification timed out");
drop(subscription);
@@ -2924,11 +2928,14 @@ impl<T: Entity> ModelHandle<T> {
}
}
+ #[cfg(any(test, feature = "test-support"))]
pub fn next_event(&self, cx: &TestAppContext) -> impl Future<Output = T::Event>
where
T::Event: Clone,
{
- let (mut tx, mut rx) = mpsc::channel(1);
+ use postage::prelude::{Sink as _, Stream as _};
+
+ let (mut tx, mut rx) = postage::mpsc::channel(1);
let mut cx = cx.cx.borrow_mut();
let subscription = cx.subscribe(self, move |_, event, _| {
tx.blocking_send(event.clone()).ok();
@@ -2941,7 +2948,7 @@ impl<T: Entity> ModelHandle<T> {
};
async move {
- let event = timeout(duration, rx.recv())
+ let event = crate::util::timeout(duration, rx.recv())
.await
.expect("next event timed out");
drop(subscription);
@@ -2949,12 +2956,15 @@ impl<T: Entity> ModelHandle<T> {
}
}
+ #[cfg(any(test, feature = "test-support"))]
pub fn condition(
&self,
cx: &TestAppContext,
mut predicate: impl FnMut(&T, &AppContext) -> bool,
) -> impl Future<Output = ()> {
- let (tx, mut rx) = mpsc::channel(1024);
+ use postage::prelude::{Sink as _, Stream as _};
+
+ let (tx, mut rx) = postage::mpsc::channel(1024);
let mut cx = cx.cx.borrow_mut();
let subscriptions = (
@@ -2981,7 +2991,7 @@ impl<T: Entity> ModelHandle<T> {
};
async move {
- timeout(duration, async move {
+ crate::util::timeout(duration, async move {
loop {
{
let cx = cx.borrow();
@@ -3059,7 +3069,7 @@ impl<T: Entity> Drop for ModelHandle<T> {
let mut ref_counts = self.ref_counts.lock();
ref_counts.dec_model(self.model_id);
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
ref_counts
.leak_detector
.lock()
@@ -3149,14 +3159,14 @@ pub struct ViewHandle<T> {
view_id: usize,
view_type: PhantomData<T>,
ref_counts: Arc<Mutex<RefCounts>>,
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
handle_id: usize,
}
impl<T: View> ViewHandle<T> {
fn new(window_id: usize, view_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
ref_counts.lock().inc_view(window_id, view_id);
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
let handle_id = ref_counts
.lock()
.leak_detector
@@ -3169,7 +3179,7 @@ impl<T: View> ViewHandle<T> {
view_type: PhantomData,
ref_counts: ref_counts.clone(),
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
handle_id,
}
}
@@ -3230,8 +3240,11 @@ impl<T: View> ViewHandle<T> {
.map_or(false, |focused_id| focused_id == self.view_id)
}
+ #[cfg(any(test, feature = "test-support"))]
pub fn next_notification(&self, cx: &TestAppContext) -> impl Future<Output = ()> {
- let (mut tx, mut rx) = mpsc::channel(1);
+ use postage::prelude::{Sink as _, Stream as _};
+
+ let (mut tx, mut rx) = postage::mpsc::channel(1);
let mut cx = cx.cx.borrow_mut();
let subscription = cx.observe(self, move |_, _| {
tx.try_send(()).ok();
@@ -3244,7 +3257,7 @@ impl<T: View> ViewHandle<T> {
};
async move {
- let notification = timeout(duration, rx.recv())
+ let notification = crate::util::timeout(duration, rx.recv())
.await
.expect("next notification timed out");
drop(subscription);
@@ -3252,12 +3265,15 @@ impl<T: View> ViewHandle<T> {
}
}
+ #[cfg(any(test, feature = "test-support"))]
pub fn condition(
&self,
cx: &TestAppContext,
mut predicate: impl FnMut(&T, &AppContext) -> bool,
) -> impl Future<Output = ()> {
- let (tx, mut rx) = mpsc::channel(1024);
+ use postage::prelude::{Sink as _, Stream as _};
+
+ let (tx, mut rx) = postage::mpsc::channel(1024);
let mut cx = cx.cx.borrow_mut();
let subscriptions = self.update(&mut *cx, |_, cx| {
@@ -3286,7 +3302,7 @@ impl<T: View> ViewHandle<T> {
};
async move {
- timeout(duration, async move {
+ crate::util::timeout(duration, async move {
loop {
{
let cx = cx.borrow();
@@ -3344,7 +3360,7 @@ impl<T> Drop for ViewHandle<T> {
self.ref_counts
.lock()
.dec_view(self.window_id, self.view_id);
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
self.ref_counts
.lock()
.leak_detector
@@ -3382,7 +3398,7 @@ pub struct AnyViewHandle {
view_type: TypeId,
type_name: &'static str,
ref_counts: Arc<Mutex<RefCounts>>,
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
handle_id: usize,
}
@@ -3396,7 +3412,7 @@ impl AnyViewHandle {
) -> Self {
ref_counts.lock().inc_view(window_id, view_id);
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
let handle_id = ref_counts
.lock()
.leak_detector
@@ -3409,7 +3425,7 @@ impl AnyViewHandle {
view_type,
type_name,
ref_counts,
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
handle_id,
}
}
@@ -3434,7 +3450,7 @@ impl AnyViewHandle {
view_id: self.view_id,
ref_counts: self.ref_counts.clone(),
view_type: PhantomData,
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
handle_id: self.handle_id,
});
unsafe {
@@ -3486,7 +3502,7 @@ impl<T: View> From<ViewHandle<T>> for AnyViewHandle {
view_type: TypeId::of::<T>(),
type_name: any::type_name::<T>(),
ref_counts: handle.ref_counts.clone(),
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
handle_id: handle.handle_id,
};
unsafe {
@@ -3502,7 +3518,7 @@ impl Drop for AnyViewHandle {
self.ref_counts
.lock()
.dec_view(self.window_id, self.view_id);
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
self.ref_counts
.lock()
.leak_detector
@@ -3516,7 +3532,7 @@ pub struct AnyModelHandle {
model_type: TypeId,
ref_counts: Arc<Mutex<RefCounts>>,
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
handle_id: usize,
}
@@ -3524,7 +3540,7 @@ impl AnyModelHandle {
fn new(model_id: usize, model_type: TypeId, ref_counts: Arc<Mutex<RefCounts>>) -> Self {
ref_counts.lock().inc_model(model_id);
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
let handle_id = ref_counts
.lock()
.leak_detector
@@ -3536,7 +3552,7 @@ impl AnyModelHandle {
model_type,
ref_counts,
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
handle_id,
}
}
@@ -3548,7 +3564,7 @@ impl AnyModelHandle {
model_type: PhantomData,
ref_counts: self.ref_counts.clone(),
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
handle_id: self.handle_id,
});
unsafe {
@@ -3594,7 +3610,7 @@ impl Drop for AnyModelHandle {
let mut ref_counts = self.ref_counts.lock();
ref_counts.dec_model(self.model_id);
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
ref_counts
.leak_detector
.lock()
@@ -3819,18 +3835,26 @@ lazy_static! {
std::env::var("LEAK_BACKTRACE").map_or(false, |b| !b.is_empty());
}
+#[cfg(any(test, feature = "test-support"))]
#[derive(Default)]
pub struct LeakDetector {
next_handle_id: usize,
- handle_backtraces: HashMap<usize, (Option<&'static str>, HashMap<usize, Option<Backtrace>>)>,
+ handle_backtraces: HashMap<
+ usize,
+ (
+ Option<&'static str>,
+ HashMap<usize, Option<backtrace::Backtrace>>,
+ ),
+ >,
}
+#[cfg(any(test, feature = "test-support"))]
impl LeakDetector {
fn handle_created(&mut self, type_name: Option<&'static str>, entity_id: usize) -> usize {
let handle_id = post_inc(&mut self.next_handle_id);
let entry = self.handle_backtraces.entry(entity_id).or_default();
let backtrace = if *LEAK_BACKTRACE {
- Some(Backtrace::new_unresolved())
+ Some(backtrace::Backtrace::new_unresolved())
} else {
None
};
@@ -3862,7 +3886,7 @@ impl LeakDetector {
for trace in backtraces.values_mut() {
if let Some(trace) = trace {
trace.resolve();
- eprintln!("{:?}", CwdBacktrace(trace));
+ eprintln!("{:?}", crate::util::CwdBacktrace(trace));
}
}
found_leaks = true;
@@ -3885,7 +3909,7 @@ struct RefCounts {
dropped_views: HashSet<(usize, usize)>,
dropped_element_states: HashSet<ElementStateId>,
- #[cfg(feature = "test-support")]
+ #[cfg(any(test, feature = "test-support"))]
leak_detector: Arc<Mutex<LeakDetector>>,
}
@@ -4067,13 +4091,11 @@ mod tests {
let handle_1 = cx.add_model(|_| Model::default());
let handle_2 = cx.add_model(|_| Model::default());
- let handle_2b = handle_2.clone();
-
handle_1.update(cx, |_, c| {
- c.subscribe(&handle_2, move |model: &mut Model, _, event, c| {
+ c.subscribe(&handle_2, move |model: &mut Model, emitter, event, c| {
model.events.push(*event);
- c.subscribe(&handle_2b, |model, _, event, _| {
+ c.subscribe(&emitter, |model, _, event, _| {
model.events.push(*event * 2);
})
.detach();
@@ -4102,12 +4124,11 @@ mod tests {
let handle_1 = cx.add_model(|_| Model::default());
let handle_2 = cx.add_model(|_| Model::default());
- let handle_2b = handle_2.clone();
handle_1.update(cx, |_, c| {
c.observe(&handle_2, move |model, observed, c| {
model.events.push(observed.read(c).count);
- c.observe(&handle_2b, |model, observed, c| {
+ c.observe(&observed, |model, observed, c| {
model.events.push(observed.read(c).count * 2);
})
.detach();
@@ -4341,14 +4362,13 @@ mod tests {
let (window_id, handle_1) = cx.add_window(Default::default(), |_| View::default());
let handle_2 = cx.add_view(window_id, |_| View::default());
- let handle_2b = handle_2.clone();
let handle_3 = cx.add_model(|_| Model);
handle_1.update(cx, |_, c| {
- c.subscribe(&handle_2, move |me, _, event, c| {
+ c.subscribe(&handle_2, move |me, emitter, event, c| {
me.events.push(*event);
- c.subscribe(&handle_2b, |me, _, event, _| {
+ c.subscribe(&emitter, |me, _, event, _| {
me.events.push(*event * 2);
})
.detach();
@@ -1,28 +1,18 @@
use anyhow::{anyhow, Result};
use async_task::Runnable;
-use backtrace::Backtrace;
-use collections::HashMap;
-use parking_lot::Mutex;
-use postage::{barrier, prelude::Stream as _};
-use rand::prelude::*;
-use smol::{channel, future::yield_now, prelude::*, Executor, Timer};
+use smol::{channel, prelude::*, Executor, Timer};
use std::{
any::Any,
fmt::{self, Display},
marker::PhantomData,
mem,
- ops::RangeInclusive,
pin::Pin,
rc::Rc,
- sync::{
- atomic::{AtomicBool, Ordering::SeqCst},
- Arc,
- },
+ sync::Arc,
task::{Context, Poll},
thread,
- time::{Duration, Instant},
+ time::Duration,
};
-use waker_fn::waker_fn;
use crate::{
platform::{self, Dispatcher},
@@ -34,6 +24,7 @@ pub enum Foreground {
dispatcher: Arc<dyn platform::Dispatcher>,
_not_send_or_sync: PhantomData<Rc<()>>,
},
+ #[cfg(any(test, feature = "test-support"))]
Deterministic {
cx_id: usize,
executor: Arc<Deterministic>,
@@ -41,9 +32,8 @@ pub enum Foreground {
}
pub enum Background {
- Deterministic {
- executor: Arc<Deterministic>,
- },
+ #[cfg(any(test, feature = "test-support"))]
+ Deterministic { executor: Arc<Deterministic> },
Production {
executor: Arc<smol::Executor<'static>>,
_stop: channel::Sender<()>,
@@ -70,39 +60,45 @@ pub enum Task<T> {
unsafe impl<T: Send> Send for Task<T> {}
+#[cfg(any(test, feature = "test-support"))]
struct DeterministicState {
- rng: StdRng,
+ rng: rand::prelude::StdRng,
seed: u64,
- scheduled_from_foreground: HashMap<usize, Vec<ForegroundRunnable>>,
+ scheduled_from_foreground: collections::HashMap<usize, Vec<ForegroundRunnable>>,
scheduled_from_background: Vec<Runnable>,
forbid_parking: bool,
- block_on_ticks: RangeInclusive<usize>,
- now: Instant,
- pending_timers: Vec<(Instant, barrier::Sender)>,
- waiting_backtrace: Option<Backtrace>,
+ block_on_ticks: std::ops::RangeInclusive<usize>,
+ now: std::time::Instant,
+ pending_timers: Vec<(std::time::Instant, postage::barrier::Sender)>,
+ waiting_backtrace: Option<backtrace::Backtrace>,
}
+#[cfg(any(test, feature = "test-support"))]
struct ForegroundRunnable {
runnable: Runnable,
main: bool,
}
+#[cfg(any(test, feature = "test-support"))]
pub struct Deterministic {
- state: Arc<Mutex<DeterministicState>>,
- parker: Mutex<parking::Parker>,
+ state: Arc<parking_lot::Mutex<DeterministicState>>,
+ parker: parking_lot::Mutex<parking::Parker>,
}
+#[cfg(any(test, feature = "test-support"))]
impl Deterministic {
pub fn new(seed: u64) -> Arc<Self> {
+ use rand::prelude::*;
+
Arc::new(Self {
- state: Arc::new(Mutex::new(DeterministicState {
+ state: Arc::new(parking_lot::Mutex::new(DeterministicState {
rng: StdRng::seed_from_u64(seed),
seed,
scheduled_from_foreground: Default::default(),
scheduled_from_background: Default::default(),
forbid_parking: false,
block_on_ticks: 0..=1000,
- now: Instant::now(),
+ now: std::time::Instant::now(),
pending_timers: Default::default(),
waiting_backtrace: None,
})),
@@ -161,6 +157,8 @@ impl Deterministic {
cx_id: usize,
main_future: Pin<Box<dyn 'a + Future<Output = Box<dyn Any>>>>,
) -> Box<dyn Any> {
+ use std::sync::atomic::{AtomicBool, Ordering::SeqCst};
+
let woken = Arc::new(AtomicBool::new(false));
let state = self.state.clone();
@@ -195,18 +193,22 @@ impl Deterministic {
}
}
- pub(crate) fn run_until_parked(&self) {
+ pub fn run_until_parked(&self) {
+ use std::sync::atomic::AtomicBool;
let woken = Arc::new(AtomicBool::new(false));
self.run_internal(woken, None);
}
fn run_internal(
&self,
- woken: Arc<AtomicBool>,
+ woken: Arc<std::sync::atomic::AtomicBool>,
mut main_task: Option<&mut AnyLocalTask>,
) -> Option<Box<dyn Any>> {
+ use rand::prelude::*;
+ use std::sync::atomic::Ordering::SeqCst;
+
let unparker = self.parker.lock().unparker();
- let waker = waker_fn(move || {
+ let waker = waker_fn::waker_fn(move || {
woken.store(true, SeqCst);
unparker.unpark();
});
@@ -261,8 +263,10 @@ impl Deterministic {
where
F: Unpin + Future<Output = T>,
{
+ use rand::prelude::*;
+
let unparker = self.parker.lock().unparker();
- let waker = waker_fn(move || {
+ let waker = waker_fn::waker_fn(move || {
unparker.unpark();
});
@@ -295,10 +299,12 @@ impl Deterministic {
}
}
+#[cfg(any(test, feature = "test-support"))]
impl DeterministicState {
fn will_park(&mut self) {
if self.forbid_parking {
let mut backtrace_message = String::new();
+ #[cfg(any(test, feature = "test-support"))]
if let Some(backtrace) = self.waiting_backtrace.as_mut() {
backtrace.resolve();
backtrace_message = format!(
@@ -330,6 +336,7 @@ impl Foreground {
pub fn spawn<T: 'static>(&self, future: impl Future<Output = T> + 'static) -> Task<T> {
let future = any_local_future(future);
let any_task = match self {
+ #[cfg(any(test, feature = "test-support"))]
Self::Deterministic { cx_id, executor } => {
executor.spawn_from_foreground(*cx_id, future, false)
}
@@ -351,6 +358,7 @@ impl Foreground {
Task::local(any_task)
}
+ #[cfg(any(test, feature = "test-support"))]
pub fn run<T: 'static>(&self, future: impl Future<Output = T>) -> T {
let future = async move { Box::new(future.await) as Box<dyn Any> }.boxed_local();
let result = match self {
@@ -360,6 +368,7 @@ impl Foreground {
*result.downcast().unwrap()
}
+ #[cfg(any(test, feature = "test-support"))]
pub fn run_until_parked(&self) {
match self {
Self::Deterministic { executor, .. } => executor.run_until_parked(),
@@ -367,6 +376,7 @@ impl Foreground {
}
}
+ #[cfg(any(test, feature = "test-support"))]
pub fn parking_forbidden(&self) -> bool {
match self {
Self::Deterministic { executor, .. } => executor.state.lock().forbid_parking,
@@ -374,15 +384,18 @@ impl Foreground {
}
}
+ #[cfg(any(test, feature = "test-support"))]
pub fn start_waiting(&self) {
match self {
Self::Deterministic { executor, .. } => {
- executor.state.lock().waiting_backtrace = Some(Backtrace::new_unresolved());
+ executor.state.lock().waiting_backtrace =
+ Some(backtrace::Backtrace::new_unresolved());
}
_ => panic!("this method can only be called on a deterministic executor"),
}
}
+ #[cfg(any(test, feature = "test-support"))]
pub fn finish_waiting(&self) {
match self {
Self::Deterministic { executor, .. } => {
@@ -392,7 +405,10 @@ impl Foreground {
}
}
+ #[cfg(any(test, feature = "test-support"))]
pub fn forbid_parking(&self) {
+ use rand::prelude::*;
+
match self {
Self::Deterministic { executor, .. } => {
let mut state = executor.state.lock();
@@ -405,8 +421,11 @@ impl Foreground {
pub async fn timer(&self, duration: Duration) {
match self {
+ #[cfg(any(test, feature = "test-support"))]
Self::Deterministic { executor, .. } => {
- let (tx, mut rx) = barrier::channel();
+ use postage::prelude::Stream as _;
+
+ let (tx, mut rx) = postage::barrier::channel();
{
let mut state = executor.state.lock();
let wakeup_at = state.now + duration;
@@ -420,6 +439,7 @@ impl Foreground {
}
}
+ #[cfg(any(test, feature = "test-support"))]
pub fn advance_clock(&self, duration: Duration) {
match self {
Self::Deterministic { executor, .. } => {
@@ -438,7 +458,8 @@ impl Foreground {
}
}
- pub fn set_block_on_ticks(&self, range: RangeInclusive<usize>) {
+ #[cfg(any(test, feature = "test-support"))]
+ pub fn set_block_on_ticks(&self, range: std::ops::RangeInclusive<usize>) {
match self {
Self::Deterministic { executor, .. } => executor.state.lock().block_on_ticks = range,
_ => panic!("this method can only be called on a deterministic executor"),
@@ -478,6 +499,7 @@ impl Background {
let future = any_future(future);
let any_task = match self {
Self::Production { executor, .. } => executor.spawn(future),
+ #[cfg(any(test, feature = "test-support"))]
Self::Deterministic { executor } => executor.spawn(future),
};
Task::send(any_task)
@@ -490,6 +512,7 @@ impl Background {
smol::pin!(future);
match self {
Self::Production { .. } => smol::block_on(&mut future),
+ #[cfg(any(test, feature = "test-support"))]
Self::Deterministic { executor, .. } => {
executor.block(&mut future, usize::MAX).unwrap()
}
@@ -509,7 +532,9 @@ impl Background {
if !timeout.is_zero() {
let output = match self {
Self::Production { .. } => smol::block_on(util::timeout(timeout, &mut future)).ok(),
+ #[cfg(any(test, feature = "test-support"))]
Self::Deterministic { executor, .. } => {
+ use rand::prelude::*;
let max_ticks = {
let mut state = executor.state.lock();
let range = state.block_on_ticks.clone();
@@ -544,7 +569,11 @@ impl Background {
}
}
+ #[cfg(any(test, feature = "test-support"))]
pub async fn simulate_random_delay(&self) {
+ use rand::prelude::*;
+ use smol::future::yield_now;
+
match self {
Self::Deterministic { executor, .. } => {
if executor.state.lock().rng.gen_bool(0.2) {