turbo_tasks/
trait_ref.rs

1use std::{fmt::Debug, future::Future, marker::PhantomData};
2
3use anyhow::Result;
4
5use crate::{
6    Vc, VcValueTrait,
7    registry::get_value_type,
8    task::shared_reference::TypedSharedReference,
9    vc::{ReadVcFuture, VcValueTraitCast, cast::VcCast},
10};
11
12/// Similar to a [`ReadRef<T>`][crate::ReadRef], but contains a value trait
13/// object instead.
14///
15/// The only way to interact with a `TraitRef<T>` is by passing
16/// it around or turning it back into a value trait vc by calling
17/// [`ReadRef::cell`][crate::ReadRef::cell].
18///
19/// Internally it stores a reference counted reference to a value on the heap.
20pub struct TraitRef<T>
21where
22    T: ?Sized,
23{
24    shared_reference: TypedSharedReference,
25    _t: PhantomData<T>,
26}
27
28impl<T> Debug for TraitRef<T> {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        f.debug_struct("TraitRef")
31            .field("shared_reference", &self.shared_reference)
32            .finish()
33    }
34}
35
36impl<T> Clone for TraitRef<T> {
37    fn clone(&self) -> Self {
38        Self {
39            shared_reference: self.shared_reference.clone(),
40            _t: PhantomData,
41        }
42    }
43}
44
45impl<T> PartialEq for TraitRef<T> {
46    fn eq(&self, other: &Self) -> bool {
47        self.shared_reference == other.shared_reference
48    }
49}
50
51impl<T> Eq for TraitRef<T> {}
52
53impl<T> std::hash::Hash for TraitRef<T> {
54    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
55        self.shared_reference.hash(state)
56    }
57}
58
59impl<U> std::ops::Deref for TraitRef<Box<U>>
60where
61    Box<U>: VcValueTrait<ValueTrait = U>,
62    U: std::ptr::Pointee<Metadata = std::ptr::DynMetadata<U>> + ?Sized,
63{
64    type Target = U;
65
66    fn deref(&self) -> &Self::Target {
67        // This lookup will fail if the value type stored does not actually implement the trait,
68        // which implies a bug in either the registry code or the macro code.
69        let downcast_ptr = <Box<U> as VcValueTrait>::get_impl_vtables().cast(
70            self.shared_reference.type_id,
71            self.shared_reference.reference.0.as_ptr() as *const (),
72        );
73        // SAFETY: the pointer is derived from an Arc
74        unsafe { &*downcast_ptr }
75    }
76}
77
78// Otherwise, TraitRef<Box<dyn Trait>> would not be Sync.
79// SAFETY: TraitRef doesn't actually contain a T.
80unsafe impl<T> Sync for TraitRef<T> where T: ?Sized {}
81
82// Otherwise, TraitRef<Box<dyn Trait>> would not be Send.
83// SAFETY: TraitRef doesn't actually contain a T.
84unsafe impl<T> Send for TraitRef<T> where T: ?Sized {}
85
86impl<T> Unpin for TraitRef<T> where T: ?Sized {}
87
88impl<T> TraitRef<T>
89where
90    T: ?Sized,
91{
92    pub(crate) fn new(shared_reference: TypedSharedReference) -> Self {
93        Self {
94            shared_reference,
95            _t: PhantomData,
96        }
97    }
98
99    pub fn ptr_eq(this: &Self, other: &Self) -> bool {
100        triomphe::Arc::ptr_eq(
101            &this.shared_reference.reference.0,
102            &other.shared_reference.reference.0,
103        )
104    }
105}
106
107impl<T> TraitRef<T>
108where
109    T: VcValueTrait + ?Sized,
110{
111    /// Returns a new cell that points to a value that implements the value
112    /// trait `T`.
113    pub fn cell(trait_ref: TraitRef<T>) -> Vc<T> {
114        let TraitRef {
115            shared_reference, ..
116        } = trait_ref;
117        let value_type = get_value_type(shared_reference.type_id);
118        (value_type.raw_cell)(shared_reference).into()
119    }
120}
121
122/// A trait that allows a value trait vc to be converted into a trait reference.
123///
124/// The signature is similar to `IntoFuture`, but we don't want trait vcs to
125/// have the same future-like semantics as value vcs when it comes to producing
126/// refs. This behavior is rarely needed, so in most cases, `.await`ing a trait
127/// vc is a mistake.
128pub trait IntoTraitRef {
129    type ValueTrait: VcValueTrait + ?Sized;
130    type Future: Future<Output = Result<<VcValueTraitCast<Self::ValueTrait> as VcCast>::Output>>;
131
132    fn into_trait_ref(self) -> Self::Future;
133}
134
135impl<T> IntoTraitRef for Vc<T>
136where
137    T: VcValueTrait + ?Sized,
138{
139    type ValueTrait = T;
140
141    type Future = ReadVcFuture<T, VcValueTraitCast<T>>;
142
143    fn into_trait_ref(self) -> Self::Future {
144        self.node
145            .into_read_with_unknown_is_serializable_cell_content()
146            .into()
147    }
148}