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, VcValueType, id::TraitTypeId, macro_helpers::NativeFunction,
13 magic_any::any_as_encode, registry, task::shared_reference::TypedSharedReference,
14 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 pub fn traits_iter(&self) -> impl Iterator<Item = TraitTypeId> + '_ {
197 self.traits.iter().cloned()
198 }
199}
200
201pub struct CollectableValueType(pub &'static once_cell::sync::Lazy<ValueType>);
203
204inventory::collect! {CollectableValueType}
205
206pub struct TraitMethod {
207 pub(crate) trait_name: &'static str,
208 pub(crate) method_name: &'static str,
209 pub(crate) default_method: Option<&'static NativeFunction>,
210}
211impl Hash for TraitMethod {
212 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
213 (self as *const TraitMethod).hash(state);
214 }
215}
216
217impl Eq for TraitMethod {}
218
219impl PartialEq for TraitMethod {
220 fn eq(&self, other: &Self) -> bool {
221 std::ptr::eq(self, other)
222 }
223}
224impl Debug for TraitMethod {
225 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
226 f.debug_struct("TraitMethod")
227 .field("trait_name", &self.trait_name)
228 .field("name", &self.method_name)
229 .field("default_method", &self.default_method)
230 .finish()
231 }
232}
233impl TraitMethod {
234 pub(crate) fn resolve_span(&self) -> Span {
235 tracing::trace_span!(
236 "turbo_tasks::resolve_trait_call",
237 name = format_args!("{}::{}", &self.trait_name, &self.method_name),
238 )
239 }
240}
241
242#[derive(Debug)]
243pub struct TraitType {
244 pub name: &'static str,
245 pub global_name: &'static str,
246 pub(crate) methods: AutoMap<&'static str, TraitMethod>,
247}
248
249impl Hash for TraitType {
250 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
251 (self as *const TraitType).hash(state);
252 }
253}
254
255impl Display for TraitType {
256 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
257 write!(f, "trait {}", self.name)
258 }
259}
260
261impl Eq for TraitType {}
262
263impl PartialEq for TraitType {
264 fn eq(&self, other: &Self) -> bool {
265 std::ptr::eq(self, other)
266 }
267}
268
269impl TraitType {
270 pub fn new(
271 name: &'static str,
272 global_name: &'static str,
273 trait_methods: Vec<(&'static str, Option<&'static NativeFunction>)>,
274 ) -> Self {
275 let mut methods = AutoMap::new();
276 for (method_name, default_method) in trait_methods {
277 let prev = methods.insert(
278 method_name,
279 TraitMethod {
280 trait_name: name,
281 method_name,
282 default_method,
283 },
284 );
285 debug_assert!(
286 prev.is_none(),
287 "duplicate methods {method_name} registered on {global_name}"
288 );
289 }
290 Self {
291 name,
292 global_name,
293 methods,
294 }
295 }
296
297 pub fn get(&self, name: &str) -> &TraitMethod {
298 self.methods.get(name).unwrap()
299 }
300}
301
302pub struct CollectableTrait(pub &'static once_cell::sync::Lazy<TraitType>);
303
304inventory::collect! {CollectableTrait}