turbo_tasks/completion.rs
1use anyhow::Result;
2
3use crate::{self as turbo_tasks, ResolvedVc, TryJoinIterExt, Vc};
4
5/// Just an empty type, but it's never equal to itself.
6///
7/// [`Vc<Completion>`] can be used as return value instead of `()` to have a concrete reference that
8/// can be awaited. It will invalidate the awaiting task everytime the referenced task has been
9/// executed.
10///
11/// Note: [`PartialEq`] is not implemented since it doesn't make sense to compare `Completion` this
12/// way. You probably want to use [`ReadRef::ptr_eq`][crate::ReadRef::ptr_eq] instead.
13#[turbo_tasks::value(cell = "new", eq = "manual")]
14#[derive(Debug)]
15pub struct Completion;
16
17#[turbo_tasks::value_impl]
18impl Completion {
19 /// This will always be the same and never invalidates the reading task.
20 #[turbo_tasks::function]
21 pub fn immutable() -> Vc<Self> {
22 Completion::cell(Completion)
23 }
24
25 /// Returns a completion from a session-dependent task. Awaiting this creates a dependency on
26 /// a session-dependent task, which will cause the calling task to be re-executed when
27 /// restored from persistent cache.
28 #[turbo_tasks::function(session_dependent)]
29 pub fn session_dependent() -> Vc<Self> {
30 Completion::cell(Completion)
31 }
32}
33
34// no #[turbo_tasks::value_impl] to inline new into the caller task
35// this ensures it's re-created on each execution
36impl Completion {
37 /// This will always be a new completion and invalidates the reading task.
38 pub fn new() -> Vc<Self> {
39 Completion::cell(Completion)
40 }
41}
42
43#[turbo_tasks::value(transparent)]
44pub struct Completions(Vec<ResolvedVc<Completion>>);
45
46#[turbo_tasks::value_impl]
47impl Completions {
48 /// Merges the list of completions into one.
49 #[turbo_tasks::function]
50 pub async fn completed(&self) -> anyhow::Result<Vc<Completion>> {
51 if self.0.len() > 100 {
52 let mid = self.0.len() / 2;
53 let (left, right) = self.0.split_at(mid);
54 let left = Vc::<Completions>::cell(left.to_vec());
55 let right = Vc::<Completions>::cell(right.to_vec());
56 let left = left.completed();
57 let right = right.completed();
58 left.await?;
59 right.await?;
60 Ok(Completion::new())
61 } else {
62 self.0
63 .iter()
64 .map(|&c| async move {
65 // Wraps the completion in a new completion. This makes it cheaper to restore
66 // since it doesn't need to restore the original task resp task chain.
67 wrap(*c).await?;
68 Ok(())
69 })
70 .try_join()
71 .await?;
72 Ok(Completion::new())
73 }
74 }
75}
76
77#[turbo_tasks::function]
78async fn wrap(completion: Vc<Completion>) -> Result<Vc<Completion>> {
79 completion.await?;
80 Ok(Completion::new())
81}