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
20pub struct ValueType {
30 pub name: &'static str,
32 pub global_name: &'static str,
34 traits: AutoSet<TraitTypeId>,
36 trait_methods: AutoMap<&'static TraitMethod, &'static NativeFunction>,
38
39 any_serialization: Option<(AnySerializationFn, AnyDeserializeSeed)>,
41
42 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 ®istry::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 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 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
180pub 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}