turbo_tasks_testing/
run.rs1use std::{
2 fmt::Debug,
3 future::Future,
4 sync::{Arc, OnceLock},
5};
6
7use anyhow::Result;
8use turbo_tasks::{TurboTasksApi, run_once, trace::TraceRawVcs};
9
10pub struct Registration {
11 execution_lock: OnceLock<()>,
12 func: fn(),
13 create_turbo_tasks: fn(&str, bool) -> Arc<dyn TurboTasksApi>,
14}
15
16impl Registration {
17 #[doc(hidden)]
18 pub const fn new(
19 create_turbo_tasks: fn(&str, bool) -> Arc<dyn TurboTasksApi>,
20 func: fn(),
21 ) -> Self {
22 Registration {
23 execution_lock: OnceLock::new(),
24 func,
25 create_turbo_tasks,
26 }
27 }
28
29 pub fn ensure_registered(&self) {
33 self.execution_lock.get_or_init(self.func);
34 }
35
36 pub fn create_turbo_tasks(&self, name: &str, initial: bool) -> Arc<dyn TurboTasksApi> {
37 (self.create_turbo_tasks)(name, initial)
38 }
39}
40
41#[macro_export]
42macro_rules! register {
43 ($($other_register_fns:expr),* $(,)?) => {{
44 use turbo_tasks::TurboTasksApi;
45 use std::sync::Arc;
46 fn create_turbo_tasks(name: &str, initial: bool) -> Arc<dyn TurboTasksApi> {
47 let inner = include!(concat!(
48 env!("CARGO_MANIFEST_DIR"),
49 "/tests/test_config.trs"
50 ));
51 (inner)(name, initial)
52 }
53 fn register_impl() {
54 $($other_register_fns();)*
55 turbo_tasks::register();
56 include!(concat!(
57 env!("OUT_DIR"),
58 "/register_test_",
59 module_path!(),
60 ".rs",
61 ));
62 }
63 turbo_tasks_testing::Registration::new(create_turbo_tasks, register_impl)
64 }};
65}
66
67pub async fn run_without_cache_check<T>(
68 registration: &Registration,
69 fut: impl Future<Output = T> + Send + 'static,
70) -> T
71where
72 T: TraceRawVcs + Send + 'static,
73{
74 registration.ensure_registered();
75 let name = closure_to_name(&fut);
76 let tt = registration.create_turbo_tasks(&name, true);
77 run_once(tt, async move { Ok(fut.await) }).await.unwrap()
78}
79
80fn closure_to_name<T>(value: &T) -> String {
81 let name = std::any::type_name_of_val(value);
82 name.replace("::{{closure}}", "").replace("::", "_")
83}
84
85pub async fn run<T, F>(
86 registration: &Registration,
87 fut: impl Fn() -> F + Send + 'static,
88) -> Result<()>
89where
90 F: Future<Output = Result<T>> + Send + 'static,
91 T: Debug + PartialEq + Eq + TraceRawVcs + Send + 'static,
92{
93 run_with_tt(registration, move |tt| run_once(tt, fut())).await
94}
95
96pub async fn run_with_tt<T, F>(
97 registration: &Registration,
98 fut: impl Fn(Arc<dyn TurboTasksApi>) -> F + Send + 'static,
99) -> Result<()>
100where
101 F: Future<Output = Result<T>> + Send + 'static,
102 T: Debug + PartialEq + Eq + TraceRawVcs + Send + 'static,
103{
104 registration.ensure_registered();
105
106 let name = closure_to_name(&fut);
107 let tt = registration.create_turbo_tasks(&name, true);
108 println!("Run #1 (without cache)");
109 let start = std::time::Instant::now();
110 let first = fut(tt.clone()).await?;
111 println!("Run #1 took {:?}", start.elapsed());
112 for i in 2..10 {
113 println!("Run #{i} (with memory cache, same TurboTasks instance)");
114 let start = std::time::Instant::now();
115 let second = fut(tt.clone()).await?;
116 println!("Run #{i} took {:?}", start.elapsed());
117 assert_eq!(first, second);
118 }
119 let start = std::time::Instant::now();
120 tt.stop_and_wait().await;
121 println!("Stopping TurboTasks took {:?}", start.elapsed());
122 for i in 10..20 {
123 let tt = registration.create_turbo_tasks(&name, false);
124 println!("Run #{i} (with persistent cache if available, new TurboTasks instance)");
125 let start = std::time::Instant::now();
126 let third = fut(tt.clone()).await?;
127 println!("Run #{i} took {:?}", start.elapsed());
128 let start = std::time::Instant::now();
129 tt.stop_and_wait().await;
130 println!("Stopping TurboTasks took {:?}", start.elapsed());
131 assert_eq!(first, third);
132 }
133 Ok(())
134}