turbo_tasks/vc/
operation.rs1use std::{
2 fmt::Debug,
3 future::Future,
4 hash::Hash,
5 marker::PhantomData,
6 pin::Pin,
7 task::{Context, Poll},
8};
9
10use anyhow::Result;
11use auto_hash_map::AutoSet;
12use bincode::{Decode, Encode};
13use serde::{Deserialize, Serialize};
14pub use turbo_tasks_macros::OperationValue;
15
16use crate::{
17 CollectiblesSource, RawVc, ReadVcFuture, ResolvedVc, TaskId, TaskInput, UpcastStrict, Vc,
18 VcValueTrait, VcValueTraitCast, VcValueType, marker_trait::impl_auto_marker_trait,
19 trace::TraceRawVcs, turbo_tasks,
20};
21
22#[must_use]
27pub struct ResolveOperationVcFuture<T>
28where
29 T: ?Sized,
30{
31 inner: super::ResolveVcFuture<T>,
32}
33
34impl<T: ?Sized> ResolveOperationVcFuture<T> {
35 pub fn strongly_consistent(mut self) -> Self {
37 self.inner.inner = self.inner.inner.strongly_consistent();
38 self
39 }
40}
41
42impl<T: ?Sized> Future for ResolveOperationVcFuture<T> {
43 type Output = anyhow::Result<ResolvedVc<T>>;
44
45 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
46 let this = unsafe { self.get_unchecked_mut() };
48 Pin::new(&mut this.inner)
50 .poll(cx)
51 .map(|r| r.map(|node| ResolvedVc { node }))
52 }
53}
54
55impl<T: ?Sized> Unpin for ResolveOperationVcFuture<T> {}
56
57#[must_use]
95#[derive(Serialize, Deserialize, Encode, Decode)]
96#[bincode(bounds = "T: ?Sized")]
97pub struct OperationVc<T>
98where
99 T: ?Sized,
100{
101 task: TaskId,
102
103 _t: PhantomData<T>,
104}
105
106impl<T: ?Sized> OperationVc<T> {
107 #[doc(hidden)]
111 #[deprecated = "This is an internal function. Use #[turbo_tasks::function(operation)] instead."]
112 pub fn cell_private(node: Vc<T>) -> Self {
113 let task = node.node.as_task_output().expect(
114 "OperationVc::cell_private must be called on the immediate return value of a task \
115 function",
116 );
117
118 Self {
119 task,
120 _t: PhantomData,
121 }
122 }
123
124 pub fn connect(self) -> Vc<T> {
132 let tt = turbo_tasks();
133 tt.connect_task(self.task);
134 Self::into_raw(self).into()
135 }
136
137 fn into_raw(vc: Self) -> RawVc {
140 RawVc::task_output(vc.task)
141 }
142
143 #[inline(always)]
147 pub fn upcast<K>(vc: Self) -> OperationVc<K>
148 where
149 T: UpcastStrict<K>,
150 K: VcValueTrait + ?Sized,
151 {
152 OperationVc {
153 task: vc.task,
154 _t: PhantomData,
155 }
156 }
157
158 pub fn resolve(self) -> ResolveOperationVcFuture<T> {
169 ResolveOperationVcFuture {
170 inner: self.connect().resolve(),
171 }
172 }
173
174 pub fn read_strongly_consistent(self) -> ReadVcFuture<T>
179 where
180 T: VcValueType,
181 {
182 self.connect().node.into_read().strongly_consistent().into()
183 }
184
185 pub fn read_trait_strongly_consistent(self) -> ReadVcFuture<T, VcValueTraitCast<T>>
190 where
191 T: VcValueTrait,
192 {
193 self.connect().into_trait_ref().strongly_consistent()
194 }
195
196 pub fn task_id(self) -> TaskId {
197 self.task
198 }
199}
200
201impl<T> Copy for OperationVc<T> where T: ?Sized {}
202
203impl<T> Clone for OperationVc<T>
204where
205 T: ?Sized,
206{
207 fn clone(&self) -> Self {
208 *self
209 }
210}
211
212impl<T> Hash for OperationVc<T>
213where
214 T: ?Sized,
215{
216 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
217 self.task.hash(state);
218 }
219}
220
221impl<T> PartialEq<OperationVc<T>> for OperationVc<T>
222where
223 T: ?Sized,
224{
225 fn eq(&self, other: &Self) -> bool {
226 self.task == other.task
227 }
228}
229
230impl<T> Eq for OperationVc<T> where T: ?Sized {}
231
232impl<T> Debug for OperationVc<T>
233where
234 T: ?Sized,
235{
236 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
237 f.debug_struct("OperationVc")
238 .field("task", &self.task)
239 .finish()
240 }
241}
242
243impl<T> TaskInput for OperationVc<T>
246where
247 T: ?Sized + Send + Sync,
248{
249 fn is_transient(&self) -> bool {
250 self.task.is_transient()
251 }
252}
253
254impl<T> TryFrom<RawVc> for OperationVc<T>
255where
256 T: ?Sized,
257{
258 type Error = anyhow::Error;
259
260 fn try_from(raw: RawVc) -> Result<Self> {
261 let Some(task) = raw.as_task_output() else {
262 anyhow::bail!("Given RawVc {raw:?} is not a TaskOutput");
263 };
264 Ok(Self {
265 task,
266 _t: PhantomData,
267 })
268 }
269}
270
271impl<T> TraceRawVcs for OperationVc<T>
272where
273 T: ?Sized,
274{
275 fn trace_raw_vcs(&self, trace_context: &mut crate::trace::TraceRawVcsContext) {
276 Self::into_raw(*self).trace_raw_vcs(trace_context);
277 }
278}
279
280impl<T> CollectiblesSource for OperationVc<T>
281where
282 T: ?Sized,
283{
284 fn drop_collectibles<Vt: VcValueTrait>(self) {
285 let tt = turbo_tasks();
286 let map = tt.read_task_collectibles(self.task, Vt::get_trait_type_id());
287 tt.unemit_collectibles(Vt::get_trait_type_id(), &map);
288 }
289
290 fn take_collectibles<Vt: VcValueTrait>(self) -> AutoSet<ResolvedVc<Vt>> {
291 let tt = turbo_tasks();
292 let map = tt.read_task_collectibles(self.task, Vt::get_trait_type_id());
293 tt.unemit_collectibles(Vt::get_trait_type_id(), &map);
294 map.into_iter()
295 .filter_map(|(raw, count)| (count > 0).then_some(raw.try_into().unwrap()))
296 .collect()
297 }
298
299 fn peek_collectibles<Vt: VcValueTrait>(self) -> AutoSet<ResolvedVc<Vt>> {
300 let tt = turbo_tasks();
301 let map = tt.read_task_collectibles(self.task, Vt::get_trait_type_id());
302 map.into_iter()
303 .filter_map(|(raw, count)| (count > 0).then_some(raw.try_into().unwrap()))
304 .collect()
305 }
306}
307
308pub unsafe trait OperationValue {}
316
317unsafe impl<T: ?Sized + Send> OperationValue for OperationVc<T> {}
318
319impl_auto_marker_trait!(OperationValue);