turbo_tasks/
value_type.rs

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