turbo_tasks/
value_type.rs

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