turbo_tasks/
macro_helpers.rs1pub use async_trait::async_trait;
4pub use once_cell::sync::{Lazy, OnceCell};
5use rustc_hash::FxHashMap;
6pub use serde;
7pub use shrink_to_fit;
8pub use tracing;
9
10use crate::{
11 FxDashMap, NonLocalValue, RawVc, TaskInput, TaskPersistence, TraitTypeId, ValueType,
12 ValueTypeId, Vc, debug::ValueDebugFormatString, task::TaskOutput,
13};
14pub use crate::{
15 global_name, inventory_submit,
16 magic_any::MagicAny,
17 manager::{find_cell_by_type, spawn_detached_for_testing},
18 native_function::{
19 CollectableFunction, NativeFunction, downcast_args_owned, downcast_args_ref,
20 },
21 value_type::{CollectableTrait, CollectableValueType},
22};
23
24#[inline(never)]
25pub async fn value_debug_format_field(value: ValueDebugFormatString<'_>) -> String {
26 match value.try_to_value_debug_string().await {
27 Ok(result) => match result.await {
28 Ok(result) => result.to_string(),
29 Err(err) => format!("{err:?}"),
30 },
31 Err(err) => format!("{err:?}"),
32 }
33}
34
35pub fn get_persistence_from_inputs(inputs: &impl TaskInput) -> TaskPersistence {
36 if inputs.is_transient() {
37 TaskPersistence::Transient
38 } else {
39 TaskPersistence::Persistent
40 }
41}
42
43pub fn get_persistence_from_inputs_and_this(
44 this: RawVc,
45 inputs: &impl TaskInput,
46) -> TaskPersistence {
47 if this.is_transient() || inputs.is_transient() {
48 TaskPersistence::Transient
49 } else {
50 TaskPersistence::Persistent
51 }
52}
53
54pub fn assert_returns_non_local_value<ReturnType, Rv>()
55where
56 ReturnType: TaskOutput<Return = Vc<Rv>>,
57 Rv: NonLocalValue + Send,
58{
59}
60
61pub fn assert_argument_is_non_local_value<Argument: NonLocalValue>() {}
62
63#[macro_export]
64macro_rules! stringify_path {
65 ($path:path) => {
66 stringify!($path)
67 };
68}
69
70#[inline(always)]
73pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as std::ptr::Pointee>::Metadata {
74 std::ptr::metadata(ptr)
76}
77
78#[derive(Default)]
81pub struct VTableRegistry<T: ?Sized> {
82 map: FxHashMap<ValueTypeId, <T as std::ptr::Pointee>::Metadata>,
83}
84
85impl<T: ?Sized> VTableRegistry<T> {
86 pub fn new(id: TraitTypeId) -> Self {
87 let mut map = FxHashMap::default();
88 match TRAIT_CAST_FNS.remove(&id) {
89 Some((_, impls)) => {
90 for (value_type_id, RawPtr(raw_fn)) in impls {
91 let cast_fn: fn(*const ()) -> *const T = unsafe { std::mem::transmute(raw_fn) };
94 let ptr = cast_fn(std::ptr::null::<()>());
99 let metadata = std::ptr::metadata(ptr);
100 let prev = map.insert(value_type_id, metadata);
101 debug_assert!(
102 prev.is_none(),
103 "multiple cast functions registered for {value_type_id}"
104 )
105 }
106 }
107 None => {
108 }
110 }
111
112 Self { map }
113 }
114
115 pub(crate) fn cast(&self, id: ValueTypeId, raw: *const ()) -> *const T {
116 let metadata = self.map.get(&id).unwrap();
117 std::ptr::from_raw_parts(raw, *metadata)
118 }
119}
120
121struct RawPtr(*const ());
122unsafe impl Sync for RawPtr {}
124unsafe impl Send for RawPtr {}
125
126static TRAIT_CAST_FNS: Lazy<FxDashMap<TraitTypeId, Vec<(ValueTypeId, RawPtr)>>> = Lazy::new(|| {
128 let map: FxDashMap<TraitTypeId, Vec<(ValueTypeId, RawPtr)>> = FxDashMap::default();
129 for CollectableTraitCastFunctions(trait_id_fn, value_id_fn, cast_fn) in
130 inventory::iter::<CollectableTraitCastFunctions>
131 {
132 map.entry(trait_id_fn())
133 .or_default()
134 .value_mut()
135 .push((value_id_fn(), RawPtr(*cast_fn)));
136 }
137 map
138});
139
140pub struct CollectableTraitCastFunctions(
142 pub fn() -> TraitTypeId,
143 pub fn() -> ValueTypeId,
144 pub *const (),
145);
146unsafe impl Sync for CollectableTraitCastFunctions {}
148inventory::collect! {CollectableTraitCastFunctions}
149
150#[allow(clippy::type_complexity)]
151pub struct CollectableTraitMethods(
152 pub &'static str,
154 pub fn() -> (TraitTypeId, Vec<(&'static str, &'static NativeFunction)>),
155);
156inventory::collect! {CollectableTraitMethods}
157
158pub fn register_trait_methods(value: &mut ValueType) {
160 #[allow(clippy::type_complexity)]
161 static TRAIT_METHODS_BY_VALUE: Lazy<
162 FxDashMap<&'static str, Vec<(TraitTypeId, Vec<(&'static str, &'static NativeFunction)>)>>,
163 > = Lazy::new(|| {
164 let map: FxDashMap<&'static str, Vec<_>> = FxDashMap::default();
165 for CollectableTraitMethods(value_name, thunk) in inventory::iter::<CollectableTraitMethods>
166 {
167 map.entry(*value_name).or_default().push(thunk());
168 }
169 map
170 });
171 match TRAIT_METHODS_BY_VALUE.remove(value.global_name) {
172 Some((_, traits)) => {
173 for (trait_type_id, methods) in traits {
174 let trait_type = crate::registry::get_trait(trait_type_id);
175 value.register_trait(trait_type_id);
176 for (name, method) in methods {
177 value.register_trait_method(trait_type.get(name), method);
178 }
179 }
180 }
181 None => {
182 }
184 }
185}
186
187#[macro_export]
192macro_rules! inventory_submit {
193 ($($item:tt)*) => {
194 #[cfg(not(rust_analyzer))]
195 $crate::macro_helpers::inventory_submit_inner! { $($item)* }
196 }
197}
198
199#[doc(hidden)]
201pub use inventory::submit as inventory_submit_inner;
202
203#[cfg(not(rust_analyzer))] #[macro_export]
206macro_rules! global_name {
207 ($($item:tt)*) => {
208
209 ::std::concat!(::std::env!("CARGO_PKG_NAME"), "@", ::std::module_path!(), "::", $($item)*)
210 }
211}
212#[cfg(rust_analyzer)]
215#[macro_export]
216macro_rules! global_name {
217 ($($item:tt)*) => {
218 $($item)*
219 }
220}