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
75// Otherwise, TraitRef<Box<dyn Trait>> would not be Sync.
76// SAFETY: TraitRef doesn't actually contain a T.
77unsafe impl<T> Sync for TraitRef<T> where T: ?Sized {}
78
79// Otherwise, TraitRef<Box<dyn Trait>> would not be Send.
80// SAFETY: TraitRef doesn't actually contain a T.
81unsafe impl<T> Send for TraitRef<T> where T: ?Sized {}
82
83impl<T> Unpin for TraitRef<T> where T: ?Sized {}
84
85impl<T> TraitRef<T>
86where
87    T: ?Sized,
88{
89    pub(crate) fn new(shared_reference: TypedSharedReference) -> Self {
90        Self {
91            shared_reference,
92            _t: PhantomData,
93        }
94    }
95
96    pub fn ptr_eq(this: &Self, other: &Self) -> bool {
97        triomphe::Arc::ptr_eq(&this.shared_reference.1.0, &other.shared_reference.1.0)
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.0);
112        (value_type.raw_cell)(shared_reference).into()
113    }
114}
115
116/// A trait that allows a value trait vc to be converted into a trait reference.
117///
118/// The signature is similar to `IntoFuture`, but we don't want trait vcs to
119/// have the same future-like semantics as value vcs when it comes to producing
120/// refs. This behavior is rarely needed, so in most cases, `.await`ing a trait
121/// vc is a mistake.
122pub trait IntoTraitRef {
123    type ValueTrait: VcValueTrait + ?Sized;
124    type Future: Future<Output = Result<<VcValueTraitCast<Self::ValueTrait> as VcCast>::Output>>;
125
126    fn into_trait_ref(self) -> Self::Future;
127}
128
129impl<T> IntoTraitRef for Vc<T>
130where
131    T: VcValueTrait + ?Sized,
132{
133    type ValueTrait = T;
134
135    type Future = ReadVcFuture<T, VcValueTraitCast<T>>;
136
137    fn into_trait_ref(self) -> Self::Future {
138        self.node.into_read().into()
139    }
140}