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
26pub struct ValueType {
36 pub name: &'static str,
38 pub global_name: &'static str,
40 traits: AutoSet<TraitTypeId>,
42 trait_methods: AutoMap<&'static TraitMethod, &'static NativeFunction>,
44
45 magic_serialization: Option<(MagicSerializationFn, MagicAnyDeserializeSeed)>,
47 any_serialization: Option<(AnySerializationFn, AnyDeserializeSeed)>,
48
49 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 ®istry::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 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 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
205pub 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}