Skip to main content

turbo_tasks/
trait_ref.rs

1use std::{fmt::Debug, marker::PhantomData};
2
3use crate::{
4    Vc, VcValueTrait, registry::get_value_type, task::shared_reference::TypedSharedReference,
5};
6
7/// Similar to a [`ReadRef<T>`][crate::ReadRef], but contains a value trait object instead.
8///
9/// Non-turbo-task methods with a `&self` receiver can be called on this reference.
10///
11/// A `TraitRef<T>` can be turned back into a value trait vc by calling [`TraitRef::cell`].
12///
13/// Internally it stores a reference counted reference to a value on the heap.
14pub struct TraitRef<T>
15where
16    T: ?Sized,
17{
18    shared_reference: TypedSharedReference,
19    _t: PhantomData<T>,
20}
21
22impl<T> Debug for TraitRef<T> {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        f.debug_struct("TraitRef")
25            .field("shared_reference", &self.shared_reference)
26            .finish()
27    }
28}
29
30impl<T> Clone for TraitRef<T> {
31    fn clone(&self) -> Self {
32        Self {
33            shared_reference: self.shared_reference.clone(),
34            _t: PhantomData,
35        }
36    }
37}
38
39impl<T> PartialEq for TraitRef<T> {
40    fn eq(&self, other: &Self) -> bool {
41        self.shared_reference == other.shared_reference
42    }
43}
44
45impl<T> Eq for TraitRef<T> {}
46
47impl<T> std::hash::Hash for TraitRef<T> {
48    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
49        self.shared_reference.hash(state)
50    }
51}
52
53impl<U> std::ops::Deref for TraitRef<Box<U>>
54where
55    Box<U>: VcValueTrait<ValueTrait = U>,
56    U: std::ptr::Pointee<Metadata = std::ptr::DynMetadata<U>> + ?Sized,
57{
58    type Target = U;
59
60    fn deref(&self) -> &Self::Target {
61        // This lookup will fail if the value type stored does not actually implement the trait,
62        // which implies a bug in either the registry code or the macro code.
63        let downcast_ptr = <Box<U> as VcValueTrait>::get_impl_vtables().cast(
64            self.shared_reference.type_id,
65            self.shared_reference.reference.0.as_ptr() as *const (),
66        );
67        // SAFETY: the pointer is derived from an Arc
68        unsafe { &*downcast_ptr }
69    }
70}
71
72// Otherwise, TraitRef<Box<dyn Trait>> would not be Sync.
73// SAFETY: TraitRef doesn't actually contain a T.
74unsafe impl<T> Sync for TraitRef<T> where T: ?Sized {}
75
76// Otherwise, TraitRef<Box<dyn Trait>> would not be Send.
77// SAFETY: TraitRef doesn't actually contain a T.
78unsafe impl<T> Send for TraitRef<T> where T: ?Sized {}
79
80impl<T> Unpin for TraitRef<T> where T: ?Sized {}
81
82impl<T> TraitRef<T>
83where
84    T: ?Sized,
85{
86    pub(crate) fn new(shared_reference: TypedSharedReference) -> Self {
87        Self {
88            shared_reference,
89            _t: PhantomData,
90        }
91    }
92
93    pub fn ptr_eq(this: &Self, other: &Self) -> bool {
94        triomphe::Arc::ptr_eq(
95            &this.shared_reference.reference.0,
96            &other.shared_reference.reference.0,
97        )
98    }
99}
100
101impl<T> TraitRef<T>
102where
103    T: VcValueTrait + ?Sized,
104{
105    /// Returns a new cell that points to a value that implements the value
106    /// trait `T`.
107    pub fn cell(trait_ref: TraitRef<T>) -> Vc<T> {
108        let TraitRef {
109            shared_reference, ..
110        } = trait_ref;
111        let value_type = get_value_type(shared_reference.type_id);
112        (value_type.raw_cell)(shared_reference).into()
113    }
114}