Skip to main content

turbo_tasks/vc/
read.rs

1use std::{
2    any::Any,
3    hash::{BuildHasher, Hash},
4    marker::PhantomData,
5    mem::ManuallyDrop,
6    pin::Pin,
7    task::Poll,
8};
9
10use anyhow::Result;
11use futures::Future;
12use pin_project_lite::pin_project;
13use rustc_hash::FxBuildHasher;
14
15use super::traits::VcValueType;
16use crate::{
17    MappedReadRef, ReadRawVcFuture, ReadRef, VcCast, VcValueTrait, VcValueTraitCast,
18    VcValueTypeCast,
19    keyed::{KeyedAccess, KeyedEq},
20};
21
22type VcReadTarget<T> = <<T as VcValueType>::Read as VcRead<T>>::Target;
23
24/// Trait that controls [`crate::Vc`]'s read representation.
25///
26/// Has two implementations:
27/// * [`VcDefaultRead`]
28/// * [`VcTransparentRead`]
29///
30/// This trait must remain sealed within this crate.
31pub trait VcRead<T>
32where
33    T: VcValueType,
34{
35    /// The read target type. This is the type that will be returned when
36    /// `.await`ing a `Vc` of a value type.
37    ///
38    /// For instance, the target of `.await`ing a `Vc<Completion>` will be a
39    /// `Completion`. When using `#[turbo_tasks::value(transparent)]`, the
40    /// target will be different than the value type.
41    type Target;
42
43    /// Convert a reference to a value to a reference to the target type.
44    fn value_to_target_ref(value: &T) -> &Self::Target;
45
46    /// Convert a value to the target type.
47    fn value_to_target(value: T) -> Self::Target;
48
49    /// Convert the target type to the value.
50    fn target_to_value(target: Self::Target) -> T;
51
52    /// Convert a reference to a target type to a reference to a value.
53    fn target_to_value_ref(target: &Self::Target) -> &T;
54
55    /// Convert a mutable reference to a target type to a reference to a value.
56    fn target_to_value_mut_ref(target: &mut Self::Target) -> &mut T;
57}
58
59/// Representation for standard `#[turbo_tasks::value]`, where a read return a
60/// reference to the value type[]
61pub struct VcDefaultRead<T> {
62    _phantom: PhantomData<T>,
63}
64
65impl<T> VcRead<T> for VcDefaultRead<T>
66where
67    T: VcValueType,
68{
69    type Target = T;
70
71    fn value_to_target_ref(value: &T) -> &Self::Target {
72        value
73    }
74
75    fn value_to_target(value: T) -> Self::Target {
76        value
77    }
78
79    fn target_to_value(target: Self::Target) -> T {
80        target
81    }
82
83    fn target_to_value_ref(target: &Self::Target) -> &T {
84        target
85    }
86
87    fn target_to_value_mut_ref(target: &mut Self::Target) -> &mut T {
88        target
89    }
90}
91
92/// Representation for `#[turbo_tasks::value(transparent)]` types, where reads
93/// return a reference to the target type.
94pub struct VcTransparentRead<T, Target> {
95    _phantom: PhantomData<(T, Target)>,
96}
97
98impl<T, Target> VcRead<T> for VcTransparentRead<T, Target>
99where
100    T: VcValueType,
101    Target: Any + Send + Sync,
102{
103    type Target = Target;
104
105    fn value_to_target_ref(value: &T) -> &Self::Target {
106        // Safety: the `VcValueType` implementor must guarantee that both `T` and
107        // `Target` are #[repr(transparent)]. This is guaranteed by the
108        // `#[turbo_tasks::value(transparent)]` macro.
109        // We can't use `std::mem::transmute` here as it doesn't support generic types.
110        // See https://users.rust-lang.org/t/transmute-doesnt-work-on-generic-types/87272/9
111        unsafe {
112            std::mem::transmute_copy::<ManuallyDrop<&T>, &Self::Target>(&ManuallyDrop::new(value))
113        }
114    }
115
116    fn value_to_target(value: T) -> Self::Target {
117        // Safety: see `Self::value_to_target_ref` above.
118        unsafe {
119            std::mem::transmute_copy::<ManuallyDrop<T>, Self::Target>(&ManuallyDrop::new(value))
120        }
121    }
122
123    fn target_to_value(target: Self::Target) -> T {
124        // Safety: see `Self::value_to_target_ref` above.
125        unsafe {
126            std::mem::transmute_copy::<ManuallyDrop<Self::Target>, T>(&ManuallyDrop::new(target))
127        }
128    }
129
130    fn target_to_value_ref(target: &Self::Target) -> &T {
131        // Safety: see `Self::value_to_target_ref` above.
132        unsafe {
133            std::mem::transmute_copy::<ManuallyDrop<&Self::Target>, &T>(&ManuallyDrop::new(target))
134        }
135    }
136
137    fn target_to_value_mut_ref(target: &mut Self::Target) -> &mut T {
138        // Safety: see `Self::value_to_target_ref` above.
139        unsafe {
140            std::mem::transmute_copy::<ManuallyDrop<&mut Self::Target>, &mut T>(&ManuallyDrop::new(
141                target,
142            ))
143        }
144    }
145}
146
147#[must_use]
148pub struct ReadVcFuture<T, Cast = VcValueTypeCast<T>>
149where
150    T: ?Sized,
151    Cast: VcCast,
152{
153    raw: ReadRawVcFuture,
154    _phantom_t: PhantomData<T>,
155    _phantom_cast: PhantomData<Cast>,
156}
157
158impl<T, Cast> ReadVcFuture<T, Cast>
159where
160    T: ?Sized,
161    Cast: VcCast,
162{
163    /// Do not use this: Use [`OperationVc::read_strongly_consistent`] instead.
164    pub fn strongly_consistent(mut self) -> Self {
165        self.raw = self.raw.strongly_consistent();
166        self
167    }
168
169    /// Returns a untracked read of the value. This will not invalidate the current function when
170    /// the read value changed.
171    pub fn untracked(mut self) -> Self {
172        self.raw = self.raw.untracked();
173        self
174    }
175
176    /// Read the value with the hint that this is the final read of the value. This might drop the
177    /// cell content. Future reads might need to recompute the value.
178    pub fn final_read_hint(mut self) -> Self {
179        self.raw = self.raw.final_read_hint();
180        self
181    }
182}
183
184impl<T> ReadVcFuture<T, VcValueTypeCast<T>>
185where
186    T: VcValueType,
187    VcReadTarget<T>: Clone,
188{
189    /// Read the value and returns a owned version of it. It might clone the value.
190    pub fn owned(self) -> ReadOwnedVcFuture<T> {
191        ReadOwnedVcFuture { future: self }
192    }
193}
194
195impl<T> ReadVcFuture<T, VcValueTypeCast<T>>
196where
197    T: VcValueType,
198    VcReadTarget<T>: KeyedEq,
199{
200    /// Read the value and selects a keyed value from it. Only depends on the used key instead of
201    /// the full value.
202    pub fn get<'l, Q>(mut self, key: &'l Q) -> ReadKeyedVcFuture<'l, T, Q>
203    where
204        Q: Hash + ?Sized,
205        VcReadTarget<T>: KeyedAccess<Q>,
206    {
207        self.raw = self.raw.track_with_key(FxBuildHasher.hash_one(key));
208        ReadKeyedVcFuture { future: self, key }
209    }
210
211    /// Read the value and checks if it contains the given key. Only depends on the used key instead
212    /// of the full value.
213    ///
214    /// Note: This is also invalidated when the value of the key changes, not only when the presence
215    /// of the key changes.
216    pub fn contains_key<'l, Q>(mut self, key: &'l Q) -> ReadContainsKeyedVcFuture<'l, T, Q>
217    where
218        Q: Hash + ?Sized,
219        VcReadTarget<T>: KeyedAccess<Q>,
220    {
221        self.raw = self.raw.track_with_key(FxBuildHasher.hash_one(key));
222        ReadContainsKeyedVcFuture { future: self, key }
223    }
224}
225
226impl<T> From<ReadRawVcFuture> for ReadVcFuture<T, VcValueTypeCast<T>>
227where
228    T: VcValueType,
229{
230    fn from(raw: ReadRawVcFuture) -> Self {
231        Self {
232            raw,
233            _phantom_t: PhantomData,
234            _phantom_cast: PhantomData,
235        }
236    }
237}
238
239impl<T> From<ReadRawVcFuture> for ReadVcFuture<T, VcValueTraitCast<T>>
240where
241    T: VcValueTrait + ?Sized,
242{
243    fn from(raw: ReadRawVcFuture) -> Self {
244        Self {
245            raw,
246            _phantom_t: PhantomData,
247            _phantom_cast: PhantomData,
248        }
249    }
250}
251
252impl<T, Cast> Future for ReadVcFuture<T, Cast>
253where
254    T: ?Sized,
255    Cast: VcCast,
256{
257    type Output = Result<Cast::Output>;
258
259    fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
260        // Safety: We never move the contents of `self`
261        let raw = unsafe { self.map_unchecked_mut(|this| &mut this.raw) };
262        Poll::Ready(std::task::ready!(raw.poll(cx)).and_then(Cast::cast))
263    }
264}
265
266pub struct ReadOwnedVcFuture<T>
267where
268    T: VcValueType,
269    VcReadTarget<T>: Clone,
270{
271    future: ReadVcFuture<T, VcValueTypeCast<T>>,
272}
273
274impl<T> Future for ReadOwnedVcFuture<T>
275where
276    T: VcValueType,
277    VcReadTarget<T>: Clone,
278{
279    type Output = Result<VcReadTarget<T>>;
280
281    fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
282        // Safety: We never move the contents of `self`
283        let future = unsafe { self.map_unchecked_mut(|this| &mut this.future) };
284        match future.poll(cx) {
285            Poll::Ready(Ok(result)) => Poll::Ready(Ok(ReadRef::into_owned(result))),
286            Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
287            Poll::Pending => Poll::Pending,
288        }
289    }
290}
291
292pin_project! {
293    pub struct ReadKeyedVcFuture<'l, T, Q>
294    where
295        T: VcValueType,
296        Q: ?Sized,
297        VcReadTarget<T>: KeyedAccess<Q>,
298
299    {
300        #[pin]
301        future: ReadVcFuture<T, VcValueTypeCast<T>>,
302        key: &'l Q,
303    }
304}
305
306impl<'l, T, Q> Future for ReadKeyedVcFuture<'l, T, Q>
307where
308    T: VcValueType,
309    Q: ?Sized,
310    VcReadTarget<T>: KeyedAccess<Q>,
311{
312    type Output = Result<Option<MappedReadRef<T, <VcReadTarget<T> as KeyedAccess<Q>>::Value>>>;
313
314    fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
315        // Safety: We never move the contents of `self`
316        let this = self.project();
317        match this.future.poll(cx) {
318            Poll::Ready(Ok(result)) => {
319                let mapped_read_ref = if let Some(value) = (*result).get(this.key) {
320                    let ptr = value as *const _;
321                    Some(unsafe { MappedReadRef::new(result.into_raw_arc(), ptr) })
322                } else {
323                    None
324                };
325                Poll::Ready(Ok(mapped_read_ref))
326            }
327            Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
328            Poll::Pending => Poll::Pending,
329        }
330    }
331}
332
333pin_project! {
334    pub struct ReadContainsKeyedVcFuture<'l, T, Q>
335    where
336        T: VcValueType,
337        Q: ?Sized,
338        VcReadTarget<T>: KeyedAccess<Q>,
339    {
340        #[pin]
341        future: ReadVcFuture<T, VcValueTypeCast<T>>,
342        key: &'l Q,
343    }
344}
345
346impl<'l, T, Q> Future for ReadContainsKeyedVcFuture<'l, T, Q>
347where
348    T: VcValueType,
349    Q: ?Sized,
350    VcReadTarget<T>: KeyedAccess<Q>,
351{
352    type Output = Result<bool>;
353
354    fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
355        // Safety: We never move the contents of `self`
356        let this = self.project();
357        match this.future.poll(cx) {
358            Poll::Ready(Ok(result)) => {
359                let result = (*result).contains_key(this.key);
360                Poll::Ready(Ok(result))
361            }
362            Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
363            Poll::Pending => Poll::Pending,
364        }
365    }
366}