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