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