turbo_tasks/
trait_ref.rs

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