turbo_tasks/
value_type.rs

1use std::{
2    any::{Any, type_name},
3    fmt::{self, Debug, Display, Formatter},
4    hash::Hash,
5    sync::Arc,
6};
7
8use auto_hash_map::{AutoMap, AutoSet};
9use serde::{Deserialize, Serialize};
10use tracing::Span;
11
12use crate::{
13    RawVc, VcValueType,
14    id::TraitTypeId,
15    macro_helpers::NativeFunction,
16    magic_any::{AnyDeserializeSeed, MagicAny, MagicAnyDeserializeSeed},
17    registry,
18    task::shared_reference::TypedSharedReference,
19    vc::VcCellMode,
20};
21
22type MagicSerializationFn = fn(&dyn MagicAny) -> &dyn erased_serde::Serialize;
23type AnySerializationFn = fn(&(dyn Any + Sync + Send)) -> &dyn erased_serde::Serialize;
24type RawCellFactoryFn = fn(TypedSharedReference) -> RawVc;
25
26// TODO this type need some refactoring when multiple languages are added to
27// turbo-task In this case a trait_method might be of a different function type.
28// It probably need to be a Vc<Function>.
29// That's also needed in a distributed world, where the function might be only
30// available on a remote instance.
31
32/// A definition of a type of data.
33///
34/// Contains a list of traits and trait methods that are available on that type.
35pub struct ValueType {
36    /// A readable name of the type
37    pub name: &'static str,
38    /// The fully qualitifed global name of the type.
39    pub global_name: &'static str,
40    /// Set of traits available
41    traits: AutoSet<TraitTypeId>,
42    /// List of trait methods available
43    trait_methods: AutoMap<&'static TraitMethod, &'static NativeFunction>,
44
45    /// Functors for serialization
46    magic_serialization: Option<(MagicSerializationFn, MagicAnyDeserializeSeed)>,
47    any_serialization: Option<(AnySerializationFn, AnyDeserializeSeed)>,
48
49    /// An implementation of
50    /// [`VcCellMode::raw_cell`][crate::vc::cell_mode::VcCellMode::raw_cell].
51    ///
52    /// Allows dynamically constructing a cell using the type id. Used inside of
53    /// [`RawVc`] where we have a type id, but not the concrete type `T` of
54    /// `Vc<T>`.
55    ///
56    /// Because we allow resolving `Vc<dyn Trait>`, it's otherwise not possible
57    /// for `RawVc` to know what the appropriate `VcCellMode` is.
58    pub(crate) raw_cell: RawCellFactoryFn,
59}
60
61impl Hash for ValueType {
62    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
63        (self as *const ValueType).hash(state);
64    }
65}
66
67impl Eq for ValueType {}
68
69impl PartialEq for ValueType {
70    fn eq(&self, other: &Self) -> bool {
71        std::ptr::eq(self, other)
72    }
73}
74
75impl Debug for ValueType {
76    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
77        let mut d = f.debug_struct("ValueType");
78        d.field("name", &self.name);
79        for trait_id in self.traits.iter() {
80            for (name, m) in &registry::get_trait(*trait_id).methods {
81                if self.trait_methods.contains_key(&m) {
82                    d.field(name, &"(trait fn)");
83                }
84            }
85        }
86        d.finish()
87    }
88}
89
90impl Display for ValueType {
91    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
92        f.write_str(self.name)
93    }
94}
95
96pub fn any_as_serialize<T: Any + Serialize + Send + Sync + 'static>(
97    this: &(dyn Any + Send + Sync),
98) -> &dyn erased_serde::Serialize {
99    if let Some(r) = this.downcast_ref::<T>() {
100        return r;
101    }
102    panic!(
103        "any_as_serialize::<{}> called with invalid type",
104        type_name::<T>()
105    );
106}
107
108impl ValueType {
109    /// This is internally used by `#[turbo_tasks::value]`
110    pub fn new<T: VcValueType>(global_name: &'static str) -> Self {
111        Self {
112            name: std::any::type_name::<T>(),
113            global_name,
114            traits: AutoSet::new(),
115            trait_methods: AutoMap::new(),
116            magic_serialization: None,
117            any_serialization: None,
118            raw_cell: <T::CellMode as VcCellMode<T>>::raw_cell,
119        }
120    }
121
122    /// This is internally used by `#[turbo_tasks::value]`
123    pub fn new_with_any_serialization<
124        T: VcValueType + Any + Serialize + for<'de> Deserialize<'de>,
125    >(
126        global_name: &'static str,
127    ) -> Self {
128        Self {
129            name: std::any::type_name::<T>(),
130            global_name,
131            traits: AutoSet::new(),
132            trait_methods: AutoMap::new(),
133            magic_serialization: None,
134            any_serialization: Some((any_as_serialize::<T>, AnyDeserializeSeed::new::<T>())),
135            raw_cell: <T::CellMode as VcCellMode<T>>::raw_cell,
136        }
137    }
138
139    pub fn magic_as_serializable<'a>(
140        &self,
141        arc: &'a Arc<dyn MagicAny>,
142    ) -> Option<&'a dyn erased_serde::Serialize> {
143        if let Some(s) = self.magic_serialization {
144            let r: &dyn MagicAny = arc;
145            Some((s.0)(r))
146        } else {
147            None
148        }
149    }
150
151    pub fn any_as_serializable<'a>(
152        &self,
153        arc: &'a triomphe::Arc<dyn Any + Sync + Send>,
154    ) -> Option<&'a dyn erased_serde::Serialize> {
155        if let Some(s) = self.any_serialization {
156            Some((s.0)(&**arc))
157        } else {
158            None
159        }
160    }
161
162    pub fn is_serializable(&self) -> bool {
163        self.any_serialization.is_some()
164    }
165
166    pub fn get_magic_deserialize_seed(&self) -> Option<MagicAnyDeserializeSeed> {
167        self.magic_serialization.map(|s| s.1)
168    }
169
170    pub fn get_any_deserialize_seed(&self) -> Option<AnyDeserializeSeed> {
171        self.any_serialization.map(|s| s.1)
172    }
173
174    pub(crate) fn register_trait_method(
175        &mut self,
176        trait_method: &'static TraitMethod,
177        native_fn: &'static NativeFunction,
178    ) {
179        self.trait_methods.insert(trait_method, native_fn);
180    }
181
182    pub fn get_trait_method(
183        &self,
184        trait_method: &'static TraitMethod,
185    ) -> Option<&'static NativeFunction> {
186        match self.trait_methods.get(trait_method) {
187            Some(f) => Some(*f),
188            None => trait_method.default_method,
189        }
190    }
191
192    pub(crate) fn register_trait(&mut self, trait_type: TraitTypeId) {
193        self.traits.insert(trait_type);
194    }
195
196    pub fn has_trait(&self, trait_type: &TraitTypeId) -> bool {
197        self.traits.contains(trait_type)
198    }
199
200    pub fn traits_iter(&self) -> impl Iterator<Item = TraitTypeId> + '_ {
201        self.traits.iter().cloned()
202    }
203}
204
205// A collectable struct for value types
206pub struct CollectableValueType(pub &'static once_cell::sync::Lazy<ValueType>);
207
208inventory::collect! {CollectableValueType}
209
210pub struct TraitMethod {
211    pub(crate) trait_name: &'static str,
212    pub(crate) method_name: &'static str,
213    pub(crate) default_method: Option<&'static NativeFunction>,
214}
215impl Hash for TraitMethod {
216    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
217        (self as *const TraitMethod).hash(state);
218    }
219}
220
221impl Eq for TraitMethod {}
222
223impl PartialEq for TraitMethod {
224    fn eq(&self, other: &Self) -> bool {
225        std::ptr::eq(self, other)
226    }
227}
228impl Debug for TraitMethod {
229    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
230        f.debug_struct("TraitMethod")
231            .field("trait_name", &self.trait_name)
232            .field("name", &self.method_name)
233            .field("default_method", &self.default_method)
234            .finish()
235    }
236}
237impl TraitMethod {
238    pub(crate) fn resolve_span(&self) -> Span {
239        tracing::trace_span!(
240            "turbo_tasks::resolve_trait_call",
241            name = format_args!("{}::{}", &self.trait_name, &self.method_name),
242        )
243    }
244}
245
246#[derive(Debug)]
247pub struct TraitType {
248    pub name: &'static str,
249    pub global_name: &'static str,
250    pub(crate) methods: AutoMap<&'static str, TraitMethod>,
251}
252
253impl Hash for TraitType {
254    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
255        (self as *const TraitType).hash(state);
256    }
257}
258
259impl Display for TraitType {
260    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
261        write!(f, "trait {}", self.name)
262    }
263}
264
265impl Eq for TraitType {}
266
267impl PartialEq for TraitType {
268    fn eq(&self, other: &Self) -> bool {
269        std::ptr::eq(self, other)
270    }
271}
272
273impl TraitType {
274    pub fn new(
275        name: &'static str,
276        global_name: &'static str,
277        trait_methods: Vec<(&'static str, Option<&'static NativeFunction>)>,
278    ) -> Self {
279        let mut methods = AutoMap::new();
280        for (method_name, default_method) in trait_methods {
281            let prev = methods.insert(
282                method_name,
283                TraitMethod {
284                    trait_name: name,
285                    method_name,
286                    default_method,
287                },
288            );
289            debug_assert!(
290                prev.is_none(),
291                "duplicate methods {method_name} registered on {global_name}"
292            );
293        }
294        Self {
295            name,
296            global_name,
297            methods,
298        }
299    }
300
301    pub fn get(&self, name: &str) -> &TraitMethod {
302        self.methods.get(name).unwrap()
303    }
304}
305
306pub struct CollectableTrait(pub &'static once_cell::sync::Lazy<TraitType>);
307
308inventory::collect! {CollectableTrait}