1use std::{
2 fmt::{self, Debug, Display, Formatter},
3 hash::Hash,
4};
5
6use auto_hash_map::{AutoMap, AutoSet};
7use bincode::{Decode, Encode};
8use tracing::Span;
9use turbo_bincode::{AnyDecodeFn, AnyEncodeFn};
10
11use crate::{
12 RawVc, SharedReference, TaskPriority, VcValueType, id::TraitTypeId,
13 macro_helpers::NativeFunction, magic_any::any_as_encode, registry,
14 task::shared_reference::TypedSharedReference, vc::VcCellMode,
15};
16
17type RawCellFactoryFn = fn(TypedSharedReference) -> RawVc;
18
19pub struct ValueType {
29 pub name: &'static str,
31 pub global_name: &'static str,
33 traits: AutoSet<TraitTypeId>,
35 trait_methods: AutoMap<&'static TraitMethod, &'static NativeFunction>,
37
38 pub bincode: Option<(AnyEncodeFn, AnyDecodeFn<SharedReference>)>,
40
41 pub(crate) raw_cell: RawCellFactoryFn,
51}
52
53impl Hash for ValueType {
54 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
55 (self as *const ValueType).hash(state);
56 }
57}
58
59impl Eq for ValueType {}
60
61impl PartialEq for ValueType {
62 fn eq(&self, other: &Self) -> bool {
63 std::ptr::eq(self, other)
64 }
65}
66
67impl Debug for ValueType {
68 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
69 let mut d = f.debug_struct("ValueType");
70 d.field("name", &self.name);
71 for trait_id in self.traits.iter() {
72 for (name, m) in ®istry::get_trait(*trait_id).methods {
73 if self.trait_methods.contains_key(&m) {
74 d.field(name, &"(trait fn)");
75 }
76 }
77 }
78 d.finish()
79 }
80}
81
82impl Display for ValueType {
83 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
84 f.write_str(self.name)
85 }
86}
87
88pub trait ManualEncodeWrapper: Encode {
89 type Value;
90
91 fn new<'a>(value: &'a Self::Value) -> impl Encode + 'a;
93}
94
95pub trait ManualDecodeWrapper: Decode<()> {
96 type Value;
97
98 fn inner(self) -> Self::Value;
99}
100
101impl ValueType {
102 pub fn new<T: VcValueType>(global_name: &'static str) -> Self {
104 Self::new_inner::<T>(global_name, None)
105 }
106
107 pub fn new_with_bincode<T: VcValueType + Encode + Decode<()>>(
109 global_name: &'static str,
110 ) -> Self {
111 Self::new_inner::<T>(
112 global_name,
113 Some((
114 |this, enc| {
115 T::encode(any_as_encode::<T>(this), enc)?;
116 Ok(())
117 },
118 |dec| {
119 let val = T::decode(dec)?;
120 Ok(SharedReference::new(triomphe::Arc::new(val)))
121 },
122 )),
123 )
124 }
125
126 pub fn new_with_bincode_wrappers<
134 T: VcValueType,
135 E: ManualEncodeWrapper<Value = T>,
136 D: ManualDecodeWrapper<Value = T>,
137 >(
138 global_name: &'static str,
139 ) -> Self {
140 Self::new_inner::<T>(
141 global_name,
142 Some((
143 |this, enc| {
144 E::new(any_as_encode::<T>(this)).encode(enc)?;
145 Ok(())
146 },
147 |dec| {
148 let val = D::inner(D::decode(dec)?);
149 Ok(SharedReference::new(triomphe::Arc::new(val)))
150 },
151 )),
152 )
153 }
154
155 fn new_inner<T: VcValueType>(
157 global_name: &'static str,
158 bincode: Option<(AnyEncodeFn, AnyDecodeFn<SharedReference>)>,
159 ) -> Self {
160 Self {
161 name: std::any::type_name::<T>(),
162 global_name,
163 traits: AutoSet::new(),
164 trait_methods: AutoMap::new(),
165 bincode,
166 raw_cell: <T::CellMode as VcCellMode<T>>::raw_cell,
167 }
168 }
169
170 pub(crate) fn register_trait_method(
171 &mut self,
172 trait_method: &'static TraitMethod,
173 native_fn: &'static NativeFunction,
174 ) {
175 self.trait_methods.insert(trait_method, native_fn);
176 }
177
178 pub fn get_trait_method(
179 &self,
180 trait_method: &'static TraitMethod,
181 ) -> Option<&'static NativeFunction> {
182 match self.trait_methods.get(trait_method) {
183 Some(f) => Some(*f),
184 None => trait_method.default_method,
185 }
186 }
187
188 pub(crate) fn register_trait(&mut self, trait_type: TraitTypeId) {
189 self.traits.insert(trait_type);
190 }
191
192 pub fn has_trait(&self, trait_type: &TraitTypeId) -> bool {
193 self.traits.contains(trait_type)
194 }
195}
196
197pub struct CollectableValueType(pub &'static once_cell::sync::Lazy<ValueType>);
199
200inventory::collect! {CollectableValueType}
201
202pub struct TraitMethod {
203 pub(crate) trait_name: &'static str,
204 pub(crate) method_name: &'static str,
205 pub(crate) default_method: Option<&'static NativeFunction>,
206}
207impl Hash for TraitMethod {
208 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
209 (self as *const TraitMethod).hash(state);
210 }
211}
212
213impl Eq for TraitMethod {}
214
215impl PartialEq for TraitMethod {
216 fn eq(&self, other: &Self) -> bool {
217 std::ptr::eq(self, other)
218 }
219}
220impl Debug for TraitMethod {
221 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
222 f.debug_struct("TraitMethod")
223 .field("trait_name", &self.trait_name)
224 .field("name", &self.method_name)
225 .field("default_method", &self.default_method)
226 .finish()
227 }
228}
229impl TraitMethod {
230 pub(crate) fn resolve_span(&self, priority: TaskPriority) -> Span {
231 tracing::trace_span!(
232 "turbo_tasks::resolve_trait_call",
233 name = format_args!("{}::{}", &self.trait_name, &self.method_name),
234 priority = %priority,
235 )
236 }
237}
238
239#[derive(Debug)]
240pub struct TraitType {
241 pub name: &'static str,
242 pub global_name: &'static str,
243 pub(crate) methods: AutoMap<&'static str, TraitMethod>,
244}
245
246impl Hash for TraitType {
247 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
248 (self as *const TraitType).hash(state);
249 }
250}
251
252impl Display for TraitType {
253 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
254 write!(f, "trait {}", self.name)
255 }
256}
257
258impl Eq for TraitType {}
259
260impl PartialEq for TraitType {
261 fn eq(&self, other: &Self) -> bool {
262 std::ptr::eq(self, other)
263 }
264}
265
266impl TraitType {
267 pub fn new(
268 name: &'static str,
269 global_name: &'static str,
270 trait_methods: Vec<(&'static str, Option<&'static NativeFunction>)>,
271 ) -> Self {
272 let mut methods = AutoMap::new();
273 for (method_name, default_method) in trait_methods {
274 let prev = methods.insert(
275 method_name,
276 TraitMethod {
277 trait_name: name,
278 method_name,
279 default_method,
280 },
281 );
282 debug_assert!(
283 prev.is_none(),
284 "duplicate methods {method_name} registered on {global_name}"
285 );
286 }
287 Self {
288 name,
289 global_name,
290 methods,
291 }
292 }
293
294 pub fn get(&self, name: &str) -> &TraitMethod {
295 self.methods.get(name).unwrap()
296 }
297}
298
299pub struct CollectableTrait(pub &'static once_cell::sync::Lazy<TraitType>);
300
301inventory::collect! {CollectableTrait}