turbo_tasks/
macro_helpers.rs1pub use async_trait::async_trait;
4pub use bincode;
5pub use once_cell::sync::{Lazy, OnceCell};
6use rustc_hash::FxHashMap;
7pub use shrink_to_fit;
8pub use tracing;
9
10use crate::{
11 FxDashMap, NonLocalValue, RawVc, TaskInput, TaskPersistence, TraitTypeId, ValueType,
12 ValueTypeId, debug::ValueDebugFormatString,
13};
14pub use crate::{
15 global_name, inventory_submit,
16 magic_any::MagicAny,
17 manager::{find_cell_by_id, 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_argument_is_non_local_value<Argument: NonLocalValue>() {}
55
56#[macro_export]
57macro_rules! stringify_path {
58 ($path:path) => {
59 stringify!($path)
60 };
61}
62
63#[inline(always)]
66pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as std::ptr::Pointee>::Metadata {
67 std::ptr::metadata(ptr)
69}
70
71#[derive(Default)]
74pub struct VTableRegistry<T: ?Sized> {
75 map: FxHashMap<ValueTypeId, <T as std::ptr::Pointee>::Metadata>,
76}
77
78impl<T: ?Sized> VTableRegistry<T> {
79 pub fn new(id: TraitTypeId) -> Self {
80 let mut map = FxHashMap::default();
81 match TRAIT_CAST_FNS.remove(&id) {
82 Some((_, impls)) => {
83 for (value_type_id, RawPtr(raw_fn)) in impls {
84 let cast_fn: fn(*const ()) -> *const T = unsafe { std::mem::transmute(raw_fn) };
87 let ptr = cast_fn(std::ptr::null::<()>());
92 let metadata = std::ptr::metadata(ptr);
93 let prev = map.insert(value_type_id, metadata);
94 debug_assert!(
95 prev.is_none(),
96 "multiple cast functions registered for {value_type_id}"
97 )
98 }
99 }
100 None => {
101 }
103 }
104
105 Self { map }
106 }
107
108 pub(crate) fn cast(&self, id: ValueTypeId, raw: *const ()) -> *const T {
109 let metadata = self.map.get(&id).unwrap();
110 std::ptr::from_raw_parts(raw, *metadata)
111 }
112}
113
114struct RawPtr(*const ());
115unsafe impl Sync for RawPtr {}
117unsafe impl Send for RawPtr {}
118
119static TRAIT_CAST_FNS: Lazy<FxDashMap<TraitTypeId, Vec<(ValueTypeId, RawPtr)>>> = Lazy::new(|| {
121 let map: FxDashMap<TraitTypeId, Vec<(ValueTypeId, RawPtr)>> = FxDashMap::default();
122 for CollectableTraitCastFunctions(trait_id_fn, value_id_fn, cast_fn) in
123 inventory::iter::<CollectableTraitCastFunctions>
124 {
125 map.entry(trait_id_fn())
126 .or_default()
127 .value_mut()
128 .push((value_id_fn(), RawPtr(*cast_fn)));
129 }
130 map
131});
132
133pub struct CollectableTraitCastFunctions(
135 pub fn() -> TraitTypeId,
136 pub fn() -> ValueTypeId,
137 pub *const (),
138);
139unsafe impl Sync for CollectableTraitCastFunctions {}
141inventory::collect! {CollectableTraitCastFunctions}
142
143#[allow(clippy::type_complexity)]
144pub struct CollectableTraitMethods(
145 pub &'static str,
147 pub fn() -> (TraitTypeId, Vec<(&'static str, &'static NativeFunction)>),
148);
149inventory::collect! {CollectableTraitMethods}
150
151pub fn register_trait_methods(value: &mut ValueType) {
153 #[allow(clippy::type_complexity)]
154 static TRAIT_METHODS_BY_VALUE: Lazy<
155 FxDashMap<&'static str, Vec<(TraitTypeId, Vec<(&'static str, &'static NativeFunction)>)>>,
156 > = Lazy::new(|| {
157 let map: FxDashMap<&'static str, Vec<_>> = FxDashMap::default();
158 for CollectableTraitMethods(value_name, thunk) in inventory::iter::<CollectableTraitMethods>
159 {
160 map.entry(*value_name).or_default().push(thunk());
161 }
162 map
163 });
164 match TRAIT_METHODS_BY_VALUE.remove(value.global_name) {
165 Some((_, traits)) => {
166 for (trait_type_id, methods) in traits {
167 let trait_type = crate::registry::get_trait(trait_type_id);
168 value.register_trait(trait_type_id);
169 for (name, method) in methods {
170 value.register_trait_method(trait_type.get(name), method);
171 }
172 }
173 }
174 None => {
175 }
177 }
178}
179
180#[macro_export]
185macro_rules! inventory_submit {
186 ($($item:tt)*) => {
187 #[cfg(not(rust_analyzer))]
188 $crate::macro_helpers::inventory_submit_inner! { $($item)* }
189 }
190}
191
192#[doc(hidden)]
194pub use inventory::submit as inventory_submit_inner;
195
196#[cfg(not(rust_analyzer))] #[macro_export]
199macro_rules! global_name {
200 ($($item:tt)*) => {
201
202 ::std::concat!(::std::env!("CARGO_PKG_NAME"), "@", ::std::module_path!(), "::", $($item)*)
203 }
204}
205#[cfg(rust_analyzer)]
208#[macro_export]
209macro_rules! global_name {
210 ($($item:tt)*) => {
211 $($item)*
212 }
213}